VirtualBox

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

Last change on this file since 46860 was 46751, checked in by vboxsync, 11 years ago

Main/glue/EventQueue.cpp: fix shutdown logic, must not keep the CritSect

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