Changeset 28436 in vbox
- Timestamp:
- Apr 17, 2010 9:40:51 PM (15 years ago)
- Location:
- trunk/src/VBox/Runtime/r0drv/linux
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
r25724 r28436 5 5 6 6 /* 7 * Copyright (C) 2006-20 07Sun Microsystems, Inc.7 * Copyright (C) 2006-2010 Sun Microsystems, Inc. 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 36 36 #include "internal/iprt.h" 37 37 #include <iprt/semaphore.h> 38 #include <iprt/alloc.h> 38 39 39 #include <iprt/assert.h> 40 40 #include <iprt/asm.h> 41 #include <iprt/mem.h> 41 42 #include <iprt/err.h> 43 #include <iprt/list.h> 42 44 43 45 #include "internal/magics.h" … … 47 49 * Structures and Typedefs * 48 50 *******************************************************************************/ 51 typedef struct RTSEMMUTEXLNXWAITER 52 { 53 /** The list entry. */ 54 RTLISTNODE ListEntry; 55 /** The waiting task. */ 56 struct task_struct *pTask; 57 /** Why did we wake up? */ 58 enum 59 { 60 /** Wakeup to take the semaphore. */ 61 RTSEMMUTEXLNXWAITER_WAKEUP, 62 /** Mutex is being destroyed. */ 63 RTSEMMUTEXLNXWAITER_DESTROYED, 64 /** Some other reason. */ 65 RTSEMMUTEXLNXWAITER_OTHER 66 } volatile enmReason; 67 } RTSEMMUTEXLNXWAITER, *PRTSEMMUTEXLNXWAITER; 68 49 69 /** 50 * Linux mutex semaphore.70 * Wrapper for the linux semaphore structure. 51 71 */ 52 72 typedef struct RTSEMMUTEXINTERNAL 53 73 { 54 74 /** Magic value (RTSEMMUTEX_MAGIC). */ 55 uint32_t volatile u32Magic; 56 /** Number of recursive locks - 0 if not owned by anyone, > 0 if owned. */ 57 uint32_t volatile cRecursion; 58 /** The wait queue. */ 59 wait_queue_head_t Head; 60 /** The current owner. */ 61 void * volatile pOwner; 75 uint32_t u32Magic; 76 /** The number of recursions. */ 77 uint32_t cRecursions; 78 /** The list of waiting threads. */ 79 RTLISTNODE WaiterList; 80 /** The current owner, NULL if none. */ 81 struct task_struct *pOwnerTask; 82 /** The number of references to this piece of memory. This is used to 83 * prevent it from being kicked from underneath us while waiting. */ 84 uint32_t volatile cRefs; 85 /** The spinlock protecting the members and falling asleep. */ 86 spinlock_t Spinlock; 62 87 } RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL; 63 88 64 89 65 66 RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem) 67 { 68 return RTSemMutexCreateEx(phMutexSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL); 69 } 70 71 72 RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags, 73 RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...) 74 { 90 RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMtx) 91 { 92 /* 93 * Allocate. 94 */ 75 95 PRTSEMMUTEXINTERNAL pThis; 76 77 AssertReturn(!(fFlags & ~RTSEMMUTEX_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);78 79 96 pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis)); 80 if (pThis) 81 { 82 pThis->u32Magic = RTSEMMUTEX_MAGIC; 83 pThis->cRecursion = 0; 84 pThis->pOwner = NULL; 85 init_waitqueue_head(&pThis->Head); 86 87 *phMutexSem = pThis; 88 AssertReleaseMsgFailed(("This mutex implementation is buggy, fix it!\n")); 89 return VINF_SUCCESS; 90 } 91 return VERR_NO_MEMORY; 97 if (!pThis) 98 return VERR_NO_MEMORY; 99 100 /* 101 * Initialize. 102 */ 103 pThis->u32Magic = RTSEMMUTEX_MAGIC; 104 pThis->cRecursions = 0; 105 pThis->pOwnerTask = NULL; 106 pThis->cRefs = 1; 107 RTListInit(&pThis->WaiterList); 108 spin_lock_init(&pThis->Spinlock); 109 110 *phMtx = pThis; 111 return VINF_SUCCESS; 92 112 } 93 113 RT_EXPORT_SYMBOL(RTSemMutexCreate); 94 114 95 115 96 RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem) 97 { 98 /* 99 * Validate input. 100 */ 101 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem; 116 RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMtx) 117 { 118 PRTSEMMUTEXINTERNAL pThis = hMtx; 119 PRTSEMMUTEXLNXWAITER pCur; 120 unsigned long fSavedIrq; 121 122 /* 123 * Validate. 124 */ 102 125 if (pThis == NIL_RTSEMMUTEX) 103 126 return VINF_SUCCESS; 104 127 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 105 Assert Return(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);106 107 /* 108 * Invalidate it and signal the object just in case.128 AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE); 129 130 /* 131 * Kill it, kick waiters and release it. 109 132 */ 110 133 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE); 111 ASMAtomicWriteU32(&pThis->cRecursion, 0); 112 Assert(!waitqueue_active(&pThis->Head)); 113 wake_up_all(&pThis->Head); 114 115 RTMemFree(pThis); 134 135 spin_lock_irqsave(&pThis->Spinlock, fSavedIrq); 136 RTListForEach(&pThis->WaiterList, pCur, RTSEMMUTEXLNXWAITER, ListEntry) 137 { 138 pCur->enmReason = RTSEMMUTEXLNXWAITER_DESTROYED; 139 wake_up_process(pCur->pTask); 140 } 141 142 if (ASMAtomicDecU32(&pThis->cRefs) != 0) 143 spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq); 144 else 145 { 146 spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq); 147 RTMemFree(pThis); 148 } 149 116 150 return VINF_SUCCESS; 117 151 } … … 119 153 120 154 155 /** 156 * Worker for rtSemMutexLinuxRequest that handles the case where we go to sleep. 157 * 158 * @returns VINF_SUCCESS, VERR_INTERRUPTED, VERR_TIMEOUT or VERR_SEM_DESTROYED. 159 * Returns without owning the spinlock. 160 * @param pThis The mutex instance. 161 * @param cMillies The timeout. 162 * @param fInterruptible The wait type. 163 * @param fSavedIrq The saved IRQ flags. 164 */ 165 static int rtSemMutexLinuxRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVAL cMillies, 166 bool fInterruptible, unsigned long fSavedIrq) 167 { 168 struct task_struct *pSelf = current; 169 int rc = VERR_TIMEOUT; 170 long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies); 171 RTSEMMUTEXLNXWAITER Waiter; 172 173 IPRT_DEBUG_SEMS_STATE(pThis, 'm'); 174 175 /* 176 * Grab a reference to the mutex and add ourselves to the waiter list. 177 */ 178 ASMAtomicIncU32(&pThis->cRefs); 179 180 Waiter.pTask = pSelf; 181 Waiter.enmReason = RTSEMMUTEXLNXWAITER_OTHER; 182 RTListAppend(&pThis->WaiterList, &Waiter.ListEntry); 183 184 /* 185 * Do the waiting. 186 */ 187 for (;;) 188 { 189 /* Check signal and timeout conditions. */ 190 if ( fInterruptible 191 && signal_pending(pSelf)) 192 { 193 rc = VERR_INTERRUPTED; 194 break; 195 } 196 197 if (!lTimeout) 198 break; 199 200 /* Go to sleep. */ 201 set_task_state(pSelf, fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); 202 spin_unlock_irq(&pThis->Spinlock); 203 204 lTimeout = schedule_timeout(lTimeout); 205 206 spin_lock_irq(&pThis->Spinlock); 207 set_current_state(TASK_RUNNING); 208 209 /* Did someone wake us up? */ 210 if (Waiter.enmReason == RTSEMMUTEXLNXWAITER_WAKEUP) 211 { 212 Assert(pThis->cRecursions == 0); 213 pThis->cRecursions = 1; 214 pThis->pOwnerTask = NULL; 215 rc = VINF_SUCCESS; 216 break; 217 } 218 219 /* Is the mutex being destroyed? */ 220 if (RT_UNLIKELY( Waiter.enmReason == RTSEMMUTEXLNXWAITER_DESTROYED 221 || pThis->u32Magic != RTSEMMUTEX_MAGIC)) 222 { 223 rc = VERR_SEM_DESTROYED; 224 break; 225 } 226 } 227 228 /* 229 * Unlink ourself from the waiter list, dereference the mutex and exit the 230 * lock. We might have to free the mutex if it was the destroyed. 231 */ 232 RTListNodeRemove(&Waiter.ListEntry); 233 IPRT_DEBUG_SEMS_STATE_RC(pThis, 'M', rc); 234 235 if (RT_LIKELY(ASMAtomicDecU32(&pThis->cRefs) != 0)) 236 spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq); 237 else 238 { 239 Assert(RT_FAILURE_NP(rc)); 240 spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq); 241 RTMemFree(pThis); 242 } 243 return rc; 244 } 245 246 247 /** 248 * Internal worker. 249 */ 250 DECLINLINE(int) rtSemMutexLinuxRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, bool fInterruptible) 251 { 252 PRTSEMMUTEXINTERNAL pThis = hMutexSem; 253 struct task_struct *pSelf = current; 254 unsigned long fSavedIrq; 255 int rc; 256 257 /* 258 * Validate. 259 */ 260 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 261 AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE); 262 Assert(pThis->cRefs >= 1); 263 264 /* 265 * Lock it and check if it's a recursion. 266 */ 267 spin_lock_irqsave(&pThis->Spinlock, fSavedIrq); 268 if (pThis->pOwnerTask == pSelf) 269 { 270 pThis->cRecursions++; 271 Assert(pThis->cRecursions > 1); 272 Assert(pThis->cRecursions < 256); 273 rc = VINF_SUCCESS; 274 } 275 /* 276 * Not a recursion, maybe it's not owned by anyone then? 277 */ 278 else if (pThis->pOwnerTask == NULL) 279 { 280 Assert(pThis->cRecursions == 0); 281 pThis->cRecursions = 1; 282 pThis->pOwnerTask = pSelf; 283 rc = VINF_SUCCESS; 284 } 285 /* 286 * Was it a polling call? 287 */ 288 else if (cMillies == 0) 289 rc = VERR_TIMEOUT; 290 /* 291 * No, so go to sleep. 292 */ 293 else 294 return rtSemMutexLinuxRequestSleep(pThis, cMillies, fInterruptible, fSavedIrq); 295 296 IPRT_DEBUG_SEMS_STATE_RC(pThis, 'M', rc); 297 spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq); 298 return rc; 299 } 300 301 121 302 #undef RTSemMutexRequest 122 RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies) 123 { 124 int rc = VINF_SUCCESS; 125 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem; 126 127 /* 128 * Validate input. 303 RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies) 304 { 305 return rtSemMutexLinuxRequest(hMutexSem, cMillies, false /*fInterruptible*/); 306 } 307 RT_EXPORT_SYMBOL(RTSemMutexRequest); 308 309 310 RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL) 311 { 312 return RTSemMutexRequest(hMutexSem, cMillies); 313 } 314 RT_EXPORT_SYMBOL(RTSemMutexRequestDebug); 315 316 317 #undef RTSemMutexRequestNoResume 318 RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies) 319 { 320 return rtSemMutexLinuxRequest(hMutexSem, cMillies, true /*fInterruptible*/); 321 } 322 RT_EXPORT_SYMBOL(RTSemMutexRequest); 323 324 325 RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL) 326 { 327 return RTSemMutexRequestNoResume(hMutexSem, cMillies); 328 } 329 RT_EXPORT_SYMBOL(RTSemMutexRequestNoResumeDebug); 330 331 332 RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMtx) 333 { 334 PRTSEMMUTEXINTERNAL pThis = hMtx; 335 struct task_struct *pSelf = current; 336 unsigned long fSavedIrq; 337 int rc; 338 339 /* 340 * Validate. 129 341 */ 130 342 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 131 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE); 132 133 /* 134 * Check for recursive request. 135 */ 136 if (pThis->pOwner == current) 137 { 138 Assert(pThis->cRecursion < 1000); 139 ASMAtomicIncU32(&pThis->cRecursion); 140 return VINF_SUCCESS; 141 } 142 143 /* 144 * Try aquire it. 145 */ 146 if (ASMAtomicCmpXchgU32(&pThis->cRecursion, 1, 0)) 147 ASMAtomicWritePtr(&pThis->pOwner, current); 343 AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE); 344 Assert(pThis->cRefs >= 1); 345 346 /* 347 * Take the lock and release one recursion. 348 */ 349 spin_lock_irqsave(&pThis->Spinlock, fSavedIrq); 350 if (pThis->pOwnerTask == pSelf) 351 { 352 Assert(pThis->cRecursions > 0); 353 if (--pThis->cRecursions == 0) 354 { 355 pThis->pOwnerTask = NULL; 356 357 /* anyone to wake up? */ 358 if (!RTListIsEmpty(&pThis->WaiterList)) 359 { 360 PRTSEMMUTEXLNXWAITER pWaiter = RTListNodeGetFirst(&pThis->WaiterList, RTSEMMUTEXLNXWAITER, ListEntry); 361 pWaiter->enmReason = RTSEMMUTEXLNXWAITER_WAKEUP; 362 wake_up_process(pWaiter->pTask); 363 } 364 IPRT_DEBUG_SEMS_STATE(pThis, 'u'); 365 } 366 } 148 367 else 149 { 150 /* 151 * Ok wait for it. 152 */ 153 DEFINE_WAIT(Wait); 154 long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies); 155 for (;;) 156 { 157 /* make everything thru schedule() atomic scheduling wise. */ 158 prepare_to_wait(&pThis->Head, &Wait, TASK_INTERRUPTIBLE); 159 160 /* check the condition. */ 161 if (ASMAtomicCmpXchgU32(&pThis->cRecursion, 1, 0)) 162 { 163 ASMAtomicWritePtr(&pThis->pOwner, current); 164 break; 165 } 166 167 /* check for pending signals. */ 168 if (signal_pending(current)) 169 { 170 rc = VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */ 171 break; 172 } 173 174 /* wait */ 175 lTimeout = schedule_timeout(lTimeout); 176 177 after_wait(&Wait); 178 179 /* Check if someone destroyed the semaphore while we was waiting. */ 180 if (pThis->u32Magic != RTSEMMUTEX_MAGIC) 181 { 182 rc = VERR_SEM_DESTROYED; 183 break; 184 } 185 186 /* check for timeout. */ 187 if (!lTimeout) 188 { 189 rc = VERR_TIMEOUT; 190 break; 191 } 192 } 193 finish_wait(&pThis->Head, &Wait); 194 } 368 rc = VERR_NOT_OWNER; 369 spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq); 370 371 AssertRC(rc); 195 372 return rc; 196 373 } 197 RT_EXPORT_SYMBOL(RTSemMutexRequest);198 199 200 RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)201 {202 /*203 * Validate input.204 */205 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;206 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);207 AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);208 209 AssertReturn(pThis->pOwner == current, VERR_NOT_OWNER);210 211 /*212 * Release the mutex.213 */214 if (pThis->cRecursion == 1)215 {216 ASMAtomicWritePtr(&pThis->pOwner, NULL);217 ASMAtomicWriteU32(&pThis->cRecursion, 0);218 wake_up(&pThis->Head);219 }220 else221 ASMAtomicDecU32(&pThis->cRecursion);222 223 return VINF_SUCCESS;224 }225 374 RT_EXPORT_SYMBOL(RTSemMutexRelease); 226 375 376 377 RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem) 378 { 379 PRTSEMMUTEXINTERNAL pThis = hMutexSem; 380 unsigned long fSavedIrq; 381 bool fOwned; 382 383 /* 384 * Validate. 385 */ 386 AssertPtrReturn(pThis, false); 387 AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), false); 388 Assert(pThis->cRefs >= 1); 389 390 /* 391 * Take the lock and release one recursion. 392 */ 393 spin_lock_irqsave(&pThis->Spinlock, fSavedIrq); 394 fOwned = pThis->pOwnerTask != NULL; 395 spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq); 396 397 return fOwned; 398 399 } 400 RT_EXPORT_SYMBOL(RTSemMutexIsOwned); 401 -
trunk/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
r25591 r28436 320 320 #endif 321 321 322 /** 323 * Puts semaphore info into the task_struct::comm field if IPRT_DEBUG_SEMS is 324 * defined. 325 */ 326 #ifdef IPRT_DEBUG_SEMS 327 # define IPRT_DEBUG_SEMS_STATE(pThis, chState) \ 328 snprintf(current->comm, TASK_COMM_LEN, "%c%lx", (chState), IPRT_DEBUG_SEMS_ADDRESS(pThis)); 329 #else 330 # define IPRT_DEBUG_SEMS_STATE(pThis, chState) do { } while (0) 331 #endif 332 333 /** 334 * Puts semaphore info into the task_struct::comm field if IPRT_DEBUG_SEMS is 335 * defined. 336 */ 337 #ifdef IPRT_DEBUG_SEMS 338 # define IPRT_DEBUG_SEMS_STATE_RC(pThis, chState, rc) \ 339 snprintf(current->comm, TASK_COMM_LEN, "%c%lx:%d", (chState), IPRT_DEBUG_SEMS_ADDRESS(pThis), rc); 340 #else 341 # define IPRT_DEBUG_SEMS_STATE_RC(pThis, chState, rc) do { } while (0) 342 #endif 343 322 344 /* 323 345 * There are some conflicting defines in iprt/param.h, sort them out here.
Note:
See TracChangeset
for help on using the changeset viewer.