VirtualBox

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

Last change on this file was 98297, checked in by vboxsync, 17 months ago

Main: rc -> hrc/vrc for all but testcases. Enabled scm rc checks accordingly. bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.7 KB
RevLine 
[16555]1/* $Id: EventQueue.cpp 98297 2023-01-25 01:59:25Z vboxsync $ */
[1]2/** @file
[46649]3 * Event queue class declaration.
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2013-2023 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[1]26 */
27
[46649]28/** @todo Adapt / update documentation! */
29
[1]30#include "VBox/com/EventQueue.h"
31
[46649]32#include <iprt/asm.h>
[43944]33#include <new> /* For bad_alloc. */
34
[22722]35#include <iprt/err.h>
[46649]36#include <iprt/semaphore.h>
[22722]37#include <iprt/time.h>
38#include <iprt/thread.h>
[38754]39#include <iprt/log.h>
[22722]40
[1]41namespace com
42{
43
44// EventQueue class
45////////////////////////////////////////////////////////////////////////////////
46
[46649]47EventQueue::EventQueue(void)
[47852]48 : mUserCnt(0),
49 mShutdown(false)
[31579]50{
[98297]51 int vrc = RTCritSectInit(&mCritSect);
52 AssertRC(vrc);
[31579]53
[98297]54 vrc = RTSemEventCreate(&mSemEvent);
55 AssertRC(vrc);
[31579]56}
57
[46649]58EventQueue::~EventQueue(void)
[31579]59{
[98297]60 int vrc = RTCritSectDelete(&mCritSect);
61 AssertRC(vrc);
[31579]62
[98297]63 vrc = RTSemEventDestroy(mSemEvent);
64 AssertRC(vrc);
[31579]65
[46649]66 EventQueueListIterator it = mEvents.begin();
67 while (it != mEvents.end())
[1]68 {
[46649]69 (*it)->Release();
70 it = mEvents.erase(it);
[46652]71 }
[1]72}
73
[23092]74/**
[31589]75 * Process events pending on this event queue, and wait up to given timeout, if
76 * nothing is available.
[23092]77 *
[31589]78 * Must be called on same thread this event queue was created on.
[23092]79 *
[31589]80 * @param cMsTimeout The timeout specified as milliseconds. Use
81 * RT_INDEFINITE_WAIT to wait till an event is posted on the
82 * queue.
[23092]83 *
[31589]84 * @returns VBox status code
85 * @retval VINF_SUCCESS if one or more messages was processed.
86 * @retval VERR_TIMEOUT if cMsTimeout expired.
87 * @retval VERR_INVALID_CONTEXT if called on the wrong thread.
88 * @retval VERR_INTERRUPTED if interruptEventQueueProcessing was called.
89 * On Windows will also be returned when WM_QUIT is encountered.
90 * On Darwin this may also be returned when the native queue is
91 * stopped or destroyed/finished.
[31598]92 * @retval VINF_INTERRUPTED if the native system call was interrupted by a
93 * an asynchronous event delivery (signal) or just felt like returning
94 * out of bounds. On darwin it will also be returned if the queue is
95 * stopped.
[23092]96 */
[31589]97int EventQueue::processEventQueue(RTMSINTERVAL cMsTimeout)
[22847]98{
[47852]99 size_t cNumEvents;
[98297]100 int vrc = RTCritSectEnter(&mCritSect);
101 if (RT_SUCCESS(vrc))
[23092]102 {
[47852]103 if (mUserCnt == 0) /* No concurrent access allowed. */
[46649]104 {
[47852]105 mUserCnt++;
106
107 cNumEvents = mEvents.size();
108 if (!cNumEvents)
109 {
[98297]110 int vrc2 = RTCritSectLeave(&mCritSect);
111 AssertRC(vrc2);
[47852]112
[98297]113 vrc = RTSemEventWaitNoResume(mSemEvent, cMsTimeout);
[47852]114
[98297]115 vrc2 = RTCritSectEnter(&mCritSect);
116 AssertRC(vrc2);
[47852]117
[98297]118 if (RT_SUCCESS(vrc))
[47852]119 {
120 if (mShutdown)
[98297]121 vrc = VERR_INTERRUPTED;
[47852]122 cNumEvents = mEvents.size();
123 }
124 }
125
[98297]126 if (RT_SUCCESS(vrc))
127 vrc = processPendingEvents(cNumEvents);
[47852]128
129 Assert(mUserCnt);
130 mUserCnt--;
[46652]131 }
[47852]132 else
[98297]133 vrc = VERR_WRONG_ORDER;
[47852]134
[98297]135 int vrc2 = RTCritSectLeave(&mCritSect);
136 if (RT_SUCCESS(vrc))
137 vrc = vrc2;
[31579]138 }
[22916]139
[98297]140 Assert(vrc != VERR_TIMEOUT || cMsTimeout != RT_INDEFINITE_WAIT);
141 return vrc;
[47852]142}
143
144/**
145 * Processes all pending events in the queue at the time of
146 * calling. Note: Does no initial locking, must be done by the
147 * caller!
148 *
149 * @return IPRT status code.
150 */
151int EventQueue::processPendingEvents(size_t cNumEvents)
152{
153 if (!cNumEvents) /* Nothing to process? Bail out early. */
154 return VINF_SUCCESS;
155
[98297]156 int vrc = VINF_SUCCESS;
[47852]157
158 EventQueueListIterator it = mEvents.begin();
159 for (size_t i = 0;
160 i < cNumEvents
161 && it != mEvents.end(); i++)
[23092]162 {
[47852]163 Event *pEvent = *it;
164 AssertPtr(pEvent);
[46649]165
[47852]166 mEvents.erase(it);
[46649]167
[98297]168 int vrc2 = RTCritSectLeave(&mCritSect);
169 AssertRC(vrc2);
[46649]170
[47852]171 pEvent->handler();
172 pEvent->Release();
[46649]173
[98297]174 vrc2 = RTCritSectEnter(&mCritSect);
175 AssertRC(vrc2);
[47852]176
177 it = mEvents.begin();
178 if (mShutdown)
179 {
[98297]180 vrc = VERR_INTERRUPTED;
[47852]181 break;
[22847]182 }
[23092]183 }
[31589]184
[98297]185 return vrc;
[22847]186}
187
[23092]188/**
[31589]189 * Interrupt thread waiting on event queue processing.
[23092]190 *
[31589]191 * Can be called on any thread.
192 *
193 * @returns VBox status code.
[23092]194 */
[46649]195int EventQueue::interruptEventQueueProcessing(void)
[22847]196{
[46649]197 ASMAtomicWriteBool(&mShutdown, true);
198
199 return RTSemEventSignal(mSemEvent);
[22847]200}
201
[1]202/**
203 * Posts an event to this event loop asynchronously.
204 *
[65082]205 * @param pEvent the event to post, must be allocated using |new|
[1]206 * @return TRUE if successful and false otherwise
207 */
[43943]208BOOL EventQueue::postEvent(Event *pEvent)
[1]209{
[98297]210 int vrc = RTCritSectEnter(&mCritSect);
211 if (RT_SUCCESS(vrc))
[46649]212 {
[46652]213 try
[46649]214 {
215 if (pEvent)
216 {
217 pEvent->AddRef();
218 mEvents.push_back(pEvent);
219 }
220 else /* No locking, since we're already in our crit sect. */
221 mShutdown = true;
[1]222
[46649]223 size_t cEvents = mEvents.size();
224 if (cEvents > _1K) /** @todo Make value configurable? */
225 {
226 static int s_cBitchedAboutLotEvents = 0;
227 if (s_cBitchedAboutLotEvents < 10)
228 LogRel(("Warning: Event queue received lots of events (%zu), expect delayed event handling (%d/10)\n",
229 cEvents, ++s_cBitchedAboutLotEvents));
230 }
[1]231
[46649]232 /* Leave critical section before signalling event. */
[98297]233 vrc = RTCritSectLeave(&mCritSect);
234 if (RT_SUCCESS(vrc))
[46649]235 {
[98297]236 int vrc2 = RTSemEventSignal(mSemEvent);
237 AssertRC(vrc2);
[46649]238 }
239 }
240 catch (std::bad_alloc &ba)
241 {
242 NOREF(ba);
[98297]243 vrc = VERR_NO_MEMORY;
[46649]244 }
[1]245
[98297]246 if (RT_FAILURE(vrc))
[46649]247 {
[98297]248 int vrc2 = RTCritSectLeave(&mCritSect);
249 AssertRC(vrc2);
[46649]250 }
[43943]251 }
[1]252
[98297]253 return RT_SUCCESS(vrc) ? TRUE : FALSE;
[1]254}
255
[22722]256}
257/* namespace com */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use