Changeset 7920 in vbox
- Timestamp:
- Apr 11, 2008 2:40:22 PM (17 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/semaphore.h
r5999 r7920 267 267 * Request read access to a read/write semaphore, resume on interruption 268 268 * 269 * Read requests cannot be nested. A deadlock error will be returned270 * on such attempts.271 * 272 * @ret urns iprt status code.273 * Will not return VERR_INTERRUPTED.269 * @returns iprt status code. 270 * @retval VINF_SUCCESS on success. 271 * @retval VERR_INTERRUPT if the wait was interrupted. 272 * @retval VERR_INVALID_HANDLE if RWSem is invalid. 273 * 274 274 * @param RWSem The Read/Write semaphore to request read access to. 275 275 * @param cMillies The number of milliseconds to wait. … … 280 280 * Request read access to a read/write semaphore, return on interruption 281 281 * 282 * Read requests cannot be nested. A deadlock error will be returned 283 * on such attempts. 284 * 285 * @returns iprt status code. 282 * @returns iprt status code. 283 * @retval VINF_SUCCESS on success. 284 * @retval VERR_INTERRUPT if the wait was interrupted. 285 * @retval VERR_INVALID_HANDLE if RWSem is invalid. 286 * 286 287 * @param RWSem The Read/Write semaphore to request read access to. 287 288 * @param cMillies The number of milliseconds to wait. … … 301 302 * Request write access to a read/write semaphore, resume on interruption. 302 303 * 303 * Write requests cannot be nested. If called by the thread currently owning304 * the write lock the function returns an error code indicating deadlock.305 * 306 * @ret urns iprt status code.307 * Will not return VERR_INTERRUPTED.304 * @returns iprt status code. 305 * @retval VINF_SUCCESS on success. 306 * @retval VERR_DEADLOCK if the caller owned the read lock. 307 * @retval VERR_INVALID_HANDLE if RWSem is invalid. 308 * 308 309 * @param RWSem The Read/Write semaphore to request write access to. 309 310 * @param cMillies The number of milliseconds to wait. … … 314 315 * Request write access to a read/write semaphore, return on interruption. 315 316 * 316 * Write requests cannot be nested. If called by the thread currently owning 317 * the write lock the function returns an error code indicating deadlock. 318 * 319 * @returns iprt status code. 317 * @returns iprt status code. 318 * @retval VINF_SUCCESS on success. 319 * @retval VERR_INTERRUPT if the wait was interrupted. 320 * @retval VERR_DEADLOCK if the caller owned the read lock. 321 * @retval VERR_INVALID_HANDLE if RWSem is invalid. 322 * 320 323 * @param RWSem The Read/Write semaphore to request write access to. 321 324 * @param cMillies The number of milliseconds to wait. -
trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp
r6738 r7920 39 39 #include <sys/time.h> 40 40 41 #include "internal/magics.h" 42 41 43 42 44 /******************************************************************************* … … 46 48 struct RTSEMRWINTERNAL 47 49 { 50 /** The usual magic. (RTSEMRW_MAGIC) */ 51 uint32_t u32Magic; 52 /* Alignment padding. */ 53 uint32_t u32Padding; 54 /** Number of write recursions. */ 55 uint32_t cWrites; 56 /** Number of read recursions by the writer. */ 57 uint32_t cWriterReads; 58 /** The write owner of the lock. */ 59 volatile pthread_t Writer; 48 60 /** pthread rwlock. */ 49 61 pthread_rwlock_t RWLock; 50 /** Variable to check if initialized.51 * 0 is uninitialized, ~0 is inititialized. */52 volatile unsigned uCheck;53 /** The write owner of the lock. */54 volatile pthread_t WROwner;55 62 }; 56 63 57 64 58 59 /** 60 * Validate a read-write semaphore handle passed to one of the interface. 61 * 62 * @returns true if valid. 63 * @returns false if invalid. 64 * @param pIntRWSem Pointer to the read-write semaphore to validate. 65 */ 66 inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem) 67 { 68 if ((uintptr_t)pIntRWSem < 0x10000) 69 return false; 70 71 if (pIntRWSem->uCheck != (unsigned)~0) 72 return false; 73 74 return true; 75 } 76 77 78 RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem) 65 RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem) 79 66 { 80 67 int rc; … … 83 70 * Allocate handle. 84 71 */ 85 struct RTSEMRWINTERNAL *p IntRWSem= (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));86 if (p IntRWSem)72 struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL)); 73 if (pThis) 87 74 { 88 75 /* 89 76 * Create the rwlock. 90 77 */ 91 pthread_rwlockattr_t 78 pthread_rwlockattr_t Attr; 92 79 rc = pthread_rwlockattr_init(&Attr); 93 80 if (!rc) 94 81 { 95 rc = pthread_rwlock_init(&p IntRWSem->RWLock, &Attr);82 rc = pthread_rwlock_init(&pThis->RWLock, &Attr); 96 83 if (!rc) 97 84 { 98 pIntRWSem->uCheck = ~0; 99 pIntRWSem->WROwner = (pthread_t)-1; 100 *pRWSem = pIntRWSem; 85 pThis->u32Magic = RTSEMRW_MAGIC; 86 pThis->u32Padding = 0; 87 pThis->cWrites = 0; 88 pThis->cWriterReads = 0; 89 pThis->Writer = (pthread_t)-1; 90 *pRWSem = pThis; 101 91 return VINF_SUCCESS; 102 92 } … … 104 94 105 95 rc = RTErrConvertFromErrno(rc); 106 RTMemFree(p IntRWSem);96 RTMemFree(pThis); 107 97 } 108 98 else … … 113 103 114 104 115 RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem) 116 { 117 /* 118 * Validate input. 119 */ 120 if (!rtsemRWValid(RWSem)) 121 { 122 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 123 return VERR_INVALID_HANDLE; 124 } 105 RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem) 106 { 107 /* 108 * Validate input, nil handle is fine. 109 */ 110 if (RWSem == NIL_RTSEMRW) 111 return VINF_SUCCESS; 112 struct RTSEMRWINTERNAL *pThis = RWSem; 113 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 114 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC, 115 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 116 VERR_INVALID_HANDLE); 117 Assert(pThis->Writer == (pthread_t)-1); 118 Assert(!pThis->cWrites); 119 Assert(!pThis->cWriterReads); 125 120 126 121 /* 127 122 * Try destroy it. 128 123 */ 129 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 130 int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock); 124 int rc = pthread_rwlock_destroy(&pThis->RWLock); 131 125 if (!rc) 132 126 { 133 p IntRWSem->uCheck = 0;134 RTMemFree(p IntRWSem);127 pThis->u32Magic++; 128 RTMemFree(pThis); 135 129 rc = VINF_SUCCESS; 136 130 } … … 145 139 146 140 147 RTDECL(int) 141 RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies) 148 142 { 149 143 /* 150 144 * Validate input. 151 145 */ 152 if (!rtsemRWValid(RWSem)) 153 { 154 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 155 return VERR_INVALID_HANDLE; 146 struct RTSEMRWINTERNAL *pThis = RWSem; 147 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 148 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC, 149 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 150 VERR_INVALID_HANDLE); 151 152 /* 153 * Check if it's the writer (implement write+read recursion). 154 */ 155 pthread_t Self = pthread_self(); 156 pthread_t Writer; 157 ASMAtomicReadSize(&pThis->Writer, &Writer); 158 if (Writer == Self) 159 { 160 Assert(pThis->cWriterReads < INT32_MAX); 161 pThis->cWriterReads++; 162 return VINF_SUCCESS; 156 163 } 157 164 … … 159 166 * Try lock it. 160 167 */ 161 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;162 168 if (cMillies == RT_INDEFINITE_WAIT) 163 169 { 164 170 /* take rwlock */ 165 int rc = pthread_rwlock_rdlock(&p IntRWSem->RWLock);171 int rc = pthread_rwlock_rdlock(&pThis->RWLock); 166 172 if (rc) 167 173 { 168 174 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc)); 175 return RTErrConvertFromErrno(rc); 176 } 177 } 178 else 179 { 180 #ifdef RT_OS_DARWIN 181 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API.")); 182 return VERR_NOT_IMPLEMENTED; 183 184 #else /* !RT_OS_DARWIN */ 185 /* 186 * Get current time and calc end of wait time. 187 */ 188 struct timespec ts = {0,0}; 189 clock_gettime(CLOCK_REALTIME, &ts); 190 if (cMillies != 0) 191 { 192 ts.tv_nsec += (cMillies % 1000) * 1000000; 193 ts.tv_sec += cMillies / 1000; 194 if (ts.tv_nsec >= 1000000000) 195 { 196 ts.tv_nsec -= 1000000000; 197 ts.tv_sec++; 198 } 199 } 200 201 /* take rwlock */ 202 int rc = pthread_rwlock_timedrdlock(&pThis->RWLock, &ts); 203 if (rc) 204 { 205 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc)); 206 return RTErrConvertFromErrno(rc); 207 } 208 #endif /* !RT_OS_DARWIN */ 209 } 210 211 return VINF_SUCCESS; 212 } 213 214 215 RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies) 216 { 217 /* EINTR isn't returned by the wait functions we're using. */ 218 return RTSemRWRequestRead(RWSem, cMillies); 219 } 220 221 222 RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem) 223 { 224 /* 225 * Validate input. 226 */ 227 struct RTSEMRWINTERNAL *pThis = RWSem; 228 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 229 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC, 230 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 231 VERR_INVALID_HANDLE); 232 233 /* 234 * Check if it's the writer. 235 */ 236 pthread_t Self = pthread_self(); 237 pthread_t Writer; 238 ASMAtomicReadSize(&pThis->Writer, &Writer); 239 if (Writer == Self) 240 { 241 AssertMsgReturn(pThis->cWriterReads > 0, 242 ("pThis=%p\n", pThis), VERR_NOT_OWNER); 243 pThis->cWriterReads--; 244 return VINF_SUCCESS; 245 } 246 247 /* 248 * Try unlock it. 249 */ 250 int rc = pthread_rwlock_unlock(&pThis->RWLock); 251 if (rc) 252 { 253 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc)); 254 return RTErrConvertFromErrno(rc); 255 } 256 257 return VINF_SUCCESS; 258 } 259 260 261 RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies) 262 { 263 /* 264 * Validate input. 265 */ 266 struct RTSEMRWINTERNAL *pThis = RWSem; 267 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 268 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC, 269 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 270 VERR_INVALID_HANDLE); 271 272 /* 273 * Recursion? 274 */ 275 pthread_t Self = pthread_self(); 276 pthread_t Writer; 277 ASMAtomicReadSize(&pThis->Writer, &Writer); 278 if (Writer == Self) 279 { 280 Assert(pThis->cWrites < INT32_MAX); 281 pThis->cWrites++; 282 return VINF_SUCCESS; 283 } 284 285 /* 286 * Try lock it. 287 */ 288 if (cMillies == RT_INDEFINITE_WAIT) 289 { 290 /* take rwlock */ 291 int rc = pthread_rwlock_wrlock(&pThis->RWLock); 292 if (rc) 293 { 294 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc)); 169 295 return RTErrConvertFromErrno(rc); 170 296 } … … 193 319 194 320 /* take rwlock */ 195 int rc = pthread_rwlock_timed rdlock(&pIntRWSem->RWLock, &ts);321 int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts); 196 322 if (rc) 197 323 { … … 202 328 } 203 329 330 ASMAtomicWriteSize(&pThis->Writer, Self); 331 pThis->cWrites = 1; 204 332 return VINF_SUCCESS; 205 333 } 206 334 207 335 208 RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies) 209 { 210 /* EINTR isn't returned by the wait functions we're using. */ 211 return RTSemRWRequestRead(RWSem, cMillies); 212 } 213 214 215 RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem) 216 { 217 /* 218 * Validate input. 219 */ 220 if (!rtsemRWValid(RWSem)) 221 { 222 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 223 return VERR_INVALID_HANDLE; 224 } 225 226 /* 227 * Try unlock it. 228 */ 229 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 230 if (pIntRWSem->WROwner == pthread_self()) 231 { 232 AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem)); 233 return VERR_NOT_OWNER; 234 } 235 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock); 236 if (rc) 237 { 238 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc)); 239 return RTErrConvertFromErrno(rc); 240 } 241 242 return VINF_SUCCESS; 243 } 244 245 246 RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies) 247 { 248 /* 249 * Validate input. 250 */ 251 if (!rtsemRWValid(RWSem)) 252 { 253 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 254 return VERR_INVALID_HANDLE; 255 } 256 257 /* 258 * Try lock it. 259 */ 260 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 261 if (cMillies == RT_INDEFINITE_WAIT) 262 { 263 /* take rwlock */ 264 int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock); 265 if (rc) 266 { 267 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc)); 268 return RTErrConvertFromErrno(rc); 269 } 270 } 271 else 272 { 273 #ifdef RT_OS_DARWIN 274 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API.")); 275 return VERR_NOT_IMPLEMENTED; 276 #else /* !RT_OS_DARWIN */ 277 /* 278 * Get current time and calc end of wait time. 279 */ 280 struct timespec ts = {0,0}; 281 clock_gettime(CLOCK_REALTIME, &ts); 282 if (cMillies != 0) 283 { 284 ts.tv_nsec += (cMillies % 1000) * 1000000; 285 ts.tv_sec += cMillies / 1000; 286 if (ts.tv_nsec >= 1000000000) 287 { 288 ts.tv_nsec -= 1000000000; 289 ts.tv_sec++; 290 } 291 } 292 293 /* take rwlock */ 294 int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts); 295 if (rc) 296 { 297 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc)); 298 return RTErrConvertFromErrno(rc); 299 } 300 #endif /* !RT_OS_DARWIN */ 301 } 302 303 #ifdef RT_OS_SOLARIS 304 ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self()); 305 #else 306 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self()); 307 #endif 308 309 return VINF_SUCCESS; 310 } 311 312 313 RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies) 336 RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies) 314 337 { 315 338 /* EINTR isn't returned by the wait functions we're using. */ … … 318 341 319 342 320 RTDECL(int) 343 RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem) 321 344 { 322 345 /* 323 346 * Validate input. 324 347 */ 325 if (!rtsemRWValid(RWSem)) 326 { 327 AssertMsgFailed(("Invalid handle %p!\n", RWSem)); 328 return VERR_INVALID_HANDLE; 329 } 348 struct RTSEMRWINTERNAL *pThis = RWSem; 349 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 350 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC, 351 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), 352 VERR_INVALID_HANDLE); 353 354 /* 355 * Verify ownership and implement recursion. 356 */ 357 pthread_t Self = pthread_self(); 358 pthread_t Writer; 359 ASMAtomicReadSize(&pThis->Writer, &Writer); 360 AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER); 361 pThis->cWrites--; 362 if (pThis->cWrites) 363 return VINF_SUCCESS; 364 AssertReturn(!pThis->cWriterReads, VERR_WRONG_ORDER); 330 365 331 366 /* 332 367 * Try unlock it. 333 368 */ 334 pthread_t Self = pthread_self(); 335 struct RTSEMRWINTERNAL *pIntRWSem = RWSem; 336 if (pIntRWSem->WROwner != Self) 337 { 338 AssertMsgFailed(("Not Write owner!\n")); 339 return VERR_NOT_OWNER; 340 } 341 342 /* 343 * Try unlock it. 344 */ 345 #ifdef RT_OS_SOLARIS 346 ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1); 347 #else 348 AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t))); 349 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1); 350 #endif 351 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock); 369 ASMAtomicWriteSize(&pThis->Writer, (pthread_t)-1); 370 int rc = pthread_rwlock_unlock(&pThis->RWLock); 352 371 if (rc) 353 372 {
Note:
See TracChangeset
for help on using the changeset viewer.