Changeset 28515 in vbox
- Timestamp:
- Apr 20, 2010 11:30:26 AM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 60316
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp
r28503 r28515 37 37 #include <iprt/semaphore.h> 38 38 39 #include <iprt/a lloc.h>39 #include <iprt/asm.h> 40 40 #include <iprt/assert.h> 41 #include <iprt/asm.h>42 41 #include <iprt/err.h> 43 #include <iprt/m p.h>42 #include <iprt/mem.h> 44 43 #include <iprt/thread.h> 45 44 … … 50 49 * Structures and Typedefs * 51 50 *******************************************************************************/ 52 #if 0 /** @todo */53 51 /** 54 52 * Darwin mutex semaphore. … … 58 56 /** Magic value (RTSEMMUTEX_MAGIC). */ 59 57 uint32_t volatile u32Magic; 60 /** The mutex. */ 61 lck_mtx_t *pMtx; 58 /** The number of waiting threads. */ 59 uint32_t cWaiters; 60 /** The number of references. */ 61 uint32_t volatile cRefs; 62 /** The number of recursions. */ 63 uint32_t cRecursions; 64 /** The handle of the owner thread. */ 65 RTNATIVETHREAD hNativeOwner; 66 /** The spinlock protecting us. */ 67 lck_spin_t *pSpinlock; 62 68 } RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL; 63 69 64 #endif 65 66 67 68 69 #if 0 /* need proper timeout lock function! */ 70 RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phFastMtx) 71 { 70 71 72 RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem) 73 { 74 return RTSemMutexCreateEx(phMutexSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL); 75 } 76 77 78 RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags, 79 RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...) 80 { 81 AssertReturn(!(fFlags & ~RTSEMMUTEX_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER); 72 82 RT_ASSERT_PREEMPTIBLE(); 83 73 84 AssertCompile(sizeof(RTSEMMUTEXINTERNAL) > sizeof(void *)); 74 85 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis)); 75 86 if (pThis) 76 87 { 77 pThis->u32Magic = RTSEMMUTEX_MAGIC; 88 pThis->u32Magic = RTSEMMUTEX_MAGIC; 89 pThis->cWaiters = 0; 90 pThis->cRefs = 1; 91 pThis->cRecursions = 0; 92 pThis->hNativeOwner = NIL_RTNATIVETHREAD; 78 93 Assert(g_pDarwinLockGroup); 79 pThis->p Mtx = lck_mtx_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);80 if (pThis->p Mtx)94 pThis->pSpinlock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL); 95 if (pThis->pSpinlock) 81 96 { 82 *ph FastMtx= pThis;97 *phMutexSem = pThis; 83 98 return VINF_SUCCESS; 84 99 } 100 85 101 RTMemFree(pThis); 86 102 } 87 103 return VERR_NO_MEMORY; 104 } 105 106 107 /** 108 * Called when the refcount reaches zero. 109 */ 110 static void rtSemMutexDarwinFree(PRTSEMMUTEXINTERNAL pThis) 111 { 112 lck_spin_unlock(pThis->pSpinlock); 113 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup); 114 RTMemFree(pThis); 88 115 } 89 116 … … 98 125 return VERR_INVALID_PARAMETER; 99 126 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 100 AssertMsg (pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);127 AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE); 101 128 RT_ASSERT_INTS_ON(); 102 129 103 130 /* 104 * Invalidate it and signal the object just in case. 105 */ 106 ASMAtomicIncU32(&pThis->u32Magic); 107 108 Assert(g_pDarwinLockGroup); 109 lck_mtx_free(pThis->pMtx, g_pDarwinLockGroup); 110 pThis->pMtx = NULL; 111 112 RTMemFree(pThis); 131 * Kill it, wake up all waiting threads and release the reference. 132 */ 133 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMMUTEX_MAGIC, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE); 134 lck_spin_lock(pThis->pSpinlock); 135 136 if (pThis->cWaiters > 0) 137 thread_wakeup_prim((event_t)pThis, FALSE /* one_thread */, THREAD_RESTART); 138 139 if (ASMAtomicDecU32(&pThis->cRefs) == 0) 140 rtSemMutexDarwinFree(pThis); 141 else 142 lck_spin_unlock(pThis->pSpinlock); 143 113 144 return VINF_SUCCESS; 114 145 } 115 146 116 147 117 RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies) 118 { 119 /* 120 * Validate input. 121 */ 122 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem; 123 if (!pThis) 124 return VERR_INVALID_PARAMETER; 125 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 126 AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE); 127 if (cMillies) 128 RT_ASSERT_PREEMPTIBLE(); 129 130 /* 131 * Get the mutex. 132 */ 133 wait_result_t rc = lck_mtx_lock_deadlink 134 #if 1 135 #else 136 NTSTATUS rcNt; 148 /** 149 * Internal worker for the sleep scenario. 150 * 151 * Called owning the spinlock, returns without it. 152 * 153 * @returns IPRT status code. 154 * @param pThis The mutex instance. 155 * @param cMillies The timeout. 156 * @param fInterruptible Whether it's interruptible 157 * (RTSemMutexRequestNoResume) or not 158 * (RTSemMutexRequest). 159 * @param hNativeSelf The thread handle of the caller. 160 */ 161 static int rtR0SemMutexDarwinRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVAL cMillies, 162 wait_interrupt_t fInterruptible, RTNATIVETHREAD hNativeSelf) 163 { 164 /* 165 * Grab a reference and indicate that we're waiting. 166 */ 167 pThis->cWaiters++; 168 ASMAtomicIncU32(&pThis->cRefs); 169 170 /* 171 * Go to sleep, use the address of the mutex instance as sleep/blocking/event id. 172 */ 173 wait_result_t rcWait; 137 174 if (cMillies == RT_INDEFINITE_WAIT) 138 rcNt = KeWaitForSingleObject(&pThis->Mutex, Executive, KernelMode, TRUE, NULL); 139 else 140 { 141 LARGE_INTEGER Timeout; 142 Timeout.QuadPart = -(int64_t)cMillies * 10000; 143 rcNt = KeWaitForSingleObject(&pThis->Mutex, Executive, KernelMode, TRUE, &Timeout); 144 } 145 switch (rcNt) 146 { 147 case STATUS_SUCCESS: 148 if (pThis->u32Magic == RTSEMMUTEX_MAGIC) 149 return VINF_SUCCESS; 150 return VERR_SEM_DESTROYED; 151 case STATUS_ALERTED: 152 return VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */ 153 case STATUS_USER_APC: 154 return VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */ 155 case STATUS_TIMEOUT: 156 return VERR_TIMEOUT; 175 rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible); 176 else 177 { 178 uint64_t u64AbsTime; 179 nanoseconds_to_absolutetime(cMillies * UINT64_C(1000000), &u64AbsTime); 180 u64AbsTime += mach_absolute_time(); 181 182 rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT, 183 (event_t)pThis, fInterruptible, u64AbsTime); 184 } 185 /* 186 * Translate the rc. 187 */ 188 int rc; 189 switch (rcWait) 190 { 191 case THREAD_AWAKENED: 192 if (RT_LIKELY(pThis->u32Magic == RTSEMMUTEX_MAGIC)) 193 { 194 if (RT_LIKELY( pThis->cRecursions == 0 195 && pThis->hNativeOwner == NIL_RTNATIVETHREAD)) 196 { 197 pThis->cRecursions = 1; 198 pThis->hNativeOwner = hNativeSelf; 199 rc = VINF_SUCCESS; 200 } 201 else 202 { 203 Assert(pThis->cRecursions == 0); 204 Assert(pThis->hNativeOwner == NIL_RTNATIVETHREAD); 205 rc = VERR_INTERNAL_ERROR_3; 206 } 207 } 208 else 209 rc = VERR_SEM_DESTROYED; 210 break; 211 212 case THREAD_TIMED_OUT: 213 Assert(cMillies != RT_INDEFINITE_WAIT); 214 rc = VERR_TIMEOUT; 215 break; 216 217 case THREAD_INTERRUPTED: 218 Assert(fInterruptible); 219 rc = VERR_INTERRUPTED; 220 break; 221 222 case THREAD_RESTART: 223 Assert(pThis->u32Magic == ~RTSEMMUTEX_MAGIC); 224 rc = VERR_SEM_DESTROYED; 225 break; 226 157 227 default: 158 AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %lx!\n", 159 pThis->u32Magic, pThis, (long)rcNt)); 160 return VERR_INTERNAL_ERROR; 161 } 162 #endif 163 return VINF_SUCCESS; 164 } 165 166 167 RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem) 228 AssertMsgFailed(("rcWait=%d\n", rcWait)); 229 rc = VERR_GENERAL_FAILURE; 230 break; 231 } 232 233 /* 234 * Dereference it and quit the lock. 235 */ 236 Assert(pThis->cWaiters > 0); 237 pThis->cWaiters--; 238 239 Assert(pThis->cRefs > 0); 240 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0)) 241 rtSemMutexDarwinFree(pThis); 242 else 243 lck_spin_unlock(pThis->pSpinlock); 244 return rc; 245 } 246 247 248 /** 249 * Internal worker for RTSemMutexRequest and RTSemMutexRequestNoResume 250 * 251 * @returns IPRT status code. 252 * @param hMutexSem The mutex handle. 253 * @param cMillies The timeout. 254 * @param fInterruptible Whether it's interruptible 255 * (RTSemMutexRequestNoResume) or not 256 * (RTSemMutexRequest). 257 */ 258 DECLINLINE(int) rtR0SemMutexDarwinRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, wait_interrupt_t fInterruptible) 168 259 { 169 260 /* … … 172 263 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem; 173 264 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 174 Assert Msg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);265 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE); 175 266 RT_ASSERT_PREEMPTIBLE(); 176 267 177 268 /* 178 * Release the mutex. 179 */ 180 #ifdef RT_USE_FAST_MUTEX 181 ExReleaseFastMutex(&pThis->Mutex); 182 #else 183 KeReleaseMutex(&pThis->Mutex, FALSE); 184 #endif 269 * Grab the lock and check out the state. 270 */ 271 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf(); 272 int rc = VINF_SUCCESS; 273 lck_spin_lock(pThis->pSpinlock); 274 275 /* Recursive call? */ 276 if (pThis->hNativeOwner == hNativeSelf) 277 { 278 Assert(pThis->cRecursions > 0); 279 Assert(pThis->cRecursions < 256); 280 pThis->cRecursions++; 281 } 282 283 /* Is it free and nobody ahead of us in the queue? */ 284 else if ( pThis->hNativeOwner == NIL_RTNATIVETHREAD 285 && pThis->cWaiters == 0) 286 { 287 pThis->hNativeOwner = hNativeSelf; 288 pThis->cRecursions = 1; 289 } 290 291 /* Polling call? */ 292 else if (cMillies == 0) 293 rc = VERR_TIMEOUT; 294 295 /* Yawn, time for a nap... */ 296 else 297 return rtR0SemMutexDarwinRequestSleep(pThis, cMillies, fInterruptible, hNativeSelf); 298 299 lck_spin_unlock(pThis->pSpinlock); 300 return rc; 301 } 302 303 304 #undef RTSemMutexRequest 305 RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies) 306 { 307 return rtR0SemMutexDarwinRequest(hMutexSem, cMillies, THREAD_UNINT); 308 } 309 310 311 RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL) 312 { 313 return RTSemMutexRequest(hMutexSem, cMillies); 314 } 315 316 317 #undef RTSemMutexRequestNoResume 318 RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies) 319 { 320 return rtR0SemMutexDarwinRequest(hMutexSem, cMillies, THREAD_ABORTSAFE); 321 } 322 323 324 RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL) 325 { 326 return RTSemMutexRequestNoResume(hMutexSem, cMillies); 327 } 328 329 330 RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem) 331 { 332 /* 333 * Validate input. 334 */ 335 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem; 336 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 337 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE); 338 RT_ASSERT_PREEMPTIBLE(); 339 340 /* 341 * Take the lock and do the job. 342 */ 343 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf(); 344 int rc = VINF_SUCCESS; 345 lck_spin_lock(pThis->pSpinlock); 346 347 if (pThis->hNativeOwner == hNativeSelf) 348 { 349 Assert(pThis->cRecursions > 0); 350 if (--pThis->cRecursions == 0) 351 { 352 pThis->hNativeOwner = NIL_RTNATIVETHREAD; 353 if (pThis->cWaiters > 0) 354 { 355 int rc2=thread_wakeup_prim((event_t)pThis, TRUE /* one_thread */, THREAD_AWAKENED); 356 } 357 358 } 359 } 360 else 361 rc = VERR_NOT_OWNER; 362 363 lck_spin_unlock(pThis->pSpinlock); 364 365 AssertRC(rc); 185 366 return VINF_SUCCESS; 186 367 } 187 368 188 #endif /* later */ 189 369 370 RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem) 371 { 372 /* 373 * Validate. 374 */ 375 RTSEMMUTEXINTERNAL *pThis = hMutexSem; 376 AssertPtrReturn(pThis, false); 377 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, false); 378 379 /* 380 * Take the lock and do the check. 381 */ 382 lck_spin_lock(pThis->pSpinlock); 383 bool fRc = pThis->hNativeOwner != NIL_RTNATIVETHREAD; 384 lck_spin_unlock(pThis->pSpinlock); 385 386 return fRc; 387 } 388
Note:
See TracChangeset
for help on using the changeset viewer.