VirtualBox

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

Last change on this file since 39498 was 39498, checked in by vboxsync, 13 years ago

RTReq refactoring.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 24.6 KB
Line 
1/* $Id: req.cpp 39498 2011-12-01 19:59:21Z vboxsync $ */
2/** @file
3 * IPRT - Request packets
4 */
5
6/*
7 * Copyright (C) 2006-2007 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/string.h>
37#include <iprt/time.h>
38#include <iprt/semaphore.h>
39#include <iprt/thread.h>
40#include <iprt/log.h>
41#include <iprt/mem.h>
42
43#include "internal/req.h"
44
45
46/*******************************************************************************
47* Internal Functions *
48*******************************************************************************/
49static int rtReqProcessOne(PRTREQ pReq);
50
51
52
53RTDECL(int) RTReqQueueCreate(RTREQQUEUE *phQueue)
54{
55 PRTREQQUEUEINT pQueue = (PRTREQQUEUEINT)RTMemAllocZ(sizeof(RTREQQUEUEINT));
56 if (!pQueue)
57 return VERR_NO_MEMORY;
58 int rc = RTSemEventCreate(&pQueue->EventSem);
59 if (RT_SUCCESS(rc))
60 {
61 *phQueue = pQueue;
62 return VINF_SUCCESS;
63 }
64
65 RTMemFree(pQueue);
66 return rc;
67}
68RT_EXPORT_SYMBOL(RTReqQueueCreate);
69
70
71RTDECL(int) RTReqQueueDestroy(RTREQQUEUE hQueue)
72{
73 /*
74 * Check input.
75 */
76 if (hQueue == NIL_RTREQQUEUE)
77 return VINF_SUCCESS;
78 PRTREQQUEUEINT pQueue = hQueue;
79 AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
80
81 RTSemEventDestroy(pQueue->EventSem);
82 pQueue->EventSem = NIL_RTSEMEVENT;
83 RTMemFree(pQueue);
84 return VINF_SUCCESS;
85}
86RT_EXPORT_SYMBOL(RTReqQueueDestroy);
87
88
89RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies)
90{
91 LogFlow(("RTReqProcess %x\n", hQueue));
92
93 /*
94 * Check input.
95 */
96 PRTREQQUEUEINT pQueue = hQueue;
97 AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
98
99 /*
100 * Process loop.
101 *
102 * We do not repeat the outer loop if we've got an informational status code
103 * since that code needs processing by our caller.
104 */
105 int rc = VINF_SUCCESS;
106 while (rc <= VINF_SUCCESS)
107 {
108 /*
109 * Get pending requests.
110 */
111 PRTREQ pReqs = ASMAtomicXchgPtrT(&pQueue->pReqs, NULL, PRTREQ);
112 if (!pReqs)
113 {
114 ASMAtomicWriteBool(&pQueue->fBusy, false); /* this aint 100% perfect, but it's good enough for now... */
115 /** @todo We currently don't care if the entire time wasted here is larger than
116 * cMillies */
117 rc = RTSemEventWait(pQueue->EventSem, cMillies);
118 if (rc != VINF_SUCCESS)
119 break;
120 continue;
121 }
122 ASMAtomicWriteBool(&pQueue->fBusy, true);
123
124 /*
125 * Reverse the list to process it in FIFO order.
126 */
127 PRTREQ pReq = pReqs;
128 if (pReq->pNext)
129 Log2(("RTReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext));
130 pReqs = NULL;
131 while (pReq)
132 {
133 Assert(pReq->enmState == RTREQSTATE_QUEUED);
134 Assert(pReq->hQueue == pQueue);
135 PRTREQ pCur = pReq;
136 pReq = pReq->pNext;
137 pCur->pNext = pReqs;
138 pReqs = pCur;
139 }
140
141
142 /*
143 * Process the requests.
144 */
145 while (pReqs)
146 {
147 /* Unchain the first request and advance the list. */
148 pReq = pReqs;
149 pReqs = pReqs->pNext;
150 pReq->pNext = NULL;
151
152 /* Process the request */
153 rc = rtReqProcessOne(pReq);
154 AssertRC(rc);
155 if (rc != VINF_SUCCESS)
156 break; /** @todo r=bird: we're dropping requests here! Add 2nd queue that can hold them. (will fix when writing a testcase) */
157 }
158 }
159
160 LogFlow(("RTReqProcess: returns %Rrc\n", rc));
161 return rc;
162}
163RT_EXPORT_SYMBOL(RTReqQueueProcess);
164
165
166RTDECL(int) RTReqQueueCall(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
167{
168 va_list va;
169 va_start(va, cArgs);
170 int rc = RTReqQueueCallV(hQueue, ppReq, cMillies, RTREQFLAGS_IPRT_STATUS, pfnFunction, cArgs, va);
171 va_end(va);
172 return rc;
173}
174RT_EXPORT_SYMBOL(RTReqQueueCall);
175
176
177RTDECL(int) RTReqQueueCallVoid(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
178{
179 va_list va;
180 va_start(va, cArgs);
181 int rc = RTReqQueueCallV(hQueue, ppReq, cMillies, RTREQFLAGS_VOID, pfnFunction, cArgs, va);
182 va_end(va);
183 return rc;
184}
185RT_EXPORT_SYMBOL(RTReqQueueCallVoid);
186
187
188RTDECL(int) RTReqQueueCallEx(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
189{
190 va_list va;
191 va_start(va, cArgs);
192 int rc = RTReqQueueCallV(hQueue, ppReq, cMillies, fFlags, pfnFunction, cArgs, va);
193 va_end(va);
194 return rc;
195}
196RT_EXPORT_SYMBOL(RTReqQueueCallEx);
197
198
199RTDECL(int) RTReqQueueCallV(RTREQQUEUE hQueue, PRTREQ *ppReq, RTMSINTERVAL cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
200{
201 LogFlow(("RTReqCallV: cMillies=%d fFlags=%#x pfnFunction=%p cArgs=%d\n", cMillies, fFlags, pfnFunction, cArgs));
202
203 /*
204 * Check input.
205 */
206 PRTREQQUEUEINT pQueue = hQueue;
207 AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
208 AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
209 AssertReturn(!(fFlags & ~(RTREQFLAGS_RETURN_MASK | RTREQFLAGS_NO_WAIT)), VERR_INVALID_PARAMETER);
210
211 if (!(fFlags & RTREQFLAGS_NO_WAIT) || ppReq)
212 {
213 AssertPtrReturn(ppReq, VERR_INVALID_POINTER);
214 *ppReq = NULL;
215 }
216
217 PRTREQ pReq = NULL;
218 AssertMsgReturn(cArgs * sizeof(uintptr_t) <= sizeof(pReq->u.Internal.aArgs), ("cArgs=%u\n", cArgs), VERR_TOO_MUCH_DATA);
219
220 /*
221 * Allocate request
222 */
223 int rc = RTReqQueueAlloc(pQueue, &pReq, RTREQTYPE_INTERNAL);
224 if (rc != VINF_SUCCESS)
225 return rc;
226
227 /*
228 * Initialize the request data.
229 */
230 pReq->fFlags = fFlags;
231 pReq->u.Internal.pfn = pfnFunction;
232 pReq->u.Internal.cArgs = cArgs;
233 for (unsigned iArg = 0; iArg < cArgs; iArg++)
234 pReq->u.Internal.aArgs[iArg] = va_arg(Args, uintptr_t);
235
236 /*
237 * Queue the request and return.
238 */
239 rc = RTReqSubmit(pReq, cMillies);
240 if ( rc != VINF_SUCCESS
241 && rc != VERR_TIMEOUT)
242 {
243 RTReqFree(pReq);
244 pReq = NULL;
245 }
246 if (!(fFlags & RTREQFLAGS_NO_WAIT))
247 {
248 *ppReq = pReq;
249 LogFlow(("RTReqCallV: returns %Rrc *ppReq=%p\n", rc, pReq));
250 }
251 else
252 LogFlow(("RTReqCallV: returns %Rrc\n", rc));
253 Assert(rc != VERR_INTERRUPTED);
254 return rc;
255}
256RT_EXPORT_SYMBOL(RTReqQueueCallV);
257
258
259RTDECL(bool) RTReqQueueIsBusy(RTREQQUEUE hQueue)
260{
261 PRTREQQUEUEINT pQueue = hQueue;
262 AssertPtrReturn(pQueue, false);
263
264 if (ASMAtomicReadBool(&pQueue->fBusy))
265 return true;
266 if (ASMAtomicReadPtrT(&pQueue->pReqs, PRTREQ) != NULL)
267 return true;
268 if (ASMAtomicReadBool(&pQueue->fBusy))
269 return true;
270 return false;
271}
272RT_EXPORT_SYMBOL(RTReqQueueIsBusy);
273
274
275/**
276 * Joins the list pList with whatever is linked up at *pHead.
277 */
278static void vmr3ReqJoinFreeSub(volatile PRTREQ *ppHead, PRTREQ pList)
279{
280 for (unsigned cIterations = 0;; cIterations++)
281 {
282 PRTREQ pHead = ASMAtomicXchgPtrT(ppHead, pList, PRTREQ);
283 if (!pHead)
284 return;
285 PRTREQ pTail = pHead;
286 while (pTail->pNext)
287 pTail = pTail->pNext;
288 pTail->pNext = pList;
289 if (ASMAtomicCmpXchgPtr(ppHead, pHead, pList))
290 return;
291 pTail->pNext = NULL;
292 if (ASMAtomicCmpXchgPtr(ppHead, pHead, NULL))
293 return;
294 pList = pHead;
295 Assert(cIterations != 32);
296 Assert(cIterations != 64);
297 }
298}
299
300
301/**
302 * Joins the list pList with whatever is linked up at *pHead.
303 */
304static void vmr3ReqJoinFree(PRTREQQUEUEINT pQueue, PRTREQ pList)
305{
306 /*
307 * Split the list if it's too long.
308 */
309 unsigned cReqs = 1;
310 PRTREQ pTail = pList;
311 while (pTail->pNext)
312 {
313 if (cReqs++ > 25)
314 {
315 const uint32_t i = pQueue->iReqFree;
316 vmr3ReqJoinFreeSub(&pQueue->apReqFree[(i + 2) % RT_ELEMENTS(pQueue->apReqFree)], pTail->pNext);
317
318 pTail->pNext = NULL;
319 vmr3ReqJoinFreeSub(&pQueue->apReqFree[(i + 2 + (i == pQueue->iReqFree)) % RT_ELEMENTS(pQueue->apReqFree)], pTail->pNext);
320 return;
321 }
322 pTail = pTail->pNext;
323 }
324 vmr3ReqJoinFreeSub(&pQueue->apReqFree[(pQueue->iReqFree + 2) % RT_ELEMENTS(pQueue->apReqFree)], pList);
325}
326
327
328RTDECL(int) RTReqQueueAlloc(RTREQQUEUE hQueue, PRTREQ *ppReq, RTREQTYPE enmType)
329{
330 /*
331 * Validate input.
332 */
333 PRTREQQUEUEINT pQueue = hQueue;
334 AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
335 AssertMsgReturn(enmType > RTREQTYPE_INVALID && enmType < RTREQTYPE_MAX, ("%d\n", enmType), VERR_RT_REQUEST_INVALID_TYPE);
336
337 /*
338 * Try get a recycled packet.
339 * While this could all be solved with a single list with a lock, it's a sport
340 * of mine to avoid locks.
341 */
342 int cTries = RT_ELEMENTS(pQueue->apReqFree) * 2;
343 while (--cTries >= 0)
344 {
345 PRTREQ volatile *ppHead = &pQueue->apReqFree[ASMAtomicIncU32(&pQueue->iReqFree) % RT_ELEMENTS(pQueue->apReqFree)];
346#if 0 /* sad, but this won't work safely because the reading of pReq->pNext. */
347 PRTREQ pNext = NULL;
348 PRTREQ pReq = *ppHead;
349 if ( pReq
350 && !ASMAtomicCmpXchgPtr(ppHead, (pNext = pReq->pNext), pReq)
351 && (pReq = *ppHead)
352 && !ASMAtomicCmpXchgPtr(ppHead, (pNext = pReq->pNext), pReq))
353 pReq = NULL;
354 if (pReq)
355 {
356 Assert(pReq->pNext == pNext); NOREF(pReq);
357#else
358 PRTREQ pReq = ASMAtomicXchgPtrT(ppHead, NULL, PRTREQ);
359 if (pReq)
360 {
361 PRTREQ pNext = pReq->pNext;
362 if ( pNext
363 && !ASMAtomicCmpXchgPtr(ppHead, pNext, NULL))
364 {
365 vmr3ReqJoinFree(pQueue, pReq->pNext);
366 }
367#endif
368 ASMAtomicDecU32(&pQueue->cReqFree);
369
370 /*
371 * Make sure the event sem is not signaled.
372 */
373 if (!pReq->fEventSemClear)
374 {
375 int rc = RTSemEventWait(pReq->EventSem, 0);
376 if (rc != VINF_SUCCESS && rc != VERR_TIMEOUT)
377 {
378 /*
379 * This shall not happen, but if it does we'll just destroy
380 * the semaphore and create a new one.
381 */
382 AssertMsgFailed(("rc=%Rrc from RTSemEventWait(%#x).\n", rc, pReq->EventSem));
383 RTSemEventDestroy(pReq->EventSem);
384 rc = RTSemEventCreate(&pReq->EventSem);
385 AssertRC(rc);
386 if (rc != VINF_SUCCESS)
387 return rc;
388 }
389 pReq->fEventSemClear = true;
390 }
391 else
392 Assert(RTSemEventWait(pReq->EventSem, 0) == VERR_TIMEOUT);
393
394 /*
395 * Initialize the packet and return it.
396 */
397 Assert(pReq->enmType == RTREQTYPE_INVALID);
398 Assert(pReq->enmState == RTREQSTATE_FREE);
399 Assert(pReq->hQueue == pQueue);
400 ASMAtomicXchgSize(&pReq->pNext, NULL);
401 pReq->enmState = RTREQSTATE_ALLOCATED;
402 pReq->iStatus = VERR_RT_REQUEST_STATUS_STILL_PENDING;
403 pReq->fFlags = RTREQFLAGS_IPRT_STATUS;
404 pReq->enmType = enmType;
405
406 *ppReq = pReq;
407 LogFlow(("RTReqAlloc: returns VINF_SUCCESS *ppReq=%p recycled\n", pReq));
408 return VINF_SUCCESS;
409 }
410 }
411
412 /*
413 * Ok allocate one.
414 */
415 PRTREQ pReq = (PRTREQ)RTMemAllocZ(sizeof(*pReq));
416 if (!pReq)
417 return VERR_NO_MEMORY;
418
419 /*
420 * Create the semaphore.
421 */
422 int rc = RTSemEventCreate(&pReq->EventSem);
423 AssertRC(rc);
424 if (rc != VINF_SUCCESS)
425 {
426 RTMemFree(pReq);
427 return rc;
428 }
429
430 /*
431 * Initialize the packet and return it.
432 */
433 pReq->pNext = NULL;
434 pReq->hQueue = pQueue;
435 pReq->enmState = RTREQSTATE_ALLOCATED;
436 pReq->iStatus = VERR_RT_REQUEST_STATUS_STILL_PENDING;
437 pReq->fEventSemClear = true;
438 pReq->fFlags = RTREQFLAGS_IPRT_STATUS;
439 pReq->enmType = enmType;
440
441 *ppReq = pReq;
442 LogFlow(("RTReqAlloc: returns VINF_SUCCESS *ppReq=%p new\n", pReq));
443 return VINF_SUCCESS;
444}
445RT_EXPORT_SYMBOL(RTReqQueueAlloc);
446
447
448RTDECL(int) RTReqFree(PRTREQ pReq)
449{
450 /*
451 * Ignore NULL (all free functions should do this imho).
452 */
453 if (!pReq)
454 return VINF_SUCCESS;
455
456
457 /*
458 * Check packet state.
459 */
460 switch (pReq->enmState)
461 {
462 case RTREQSTATE_ALLOCATED:
463 case RTREQSTATE_COMPLETED:
464 break;
465 default:
466 AssertMsgFailed(("Invalid state %d!\n", pReq->enmState));
467 return VERR_RT_REQUEST_STATE;
468 }
469
470 /*
471 * Make it a free packet and put it into one of the free packet lists.
472 */
473 pReq->enmState = RTREQSTATE_FREE;
474 pReq->iStatus = VERR_RT_REQUEST_STATUS_FREED;
475 pReq->enmType = RTREQTYPE_INVALID;
476
477 PRTREQQUEUEINT pQueue = pReq->hQueue;
478 if (pQueue->cReqFree < 128)
479 {
480 ASMAtomicIncU32(&pQueue->cReqFree);
481 PRTREQ volatile *ppHead = &pQueue->apReqFree[ASMAtomicIncU32(&pQueue->iReqFree) % RT_ELEMENTS(pQueue->apReqFree)];
482 PRTREQ pNext;
483 do
484 {
485 pNext = *ppHead;
486 ASMAtomicWritePtr(&pReq->pNext, pNext);
487 } while (!ASMAtomicCmpXchgPtr(ppHead, pReq, pNext));
488 }
489 else
490 {
491 RTSemEventDestroy(pReq->EventSem);
492 RTMemFree(pReq);
493 }
494 return VINF_SUCCESS;
495}
496RT_EXPORT_SYMBOL(RTReqFree);
497
498
499RTDECL(int) RTReqSubmit(PRTREQ pReq, RTMSINTERVAL cMillies)
500{
501 LogFlow(("RTReqQueue: pReq=%p cMillies=%d\n", pReq, cMillies));
502 /*
503 * Verify the supplied package.
504 */
505 if (pReq->enmState != RTREQSTATE_ALLOCATED)
506 {
507 AssertMsgFailed(("Invalid state %d\n", pReq->enmState));
508 return VERR_RT_REQUEST_STATE;
509 }
510 if ( !pReq->hQueue
511 || pReq->pNext
512 || !pReq->EventSem)
513 {
514 AssertMsgFailed(("Invalid request package! Anyone cooking their own packages???\n"));
515 return VERR_RT_REQUEST_INVALID_PACKAGE;
516 }
517 if ( pReq->enmType < RTREQTYPE_INVALID
518 || pReq->enmType > RTREQTYPE_MAX)
519 {
520 AssertMsgFailed(("Invalid package type %d valid range %d-%d inclusively. This was verified on alloc too...\n",
521 pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1));
522 return VERR_RT_REQUEST_INVALID_TYPE;
523 }
524
525 int rc = VINF_SUCCESS;
526 /*
527 * Insert it.
528 */
529 PRTREQQUEUEINT pQueue = ((RTREQ volatile *)pReq)->hQueue; /* volatile paranoia */
530 unsigned fFlags = ((RTREQ volatile *)pReq)->fFlags; /* volatile paranoia */
531 pReq->enmState = RTREQSTATE_QUEUED;
532 PRTREQ pNext;
533 do
534 {
535 pNext = pQueue->pReqs;
536 pReq->pNext = pNext;
537 ASMAtomicWriteBool(&pQueue->fBusy, true);
538 } while (!ASMAtomicCmpXchgPtr(&pQueue->pReqs, pReq, pNext));
539
540 /*
541 * Notify queue thread.
542 */
543 RTSemEventSignal(pQueue->EventSem);
544
545 /*
546 * Wait and return.
547 */
548 if (!(fFlags & RTREQFLAGS_NO_WAIT))
549 rc = RTReqWait(pReq, cMillies);
550 LogFlow(("RTReqQueue: returns %Rrc\n", rc));
551 return rc;
552}
553RT_EXPORT_SYMBOL(RTReqSubmit);
554
555
556RTDECL(int) RTReqWait(PRTREQ pReq, RTMSINTERVAL cMillies)
557{
558 LogFlow(("RTReqWait: pReq=%p cMillies=%d\n", pReq, cMillies));
559
560 /*
561 * Verify the supplied package.
562 */
563 if ( pReq->enmState != RTREQSTATE_QUEUED
564 && pReq->enmState != RTREQSTATE_PROCESSING
565 && pReq->enmState != RTREQSTATE_COMPLETED)
566 {
567 AssertMsgFailed(("Invalid state %d\n", pReq->enmState));
568 return VERR_RT_REQUEST_STATE;
569 }
570 if ( !pReq->hQueue
571 || !pReq->EventSem)
572 {
573 AssertMsgFailed(("Invalid request package! Anyone cooking their own packages???\n"));
574 return VERR_RT_REQUEST_INVALID_PACKAGE;
575 }
576 if ( pReq->enmType < RTREQTYPE_INVALID
577 || pReq->enmType > RTREQTYPE_MAX)
578 {
579 AssertMsgFailed(("Invalid package type %d valid range %d-%d inclusively. This was verified on alloc and queue too...\n",
580 pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1));
581 return VERR_RT_REQUEST_INVALID_TYPE;
582 }
583
584 /*
585 * Wait on the package.
586 */
587 int rc;
588 if (cMillies != RT_INDEFINITE_WAIT)
589 rc = RTSemEventWait(pReq->EventSem, cMillies);
590 else
591 {
592 do
593 {
594 rc = RTSemEventWait(pReq->EventSem, RT_INDEFINITE_WAIT);
595 Assert(rc != VERR_TIMEOUT);
596 } while (pReq->enmState != RTREQSTATE_COMPLETED);
597 }
598 if (rc == VINF_SUCCESS)
599 ASMAtomicXchgSize(&pReq->fEventSemClear, true);
600 if (pReq->enmState == RTREQSTATE_COMPLETED)
601 rc = VINF_SUCCESS;
602 LogFlow(("RTReqWait: returns %Rrc\n", rc));
603 Assert(rc != VERR_INTERRUPTED);
604 return rc;
605}
606RT_EXPORT_SYMBOL(RTReqWait);
607
608
609/**
610 * Process one request.
611 *
612 * @returns IPRT status code.
613 *
614 * @param pReq Request packet to process.
615 */
616static int rtReqProcessOne(PRTREQ pReq)
617{
618 LogFlow(("rtReqProcessOne: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags));
619
620 /*
621 * Process the request.
622 */
623 Assert(pReq->enmState == RTREQSTATE_QUEUED);
624 pReq->enmState = RTREQSTATE_PROCESSING;
625 int rcRet = VINF_SUCCESS; /* the return code of this function. */
626 int rcReq = VERR_NOT_IMPLEMENTED; /* the request status. */
627 switch (pReq->enmType)
628 {
629 /*
630 * A packed down call frame.
631 */
632 case RTREQTYPE_INTERNAL:
633 {
634 uintptr_t *pauArgs = &pReq->u.Internal.aArgs[0];
635 union
636 {
637 PFNRT pfn;
638 DECLCALLBACKMEMBER(int, pfn00)(void);
639 DECLCALLBACKMEMBER(int, pfn01)(uintptr_t);
640 DECLCALLBACKMEMBER(int, pfn02)(uintptr_t, uintptr_t);
641 DECLCALLBACKMEMBER(int, pfn03)(uintptr_t, uintptr_t, uintptr_t);
642 DECLCALLBACKMEMBER(int, pfn04)(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
643 DECLCALLBACKMEMBER(int, pfn05)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
644 DECLCALLBACKMEMBER(int, pfn06)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
645 DECLCALLBACKMEMBER(int, pfn07)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
646 DECLCALLBACKMEMBER(int, pfn08)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
647 DECLCALLBACKMEMBER(int, pfn09)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
648 DECLCALLBACKMEMBER(int, pfn10)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
649 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);
650 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);
651 } u;
652 u.pfn = pReq->u.Internal.pfn;
653#ifndef RT_ARCH_X86
654 switch (pReq->u.Internal.cArgs)
655 {
656 case 0: rcRet = u.pfn00(); break;
657 case 1: rcRet = u.pfn01(pauArgs[0]); break;
658 case 2: rcRet = u.pfn02(pauArgs[0], pauArgs[1]); break;
659 case 3: rcRet = u.pfn03(pauArgs[0], pauArgs[1], pauArgs[2]); break;
660 case 4: rcRet = u.pfn04(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3]); break;
661 case 5: rcRet = u.pfn05(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4]); break;
662 case 6: rcRet = u.pfn06(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5]); break;
663 case 7: rcRet = u.pfn07(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6]); break;
664 case 8: rcRet = u.pfn08(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7]); break;
665 case 9: rcRet = u.pfn09(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8]); break;
666 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;
667 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;
668 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;
669 default:
670 AssertReleaseMsgFailed(("cArgs=%d\n", pReq->u.Internal.cArgs));
671 rcRet = rcReq = VERR_INTERNAL_ERROR;
672 break;
673 }
674#else /* RT_ARCH_X86 */
675 size_t cbArgs = pReq->u.Internal.cArgs * sizeof(uintptr_t);
676# ifdef __GNUC__
677 __asm__ __volatile__("movl %%esp, %%edx\n\t"
678 "subl %2, %%esp\n\t"
679 "andl $0xfffffff0, %%esp\n\t"
680 "shrl $2, %2\n\t"
681 "movl %%esp, %%edi\n\t"
682 "rep movsl\n\t"
683 "movl %%edx, %%edi\n\t"
684 "call *%%eax\n\t"
685 "mov %%edi, %%esp\n\t"
686 : "=a" (rcRet),
687 "=S" (pauArgs),
688 "=c" (cbArgs)
689 : "0" (u.pfn),
690 "1" (pauArgs),
691 "2" (cbArgs)
692 : "edi", "edx");
693# else
694 __asm
695 {
696 xor edx, edx /* just mess it up. */
697 mov eax, u.pfn
698 mov ecx, cbArgs
699 shr ecx, 2
700 mov esi, pauArgs
701 mov ebx, esp
702 sub esp, cbArgs
703 and esp, 0xfffffff0
704 mov edi, esp
705 rep movsd
706 call eax
707 mov esp, ebx
708 mov rcRet, eax
709 }
710# endif
711#endif /* RT_ARCH_X86 */
712 if ((pReq->fFlags & (RTREQFLAGS_RETURN_MASK)) == RTREQFLAGS_VOID)
713 rcRet = VINF_SUCCESS;
714 rcReq = rcRet;
715 break;
716 }
717
718 default:
719 AssertMsgFailed(("pReq->enmType=%d\n", pReq->enmType));
720 rcReq = VERR_NOT_IMPLEMENTED;
721 break;
722 }
723
724 /*
725 * Complete the request.
726 */
727 pReq->iStatus = rcReq;
728 pReq->enmState = RTREQSTATE_COMPLETED;
729 if (pReq->fFlags & RTREQFLAGS_NO_WAIT)
730 {
731 /* Free the packet, nobody is waiting. */
732 LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc - freeing it\n",
733 pReq, rcReq, rcRet));
734 RTReqFree(pReq);
735 }
736 else
737 {
738 /* Notify the waiter and him free up the packet. */
739 LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc - notifying waiting thread\n",
740 pReq, rcReq, rcRet));
741 ASMAtomicXchgSize(&pReq->fEventSemClear, false);
742 int rc2 = RTSemEventSignal(pReq->EventSem);
743 if (rc2 != VINF_SUCCESS)
744 {
745 AssertRC(rc2);
746 rcRet = rc2;
747 }
748 }
749 return rcRet;
750}
751
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