VirtualBox

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

Last change on this file since 55747 was 47852, checked in by vboxsync, 11 years ago

Main/Event Queue: Forward ported r86728 + r87009 from 4.1.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.4 KB
Line 
1/* $Id: EventQueue.cpp 47852 2013-08-19 17:06:37Z 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.virtualbox.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 : mUserCnt(0),
39 mShutdown(false)
40{
41 int rc = RTCritSectInit(&mCritSect);
42 AssertRC(rc);
43
44 rc = RTSemEventCreate(&mSemEvent);
45 AssertRC(rc);
46}
47
48EventQueue::~EventQueue(void)
49{
50 int rc = RTCritSectDelete(&mCritSect);
51 AssertRC(rc);
52
53 rc = RTSemEventDestroy(mSemEvent);
54 AssertRC(rc);
55
56 EventQueueListIterator it = mEvents.begin();
57 while (it != mEvents.end())
58 {
59 (*it)->Release();
60 it = mEvents.erase(it);
61 }
62}
63
64/**
65 * Process events pending on this event queue, and wait up to given timeout, if
66 * nothing is available.
67 *
68 * Must be called on same thread this event queue was created on.
69 *
70 * @param cMsTimeout The timeout specified as milliseconds. Use
71 * RT_INDEFINITE_WAIT to wait till an event is posted on the
72 * queue.
73 *
74 * @returns VBox status code
75 * @retval VINF_SUCCESS if one or more messages was processed.
76 * @retval VERR_TIMEOUT if cMsTimeout expired.
77 * @retval VERR_INVALID_CONTEXT if called on the wrong thread.
78 * @retval VERR_INTERRUPTED if interruptEventQueueProcessing was called.
79 * On Windows will also be returned when WM_QUIT is encountered.
80 * On Darwin this may also be returned when the native queue is
81 * stopped or destroyed/finished.
82 * @retval VINF_INTERRUPTED if the native system call was interrupted by a
83 * an asynchronous event delivery (signal) or just felt like returning
84 * out of bounds. On darwin it will also be returned if the queue is
85 * stopped.
86 */
87int EventQueue::processEventQueue(RTMSINTERVAL cMsTimeout)
88{
89 size_t cNumEvents;
90 int rc = RTCritSectEnter(&mCritSect);
91 if (RT_SUCCESS(rc))
92 {
93 if (mUserCnt == 0) /* No concurrent access allowed. */
94 {
95 mUserCnt++;
96
97 cNumEvents = mEvents.size();
98 if (!cNumEvents)
99 {
100 int rc2 = RTCritSectLeave(&mCritSect);
101 AssertRC(rc2);
102
103 rc = RTSemEventWaitNoResume(mSemEvent, cMsTimeout);
104
105 rc2 = RTCritSectEnter(&mCritSect);
106 AssertRC(rc2);
107
108 if (RT_SUCCESS(rc))
109 {
110 if (mShutdown)
111 rc = VERR_INTERRUPTED;
112 cNumEvents = mEvents.size();
113 }
114 }
115
116 if (RT_SUCCESS(rc))
117 rc = processPendingEvents(cNumEvents);
118
119 Assert(mUserCnt);
120 mUserCnt--;
121 }
122 else
123 rc = VERR_WRONG_ORDER;
124
125 int rc2 = RTCritSectLeave(&mCritSect);
126 if (RT_SUCCESS(rc))
127 rc = rc2;
128 }
129
130 Assert(rc != VERR_TIMEOUT || cMsTimeout != RT_INDEFINITE_WAIT);
131 return rc;
132}
133
134/**
135 * Processes all pending events in the queue at the time of
136 * calling. Note: Does no initial locking, must be done by the
137 * caller!
138 *
139 * @return IPRT status code.
140 */
141int EventQueue::processPendingEvents(size_t cNumEvents)
142{
143 if (!cNumEvents) /* Nothing to process? Bail out early. */
144 return VINF_SUCCESS;
145
146 int rc = VINF_SUCCESS;
147
148 EventQueueListIterator it = mEvents.begin();
149 for (size_t i = 0;
150 i < cNumEvents
151 && it != mEvents.end(); i++)
152 {
153 Event *pEvent = *it;
154 AssertPtr(pEvent);
155
156 mEvents.erase(it);
157
158 int rc2 = RTCritSectLeave(&mCritSect);
159 AssertRC(rc2);
160
161 pEvent->handler();
162 pEvent->Release();
163
164 rc2 = RTCritSectEnter(&mCritSect);
165 AssertRC(rc2);
166
167 it = mEvents.begin();
168 if (mShutdown)
169 {
170 rc = VERR_INTERRUPTED;
171 break;
172 }
173 }
174
175 return rc;
176}
177
178/**
179 * Interrupt thread waiting on event queue processing.
180 *
181 * Can be called on any thread.
182 *
183 * @returns VBox status code.
184 */
185int EventQueue::interruptEventQueueProcessing(void)
186{
187 ASMAtomicWriteBool(&mShutdown, true);
188
189 return RTSemEventSignal(mSemEvent);
190}
191
192/**
193 * Posts an event to this event loop asynchronously.
194 *
195 * @param event the event to post, must be allocated using |new|
196 * @return TRUE if successful and false otherwise
197 */
198BOOL EventQueue::postEvent(Event *pEvent)
199{
200 int rc = RTCritSectEnter(&mCritSect);
201 if (RT_SUCCESS(rc))
202 {
203 try
204 {
205 if (pEvent)
206 {
207 pEvent->AddRef();
208 mEvents.push_back(pEvent);
209 }
210 else /* No locking, since we're already in our crit sect. */
211 mShutdown = true;
212
213 size_t cEvents = mEvents.size();
214 if (cEvents > _1K) /** @todo Make value configurable? */
215 {
216 static int s_cBitchedAboutLotEvents = 0;
217 if (s_cBitchedAboutLotEvents < 10)
218 LogRel(("Warning: Event queue received lots of events (%zu), expect delayed event handling (%d/10)\n",
219 cEvents, ++s_cBitchedAboutLotEvents));
220 }
221
222 /* Leave critical section before signalling event. */
223 rc = RTCritSectLeave(&mCritSect);
224 if (RT_SUCCESS(rc))
225 {
226 int rc2 = RTSemEventSignal(mSemEvent);
227 AssertRC(rc2);
228 }
229 }
230 catch (std::bad_alloc &ba)
231 {
232 NOREF(ba);
233 rc = VERR_NO_MEMORY;
234 }
235
236 if (RT_FAILURE(rc))
237 {
238 int rc2 = RTCritSectLeave(&mCritSect);
239 AssertRC(rc2);
240 }
241 }
242
243 return RT_SUCCESS(rc) ? TRUE : FALSE;
244}
245
246}
247/* namespace com */
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