VirtualBox

source: vbox/trunk/src/VBox/Main/glue/EventQueue.cpp@ 46649

最後變更 在這個檔案從46649是 46649,由 vboxsync 提交於 12 年 前

Forward ported r85941 and required build fixes (Main: Implemented new event queue to separate system's native event queue and our own. Also, XPCOM is not needed for handling our own events. On Windows this also fixes the system's queue quota limitation).

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 5.6 KB
 
1/* $Id: EventQueue.cpp 46649 2013-06-19 11:47:32Z vboxsync $ */
2/** @file
3 * Event queue class declaration.
4 */
5
6/*
7 * Copyright (C) 2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** @todo Adapt / update documentation! */
19
20#include "VBox/com/EventQueue.h"
21
22#include <iprt/asm.h>
23#include <new> /* For bad_alloc. */
24
25#include <iprt/err.h>
26#include <iprt/semaphore.h>
27#include <iprt/time.h>
28#include <iprt/thread.h>
29#include <iprt/log.h>
30
31namespace com
32{
33
34// EventQueue class
35////////////////////////////////////////////////////////////////////////////////
36
37EventQueue::EventQueue(void)
38 : mShutdown(false)
39{
40 int rc = RTCritSectInit(&mCritSect);
41 AssertRC(rc);
42
43 rc = RTSemEventCreate(&mSemEvent);
44 AssertRC(rc);
45}
46
47EventQueue::~EventQueue(void)
48{
49 int rc = RTCritSectDelete(&mCritSect);
50 AssertRC(rc);
51
52 rc = RTSemEventDestroy(mSemEvent);
53 AssertRC(rc);
54
55 EventQueueListIterator it = mEvents.begin();
56 while (it != mEvents.end())
57 {
58 (*it)->Release();
59 it = mEvents.erase(it);
60 }
61}
62
63/**
64 * Process events pending on this event queue, and wait up to given timeout, if
65 * nothing is available.
66 *
67 * Must be called on same thread this event queue was created on.
68 *
69 * @param cMsTimeout The timeout specified as milliseconds. Use
70 * RT_INDEFINITE_WAIT to wait till an event is posted on the
71 * queue.
72 *
73 * @returns VBox status code
74 * @retval VINF_SUCCESS if one or more messages was processed.
75 * @retval VERR_TIMEOUT if cMsTimeout expired.
76 * @retval VERR_INVALID_CONTEXT if called on the wrong thread.
77 * @retval VERR_INTERRUPTED if interruptEventQueueProcessing was called.
78 * On Windows will also be returned when WM_QUIT is encountered.
79 * On Darwin this may also be returned when the native queue is
80 * stopped or destroyed/finished.
81 * @retval VINF_INTERRUPTED if the native system call was interrupted by a
82 * an asynchronous event delivery (signal) or just felt like returning
83 * out of bounds. On darwin it will also be returned if the queue is
84 * stopped.
85 */
86int EventQueue::processEventQueue(RTMSINTERVAL cMsTimeout)
87{
88 bool fWait;
89 int rc = RTCritSectEnter(&mCritSect);
90 if (RT_SUCCESS(rc))
91 {
92 fWait = mEvents.size() == 0;
93 if (!fWait)
94 {
95 int rc2 = RTCritSectLeave(&mCritSect);
96 AssertRC(rc2);
97 }
98 }
99
100 if (fWait)
101 {
102 int rc2 = RTCritSectLeave(&mCritSect);
103 AssertRC(rc2);
104
105 rc = RTSemEventWaitNoResume(mSemEvent, cMsTimeout);
106 }
107
108 if (RT_SUCCESS(rc))
109 {
110 if (ASMAtomicReadBool(&mShutdown))
111 return VERR_INTERRUPTED;
112
113 if (fWait)
114 rc = RTCritSectEnter(&mCritSect);
115 if (RT_SUCCESS(rc))
116 {
117 EventQueueListIterator it = mEvents.begin();
118 if (it != mEvents.end())
119 {
120 Event *pEvent = *it;
121 AssertPtr(pEvent);
122
123 mEvents.erase(it);
124
125 int rc2 = RTCritSectLeave(&mCritSect);
126 if (RT_SUCCESS(rc))
127 rc = rc2;
128
129 pEvent->handler();
130 pEvent->Release();
131 }
132 else
133 {
134 int rc2 = RTCritSectLeave(&mCritSect);
135 if (RT_SUCCESS(rc))
136 rc = rc2;
137 }
138 }
139 }
140
141 Assert(rc != VERR_TIMEOUT || cMsTimeout != RT_INDEFINITE_WAIT);
142 return rc;
143}
144
145/**
146 * Interrupt thread waiting on event queue processing.
147 *
148 * Can be called on any thread.
149 *
150 * @returns VBox status code.
151 */
152int EventQueue::interruptEventQueueProcessing(void)
153{
154 ASMAtomicWriteBool(&mShutdown, true);
155
156 return RTSemEventSignal(mSemEvent);
157}
158
159/**
160 * Posts an event to this event loop asynchronously.
161 *
162 * @param event the event to post, must be allocated using |new|
163 * @return TRUE if successful and false otherwise
164 */
165BOOL EventQueue::postEvent(Event *pEvent)
166{
167 int rc = RTCritSectEnter(&mCritSect);
168 if (RT_SUCCESS(rc))
169 {
170 try
171 {
172 if (pEvent)
173 {
174 pEvent->AddRef();
175 mEvents.push_back(pEvent);
176 }
177 else /* No locking, since we're already in our crit sect. */
178 mShutdown = true;
179
180 size_t cEvents = mEvents.size();
181 if (cEvents > _1K) /** @todo Make value configurable? */
182 {
183 static int s_cBitchedAboutLotEvents = 0;
184 if (s_cBitchedAboutLotEvents < 10)
185 LogRel(("Warning: Event queue received lots of events (%zu), expect delayed event handling (%d/10)\n",
186 cEvents, ++s_cBitchedAboutLotEvents));
187 }
188
189 /* Leave critical section before signalling event. */
190 rc = RTCritSectLeave(&mCritSect);
191 if (RT_SUCCESS(rc))
192 {
193 int rc2 = RTSemEventSignal(mSemEvent);
194 AssertRC(rc2);
195 }
196 }
197 catch (std::bad_alloc &ba)
198 {
199 NOREF(ba);
200 rc = VERR_NO_MEMORY;
201 }
202
203 if (RT_FAILURE(rc))
204 {
205 int rc2 = RTCritSectLeave(&mCritSect);
206 AssertRC(rc2);
207 }
208 }
209
210 return RT_SUCCESS(rc) ? TRUE : FALSE;
211}
212
213}
214/* namespace com */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette