Changeset 33042 in vbox for trunk/src/VBox/Runtime
- Timestamp:
- Oct 11, 2010 3:55:26 PM (14 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/Makefile.kmk
r33038 r33042 1510 1510 darwin/RTErrConvertFromDarwinKern.cpp \ 1511 1511 generic/RTAssertShouldPanic-generic.cpp \ 1512 generic/RTSemEventMultiWait-2-ex-generic.cpp \ 1513 generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \ 1512 1514 generic/RTTimerCreate-generic.cpp \ 1513 1515 generic/mppresent-generic.cpp \ -
trunk/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp
r29255 r33042 39 39 #endif 40 40 #include <iprt/err.h> 41 #include <iprt/lockvalidator.h> 41 42 #include <iprt/mem.h> 42 43 #include <iprt/mp.h> 43 44 #include <iprt/thread.h> 45 #include <iprt/time.h> 44 46 45 47 #include "internal/magics.h" 48 49 50 /******************************************************************************* 51 * Defined Constants And Macros * 52 *******************************************************************************/ 53 /** @name fStateAndGen values 54 * @{ */ 55 /** The state bit number. */ 56 #define RTSEMEVENTMULTIDARWIN_STATE_BIT 0 57 /** The state mask. */ 58 #define RTSEMEVENTMULTIDARWIN_STATE_MASK RT_BIT_32(RTSEMEVENTMULTIDARWIN_STATE_BIT) 59 /** The generation mask. */ 60 #define RTSEMEVENTMULTIDARWIN_GEN_MASK ~RTSEMEVENTMULTIDARWIN_STATE_MASK 61 /** The generation shift. */ 62 #define RTSEMEVENTMULTIDARWIN_GEN_SHIFT 1 63 /** The initial variable value. */ 64 #define RTSEMEVENTMULTIDARWIN_STATE_GEN_INIT UINT32_C(0xfffffffc) 65 /** @} */ 46 66 47 67 … … 56 76 /** Magic value (RTSEMEVENTMULTI_MAGIC). */ 57 77 uint32_t volatile u32Magic; 58 /** The number of waiting threads. */ 59 uint32_t volatile cWaiters; 60 /** Set if the event object is signaled. */ 61 uint8_t volatile fSignaled; 62 /** The number of threads in the process of waking up. */ 63 uint32_t volatile cWaking; 78 /** The object state bit and generation counter. 79 * The generation counter is incremented every time the object is 80 * signalled. */ 81 uint32_t volatile fStateAndGen; 82 /** Reference counter. */ 83 uint32_t volatile cRefs; 84 /** Set if there are blocked threads. */ 85 bool volatile fHaveBlockedThreads; 64 86 /** The spinlock protecting us. */ 65 87 lck_spin_t *pSpinlock; … … 85 107 if (pThis) 86 108 { 87 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;88 pThis-> cWaiters = 0;89 pThis->c Waking = 0;90 pThis->f Signaled = 0;109 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC; 110 pThis->fStateAndGen = RTSEMEVENTMULTIDARWIN_STATE_GEN_INIT; 111 pThis->cRefs = 1; 112 pThis->fHaveBlockedThreads = false; 91 113 Assert(g_pDarwinLockGroup); 92 114 pThis->pSpinlock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL); … … 104 126 105 127 128 /** 129 * Retain a reference to the semaphore. 130 * 131 * @param pThis The semaphore. 132 */ 133 DECLINLINE(void) rtR0SemEventMultiDarwinRetain(PRTSEMEVENTMULTIINTERNAL pThis) 134 { 135 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); 136 Assert(cRefs && cRefs < 100000); 137 } 138 139 140 /** 141 * Release a reference, destroy the thing if necessary. 142 * 143 * @param pThis The semaphore. 144 */ 145 DECLINLINE(void) rtR0SemEventMultiDarwinRelease(PRTSEMEVENTMULTIINTERNAL pThis) 146 { 147 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0)) 148 { 149 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC); 150 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup); 151 RTMemFree(pThis); 152 } 153 } 154 155 106 156 RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem) 107 157 { … … 111 161 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 112 162 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE); 163 Assert(pThis->cRefs > 0); 113 164 RT_ASSERT_INTS_ON(); 114 165 115 166 lck_spin_lock(pThis->pSpinlock); 116 ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */ 117 if (pThis->cWaiters > 0) 118 { 119 /* abort waiting thread, last man cleans up. */ 120 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters); 167 168 ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC); /* make the handle invalid */ 169 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTIDARWIN_GEN_MASK); 170 if (pThis->fHaveBlockedThreads) 171 { 172 /* abort waiting threads. */ 121 173 thread_wakeup_prim((event_t)pThis, FALSE /* all threads */, THREAD_RESTART); 122 lck_spin_unlock(pThis->pSpinlock); 123 } 124 else if (pThis->cWaking) 125 /* the last waking thread is gonna do the cleanup */ 126 lck_spin_unlock(pThis->pSpinlock); 127 else 128 { 129 lck_spin_unlock(pThis->pSpinlock); 130 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup); 131 RTMemFree(pThis); 132 } 174 } 175 176 lck_spin_unlock(pThis->pSpinlock); 177 rtR0SemEventMultiDarwinRelease(pThis); 133 178 134 179 return VINF_SUCCESS; … … 144 189 RT_ASSERT_INTS_ON(); 145 190 191 rtR0SemEventMultiDarwinRetain(pThis); 146 192 lck_spin_lock(pThis->pSpinlock); 147 193 148 ASMAtomicXchgU8(&pThis->fSignaled, true); 149 if (pThis->cWaiters > 0) 150 { 151 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters); 152 ASMAtomicXchgU32(&pThis->cWaiters, 0); 194 uint32_t fNew = ASMAtomicUoReadU32(&pThis->fStateAndGen); 195 fNew += 1 << RTSEMEVENTMULTIDARWIN_GEN_SHIFT; 196 fNew |= RTSEMEVENTMULTIDARWIN_STATE_MASK; 197 ASMAtomicWriteU32(&pThis->fStateAndGen, fNew); 198 199 if (pThis->fHaveBlockedThreads) 200 { 201 ASMAtomicWriteBool(&pThis->fHaveBlockedThreads, false); 153 202 thread_wakeup_prim((event_t)pThis, FALSE /* all threads */, THREAD_AWAKENED); 154 203 } 155 204 156 205 lck_spin_unlock(pThis->pSpinlock); 206 rtR0SemEventMultiDarwinRelease(pThis); 157 207 158 208 RT_ASSERT_PREEMPT_CPUID(); … … 169 219 RT_ASSERT_INTS_ON(); 170 220 221 rtR0SemEventMultiDarwinRetain(pThis); 171 222 lck_spin_lock(pThis->pSpinlock); 172 ASMAtomicXchgU8(&pThis->fSignaled, false); 223 224 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTIDARWIN_STATE_MASK); 225 173 226 lck_spin_unlock(pThis->pSpinlock); 227 rtR0SemEventMultiDarwinRelease(pThis); 174 228 175 229 RT_ASSERT_PREEMPT_CPUID(); … … 178 232 179 233 180 static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, wait_interrupt_t fInterruptible) 181 { 182 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; 234 /** 235 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug. 236 * 237 * @returns VBox status code. 238 * @param pThis The event semaphore. 239 * @param fFlags See RTSemEventMultiWaitEx. 240 * @param uTimeout See RTSemEventMultiWaitEx. 241 * @param pSrcPos The source code position of the wait. 242 */ 243 static int rtR0SemEventMultiDarwinWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, 244 PCRTLOCKVALSRCPOS pSrcPos) 245 { 246 /* 247 * Validate input. 248 */ 183 249 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 184 250 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE); 185 if (cMillies) 251 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); 252 if (uTimeout != 0 || (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)) 186 253 RT_ASSERT_PREEMPTIBLE(); 187 254 255 rtR0SemEventMultiDarwinRetain(pThis); 188 256 lck_spin_lock(pThis->pSpinlock); 189 257 258 /* 259 * Is the event already signalled or do we have to wait? 260 */ 190 261 int rc; 191 if (pThis->fSignaled) 262 uint32_t const fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen); 263 if (fOrgStateAndGen & RTSEMEVENTMULTIDARWIN_STATE_MASK) 192 264 rc = VINF_SUCCESS; 193 else if (!cMillies)194 rc = VERR_TIMEOUT;195 265 else 196 266 { 197 ASMAtomicIncU32(&pThis->cWaiters); 198 199 wait_result_t rcWait; 200 if (cMillies == RT_INDEFINITE_WAIT) 201 rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible); 267 /* 268 * We have to wait. So, we'll need to convert the timeout and figure 269 * out if it's indefinite or not. 270 */ 271 uint64_t uNsAbsTimeout = 1; 272 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE)) 273 { 274 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) 275 uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000) 276 ? uTimeout * UINT32_C(1000000) 277 : UINT64_MAX; 278 if (uTimeout == UINT64_MAX) 279 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE; 280 else 281 { 282 uint64_t u64Now; 283 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE) 284 { 285 if (uTimeout != 0) 286 { 287 u64Now = RTTimeSystemNanoTS(); 288 uNsAbsTimeout = u64Now + uTimeout; 289 if (uNsAbsTimeout < u64Now) /* overflow */ 290 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE; 291 } 292 } 293 else 294 { 295 uNsAbsTimeout = uTimeout; 296 u64Now = RTTimeSystemNanoTS(); 297 uTimeout = u64Now < uTimeout ? uTimeout - u64Now : 0; 298 } 299 } 300 } 301 302 if ( !(fFlags & RTSEMWAIT_FLAGS_INDEFINITE) 303 && uTimeout == 0) 304 { 305 /* 306 * Poll call, we already checked the condition above so no need to 307 * wait for anything. 308 */ 309 rc = VERR_TIMEOUT; 310 } 202 311 else 203 312 { 204 uint64_t u64AbsTime; 205 nanoseconds_to_absolutetime(cMillies * UINT64_C(1000000), &u64AbsTime); 206 u64AbsTime += mach_absolute_time(); 207 208 rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT, 209 (event_t)pThis, fInterruptible, u64AbsTime); 313 for (;;) 314 { 315 /* 316 * Do the actual waiting. 317 */ 318 ASMAtomicWriteBool(&pThis->fHaveBlockedThreads, true); 319 wait_interrupt_t fInterruptible = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE ? THREAD_ABORTSAFE : THREAD_UNINT; 320 wait_result_t rcWait; 321 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE) 322 rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible); 323 else 324 { 325 uint64_t u64AbsTime; 326 nanoseconds_to_absolutetime(uNsAbsTimeout, &u64AbsTime); 327 rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT, 328 (event_t)pThis, fInterruptible, u64AbsTime); 329 } 330 331 /* 332 * Deal with the wait result. 333 */ 334 if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC)) 335 { 336 switch (rcWait) 337 { 338 case THREAD_AWAKENED: 339 if (RT_LIKELY(ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)) 340 rc = VINF_SUCCESS; 341 else if (fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE) 342 rc = VERR_INTERRUPTED; 343 else 344 continue; /* Seen this happen after fork/exec/something. */ 345 break; 346 347 case THREAD_TIMED_OUT: 348 Assert(!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE)); 349 rc = VERR_TIMEOUT; 350 break; 351 352 case THREAD_INTERRUPTED: 353 Assert(fInterruptible != THREAD_UNINT); 354 rc = VERR_INTERRUPTED; 355 break; 356 357 case THREAD_RESTART: 358 AssertMsg(pThis->u32Magic == ~RTSEMEVENTMULTI_MAGIC, ("%#x\n", pThis->u32Magic)); 359 rc = VERR_SEM_DESTROYED; 360 break; 361 362 default: 363 AssertMsgFailed(("rcWait=%d\n", rcWait)); 364 rc = VERR_INTERNAL_ERROR_3; 365 break; 366 } 367 } 368 else 369 rc = VERR_SEM_DESTROYED; 370 break; 371 } 210 372 } 211 switch (rcWait)212 {213 case THREAD_AWAKENED:214 Assert(pThis->cWaking > 0);215 if ( !ASMAtomicDecU32(&pThis->cWaking)216 && pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)217 {218 /* the event was destroyed after we woke up, as the last thread do the cleanup. */219 lck_spin_unlock(pThis->pSpinlock);220 Assert(g_pDarwinLockGroup);221 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);222 RTMemFree(pThis);223 return VINF_SUCCESS;224 }225 rc = VINF_SUCCESS;226 break;227 228 case THREAD_TIMED_OUT:229 Assert(cMillies != RT_INDEFINITE_WAIT);230 ASMAtomicDecU32(&pThis->cWaiters);231 rc = VERR_TIMEOUT;232 break;233 234 case THREAD_INTERRUPTED:235 Assert(fInterruptible);236 ASMAtomicDecU32(&pThis->cWaiters);237 rc = VERR_INTERRUPTED;238 break;239 240 case THREAD_RESTART:241 /* Last one out does the cleanup. */242 if (!ASMAtomicDecU32(&pThis->cWaking))243 {244 lck_spin_unlock(pThis->pSpinlock);245 Assert(g_pDarwinLockGroup);246 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);247 RTMemFree(pThis);248 return VERR_SEM_DESTROYED;249 }250 251 rc = VERR_SEM_DESTROYED;252 break;253 254 default:255 AssertMsgFailed(("rcWait=%d\n", rcWait));256 rc = VERR_GENERAL_FAILURE;257 break;258 }259 373 } 260 374 261 375 lck_spin_unlock(pThis->pSpinlock); 376 rtR0SemEventMultiDarwinRelease(pThis); 262 377 return rc; 263 378 } 264 379 265 266 RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies) 267 { 268 return rtSemEventMultiWait(hEventMultiSem, cMillies, THREAD_UNINT); 269 } 270 271 272 RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies) 273 { 274 return rtSemEventMultiWait(hEventMultiSem, cMillies, THREAD_ABORTSAFE); 275 } 276 380 #undef RTSemEventMultiWaitEx 381 RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout) 382 { 383 #ifndef RTSEMEVENT_STRICT 384 return rtR0SemEventMultiDarwinWait(hEventMultiSem, fFlags, uTimeout, NULL); 385 #else 386 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API(); 387 return rtR0SemEventMultiDarwinWait(hEventMultiSem, fFlags, uTimeout, &SrcPos); 388 #endif 389 } 390 391 392 RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout, 393 RTHCUINTPTR uId, RT_SRC_POS_DECL) 394 { 395 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API(); 396 return rtR0SemEventMultiDarwinWait(hEventMultiSem, fFlags, uTimeout, &SrcPos); 397 } 398
Note:
See TracChangeset
for help on using the changeset viewer.