- Timestamp:
- Oct 24, 2010 12:55:23 PM (14 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 1 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxGuest/freebsd/Makefile
r31518 r33376 113 113 RTRandAdvCreateSystemFaster-generic.c \ 114 114 RTRandAdvCreateSystemTruer-generic.c \ 115 RTSemEventWait-2-ex-generic.c \ 116 RTSemEventWaitNoResume-2-ex-generic.c \ 117 RTSemEventMultiWait-2-ex-generic.c \ 118 RTSemEventMultiWaitNoResume-2-ex-generic.c \ 115 119 RTTimerCreate-generic.c \ 116 120 timer-generic.c \ -
trunk/src/VBox/Additions/common/VBoxGuest/freebsd/files_vboxguest
r33111 r33376 147 147 ${PATH_ROOT}/src/VBox/Runtime/generic/RTRandAdvCreateSystemTruer-generic.cpp=>generic/RTRandAdvCreateSystemTruer-generic.c \ 148 148 ${PATH_ROOT}/src/VBox/Runtime/generic/uuid-generic.cpp=>generic/uuid-generic.c \ 149 ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp=>generic/RTSemEventWait-2-ex-generic.c \ 150 ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventWaitNoResume-2-ex-generic.c \ 151 ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp=>generic/RTSemEventMultiWait-2-ex-generic.c \ 152 ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventMultiWaitNoResume-2-ex-generic.c \ 149 153 ${PATH_ROOT}/src/VBox/Runtime/generic/RTTimerCreate-generic.cpp=>generic/RTTimerCreate-generic.c \ 150 154 ${PATH_ROOT}/src/VBox/Runtime/generic/timer-generic.cpp=>generic/timer-generic.c \ … … 171 175 ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/thread2-r0drv-freebsd.c=>r0drv/freebsd/thread2-r0drv-freebsd.c \ 172 176 ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/time-r0drv-freebsd.c=>r0drv/freebsd/time-r0drv-freebsd.c \ 177 ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h=>r0drv/freebsd/sleepqueue-r0drv-freebsd.h \ 173 178 ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c=>r0drv/generic/semspinmutex-r0drv-generic.c \ 174 179 ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp=>r0drv/generic/mpnotification-r0drv-generic.c \ -
trunk/src/VBox/HostDrivers/Support/freebsd/Makefile
r32572 r33376 128 128 RTRandAdvCreateSystemFaster-generic.c \ 129 129 RTRandAdvCreateSystemTruer-generic.c \ 130 RTSemEventWait-2-ex-generic.c \ 131 RTSemEventWaitNoResume-2-ex-generic.c \ 132 RTSemEventMultiWait-2-ex-generic.c \ 133 RTSemEventMultiWaitNoResume-2-ex-generic.c \ 130 134 RTTimerCreate-generic.c \ 131 135 timer-generic.c \ -
trunk/src/VBox/HostDrivers/Support/freebsd/files_vboxdrv
r33111 r33376 150 150 ${PATH_ROOT}/src/VBox/Runtime/generic/RTRandAdvCreateSystemTruer-generic.cpp=>generic/RTRandAdvCreateSystemTruer-generic.c \ 151 151 ${PATH_ROOT}/src/VBox/Runtime/generic/uuid-generic.cpp=>generic/uuid-generic.c \ 152 ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp=>generic/RTSemEventWait-2-ex-generic.c \ 153 ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventWaitNoResume-2-ex-generic.c \ 154 ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp=>generic/RTSemEventMultiWait-2-ex-generic.c \ 155 ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventMultiWaitNoResume-2-ex-generic.c \ 152 156 ${PATH_ROOT}/src/VBox/Runtime/generic/RTTimerCreate-generic.cpp=>generic/RTTimerCreate-generic.c \ 153 157 ${PATH_ROOT}/src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp=>generic/RTMpGetArraySize-generic.c \ … … 176 180 ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/thread2-r0drv-freebsd.c=>r0drv/freebsd/thread2-r0drv-freebsd.c \ 177 181 ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/time-r0drv-freebsd.c=>r0drv/freebsd/time-r0drv-freebsd.c \ 182 ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h=>r0drv/freebsd/sleepqueue-r0drv-freebsd.h \ 178 183 ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c=>r0drv/generic/semspinmutex-r0drv-generic.c \ 179 184 ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/mpnotification-r0drv-generic.cpp=>r0drv/generic/mpnotification-r0drv-generic.c \ -
trunk/src/VBox/Runtime/r0drv/freebsd/semevent-r0drv-freebsd.c
r33269 r33376 33 33 *******************************************************************************/ 34 34 #include "the-freebsd-kernel.h" 35 35 #include "internal/iprt.h" 36 36 #include <iprt/semaphore.h> 37 #include <iprt/alloc.h> 37 38 38 #include <iprt/asm.h> 39 39 #include <iprt/assert.h> 40 40 #include <iprt/err.h> 41 #include <iprt/spinlock.h> 42 41 #include <iprt/lockvalidator.h> 42 #include <iprt/mem.h> 43 44 #include "sleepqueue-r0drv-freebsd.h" 43 45 #include "internal/magics.h" 44 46 … … 54 56 /** Magic value (RTSEMEVENT_MAGIC). */ 55 57 uint32_t volatile u32Magic; 56 /** The number of waiting threads. */ 57 uint32_t volatile cWaiters; 58 /** Set if the event object is signaled. */ 59 uint8_t volatile fSignaled; 60 /** The number of threads in the process of waking up. */ 61 uint32_t volatile cWaking; 62 /** Spinlock protecting this structure. */ 63 RTSPINLOCK hSpinLock; 58 /** The object status - !0 when signaled and 0 when reset. */ 59 uint32_t volatile fState; 60 /** Reference counter. */ 61 uint32_t volatile cRefs; 64 62 } RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL; 65 63 … … 83 81 84 82 pThis->u32Magic = RTSEMEVENT_MAGIC; 85 pThis->cWaiters = 0; 86 pThis->cWaking = 0; 87 pThis->fSignaled = 0; 88 int rc = RTSpinlockCreate(&pThis->hSpinLock); 89 if (RT_SUCCESS(rc)) 90 { 91 *phEventSem = pThis; 92 return VINF_SUCCESS; 93 } 94 95 RTMemFree(pThis); 96 return rc; 83 pThis->cRefs = 1; 84 pThis->fState = 0; 85 86 *phEventSem = pThis; 87 return VINF_SUCCESS; 88 } 89 90 91 /** 92 * Retains a reference to the event semaphore. 93 * 94 * @param pThis The event semaphore. 95 */ 96 DECLINLINE(void) rtR0SemEventBsdRetain(PRTSEMEVENTINTERNAL pThis) 97 { 98 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); 99 Assert(cRefs < 100000); NOREF(cRefs); 100 } 101 102 103 /** 104 * Releases a reference to the event semaphore. 105 * 106 * @param pThis The event semaphore. 107 */ 108 DECLINLINE(void) rtR0SemEventBsdRelease(PRTSEMEVENTINTERNAL pThis) 109 { 110 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0)) 111 RTMemFree(pThis); 97 112 } 98 113 … … 100 115 RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem) 101 116 { 117 /* 118 * Validate input. 119 */ 102 120 PRTSEMEVENTINTERNAL pThis = hEventSem; 103 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;104 105 121 if (pThis == NIL_RTSEMEVENT) 106 122 return VINF_SUCCESS; 123 AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE); 124 Assert(pThis->cRefs > 0); 125 126 /* 127 * Invalidate it and signal the object just in case. 128 */ 129 ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENT_MAGIC); 130 ASMAtomicWriteU32(&pThis->fState, 0); 131 rtR0SemBsdBroadcast(pThis); 132 rtR0SemEventBsdRelease(pThis); 133 return VINF_SUCCESS; 134 } 135 136 137 RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem) 138 { 139 /* 140 * Validate input. 141 */ 142 PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem; 107 143 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 108 AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE); 109 110 RTSpinlockAcquire(pThis->hSpinLock, &Tmp); 111 112 ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */ 113 if (pThis->cWaiters > 0) 114 { 115 /* abort waiting thread, last man cleans up. */ 116 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters); 117 sleepq_lock(pThis); 118 sleepq_broadcast(pThis, SLEEPQ_CONDVAR, 0, 0); 119 sleepq_release(pThis); 120 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 121 } 122 else if (pThis->cWaking) 123 /* the last waking thread is gonna do the cleanup */ 124 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 144 AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE); 145 rtR0SemEventBsdRetain(pThis); 146 147 /* 148 * Signal the event object. 149 */ 150 ASMAtomicWriteU32(&pThis->fState, 1); 151 rtR0SemBsdSignal(pThis); 152 rtR0SemEventBsdRelease(pThis); 153 return VINF_SUCCESS; 154 } 155 156 /** 157 * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug. 158 * 159 * @returns VBox status code. 160 * @param pThis The event semaphore. 161 * @param fFlags See RTSemEventWaitEx. 162 * @param uTimeout See RTSemEventWaitEx. 163 * @param pSrcPos The source code position of the wait. 164 */ 165 static int rtR0SemEventWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, 166 PCRTLOCKVALSRCPOS pSrcPos) 167 { 168 int rc; 169 170 /* 171 * Validate the input. 172 */ 173 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); 174 AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); 175 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); 176 rtR0SemEventBsdRetain(pThis); 177 178 /* 179 * Try grab the event without setting up the wait. 180 */ 181 if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1)) 182 rc = VINF_SUCCESS; 125 183 else 126 184 { 127 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 128 RTSpinlockDestroy(pThis->hSpinLock); 129 RTMemFree(pThis); 130 } 131 132 return VINF_SUCCESS; 133 } 134 135 136 RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem) 137 { 138 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 139 PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem; 140 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 141 AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, 142 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 143 VERR_INVALID_HANDLE); 144 145 RTSpinlockAcquire(pThis->hSpinLock, &Tmp); 146 147 if (pThis->cWaiters > 0) 148 { 149 ASMAtomicDecU32(&pThis->cWaiters); 150 ASMAtomicIncU32(&pThis->cWaking); 151 sleepq_lock(pThis); 152 int fWakeupSwapProc = sleepq_signal(pThis, SLEEPQ_CONDVAR, 0, 0); 153 sleepq_release(pThis); 154 if (fWakeupSwapProc) 155 kick_proc0(); 156 } 157 else 158 ASMAtomicXchgU8(&pThis->fSignaled, true); 159 160 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 161 return VINF_SUCCESS; 162 } 163 164 165 static int rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, bool fInterruptible) 166 { 167 int rc; 168 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 169 PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem; 170 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 171 AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, 172 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 173 VERR_INVALID_HANDLE); 174 175 RTSpinlockAcquire(pThis->hSpinLock, &Tmp); 176 177 if (pThis->fSignaled) 178 { 179 Assert(!pThis->cWaiters); 180 ASMAtomicXchgU8(&pThis->fSignaled, false); 181 rc = VINF_SUCCESS; 182 } 183 else 184 { 185 if (cMillies == 0) 186 rc = VERR_TIMEOUT; 187 else 185 /* 186 * We have to wait. 187 */ 188 RTR0SEMBSDSLEEP Wait; 189 rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis); 190 if (RT_SUCCESS(rc)) 188 191 { 189 ASMAtomicIncU32(&pThis->cWaiters); 190 191 int fFlags = SLEEPQ_CONDVAR; 192 193 if (fInterruptible) 194 fFlags |= SLEEPQ_INTERRUPTIBLE; 195 196 sleepq_lock(pThis); 197 sleepq_add(pThis, NULL, "IPRT Event Semaphore", fFlags, 0); 198 199 if (cMillies != RT_INDEFINITE_WAIT) 192 for (;;) 200 193 { 201 /* 202 * Translate milliseconds into ticks and go to sleep. 203 */ 204 struct timeval tv; 205 206 tv.tv_sec = cMillies / 1000; 207 tv.tv_usec = (cMillies % 1000) * 1000; 208 209 sleepq_set_timeout(pThis, tvtohz(&tv)); 210 211 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 212 213 if (fInterruptible) 214 rc = SLEEPQ_TIMEDWAIT_SIG(pThis); 215 else 216 rc = SLEEPQ_TIMEDWAIT(pThis); 217 } 218 else 219 { 220 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 221 222 if (fInterruptible) 223 rc = SLEEPQ_WAIT_SIG(pThis); 194 /* The destruction test. */ 195 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC)) 196 rc = VERR_SEM_DESTROYED; 224 197 else 225 198 { 226 rc = 0; 227 SLEEPQ_WAIT(pThis); 228 } 229 } 230 231 RTSpinlockAcquire(pThis->hSpinLock, &Tmp); 232 233 switch (rc) 234 { 235 case 0: 236 if (pThis->u32Magic == RTSEMEVENT_MAGIC) 237 { 238 ASMAtomicDecU32(&pThis->cWaking); 199 rtR0SemBsdWaitPrepare(&Wait); 200 201 /* Check the exit conditions. */ 202 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC)) 203 rc = VERR_SEM_DESTROYED; 204 else if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1)) 239 205 rc = VINF_SUCCESS; 240 } 206 else if (rtR0SemBsdWaitHasTimedOut(&Wait)) 207 rc = VERR_TIMEOUT; 208 else if (rtR0SemBsdWaitWasInterrupted(&Wait)) 209 rc = VERR_INTERRUPTED; 241 210 else 242 211 { 243 rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've 244 * could've woken up just before destruction... */ 245 if (!ASMAtomicDecU32(&pThis->cWaking)) 246 { 247 /* The event was destroyed, as the last thread do the cleanup. 248 we don't actually know whether */ 249 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 250 RTSpinlockDestroy(pThis->hSpinLock); 251 RTMemFree(pThis); 252 return rc; 253 } 212 /* Do the wait and then recheck the conditions. */ 213 rtR0SemBsdWaitDoIt(&Wait); 214 continue; 254 215 } 255 break; 256 257 case EWOULDBLOCK: 258 Assert(cMillies != RT_INDEFINITE_WAIT); 259 if (pThis->cWaiters > 0) 260 ASMAtomicDecU32(&pThis->cWaiters); 261 rc = VERR_TIMEOUT; 262 break; 263 264 case EINTR: 265 case ERESTART: 266 Assert(fInterruptible); 267 if (pThis->cWaiters > 0) 268 ASMAtomicDecU32(&pThis->cWaiters); 269 rc = VERR_INTERRUPTED; 270 break; 271 272 default: 273 AssertMsgFailed(("sleepq_* -> %d\n", rc)); 274 rc = VERR_GENERAL_FAILURE; 275 break; 216 } 217 break; 276 218 } 219 220 rtR0SemBsdWaitDelete(&Wait); 277 221 } 278 222 } 279 223 280 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 281 224 rtR0SemEventBsdRelease(pThis); 282 225 return rc; 283 226 } 284 227 285 228 286 RTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies) 287 { 288 return rtSemEventWait(hEventSem, cMillies, false /* not interruptible */); 289 } 290 291 292 RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies) 293 { 294 return rtSemEventWait(hEventSem, cMillies, true /* interruptible */); 295 } 229 #undef RTSemEventWaitEx 230 RTDECL(int) RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout) 231 { 232 #ifndef RTSEMEVENT_STRICT 233 return rtR0SemEventWait(hEventSem, fFlags, uTimeout, NULL); 234 #else 235 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API(); 236 return rtR0SemEventWait(hEventSem, fFlags, uTimeout, &SrcPos); 237 #endif 238 } 239 RT_EXPORT_SYMBOL(RTSemEventWaitEx); 240 241 242 RTDECL(int) RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout, 243 RTHCUINTPTR uId, RT_SRC_POS_DECL) 244 { 245 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API(); 246 return rtR0SemEventWait(hEventSem, fFlags, uTimeout, &SrcPos); 247 } 248 RT_EXPORT_SYMBOL(RTSemEventWaitExDebug); 296 249 297 250 -
trunk/src/VBox/Runtime/r0drv/freebsd/semeventmulti-r0drv-freebsd.c
r33155 r33376 33 33 *******************************************************************************/ 34 34 #include "the-freebsd-kernel.h" 35 35 #include "internal/iprt.h" 36 36 #include <iprt/semaphore.h> 37 #include <iprt/alloc.h> 37 38 #include <iprt/assert.h> 38 39 #include <iprt/asm.h> 39 #include <iprt/assert.h>40 40 #include <iprt/err.h> 41 #include <iprt/spinlock.h> 42 41 #include <iprt/mem.h> 42 #include <iprt/lockvalidator.h> 43 44 #include "sleepqueue-r0drv-freebsd.h" 43 45 #include "internal/magics.h" 46 47 48 /******************************************************************************* 49 * Defined Constants And Macros * 50 *******************************************************************************/ 51 /** @name fStateAndGen values 52 * @{ */ 53 /** The state bit number. */ 54 #define RTSEMEVENTMULTIBSD_STATE_BIT 0 55 /** The state mask. */ 56 #define RTSEMEVENTMULTIBSD_STATE_MASK RT_BIT_32(RTSEMEVENTMULTIBSD_STATE_BIT) 57 /** The generation mask. */ 58 #define RTSEMEVENTMULTIBSD_GEN_MASK ~RTSEMEVENTMULTIBSD_STATE_MASK 59 /** The generation shift. */ 60 #define RTSEMEVENTMULTIBSD_GEN_SHIFT 1 61 /** The initial variable value. */ 62 #define RTSEMEVENTMULTIBSD_STATE_GEN_INIT UINT32_C(0xfffffffc) 63 /** @} */ 44 64 45 65 /******************************************************************************* … … 53 73 /** Magic value (RTSEMEVENTMULTI_MAGIC). */ 54 74 uint32_t volatile u32Magic; 55 /** The number of waiting threads. */ 56 uint32_t volatile cWaiters; 57 /** Set if the event object is signaled. */ 58 uint8_t volatile fSignaled; 59 /** The number of threads in the process of waking up. */ 60 uint32_t volatile cWaking; 61 /** Spinlock protecting this structure. */ 62 RTSPINLOCK hSpinLock; 75 /** The object state bit and generation counter. 76 * The generation counter is incremented every time the object is 77 * signalled. */ 78 uint32_t volatile fStateAndGen; 79 /** Reference counter. */ 80 uint32_t volatile cRefs; 63 81 } RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL; 64 82 … … 73 91 const char *pszNameFmt, ...) 74 92 { 75 AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *)); 93 PRTSEMEVENTMULTIINTERNAL pThis; 94 76 95 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER); 77 AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER); 78 79 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAllocZ(sizeof(*pThis)); 96 pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis)); 80 97 if (pThis) 81 98 { 82 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC; 83 pThis->cWaiters = 0; 84 pThis->cWaking = 0; 85 pThis->fSignaled = 0; 86 int rc = RTSpinlockCreate(&pThis->hSpinLock); 87 if (RT_SUCCESS(rc)) 88 { 89 *phEventMultiSem = pThis; 90 return VINF_SUCCESS; 91 } 92 93 RTMemFree(pThis); 94 return rc; 99 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC; 100 pThis->fStateAndGen = RTSEMEVENTMULTIBSD_STATE_GEN_INIT; 101 pThis->cRefs = 1; 102 103 *phEventMultiSem = pThis; 104 return VINF_SUCCESS; 95 105 } 96 106 return VERR_NO_MEMORY; … … 98 108 99 109 110 /** 111 * Retain a reference to the semaphore. 112 * 113 * @param pThis The semaphore. 114 */ 115 DECLINLINE(void) rtR0SemEventMultiBsdRetain(PRTSEMEVENTMULTIINTERNAL pThis) 116 { 117 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); 118 Assert(cRefs && cRefs < 100000); 119 } 120 121 122 /** 123 * Release a reference, destroy the thing if necessary. 124 * 125 * @param pThis The semaphore. 126 */ 127 DECLINLINE(void) rtR0SemEventMultiBsdRelease(PRTSEMEVENTMULTIINTERNAL pThis) 128 { 129 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0)) 130 { 131 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC); 132 RTMemFree(pThis); 133 } 134 } 135 136 100 137 RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem) 101 138 { 139 /* 140 * Validate input. 141 */ 102 142 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; 103 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;104 105 143 if (pThis == NIL_RTSEMEVENTMULTI) 106 144 return VINF_SUCCESS; 107 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 108 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE); 109 110 RTSpinlockAcquire(pThis->hSpinLock, &Tmp); 111 ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */ 112 if (pThis->cWaiters > 0) 145 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); 146 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); 147 Assert(pThis->cRefs > 0); 148 149 /* 150 * Invalidate it and signal the object just in case. 151 */ 152 ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC); 153 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTIBSD_GEN_MASK); 154 rtR0SemBsdBroadcast(pThis); 155 rtR0SemEventMultiBsdRelease(pThis); 156 return VINF_SUCCESS; 157 } 158 159 160 RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem) 161 { 162 uint32_t fNew; 163 uint32_t fOld; 164 165 /* 166 * Validate input. 167 */ 168 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; 169 if (!pThis) 170 return VERR_INVALID_PARAMETER; 171 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); 172 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); 173 rtR0SemEventMultiBsdRetain(pThis); 174 175 /* 176 * Signal the event object. The cause of the parnoia here is racing to try 177 * deal with racing RTSemEventMultiSignal calls (should probably be 178 * forbidden, but it's relatively easy to handle). 179 */ 180 do 113 181 { 114 /* abort waiting thread, last man cleans up. */ 115 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters); 116 sleepq_lock(pThis); 117 sleepq_broadcast(pThis, SLEEPQ_CONDVAR, 0, 0); 118 sleepq_release(pThis); 119 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 182 fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen); 183 fNew += 1 << RTSEMEVENTMULTIBSD_GEN_SHIFT; 184 fNew |= RTSEMEVENTMULTIBSD_STATE_MASK; 120 185 } 121 else if (pThis->cWaking) 122 /* the last waking thread is gonna do the cleanup */ 123 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 124 else 125 { 126 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 127 RTSpinlockDestroy(pThis->hSpinLock); 128 RTMemFree(pThis); 129 } 130 186 while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld)); 187 188 rtR0SemBsdBroadcast(pThis); 189 rtR0SemEventMultiBsdRelease(pThis); 131 190 return VINF_SUCCESS; 132 191 } 133 192 134 193 135 RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem) 136 { 137 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 194 RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem) 195 { 196 /* 197 * Validate input. 198 */ 138 199 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; 139 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 140 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, 141 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 142 VERR_INVALID_HANDLE); 143 144 RTSpinlockAcquire(pThis->hSpinLock, &Tmp); 145 146 ASMAtomicXchgU8(&pThis->fSignaled, true); 147 if (pThis->cWaiters > 0) 148 { 149 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters); 150 ASMAtomicXchgU32(&pThis->cWaiters, 0); 151 sleepq_lock(pThis); 152 int fWakeupSwapProc = sleepq_signal(pThis, SLEEPQ_CONDVAR, 0, 0); 153 sleepq_release(pThis); 154 if (fWakeupSwapProc) 155 kick_proc0(); 156 } 157 158 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 200 if (!pThis) 201 return VERR_INVALID_PARAMETER; 202 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); 203 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); 204 rtR0SemEventMultiBsdRetain(pThis); 205 206 /* 207 * Reset it. 208 */ 209 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTIBSD_STATE_MASK); 210 211 rtR0SemEventMultiBsdRelease(pThis); 159 212 return VINF_SUCCESS; 160 213 } 161 214 162 215 163 RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem) 164 { 165 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 166 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; 167 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 168 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, 169 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 170 VERR_INVALID_HANDLE); 171 172 RTSpinlockAcquire(pThis->hSpinLock, &Tmp); 173 ASMAtomicXchgU8(&pThis->fSignaled, false); 174 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 175 return VINF_SUCCESS; 176 } 177 178 179 static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, bool fInterruptible) 180 { 181 int rc; 182 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 183 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; 184 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 185 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, 186 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 187 VERR_INVALID_HANDLE); 188 189 RTSpinlockAcquire(pThis->hSpinLock, &Tmp); 190 191 if (pThis->fSignaled) 216 /** 217 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug. 218 * 219 * @returns VBox status code. 220 * @param pThis The event semaphore. 221 * @param fFlags See RTSemEventMultiWaitEx. 222 * @param uTimeout See RTSemEventMultiWaitEx. 223 * @param pSrcPos The source code position of the wait. 224 */ 225 static int rtR0SemEventMultiBsdWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, 226 PCRTLOCKVALSRCPOS pSrcPos) 227 { 228 uint32_t fOrgStateAndGen; 229 int rc; 230 231 /* 232 * Validate the input. 233 */ 234 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); 235 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); 236 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); 237 rtR0SemEventMultiBsdRetain(pThis); 238 239 /* 240 * Is the event already signalled or do we have to wait? 241 */ 242 fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen); 243 if (fOrgStateAndGen & RTSEMEVENTMULTIBSD_STATE_MASK) 192 244 rc = VINF_SUCCESS; 193 245 else 194 246 { 195 if (cMillies == 0) 196 rc = VERR_TIMEOUT; 197 else 247 /* 248 * We have to wait. 249 */ 250 RTR0SEMBSDSLEEP Wait; 251 rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis); 252 if (RT_SUCCESS(rc)) 198 253 { 199 ASMAtomicIncU32(&pThis->cWaiters); 200 201 int fFlags = SLEEPQ_CONDVAR; 202 203 if (fInterruptible) 204 fFlags |= SLEEPQ_INTERRUPTIBLE; 205 206 sleepq_lock(pThis); 207 sleepq_add(pThis, NULL, "IPRT Event Semaphore", fFlags, 0); 208 209 if (cMillies != RT_INDEFINITE_WAIT) 254 for (;;) 210 255 { 211 /* 212 * Translate milliseconds into ticks and go to sleep. 213 */ 214 struct timeval tv; 215 216 tv.tv_sec = cMillies / 1000; 217 tv.tv_usec = (cMillies % 1000) * 1000; 218 219 sleepq_set_timeout(pThis, tvtohz(&tv)); 220 221 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 222 223 if (fInterruptible) 224 rc = SLEEPQ_TIMEDWAIT_SIG(pThis); 225 else 226 rc = SLEEPQ_TIMEDWAIT(pThis); 227 } 228 else 229 { 230 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 231 232 if (fInterruptible) 233 rc = SLEEPQ_WAIT_SIG(pThis); 256 /* The destruction test. */ 257 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) 258 rc = VERR_SEM_DESTROYED; 234 259 else 235 260 { 236 rc = 0; 237 SLEEPQ_WAIT(pThis); 238 } 239 } 240 241 RTSpinlockAcquire(pThis->hSpinLock, &Tmp); 242 243 switch (rc) 244 { 245 case 0: 246 if (pThis->u32Magic == RTSEMEVENTMULTI_MAGIC) 247 { 248 ASMAtomicDecU32(&pThis->cWaking); 261 rtR0SemBsdWaitPrepare(&Wait); 262 263 /* Check the exit conditions. */ 264 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) 265 rc = VERR_SEM_DESTROYED; 266 else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen) 249 267 rc = VINF_SUCCESS; 250 } 268 else if (rtR0SemBsdWaitHasTimedOut(&Wait)) 269 rc = VERR_TIMEOUT; 270 else if (rtR0SemBsdWaitWasInterrupted(&Wait)) 271 rc = VERR_INTERRUPTED; 251 272 else 252 273 { 253 rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've 254 * could've woken up just before destruction... */ 255 if (!ASMAtomicDecU32(&pThis->cWaking)) 256 { 257 /* The event was destroyed, as the last thread do the cleanup. 258 we don't actually know whether */ 259 RTSpinlockRelease(pThis->hSpinLock, &Tmp); 260 RTSpinlockDestroy(pThis->hSpinLock); 261 RTMemFree(pThis); 262 return rc; 263 } 274 /* Do the wait and then recheck the conditions. */ 275 rtR0SemBsdWaitDoIt(&Wait); 276 continue; 264 277 } 265 break; 266 267 case EWOULDBLOCK: 268 Assert(cMillies != RT_INDEFINITE_WAIT); 269 if (pThis->cWaiters > 0) 270 ASMAtomicDecU32(&pThis->cWaiters); 271 rc = VERR_TIMEOUT; 272 break; 273 274 case EINTR: 275 case ERESTART: 276 Assert(fInterruptible); 277 if (pThis->cWaiters > 0) 278 ASMAtomicDecU32(&pThis->cWaiters); 279 rc = VERR_INTERRUPTED; 280 break; 281 282 default: 283 AssertMsgFailed(("sleepq_* -> %d\n", rc)); 284 rc = VERR_GENERAL_FAILURE; 285 break; 278 } 279 break; 286 280 } 281 282 rtR0SemBsdWaitDelete(&Wait); 287 283 } 288 284 } 289 285 290 RTSpinlockRelease(pThis->hSpinLock, &Tmp);286 rtR0SemEventMultiBsdRelease(pThis); 291 287 return rc; 292 288 } 293 289 294 290 295 RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies) 296 { 297 return rtSemEventMultiWait(hEventMultiSem, cMillies, false /* not interruptible */); 298 } 299 300 301 RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies) 302 { 303 return rtSemEventMultiWait(hEventMultiSem, cMillies, true /* interruptible */); 304 } 291 #undef RTSemEventMultiWaitEx 292 RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout) 293 { 294 #ifndef RTSEMEVENT_STRICT 295 return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, NULL); 296 #else 297 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API(); 298 return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos); 299 #endif 300 } 301 RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx); 302 303 304 RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout, 305 RTHCUINTPTR uId, RT_SRC_POS_DECL) 306 { 307 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API(); 308 return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos); 309 } 310 RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug); 305 311 306 312 307 313 RTDECL(uint32_t) RTSemEventMultiGetResolution(void) 308 314 { 309 return 1000000000 / hz; 310 } 311 315 return rtR0SemBsdWaitGetResolution(); 316 } 317 RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution); 318
Note:
See TracChangeset
for help on using the changeset viewer.