VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/req.cpp@ 88813

Last change on this file since 88813 was 88813, checked in by vboxsync, 4 years ago

IPRT/RTReq: Added a RTReqCancel function. Changed the behavior of the RTREQFLAGS_NO_WAIT to optionally return the request handle rather than obstinately returning NIL even when the phReq parameter is not NULL. This makes the usage clearer and allows canceling NO_WAIT requests. (Needed in DrvAudio.) bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 19.6 KB
Line 
1/* $Id: req.cpp 88813 2021-05-01 18:15:13Z vboxsync $ */
2/** @file
3 * IPRT - Request packets
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/req.h>
32#include "internal/iprt.h"
33
34#include <iprt/assert.h>
35#include <iprt/asm.h>
36#include <iprt/err.h>
37#include <iprt/string.h>
38#include <iprt/time.h>
39#include <iprt/semaphore.h>
40#include <iprt/thread.h>
41#include <iprt/log.h>
42#include <iprt/mem.h>
43
44#include "internal/req.h"
45#include "internal/magics.h"
46
47
48/*********************************************************************************************************************************
49* Internal Functions *
50*********************************************************************************************************************************/
51
52
53/**
54 * Allocate a new request from the heap.
55 *
56 * @returns IPRT status code.
57 * @param enmType The reques type.
58 * @param fPoolOrQueue The owner type.
59 * @param pvOwner The owner.
60 * @param phReq Where to return the request handle.
61 */
62DECLHIDDEN(int) rtReqAlloc(RTREQTYPE enmType, bool fPoolOrQueue, void *pvOwner, PRTREQ *phReq)
63{
64 PRTREQ pReq = (PRTREQ)RTMemAllocZ(sizeof(*pReq));
65 if (RT_UNLIKELY(!pReq))
66 return VERR_NO_MEMORY;
67
68 /*
69 * Create the semaphore used for waiting.
70 */
71 int rc = RTSemEventCreate(&pReq->EventSem);
72 AssertRCReturnStmt(rc, RTMemFree(pReq), rc);
73
74 /*
75 * Initialize the packet and return it.
76 */
77 pReq->u32Magic = RTREQ_MAGIC;
78 pReq->fEventSemClear = true;
79 pReq->fSignalPushBack = true;
80 pReq->fPoolOrQueue = fPoolOrQueue;
81 pReq->iStatusX = VERR_RT_REQUEST_STATUS_STILL_PENDING;
82 pReq->enmState = RTREQSTATE_ALLOCATED;
83 pReq->pNext = NULL;
84 pReq->uOwner.pv = pvOwner;
85 pReq->fFlags = RTREQFLAGS_IPRT_STATUS;
86 pReq->enmType = enmType;
87 pReq->cRefs = 1;
88
89 *phReq = pReq;
90 return VINF_SUCCESS;
91}
92
93
94/**
95 * Re-initializes a request when it's being recycled.
96 *
97 * @returns IRPT status code, the request is freed on failure.
98 * @param pReq The request.
99 * @param enmType The request type.
100 */
101DECLHIDDEN(int) rtReqReInit(PRTREQINT pReq, RTREQTYPE enmType)
102{
103 Assert(pReq->u32Magic == RTREQ_MAGIC);
104 Assert(pReq->enmType == RTREQTYPE_INVALID);
105 Assert(pReq->enmState == RTREQSTATE_FREE);
106 Assert(pReq->cRefs == 0);
107
108 /*
109 * Make sure the event sem is not signaled.
110 */
111 if (!pReq->fEventSemClear)
112 {
113 int rc = RTSemEventWait(pReq->EventSem, 0);
114 if (rc != VINF_SUCCESS && rc != VERR_TIMEOUT)
115 {
116 /*
117 * This shall not happen, but if it does we'll just destroy
118 * the semaphore and create a new one.
119 */
120 AssertMsgFailed(("rc=%Rrc from RTSemEventWait(%#x).\n", rc, pReq->EventSem));
121 RTSemEventDestroy(pReq->EventSem);
122 rc = RTSemEventCreate(&pReq->EventSem);
123 if (RT_FAILURE(rc))
124 {
125 AssertRC(rc);
126 pReq->EventSem = NIL_RTSEMEVENT;
127 rtReqFreeIt(pReq);
128 return rc;
129 }
130 }
131 pReq->fEventSemClear = true;
132 }
133 else
134 Assert(RTSemEventWait(pReq->EventSem, 0) == VERR_TIMEOUT);
135
136 /*
137 * Initialize the packet and return it.
138 */
139 ASMAtomicWriteNullPtr(&pReq->pNext);
140 pReq->iStatusX = VERR_RT_REQUEST_STATUS_STILL_PENDING;
141 pReq->enmState = RTREQSTATE_ALLOCATED;
142 pReq->fFlags = RTREQFLAGS_IPRT_STATUS;
143 pReq->enmType = enmType;
144 pReq->cRefs = 1;
145 return VINF_SUCCESS;
146}
147
148
149RTDECL(uint32_t) RTReqRetain(PRTREQ hReq)
150{
151 PRTREQINT pReq = hReq;
152 AssertPtrReturn(pReq, UINT32_MAX);
153 AssertReturn(pReq->u32Magic == RTREQ_MAGIC, UINT32_MAX);
154
155 return ASMAtomicIncU32(&pReq->cRefs);
156}
157RT_EXPORT_SYMBOL(RTReqRetain);
158
159
160/**
161 * Frees a request.
162 *
163 * @param pReq The request.
164 */
165DECLHIDDEN(void) rtReqFreeIt(PRTREQINT pReq)
166{
167 Assert(pReq->u32Magic == RTREQ_MAGIC);
168 Assert(pReq->cRefs == 0);
169
170 pReq->u32Magic = RTREQ_MAGIC_DEAD;
171 RTSemEventDestroy(pReq->EventSem);
172 pReq->EventSem = NIL_RTSEMEVENT;
173 RTSemEventMultiDestroy(pReq->hPushBackEvt);
174 pReq->hPushBackEvt = NIL_RTSEMEVENTMULTI;
175 RTMemFree(pReq);
176}
177
178
179RTDECL(uint32_t) RTReqRelease(PRTREQ hReq)
180{
181 /*
182 * Ignore NULL and validate the request.
183 */
184 if (!hReq)
185 return 0;
186 PRTREQINT pReq = hReq;
187 AssertPtrReturn(pReq, UINT32_MAX);
188 AssertReturn(pReq->u32Magic == RTREQ_MAGIC, UINT32_MAX);
189
190 /*
191 * Drop a reference, recycle the request when we reach 0.
192 */
193 uint32_t cRefs = ASMAtomicDecU32(&pReq->cRefs);
194 if (cRefs == 0)
195 {
196 /*
197 * Check packet state.
198 */
199 RTREQSTATE const enmState = pReq->enmState;
200 switch (enmState)
201 {
202 case RTREQSTATE_ALLOCATED:
203 case RTREQSTATE_COMPLETED:
204 break;
205 default:
206 AssertMsgFailedReturn(("Invalid state %d!\n", enmState), 0);
207 }
208
209 /*
210 * Make it a free packet and put it into one of the free packet lists.
211 */
212 pReq->enmState = RTREQSTATE_FREE;
213 pReq->iStatusX = VERR_RT_REQUEST_STATUS_FREED;
214 pReq->enmType = RTREQTYPE_INVALID;
215
216 bool fRecycled;
217 if (pReq->fPoolOrQueue)
218 fRecycled = rtReqPoolRecycle(pReq->uOwner.hPool, pReq);
219 else
220 fRecycled = rtReqQueueRecycle(pReq->uOwner.hQueue, pReq);
221 if (!fRecycled)
222 rtReqFreeIt(pReq);
223 }
224
225 return cRefs;
226}
227RT_EXPORT_SYMBOL(RTReqRelease);
228
229
230RTDECL(int) RTReqSubmit(PRTREQ hReq, RTMSINTERVAL cMillies)
231{
232 LogFlow(("RTReqSubmit: hReq=%p cMillies=%d\n", hReq, cMillies));
233
234 /*
235 * Verify the supplied package.
236 */
237 PRTREQINT pReq = hReq;
238 AssertPtrReturn(pReq, VERR_INVALID_HANDLE);
239 AssertReturn(pReq->u32Magic == RTREQ_MAGIC, VERR_INVALID_HANDLE);
240 AssertMsgReturn(pReq->enmState == RTREQSTATE_ALLOCATED, ("%d\n", pReq->enmState), VERR_RT_REQUEST_STATE);
241 AssertMsgReturn(pReq->uOwner.hQueue && !pReq->pNext && pReq->EventSem != NIL_RTSEMEVENT,
242 ("Invalid request package! Anyone cooking their own packages???\n"),
243 VERR_RT_REQUEST_INVALID_PACKAGE);
244 AssertMsgReturn(pReq->enmType > RTREQTYPE_INVALID && pReq->enmType < RTREQTYPE_MAX,
245 ("Invalid package type %d valid range %d-%d inclusively. This was verified on alloc too...\n",
246 pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1),
247 VERR_RT_REQUEST_INVALID_TYPE);
248
249 /*
250 * Insert it. Always grab a reference for the queue (we used to
251 * donate the caller's reference in the NO_WAIT case once upon a time).
252 */
253 pReq->uSubmitNanoTs = RTTimeNanoTS();
254 pReq->enmState = RTREQSTATE_QUEUED;
255 unsigned fFlags = ((RTREQ volatile *)pReq)->fFlags; /* volatile paranoia */
256 RTReqRetain(pReq);
257
258 if (!pReq->fPoolOrQueue)
259 rtReqQueueSubmit(pReq->uOwner.hQueue, pReq);
260 else
261 rtReqPoolSubmit(pReq->uOwner.hPool, pReq);
262
263 /*
264 * Wait and return.
265 */
266 int rc = VINF_SUCCESS;
267 if (!(fFlags & RTREQFLAGS_NO_WAIT))
268 rc = RTReqWait(pReq, cMillies);
269
270 LogFlow(("RTReqSubmit: returns %Rrc\n", rc));
271 return rc;
272}
273RT_EXPORT_SYMBOL(RTReqSubmit);
274
275
276RTDECL(int) RTReqWait(PRTREQ hReq, RTMSINTERVAL cMillies)
277{
278 LogFlow(("RTReqWait: hReq=%p cMillies=%d\n", hReq, cMillies));
279
280 /*
281 * Verify the supplied package.
282 */
283 PRTREQINT pReq = hReq;
284 AssertPtrReturn(pReq, VERR_INVALID_HANDLE);
285 AssertReturn(pReq->u32Magic == RTREQ_MAGIC, VERR_INVALID_HANDLE);
286 RTREQSTATE enmState = pReq->enmState;
287 AssertMsgReturn( enmState == RTREQSTATE_QUEUED
288 || enmState == RTREQSTATE_PROCESSING
289 || enmState == RTREQSTATE_COMPLETED
290 || enmState == RTREQSTATE_CANCELLED,
291 ("Invalid state %d\n", enmState),
292 VERR_RT_REQUEST_STATE);
293 AssertMsgReturn(pReq->uOwner.hQueue && pReq->EventSem != NIL_RTSEMEVENT,
294 ("Invalid request package! Anyone cooking their own packages???\n"),
295 VERR_RT_REQUEST_INVALID_PACKAGE);
296 AssertMsgReturn(pReq->enmType > RTREQTYPE_INVALID && pReq->enmType < RTREQTYPE_MAX,
297 ("Invalid package type %d valid range %d-%d inclusively. This was verified on alloc too...\n",
298 pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1),
299 VERR_RT_REQUEST_INVALID_TYPE);
300
301 /*
302 * Wait on the package.
303 */
304 int rc;
305 if (cMillies != RT_INDEFINITE_WAIT)
306 rc = RTSemEventWait(pReq->EventSem, cMillies);
307 else
308 {
309 do
310 {
311 rc = RTSemEventWait(pReq->EventSem, RT_INDEFINITE_WAIT);
312 Assert(rc != VERR_TIMEOUT);
313 } while (pReq->enmState != RTREQSTATE_COMPLETED);
314 }
315 if (rc == VINF_SUCCESS)
316 ASMAtomicWriteBool(&pReq->fEventSemClear, true);
317 if (pReq->enmState == RTREQSTATE_COMPLETED)
318 rc = VINF_SUCCESS;
319 LogFlow(("RTReqWait: returns %Rrc\n", rc));
320 Assert(rc != VERR_INTERRUPTED);
321 Assert(pReq->cRefs >= 1);
322 return rc;
323}
324RT_EXPORT_SYMBOL(RTReqWait);
325
326
327RTDECL(int) RTReqCancel(PRTREQ hReq)
328{
329 LogFlow(("RTReqCancel: hReq=%p\n", hReq));
330
331 /*
332 * Verify the supplied package.
333 */
334 PRTREQINT pReq = hReq;
335 AssertPtrReturn(pReq, VERR_INVALID_HANDLE);
336 AssertReturn(pReq->u32Magic == RTREQ_MAGIC, VERR_INVALID_HANDLE);
337 //AssertMsgReturn(pReq->enmState == RTREQSTATE_ALLOCATED, ("%d\n", pReq->enmState), VERR_RT_REQUEST_STATE);
338 AssertMsgReturn(pReq->uOwner.hQueue && !pReq->pNext && pReq->EventSem != NIL_RTSEMEVENT,
339 ("Invalid request package! Anyone cooking their own packages???\n"),
340 VERR_RT_REQUEST_INVALID_PACKAGE);
341 AssertMsgReturn(pReq->enmType > RTREQTYPE_INVALID && pReq->enmType < RTREQTYPE_MAX,
342 ("Invalid package type %d valid range %d-%d inclusively. This was verified on alloc too...\n",
343 pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1),
344 VERR_RT_REQUEST_INVALID_TYPE);
345
346 /*
347 * Try cancel the request itself by changing its state.
348 */
349 int rc;
350 if (ASMAtomicCmpXchgU32((uint32_t volatile *)&pReq->enmState, RTREQSTATE_CANCELLED, RTREQSTATE_QUEUED))
351 {
352 if (pReq->fPoolOrQueue)
353 rtReqPoolCancel(pReq->uOwner.hPool, pReq);
354 rc = VINF_SUCCESS;
355 }
356 else
357 {
358 Assert(pReq->enmState == RTREQSTATE_PROCESSING || pReq->enmState == RTREQSTATE_COMPLETED);
359 rc = VERR_RT_REQUEST_STATE;
360 }
361
362 LogFlow(("RTReqCancel: returns %Rrc\n", rc));
363 return rc;
364}
365RT_EXPORT_SYMBOL(RTReqCancel);
366
367
368RTDECL(int) RTReqGetStatus(PRTREQ hReq)
369{
370 PRTREQINT pReq = hReq;
371 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
372 AssertReturn(pReq->u32Magic == RTREQ_MAGIC, VERR_INVALID_POINTER);
373 return pReq->iStatusX;
374}
375RT_EXPORT_SYMBOL(RTReqGetStatus);
376
377
378
379/**
380 * Process one request.
381 *
382 * @returns IPRT status code.
383 *
384 * @param pReq Request packet to process.
385 */
386DECLHIDDEN(int) rtReqProcessOne(PRTREQINT pReq)
387{
388 LogFlow(("rtReqProcessOne: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags));
389
390 /*
391 * Try switch the request status to processing.
392 */
393 int rcRet = VINF_SUCCESS; /* the return code of this function. */
394 int rcReq = VERR_NOT_IMPLEMENTED; /* the request status. */
395 if (ASMAtomicCmpXchgU32((uint32_t volatile *)&pReq->enmState, RTREQSTATE_PROCESSING, RTREQSTATE_QUEUED))
396 {
397 /*
398 * Process the request.
399 */
400 pReq->enmState = RTREQSTATE_PROCESSING;
401 switch (pReq->enmType)
402 {
403 /*
404 * A packed down call frame.
405 */
406 case RTREQTYPE_INTERNAL:
407 {
408 uintptr_t *pauArgs = &pReq->u.Internal.aArgs[0];
409 union
410 {
411 PFNRT pfn;
412 DECLCALLBACKMEMBER(int, pfn00,(void));
413 DECLCALLBACKMEMBER(int, pfn01,(uintptr_t));
414 DECLCALLBACKMEMBER(int, pfn02,(uintptr_t, uintptr_t));
415 DECLCALLBACKMEMBER(int, pfn03,(uintptr_t, uintptr_t, uintptr_t));
416 DECLCALLBACKMEMBER(int, pfn04,(uintptr_t, uintptr_t, uintptr_t, uintptr_t));
417 DECLCALLBACKMEMBER(int, pfn05,(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t));
418 DECLCALLBACKMEMBER(int, pfn06,(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t));
419 DECLCALLBACKMEMBER(int, pfn07,(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t));
420 DECLCALLBACKMEMBER(int, pfn08,(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t));
421 DECLCALLBACKMEMBER(int, pfn09,(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t));
422 DECLCALLBACKMEMBER(int, pfn10,(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t));
423 DECLCALLBACKMEMBER(int, pfn11,(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t));
424 DECLCALLBACKMEMBER(int, pfn12,(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t));
425 } u;
426 u.pfn = pReq->u.Internal.pfn;
427#ifndef RT_ARCH_X86
428 switch (pReq->u.Internal.cArgs)
429 {
430 case 0: rcRet = u.pfn00(); break;
431 case 1: rcRet = u.pfn01(pauArgs[0]); break;
432 case 2: rcRet = u.pfn02(pauArgs[0], pauArgs[1]); break;
433 case 3: rcRet = u.pfn03(pauArgs[0], pauArgs[1], pauArgs[2]); break;
434 case 4: rcRet = u.pfn04(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3]); break;
435 case 5: rcRet = u.pfn05(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4]); break;
436 case 6: rcRet = u.pfn06(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5]); break;
437 case 7: rcRet = u.pfn07(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6]); break;
438 case 8: rcRet = u.pfn08(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7]); break;
439 case 9: rcRet = u.pfn09(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8]); break;
440 case 10: rcRet = u.pfn10(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9]); break;
441 case 11: rcRet = u.pfn11(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10]); break;
442 case 12: rcRet = u.pfn12(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10], pauArgs[11]); break;
443 default:
444 AssertReleaseMsgFailed(("cArgs=%d\n", pReq->u.Internal.cArgs));
445 rcRet = rcReq = VERR_INTERNAL_ERROR;
446 break;
447 }
448#else /* RT_ARCH_X86 */
449 size_t cbArgs = pReq->u.Internal.cArgs * sizeof(uintptr_t);
450# ifdef __GNUC__
451 __asm__ __volatile__("movl %%esp, %%edx\n\t"
452 "subl %2, %%esp\n\t"
453 "andl $0xfffffff0, %%esp\n\t"
454 "shrl $2, %2\n\t"
455 "movl %%esp, %%edi\n\t"
456 "rep movsl\n\t"
457 "movl %%edx, %%edi\n\t"
458 "call *%%eax\n\t"
459 "mov %%edi, %%esp\n\t"
460 : "=a" (rcRet),
461 "=S" (pauArgs),
462 "=c" (cbArgs)
463 : "0" (u.pfn),
464 "1" (pauArgs),
465 "2" (cbArgs)
466 : "edi", "edx");
467# else
468 __asm
469 {
470 xor edx, edx /* just mess it up. */
471 mov eax, u.pfn
472 mov ecx, cbArgs
473 shr ecx, 2
474 mov esi, pauArgs
475 mov ebx, esp
476 sub esp, cbArgs
477 and esp, 0xfffffff0
478 mov edi, esp
479 rep movsd
480 call eax
481 mov esp, ebx
482 mov rcRet, eax
483 }
484# endif
485#endif /* RT_ARCH_X86 */
486 if ((pReq->fFlags & (RTREQFLAGS_RETURN_MASK)) == RTREQFLAGS_VOID)
487 rcRet = VINF_SUCCESS;
488 rcReq = rcRet;
489 break;
490 }
491
492 default:
493 AssertMsgFailed(("pReq->enmType=%d\n", pReq->enmType));
494 rcReq = VERR_NOT_IMPLEMENTED;
495 break;
496 }
497 }
498 else
499 {
500 Assert(pReq->enmState == RTREQSTATE_CANCELLED);
501 rcReq = VERR_CANCELLED;
502 }
503
504 /*
505 * Complete the request and then release our request handle reference.
506 */
507 pReq->iStatusX = rcReq;
508 pReq->enmState = RTREQSTATE_COMPLETED;
509 if (pReq->fFlags & RTREQFLAGS_NO_WAIT)
510 LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc (no wait)\n",
511 pReq, rcReq, rcRet));
512 else
513 {
514 /* Notify the waiting thread. */
515 LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc - notifying waiting thread\n",
516 pReq, rcReq, rcRet));
517 ASMAtomicWriteBool(&pReq->fEventSemClear, false);
518 int rc2 = RTSemEventSignal(pReq->EventSem);
519 if (rc2 != VINF_SUCCESS)
520 {
521 AssertRC(rc2);
522 rcRet = rc2;
523 }
524 }
525 RTReqRelease(pReq);
526 return rcRet;
527}
528
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