VirtualBox

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

Last change on this file since 7692 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.4 KB
Line 
1/** @file
2 *
3 * MS COM / XPCOM Abstraction Layer:
4 * Event and EventQueue class declaration
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "VBox/com/EventQueue.h"
20
21namespace com
22{
23
24// EventQueue class
25////////////////////////////////////////////////////////////////////////////////
26
27#if defined (RT_OS_WINDOWS)
28
29#define CHECK_THREAD_RET(ret) \
30 do { \
31 AssertMsg (GetCurrentThreadId() == mThreadId, ("Must be on event queue thread!")); \
32 if (GetCurrentThreadId() != mThreadId) \
33 return ret; \
34 } while (0)
35
36#else // !defined (RT_OS_WINDOWS)
37
38#define CHECK_THREAD_RET(ret) \
39 do { \
40 if (!mEventQ) \
41 return ret; \
42 BOOL isOnCurrentThread = FALSE; \
43 mEventQ->IsOnCurrentThread (&isOnCurrentThread); \
44 AssertMsg (isOnCurrentThread, ("Must be on event queue thread!")); \
45 if (!isOnCurrentThread) \
46 return ret; \
47 } while (0)
48
49#endif // !defined (RT_OS_WINDOWS)
50
51/**
52 * Constructs an event queue for the current thread.
53 *
54 * Currently, there can be only one event queue per thread, so if an event
55 * queue for the current thread already exists, this object is simply attached
56 * to the existing event queue.
57 */
58EventQueue::EventQueue()
59{
60#if defined (RT_OS_WINDOWS)
61
62 mThreadId = GetCurrentThreadId();
63 // force the system to create the message queue for the current thread
64 MSG msg;
65 PeekMessage (&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
66
67#else
68
69 mEQCreated = FALSE;
70
71 mLastEvent = NULL;
72 mGotEvent = FALSE;
73
74 // Here we reference the global nsIEventQueueService instance and hold it
75 // until we're destroyed. This is necessary to keep NS_ShutdownXPCOM() away
76 // from calling StopAcceptingEvents() on all event queues upon destruction of
77 // nsIEventQueueService, and makes sense when, for some reason, this happens
78 // *before* we're able to send a NULL event to stop our event handler thread
79 // when doing unexpected cleanup caused indirectly by NS_ShutdownXPCOM()
80 // that is performing a global cleanup of everything. A good example of such
81 // situation is when NS_ShutdownXPCOM() is called while the VirtualBox component
82 // is still alive (because it is still referenced): eventually, it results in
83 // a VirtualBox::uninit() call from where it is already not possible to post
84 // NULL to the event thread (because it stopped accepting events).
85
86 nsresult rc = NS_GetEventQueueService (getter_AddRefs (mEventQService));
87
88 if (NS_SUCCEEDED (rc))
89 {
90 rc = mEventQService->GetThreadEventQueue (NS_CURRENT_THREAD,
91 getter_AddRefs (mEventQ));
92 if (rc == NS_ERROR_NOT_AVAILABLE)
93 {
94 rc = mEventQService->CreateMonitoredThreadEventQueue();
95 if (NS_SUCCEEDED (rc))
96 {
97 mEQCreated = TRUE;
98 rc = mEventQService->GetThreadEventQueue (NS_CURRENT_THREAD,
99 getter_AddRefs (mEventQ));
100 }
101 }
102 }
103 AssertComRC (rc);
104
105#endif
106}
107
108EventQueue::~EventQueue()
109{
110#if defined (RT_OS_WINDOWS)
111#else
112 // process all pending events before destruction
113 if (mEventQ)
114 {
115 if (mEQCreated)
116 {
117 mEventQ->StopAcceptingEvents();
118 mEventQ->ProcessPendingEvents();
119 mEventQService->DestroyThreadEventQueue();
120 }
121 mEventQ = nsnull;
122 mEventQService = nsnull;
123 }
124#endif
125}
126
127/**
128 * Posts an event to this event loop asynchronously.
129 *
130 * @param event the event to post, must be allocated using |new|
131 * @return TRUE if successful and false otherwise
132 */
133BOOL EventQueue::postEvent (Event *event)
134{
135#if defined (RT_OS_WINDOWS)
136
137 return PostThreadMessage (mThreadId, WM_USER, (WPARAM) event, NULL);
138
139#else
140
141 if (!mEventQ)
142 return FALSE;
143
144 MyPLEvent *ev = new MyPLEvent (event);
145 mEventQ->InitEvent (ev, this, plEventHandler, plEventDestructor);
146 HRESULT rc = mEventQ->PostEvent (ev);
147 return NS_SUCCEEDED (rc);
148
149#endif
150}
151
152/**
153 * Waits for a single event.
154 * This method must be called on the same thread where this event queue
155 * is created.
156 *
157 * After this method returns TRUE and non-NULL event, the caller should call
158 * #handleEvent() in order to process the returned event (otherwise the event
159 * is just removed from the queue, but not processed).
160 *
161 * There is a special case when the returned event is NULL (and the method
162 * returns TRUE), meaning that this event queue must finish its execution
163 * (i.e., quit the event loop),
164 *
165 * @param event next event removed from the queue
166 * @return TRUE if successful and false otherwise
167 */
168BOOL EventQueue::waitForEvent (Event **event)
169{
170 Assert (event);
171 if (!event)
172 return FALSE;
173
174 *event = NULL;
175
176 CHECK_THREAD_RET (FALSE);
177
178#if defined (RT_OS_WINDOWS)
179
180 MSG msg;
181 BOOL rc = GetMessage (&msg, NULL, WM_USER, WM_USER);
182 // check for error
183 if (rc == -1)
184 return FALSE;
185 // check for WM_QUIT
186 if (!rc)
187 return TRUE;
188
189 // retrieve our event
190 *event = (Event *) msg.wParam;
191
192#else
193
194 PLEvent *ev = NULL;
195 HRESULT rc;
196
197 mGotEvent = FALSE;
198
199 do
200 {
201 rc = mEventQ->WaitForEvent (&ev);
202 // check for error
203 if (FAILED (rc))
204 return FALSE;
205 // check for EINTR signal
206 if (!ev)
207 return TRUE;
208
209 // run PLEvent handler. This will just set mLastEvent if it is an
210 // MyPLEvent instance, and then delete ev.
211 mEventQ->HandleEvent (ev);
212 }
213 while (!mGotEvent);
214
215 // retrieve our event
216 *event = mLastEvent;
217
218#endif
219
220 return TRUE;
221}
222
223/**
224 * Handles the given event and |delete|s it.
225 * This method must be called on the same thread where this event queue
226 * is created.
227 */
228BOOL EventQueue::handleEvent (Event *event)
229{
230 Assert (event);
231 if (!event)
232 return FALSE;
233
234 CHECK_THREAD_RET (FALSE);
235
236 event->handler();
237 delete event;
238
239 return TRUE;
240}
241
242} /* namespace com */
243
Note: See TracBrowser for help on using the repository browser.

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