Changeset 822 in vbox for trunk/src/VBox
- Timestamp:
- Feb 10, 2007 4:30:51 AM (18 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/Makefile
r762 r822 265 265 r3/posix/path-posix.cpp \ 266 266 r3/posix/process-posix.cpp \ 267 r3/posix/sems-posix.cpp \268 267 r3/posix/system-posix.cpp \ 269 268 r3/posix/thread-posix.cpp \ … … 272 271 generic/utf16locale-generic.cpp \ 273 272 r3/posix/utf8-posix.cpp \ 274 timesup.cpp \ 273 timesup.cpp 274 ifeq ($(BUILD_TARGET_ARCH),amd64) 275 RuntimeR3_SOURCES.linux += r3/linux/sems-linux.cpp 276 else 277 RuntimeR3_SOURCES.linux += r3/posix/sems-posix.cpp 278 endif 279 275 280 276 281 RuntimeR3_SOURCES.os2 = \ -
trunk/src/VBox/Runtime/r3/linux/sems-linux.cpp
r820 r822 1 1 /* $Id$ */ 2 2 /** @file 3 * InnoTek Portable Runtime - Semaphores, POSIX.3 * InnoTek Portable Runtime - Semaphores, Linux (AMD64 only ATM). 4 4 */ 5 5 … … 30 30 31 31 #include <errno.h> 32 #include <limits.h> 32 33 #include <pthread.h> 33 34 #include <unistd.h> 34 35 #include <sys/time.h> 35 36 #ifdef __DARWIN__ 37 # define pthread_yield() pthread_yield_np() 38 #endif 36 #include <sys/syscall.h> 37 #include <linux/futex.h> 39 38 40 39 … … 43 42 *******************************************************************************/ 44 43 45 /** Internal representation of the POSIX implementation of an Event semaphore. 46 * The POSIX implementation uses a mutex and a condition variable to implement 47 * the automatic reset event semaphore semantics. 48 * 49 * This must be identical to RTSEMEVENTMULTIINTERNAL! 44 /** 45 * Linux (single wakup) event semaphore. 50 46 */ 51 47 struct RTSEMEVENTINTERNAL 52 48 { 53 /** pthread condition. */ 54 pthread_cond_t Cond; 55 /** pthread mutex which protects the condition and the event state. */ 56 pthread_mutex_t Mutex; 57 /** The state of the semaphore. 58 * This is operated while owning mutex and using atomic updating. */ 59 volatile uint32_t u32State; 60 /** Number of waiters. */ 61 volatile uint32_t cWaiters; 49 /** Magic value. */ 50 intptr_t volatile iMagic; 51 /** The futex state variable. 52 * <0 means signaled. 53 * 0 means not signaled, no waiters. 54 * >0 means not signaled, and the value gives the number of waiters. 55 */ 56 int32_t volatile cWaiters; 62 57 }; 63 58 64 /** Posix internal representation of a Mutex Multi semaphore. 65 * This must be identical to RTSEMEVENTINTERNAL! */ 59 #define RTSEMEVENT_MAGIC ((intptr_t)-16) 60 61 62 /** 63 * Linux multiple wakup event semaphore. 64 */ 66 65 struct RTSEMEVENTMULTIINTERNAL 67 66 { 68 /** pthread condition. */ 69 pthread_cond_t Cond; 70 /** pthread mutex which protects the condition and the event state. */ 71 pthread_mutex_t Mutex; 72 /** The state of the semaphore. 73 * This is operated while owning mutex and using atomic updating. */ 74 volatile uint32_t u32State; 75 /** Number of waiters. */ 76 volatile uint32_t cWaiters; 67 /** Magic value. */ 68 intptr_t volatile iMagic; 69 /** The futex state variable. 70 * -1 means signaled. 71 * 0 means not signaled, no waiters. 72 * >0 means not signaled, and the value gives the number of waiters. 73 */ 74 int32_t volatile iState; 77 75 }; 78 76 79 /** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL. 80 * @{ */ 81 /** The object isn't initialized. */ 82 #define EVENT_STATE_UNINITIALIZED 0 83 /** The semaphore is is signaled. */ 84 #define EVENT_STATE_SIGNALED 0xff00ff00 85 /** The semaphore is not signaled. */ 86 #define EVENT_STATE_NOT_SIGNALED 0x00ff00ff 87 /** @} */ 88 89 90 /** Posix internal representation of a Mutex semaphore. */ 77 #define RTSEMEVENTMULTI_MAGIC ((intptr_t)-128) 78 79 /** 80 * Posix internal representation of a Mutex semaphore. 81 */ 91 82 struct RTSEMMUTEXINTERNAL 92 83 { … … 99 90 }; 100 91 101 /** Posix internal representation of a read-write semaphore. */ 92 93 /** 94 * Posix internal representation of a read-write semaphore. 95 */ 102 96 struct RTSEMRWINTERNAL 103 97 { … … 113 107 114 108 /** 115 * Validate an Event semaphore handle passed to one of the interface. 116 * 117 * @returns true if valid. 118 * @returns false if invalid. 119 * @param pIntEventSem Pointer to the event semaphore to validate. 109 * Wrapper for the futex syscall. 120 110 */ 121 inline bool rtsemEventValid(struct RTSEMEVENTINTERNAL *pIntEventSem)122 { 123 if ((uintptr_t)pIntEventSem < 0x10000)124 return false;125 126 uint32_t u32 = pIntEventSem->u32State; /* this is volatile, so a explicit read like this is needed. */127 if ( u32 != EVENT_STATE_NOT_SIGNALED128 && u32 != EVENT_STATE_SIGNALED)129 return false;130 131 return true; 132 } 111 static long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3) 112 { 113 errno = 0; 114 long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3); 115 if (rc < 0) 116 { 117 Assert(rc == -1); 118 rc = -errno; 119 } 120 return rc; 121 } 122 133 123 134 124 135 125 RTDECL(int) RTSemEventCreate(PRTSEMEVENT pEventSem) 136 126 { 137 int rc;138 139 127 /* 140 128 * Allocate semaphore handle. … … 143 131 if (pIntEventSem) 144 132 { 145 /* 146 * Create the condition variable. 133 pIntEventSem->iMagic = RTSEMEVENT_MAGIC; 134 pIntEventSem->cWaiters = 0; 135 *pEventSem = pIntEventSem; 136 return VINF_SUCCESS; 137 } 138 return VERR_NO_MEMORY; 139 } 140 141 142 RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem) 143 { 144 /* 145 * Validate input. 146 */ 147 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 148 AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 149 VERR_INVALID_HANDLE); 150 151 /* 152 * Invalidate the semaphore and wake up anyone waiting on it. 153 */ 154 ASMAtomicXchgSize(&pIntEventSem->iMagic, RTSEMEVENT_MAGIC + 1); 155 if (ASMAtomicXchgS32(&pIntEventSem->cWaiters, INT32_MIN / 2) > 0) 156 { 157 sys_futex(&pIntEventSem->cWaiters, FUTEX_WAKE, INT_MAX, NULL, NULL, 0); 158 usleep(1000); 159 } 160 161 /* 162 * Free the semaphore memory and be gone. 163 */ 164 RTMemFree(pIntEventSem); 165 return VINF_SUCCESS; 166 } 167 168 169 RTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem) 170 { 171 /* 172 * Validate input. 173 */ 174 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 175 AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 176 VERR_INVALID_HANDLE); 177 /* 178 * Try signal it. 179 */ 180 for (unsigned i = 0;; i++) 181 { 182 int32_t iCur = pIntEventSem->cWaiters; 183 if (iCur < 0) 184 break; /* already signaled */ 185 if (iCur == 0) 186 { 187 if (ASMAtomicCmpXchgS32(&pIntEventSem->cWaiters, -1, 0)) 188 break; /* nobody is waiting */ 189 } 190 else if (ASMAtomicCmpXchgS32(&pIntEventSem->cWaiters, iCur - 1, iCur)) 191 { 192 /* somebody is waiting, wake up one. */ 193 long cWoken = sys_futex(&pIntEventSem->cWaiters, FUTEX_WAKE, 1, NULL, NULL, 0); 194 if (cWoken == 1) 195 break; 196 ASMAtomicIncS32(&pIntEventSem->cWaiters); 197 AssertMsg(cWoken == 0, ("%ld\n", cWoken)); 198 199 /* 200 * We're waiting for the threads to start executing, that's kind of 201 * silly really. But for now, take care that we don't prevent them 202 * from executing. 203 */ 204 if ((i % 128) == 127) 205 usleep(1000); 206 else if ((i % 16) == 15) 207 pthread_yield(); 208 else 209 Assert(i < 1024); 210 } 211 } 212 return VINF_SUCCESS; 213 } 214 215 216 static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume) 217 { 218 /* 219 * Validate input. 220 */ 221 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 222 AssertReturn(VALID_PTR(pIntEventSem) && pIntEventSem->iMagic == RTSEMEVENT_MAGIC, 223 VERR_INVALID_HANDLE); 224 225 /* 226 * Quickly check whether it's signaled. 227 */ 228 if (ASMAtomicCmpXchgS32(&pIntEventSem->cWaiters, 0, -1)) 229 return VINF_SUCCESS; 230 231 /* 232 * Convert timeout value. 233 */ 234 struct timespec ts; 235 struct timespec *pTimeout = 0; 236 if (cMillies != RT_INDEFINITE_WAIT) 237 { 238 ts.tv_sec = cMillies / 1000; 239 ts.tv_nsec = (cMillies % 1000) * 1000000; 240 pTimeout = &ts; 241 } 242 243 /* 244 * The wait loop. 245 */ 246 for (unsigned i = 0;; i++) 247 { 248 /* 249 * Announce that we're among the waiters. 147 250 */ 148 pthread_condattr_t CondAttr; 149 rc = pthread_condattr_init(&CondAttr); 150 if (!rc) 151 { 152 rc = pthread_cond_init(&pIntEventSem->Cond, &CondAttr); 153 if (!rc) 251 int32_t iNew = ASMAtomicIncS32(&pIntEventSem->cWaiters); 252 if (iNew == 0) 253 return VINF_SUCCESS; 254 if (RT_LIKELY(iNew > 0)) 255 { 256 /* 257 * Go to sleep. 258 */ 259 long rc = sys_futex(&pIntEventSem->cWaiters, FUTEX_WAIT, iNew, pTimeout, NULL, 0); 260 if (RT_UNLIKELY(pIntEventSem->iMagic != RTSEMEVENT_MAGIC)) 261 return VERR_SEM_DESTROYED; 262 if (rc == 0) 263 return VINF_SUCCESS; 264 265 /* don't count us among the waiters. */ 266 iNew = ASMAtomicDecS32(&pIntEventSem->cWaiters); 267 Assert(iNew >= 0); 268 269 /* 270 * Act on the wakup code. 271 */ 272 if (rc == -ETIMEDOUT) 154 273 { 155 /* 156 * Create the semaphore. 157 */ 158 pthread_mutexattr_t MutexAttr; 159 rc = pthread_mutexattr_init(&MutexAttr); 160 if (!rc) 161 { 162 rc = pthread_mutex_init(&pIntEventSem->Mutex, &MutexAttr); 163 if (!rc) 164 { 165 pthread_mutexattr_destroy(&MutexAttr); 166 pthread_condattr_destroy(&CondAttr); 167 168 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED); 169 ASMAtomicXchgU32(&pIntEventSem->cWaiters, 0); 170 171 *pEventSem = pIntEventSem; 172 return VINF_SUCCESS; 173 } 174 pthread_mutexattr_destroy(&MutexAttr); 175 } 176 pthread_cond_destroy(&pIntEventSem->Cond); 274 Assert(pTimeout); 275 return VERR_TIMEOUT; 276 } 277 if (rc == -EWOULDBLOCK) 278 /* retry with new value. */; 279 else if (rc == -EINTR) 280 { 281 if (!fAutoResume) 282 return VERR_INTERRUPTED; 177 283 } 178 pthread_condattr_destroy(&CondAttr); 179 } 180 181 rc = RTErrConvertFromErrno(rc); 182 RTMemFree(pIntEventSem); 183 } 184 else 185 rc = VERR_NO_MEMORY; 186 187 return rc; 188 } 189 190 191 RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem) 192 { 193 /* 194 * Validate handle. 195 */ 196 if (!rtsemEventValid(EventSem)) 197 { 198 AssertMsgFailed(("Invalid handle %p!\n", EventSem)); 199 return VERR_INVALID_HANDLE; 200 } 201 202 /* 203 * Abort all waiters forcing them to return failure. 204 * 205 */ 206 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 207 int rc; 208 for (int i = 30; i > 0; i--) 209 { 210 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_UNINITIALIZED); 211 rc = pthread_cond_destroy(&pIntEventSem->Cond); 212 if (rc != EBUSY) 213 break; 214 pthread_cond_broadcast(&pIntEventSem->Cond); 215 usleep(1000); 216 } while (rc == EBUSY); 217 if (rc) 218 { 219 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", EventSem, rc)); 220 return RTErrConvertFromErrno(rc); 221 } 222 223 /* 224 * Destroy the semaphore 225 * If it's busy we'll wait a bit to give the threads a chance to be scheduled. 226 */ 227 for (int i = 30; i > 0; i--) 228 { 229 rc = pthread_mutex_destroy(&pIntEventSem->Mutex); 230 if (rc != EBUSY) 231 break; 232 usleep(1000); 233 } 234 if (rc) 235 { 236 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", EventSem, rc)); 237 return RTErrConvertFromErrno(rc); 238 } 239 240 /* 241 * Free the semaphore memory and be gone. 242 */ 243 RTMemFree(pIntEventSem); 244 return VINF_SUCCESS; 245 } 246 247 248 RTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem) 249 { 250 /* 251 * Validate input. 252 */ 253 if (!rtsemEventValid(EventSem)) 254 { 255 AssertMsgFailed(("Invalid handle %p!\n", EventSem)); 256 return VERR_INVALID_HANDLE; 257 } 258 259 /* 260 * Lock the mutex semaphore. 261 */ 262 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 263 int rc = pthread_mutex_lock(&pIntEventSem->Mutex); 264 if (rc) 265 { 266 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc)); 267 return RTErrConvertFromErrno(rc); 268 } 269 270 /* 271 * Check the state. 272 */ 273 if (pIntEventSem->u32State == EVENT_STATE_NOT_SIGNALED) 274 { 275 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_SIGNALED); 276 rc = pthread_cond_signal(&pIntEventSem->Cond); 277 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", EventSem, rc)); 278 } 279 else if (pIntEventSem->u32State == EVENT_STATE_SIGNALED) 280 { 281 rc = pthread_cond_signal(&pIntEventSem->Cond); /* give'm another kick... */ 282 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", EventSem, rc)); 283 } 284 else 285 rc = VERR_SEM_DESTROYED; 286 287 /* 288 * Release the mutex and return. 289 */ 290 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex); 291 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); 292 if (rc) 293 return RTErrConvertFromErrno(rc); 294 if (rc2) 295 return RTErrConvertFromErrno(rc2); 296 297 return VINF_SUCCESS; 298 } 299 300 301 static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume) 302 { 303 /* 304 * Validate input. 305 */ 306 if (!rtsemEventValid(EventSem)) 307 { 308 AssertMsgFailed(("Invalid handle %p!\n", EventSem)); 309 return VERR_INVALID_HANDLE; 310 } 311 312 /* 313 * Timed or indefinite wait? 314 */ 315 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem; 316 if (cMillies == RT_INDEFINITE_WAIT) 317 { 318 /* for fairness, yield before going to sleep. */ 319 if ( ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1 320 && pIntEventSem->u32State == EVENT_STATE_SIGNALED) 321 pthread_yield(); 322 323 /* take mutex */ 324 int rc = pthread_mutex_lock(&pIntEventSem->Mutex); 325 if (rc) 326 { 327 ASMAtomicDecU32(&pIntEventSem->cWaiters); 328 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc)); 329 return RTErrConvertFromErrno(rc); 330 } 331 332 for (;;) 333 { 334 /* check state. */ 335 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED) 284 else 336 285 { 337 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED); 338 ASMAtomicDecU32(&pIntEventSem->cWaiters); 339 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 340 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 341 return VINF_SUCCESS; 342 } 343 if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED) 344 { 345 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 346 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 347 return VERR_SEM_DESTROYED; 348 } 349 350 /* wait */ 351 rc = pthread_cond_wait(&pIntEventSem->Cond, &pIntEventSem->Mutex); 352 if (rc) 353 { 354 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc)); 355 ASMAtomicDecU32(&pIntEventSem->cWaiters); 356 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex); 357 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc2)); NOREF(rc2); 286 /* this shouldn't happen! */ 287 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno)); 358 288 return RTErrConvertFromErrno(rc); 359 289 } 360 290 } 361 } 362 else 363 { 364 /* 365 * Get current time and calc end of wait time. 366 */ 367 struct timespec ts = {0,0}; 368 #ifdef __DARWIN__ 369 struct timeval tv = {0,0}; 370 gettimeofday(&tv, NULL); 371 ts.tv_sec = tv.tv_sec; 372 ts.tv_nsec = tv.tv_usec * 1000; 373 #else 374 clock_gettime(CLOCK_REALTIME, &ts); 375 #endif 376 if (cMillies != 0) 377 { 378 ts.tv_nsec += (cMillies % 1000) * 1000000; 379 ts.tv_sec += cMillies / 1000; 380 if (ts.tv_nsec >= 1000000000) 381 { 382 ts.tv_nsec -= 1000000000; 383 ts.tv_sec++; 384 } 385 } 386 387 /* for fairness, yield before going to sleep. */ 388 if (ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1) 389 pthread_yield(); 390 391 /* take mutex */ 392 #ifdef __DARWIN__ 393 int rc = pthread_mutex_lock(&pIntEventSem->Mutex); 394 #else 395 int rc = pthread_mutex_timedlock(&pIntEventSem->Mutex, &ts); 396 #endif 397 if (rc) 398 { 399 ASMAtomicDecU32(&pIntEventSem->cWaiters); 400 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", EventSem, rc)); 401 return RTErrConvertFromErrno(rc); 402 } 403 404 for (;;) 405 { 406 /* check state. */ 407 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED) 408 { 409 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED); 410 ASMAtomicDecU32(&pIntEventSem->cWaiters); 411 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 412 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 413 return VINF_SUCCESS; 414 } 415 if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED) 416 { 417 rc = pthread_mutex_unlock(&pIntEventSem->Mutex); 418 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc); 291 else 292 { 293 /* 294 * Somebody is signaling the semaphore, let's try again. 295 * But take care to yield and sleep after a while like always. 296 * (Could probably change this to string only and return right away...) 297 */ 298 ASMAtomicDecS32(&pIntEventSem->cWaiters); 299 if ((i % 128) == 127) 300 usleep(1000); 301 else if ((i % 16) == 15) 302 pthread_yield(); 303 else 304 AssertReleaseMsg(i < 4096, ("iNew=%d\n", iNew)); 305 if (RT_UNLIKELY(pIntEventSem->iMagic != RTSEMEVENT_MAGIC)) 419 306 return VERR_SEM_DESTROYED; 420 } 421 422 /* wait */ 423 rc = pthread_cond_timedwait(&pIntEventSem->Cond, &pIntEventSem->Mutex, &ts); 424 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */ 425 { 426 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc)); 427 ASMAtomicDecU32(&pIntEventSem->cWaiters); 428 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex); 429 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", EventSem, rc2)); NOREF(rc2); 430 return RTErrConvertFromErrno(rc); 431 } 432 } /* for (;;) */ 307 } 433 308 } 434 309 } … … 452 327 453 328 454 455 /**456 * Validate an event multi semaphore handle passed to one of the interface.457 *458 * @returns true if valid.459 * @returns false if invalid.460 * @param pIntEventMultiSem Pointer to the event semaphore to validate.461 */462 inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem)463 {464 if ((uintptr_t)pIntEventMultiSem < 0x10000)465 return false;466 467 uint32_t u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */468 if ( u32 != EVENT_STATE_NOT_SIGNALED469 && u32 != EVENT_STATE_SIGNALED)470 return false;471 472 return true;473 }474 475 476 329 RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem) 477 330 { 478 /* the code and the structure is identical with other type for this function. */ 479 return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem); 331 /* 332 * Allocate semaphore handle. 333 */ 334 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL)); 335 if (pIntEventMultiSem) 336 { 337 pIntEventMultiSem->iMagic = RTSEMEVENTMULTI_MAGIC; 338 pIntEventMultiSem->iState = 0; 339 *pEventMultiSem = pIntEventMultiSem; 340 return VINF_SUCCESS; 341 } 342 return VERR_NO_MEMORY; 480 343 } 481 344 … … 483 346 RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem) 484 347 { 485 /* the code and the structure is identical with other type for this function. */ 486 return RTSemEventDestroy((RTSEMEVENT)EventMultiSem); 348 /* 349 * Validate input. 350 */ 351 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 352 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 353 VERR_INVALID_HANDLE); 354 355 /* 356 * Invalidate the semaphore and wake up anyone waiting on it. 357 */ 358 ASMAtomicXchgSize(&pIntEventMultiSem->iMagic, RTSEMEVENTMULTI_MAGIC + 1); 359 if (ASMAtomicXchgS32(&pIntEventMultiSem->iState, -1) == 1) 360 { 361 sys_futex(&pIntEventMultiSem->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0); 362 usleep(1000); 363 } 364 365 /* 366 * Free the semaphore memory and be gone. 367 */ 368 RTMemFree(pIntEventMultiSem); 369 return VINF_SUCCESS; 487 370 } 488 371 … … 490 373 RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem) 491 374 { 492 /* the code and the structure is identical with other type for this function. */ 493 return RTSemEventSignal((RTSEMEVENT)EventMultiSem); 375 /* 376 * Validate input. 377 */ 378 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 379 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 380 VERR_INVALID_HANDLE); 381 /* 382 * Signal it. 383 */ 384 int32_t iOld = ASMAtomicXchgS32(&pIntEventMultiSem->iState, -1); 385 if (iOld > 0) 386 { 387 /* wake up sleeping threads. */ 388 long cWoken = sys_futex(&pIntEventMultiSem->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0); 389 AssertMsg(cWoken >= 0, ("%ld\n", cWoken)); NOREF(cWoken); 390 } 391 Assert(iOld == 0 || iOld == -1 || iOld == 1); 392 return VINF_SUCCESS; 494 393 } 495 394 … … 500 399 * Validate input. 501 400 */ 502 if (!rtsemEventMultiValid(EventMultiSem))503 {504 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));505 return VERR_INVALID_HANDLE;506 }507 508 /*509 * Lock the mutex semaphore.510 */511 401 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 512 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex); 513 if (rc) 514 { 515 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 516 return RTErrConvertFromErrno(rc); 517 } 518 519 /* 520 * Check the state. 521 */ 522 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED) 523 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED); 524 else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED) 525 rc = VERR_SEM_DESTROYED; 526 527 /* 528 * Release the mutex and return. 529 */ 530 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 531 if (rc) 532 { 533 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 534 return RTErrConvertFromErrno(rc); 535 } 536 537 return VINF_SUCCESS; 538 402 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 403 VERR_INVALID_HANDLE); 404 #ifdef RT_STRICT 405 int32_t i = pIntEventMultiSem->iState; 406 Assert(i == 0 || i == -1 || i == 1); 407 #endif 408 409 /* 410 * Reset it. 411 */ 412 ASMAtomicCmpXchgS32(&pIntEventMultiSem->iState, 0, -1); 413 return VINF_SUCCESS; 539 414 } 540 415 … … 545 420 * Validate input. 546 421 */ 547 if (!rtsemEventMultiValid(EventMultiSem))548 {549 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));550 return VERR_INVALID_HANDLE;551 }552 553 /*554 * Timed or indefinite wait?555 */556 422 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem; 557 if (cMillies == RT_INDEFINITE_WAIT) 558 { 559 /* take mutex */ 560 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex); 561 if (rc) 562 { 563 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 564 return RTErrConvertFromErrno(rc); 565 } 566 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters); 567 568 for (;;) 569 { 570 /* check state. */ 571 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED) 423 AssertReturn(VALID_PTR(pIntEventMultiSem) && pIntEventMultiSem->iMagic == RTSEMEVENTMULTI_MAGIC, 424 VERR_INVALID_HANDLE); 425 426 /* 427 * Quickly check whether it's signaled. 428 */ 429 int32_t iCur = pIntEventMultiSem->iState; 430 Assert(iCur == 0 || iCur == -1 || iCur == 1); 431 if (iCur == -1) 432 return VINF_SUCCESS; 433 if (!cMillies) 434 return VERR_TIMEOUT; 435 436 /* 437 * Convert timeout value. 438 */ 439 struct timespec ts; 440 struct timespec *pTimeout = NULL; 441 if (cMillies != RT_INDEFINITE_WAIT) 442 { 443 ts.tv_sec = cMillies / 1000; 444 ts.tv_nsec = (cMillies % 1000) * 1000000; 445 pTimeout = &ts; 446 } 447 448 /* 449 * The wait loop. 450 */ 451 for (unsigned i = 0;; i++) 452 { 453 /* 454 * Start waiting. We only account for there being or having been 455 * threads waiting on the semaphore to keep things simple. 456 */ 457 iCur = pIntEventMultiSem->iState; 458 Assert(iCur == 0 || iCur == -1 || iCur == 1); 459 if ( iCur == 1 460 || ASMAtomicCmpXchgS32(&pIntEventMultiSem->iState, 1, 0)) 461 { 462 long rc = sys_futex(&pIntEventMultiSem->iState, FUTEX_WAIT, 1, pTimeout, NULL, 0); 463 if (RT_UNLIKELY(pIntEventMultiSem->iMagic != RTSEMEVENTMULTI_MAGIC)) 464 return VERR_SEM_DESTROYED; 465 if (rc == 0) 466 return VINF_SUCCESS; 467 468 /* 469 * Act on the wakup code. 470 */ 471 if (rc == -ETIMEDOUT) 572 472 { 573 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 574 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 575 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 576 return VINF_SUCCESS; 473 Assert(pTimeout); 474 return VERR_TIMEOUT; 475 } 476 if (rc == -EWOULDBLOCK) 477 /* retry, the value changed. */; 478 else if (rc == -EINTR) 479 { 480 if (!fAutoResume) 481 return VERR_INTERRUPTED; 577 482 } 578 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)483 else 579 484 { 580 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 581 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 582 return VERR_SEM_DESTROYED; 583 } 584 585 /* wait */ 586 rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex); 587 if (rc) 588 { 589 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 590 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 591 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 592 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2); 485 /* this shouldn't happen! */ 486 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno)); 593 487 return RTErrConvertFromErrno(rc); 594 488 } 595 489 } 596 } 597 else 598 { 599 /* 600 * Get current time and calc end of wait time. 601 */ 602 struct timespec ts = {0,0}; 603 #ifdef __DARWIN__ 604 struct timeval tv = {0,0}; 605 gettimeofday(&tv, NULL); 606 ts.tv_sec = tv.tv_sec; 607 ts.tv_nsec = tv.tv_usec * 1000; 608 #else 609 clock_gettime(CLOCK_REALTIME, &ts); 610 #endif 611 if (cMillies != 0) 612 { 613 ts.tv_nsec += (cMillies % 1000) * 1000000; 614 ts.tv_sec += cMillies / 1000; 615 if (ts.tv_nsec >= 1000000000) 616 { 617 ts.tv_nsec -= 1000000000; 618 ts.tv_sec++; 619 } 620 } 621 622 /* take mutex */ 623 #ifdef __DARWIN__ 624 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex); 625 #else 626 int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts); 627 #endif 628 if (rc) 629 { 630 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 631 return RTErrConvertFromErrno(rc); 632 } 633 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters); 634 635 for (;;) 636 { 637 /* check state. */ 638 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED) 639 { 640 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED); 641 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 642 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 643 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 644 return VINF_SUCCESS; 645 } 646 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED) 647 { 648 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 649 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc); 650 return VERR_SEM_DESTROYED; 651 } 652 653 /* wait */ 654 rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts); 655 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */ 656 { 657 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc)); 658 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters); 659 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex); 660 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2); 661 return RTErrConvertFromErrno(rc); 662 } 663 } 490 else if (iCur == -1) 491 return VINF_SUCCESS; 664 492 } 665 493 } … … 812 640 else 813 641 { 814 #ifdef __DARWIN__815 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));816 return VERR_NOT_IMPLEMENTED;817 #else /* !__DARWIN__ */818 642 /* 819 643 * Get current time and calc end of wait time. … … 839 663 return RTErrConvertFromErrno(rc); 840 664 } 841 #endif /* !__DARWIN__ */842 665 } 843 666 … … 1030 853 else 1031 854 { 1032 #ifdef __DARWIN__1033 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));1034 return VERR_NOT_IMPLEMENTED;1035 #else /* !__DARWIN__ */1036 855 /* 1037 856 * Get current time and calc end of wait time. … … 1057 876 return RTErrConvertFromErrno(rc); 1058 877 } 1059 #endif /* !__DARWIN__ */1060 878 } 1061 879 … … 1129 947 else 1130 948 { 1131 #ifdef __DARWIN__1132 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));1133 return VERR_NOT_IMPLEMENTED;1134 #else /* !__DARWIN__ */1135 949 /* 1136 950 * Get current time and calc end of wait time. … … 1156 970 return RTErrConvertFromErrno(rc); 1157 971 } 1158 #endif /* !__DARWIN__ */1159 972 } 1160 973
Note:
See TracChangeset
for help on using the changeset viewer.