VirtualBox

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

Last change on this file since 2397 was 1, checked in by vboxsync, 55 years ago

import

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