VirtualBox

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

Last change on this file since 46717 was 46717, checked in by vboxsync, 12 years ago

Main/glue/EventQueue: fix attempt, not fully verified

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 5.7 KB
Line 
1/* $Id: EventQueue.cpp 46717 2013-06-21 08:34:43Z 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 : 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 else
100 {
101 int rc2 = RTCritSectLeave(&mCritSect);
102 AssertRC(rc2);
103 fWait = false;
104 }
105
106 if (fWait)
107 {
108 rc = RTSemEventWaitNoResume(mSemEvent, cMsTimeout);
109 if (RT_SUCCESS(rc))
110 rc = RTCritSectEnter(&mCritSect);
111 }
112
113 if (RT_SUCCESS(rc))
114 {
115 if (ASMAtomicReadBool(&mShutdown))
116 return VERR_INTERRUPTED;
117
118 if (RT_SUCCESS(rc))
119 {
120 EventQueueListIterator it = mEvents.begin();
121 if (it != mEvents.end())
122 {
123 Event *pEvent = *it;
124 AssertPtr(pEvent);
125
126 mEvents.erase(it);
127
128 int rc2 = RTCritSectLeave(&mCritSect);
129 if (RT_SUCCESS(rc))
130 rc = rc2;
131
132 pEvent->handler();
133 pEvent->Release();
134 }
135 else
136 {
137 int rc2 = RTCritSectLeave(&mCritSect);
138 if (RT_SUCCESS(rc))
139 rc = rc2;
140 }
141 }
142 }
143
144 Assert(rc != VERR_TIMEOUT || cMsTimeout != RT_INDEFINITE_WAIT);
145 return rc;
146}
147
148/**
149 * Interrupt thread waiting on event queue processing.
150 *
151 * Can be called on any thread.
152 *
153 * @returns VBox status code.
154 */
155int EventQueue::interruptEventQueueProcessing(void)
156{
157 ASMAtomicWriteBool(&mShutdown, true);
158
159 return RTSemEventSignal(mSemEvent);
160}
161
162/**
163 * Posts an event to this event loop asynchronously.
164 *
165 * @param event the event to post, must be allocated using |new|
166 * @return TRUE if successful and false otherwise
167 */
168BOOL EventQueue::postEvent(Event *pEvent)
169{
170 int rc = RTCritSectEnter(&mCritSect);
171 if (RT_SUCCESS(rc))
172 {
173 try
174 {
175 if (pEvent)
176 {
177 pEvent->AddRef();
178 mEvents.push_back(pEvent);
179 }
180 else /* No locking, since we're already in our crit sect. */
181 mShutdown = true;
182
183 size_t cEvents = mEvents.size();
184 if (cEvents > _1K) /** @todo Make value configurable? */
185 {
186 static int s_cBitchedAboutLotEvents = 0;
187 if (s_cBitchedAboutLotEvents < 10)
188 LogRel(("Warning: Event queue received lots of events (%zu), expect delayed event handling (%d/10)\n",
189 cEvents, ++s_cBitchedAboutLotEvents));
190 }
191
192 /* Leave critical section before signalling event. */
193 rc = RTCritSectLeave(&mCritSect);
194 if (RT_SUCCESS(rc))
195 {
196 int rc2 = RTSemEventSignal(mSemEvent);
197 AssertRC(rc2);
198 }
199 }
200 catch (std::bad_alloc &ba)
201 {
202 NOREF(ba);
203 rc = VERR_NO_MEMORY;
204 }
205
206 if (RT_FAILURE(rc))
207 {
208 int rc2 = RTCritSectLeave(&mCritSect);
209 AssertRC(rc2);
210 }
211 }
212
213 return RT_SUCCESS(rc) ? TRUE : FALSE;
214}
215
216}
217/* namespace com */
Note: See TracBrowser for help on using the repository browser.

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