VirtualBox

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

Last change on this file since 18145 was 16555, checked in by vboxsync, 16 years ago

export

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