Changeset 39500 in vbox
- Timestamp:
- Dec 1, 2011 8:26:48 PM (13 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/req.h
r39498 r39500 109 109 typedef struct RTREQ 110 110 { 111 /** Magic number (RTREQ_MAGIC). */ 112 uint32_t u32Magic; 113 /** Set if the event semaphore is clear. */ 114 volatile bool fEventSemClear; 115 /** Set if pool, clear if queue. */ 116 volatile bool fPoolOrQueue; 117 /** IPRT status code for the completed request. */ 118 volatile int32_t iStatus; 119 /** Request state. */ 120 volatile RTREQSTATE enmState; 121 111 122 /** Pointer to the next request in the chain. */ 112 123 struct RTREQ * volatile pNext; 113 /** Pointer to the queue this packet belongs to. */ 114 RTREQQUEUE hQueue; 115 /** Request state. */ 116 volatile RTREQSTATE enmState; 117 /** iprt status code for the completed request. */ 118 volatile int iStatus; 124 125 union 126 { 127 /** Pointer to the pool this packet belongs to. */ 128 RTREQPOOL hPool; 129 /** Pointer to the queue this packet belongs to. */ 130 RTREQQUEUE hQueue; 131 } uOwner; 132 119 133 /** Requester event sem. 120 134 * The request can use this event semaphore to wait/poll for completion … … 122 136 */ 123 137 RTSEMEVENT EventSem; 124 /** Set if the event semaphore is clear. */125 volatile bool fEventSemClear;126 138 /** Flags, RTREQ_FLAGS_*. */ 127 u nsignedfFlags;139 uint32_t fFlags; 128 140 /** Request type. */ 129 141 RTREQTYPE enmType; … … 137 149 PFNRT pfn; 138 150 /** Number of arguments. */ 139 u nsignedcArgs;151 uint32_t cArgs; 140 152 /** Array of arguments. */ 141 153 uintptr_t aArgs[64]; -
trunk/src/VBox/Runtime/Makefile.kmk
r39448 r39500 321 321 common/misc/once.cpp \ 322 322 common/misc/req.cpp \ 323 common/misc/reqpool.cpp \ 324 common/misc/reqqueue.cpp \ 323 325 common/misc/sanity-c.c \ 324 326 common/misc/sanity-cpp.cpp \ -
trunk/src/VBox/Runtime/common/misc/req.cpp
r39498 r39500 5 5 6 6 /* 7 * Copyright (C) 2006-20 07Oracle Corporation7 * Copyright (C) 2006-2011 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 42 42 43 43 #include "internal/req.h" 44 #include "internal/magics.h" 44 45 45 46 … … 47 48 * Internal Functions * 48 49 *******************************************************************************/ 49 static int rtReqProcessOne(PRTREQ pReq); 50 51 52 53 RTDECL(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 } 68 RT_EXPORT_SYMBOL(RTReqQueueCreate); 69 70 71 RTDECL(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 } 86 RT_EXPORT_SYMBOL(RTReqQueueDestroy); 87 88 89 RTDECL(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 } 163 RT_EXPORT_SYMBOL(RTReqQueueProcess); 164 165 166 RTDECL(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 } 174 RT_EXPORT_SYMBOL(RTReqQueueCall); 175 176 177 RTDECL(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 } 185 RT_EXPORT_SYMBOL(RTReqQueueCallVoid); 186 187 188 RTDECL(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 } 196 RT_EXPORT_SYMBOL(RTReqQueueCallEx); 197 198 199 RTDECL(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 } 256 RT_EXPORT_SYMBOL(RTReqQueueCallV); 257 258 259 RTDECL(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 } 272 RT_EXPORT_SYMBOL(RTReqQueueIsBusy); 273 274 275 /** 276 * Joins the list pList with whatever is linked up at *pHead. 277 */ 278 static 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 */ 304 static 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 328 RTDECL(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 } 445 RT_EXPORT_SYMBOL(RTReqQueueAlloc); 50 446 51 447 52 … … 453 58 if (!pReq) 454 59 return VINF_SUCCESS; 455 60 AssertPtrReturn(pReq, VERR_INVALID_POINTER); 61 AssertReturn(pReq->u32Magic == RTREQ_MAGIC, VERR_INVALID_PARAMETER); 456 62 457 63 /* … … 475 81 pReq->enmType = RTREQTYPE_INVALID; 476 82 477 PRTREQQUEUEINT pQueue = pReq-> hQueue;83 PRTREQQUEUEINT pQueue = pReq->uOwner.hQueue; 478 84 if (pQueue->cReqFree < 128) 479 85 { … … 508 114 return VERR_RT_REQUEST_STATE; 509 115 } 510 if ( !pReq-> hQueue116 if ( !pReq->uOwner.hQueue 511 117 || pReq->pNext 512 118 || !pReq->EventSem) … … 527 133 * Insert it. 528 134 */ 529 PRTREQQUEUEINT pQueue = ((RTREQ volatile *)pReq)-> hQueue;/* volatile paranoia */135 PRTREQQUEUEINT pQueue = ((RTREQ volatile *)pReq)->uOwner.hQueue; /* volatile paranoia */ 530 136 unsigned fFlags = ((RTREQ volatile *)pReq)->fFlags; /* volatile paranoia */ 531 137 pReq->enmState = RTREQSTATE_QUEUED; … … 568 174 return VERR_RT_REQUEST_STATE; 569 175 } 570 if ( !pReq-> hQueue176 if ( !pReq->uOwner.hQueue 571 177 || !pReq->EventSem) 572 178 { … … 614 220 * @param pReq Request packet to process. 615 221 */ 616 static intrtReqProcessOne(PRTREQ pReq)222 DECLHIDDEN(int) rtReqProcessOne(PRTREQ pReq) 617 223 { 618 224 LogFlow(("rtReqProcessOne: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags)); -
trunk/src/VBox/Runtime/include/internal/magics.h
r37396 r39500 111 111 /** RTRANDINT::u32Magic. (Alan Moore) */ 112 112 #define RTRANDINT_MAGIC UINT32_C(0x19531118) 113 /** The value of RTREQ::u32Magic. */ 114 #define RTREQ_MAGIC UINT32_C(0xfeed0001) /**< @todo find a value */ 115 /** The value of RTREQ::u32Magic of a freed request. */ 116 #define RTREQ_MAGIC_DEAD (~RTREQ_MAGIC) 117 /** The value of RTREQPOOLINT::u32Magic. */ 118 #define RTREQPOOL_MAGIC UINT32_C(0xfeed0002)/**< @todo find a value */ 119 /** The value of RTREQPOOLINT::u32Magic after destruction. */ 120 #define RTREQPOOL_MAGIC_DEAD (~RTREQPOOL_MAGIC) 121 /** The value of RTREQQUEUEINT::u32Magic. */ 122 #define RTREQQUEUE_MAGIC UINT32_C(0xfeed0003)/**< @todo find a value */ 123 /** The value of RTREQQUEUEINT::u32Magic after destruction. */ 124 #define RTREQQUEUE_MAGIC_DEAD (~RTREQQUEUE_MAGIC) 113 125 /** The value of RTS3::u32Magic. (Edgar Wallace) */ 114 126 #define RTS3_MAGIC UINT32_C(0x18750401) -
trunk/src/VBox/Runtime/include/internal/req.h
r39499 r39500 37 37 typedef struct RTREQQUEUEINT 38 38 { 39 /** @todo magic */ 39 /** Magic value (RTREQQUEUE_MAGIC). */ 40 uint32_t u32Magic; 41 /** Set if busy (pending or processing requests). */ 42 bool volatile fBusy; 40 43 /** Head of the request queue. Atomic. */ 41 44 volatile PRTREQ pReqs; … … 50 53 */ 51 54 RTSEMEVENT EventSem; 52 /** Set if busy (pending or processing requests). */53 bool volatile fBusy;54 55 } RTREQQUEUEINT; 55 56 … … 58 59 59 60 61 62 DECLHIDDEN(int) rtReqProcessOne(PRTREQ pReq); 63 60 64 RT_C_DECLS_END 61 65
Note:
See TracChangeset
for help on using the changeset viewer.