- Timestamp:
- Sep 11, 2009 10:14:54 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/linux/semevent-linux.cpp
r14468 r22950 34 34 /* 35 35 * glibc 2.6 fixed a serious bug in the mutex implementation. We wrote this 36 * linux specific event semaphores code in order to work around the bug. As it 37 * turns out, this code seems to have an unresolved issue (#2599), so we'll 38 * fall back on the pthread based implementation if glibc is known to contain 39 * the bug fix. 36 * linux specific event semaphores code in order to work around the bug. We 37 * will fall back on the pthread-based implementation if glibc is known to 38 * contain the bug fix. 40 39 * 41 40 * The external refernce to epoll_pwait is a hack which prevents that we link … … 82 81 intptr_t volatile iMagic; 83 82 /** The futex state variable. 84 * <0 means signaled.85 * 0 means not signaled, no waiters.86 * >0 means not signaled, and the value gives the number of waiters.87 */83 * 0 means not signalled. 84 * 1 means signalled */ 85 uint32_t volatile fSignalled; 86 /** The number of waiting threads */ 88 87 int32_t volatile cWaiters; 89 88 }; … … 93 92 * Wrapper for the futex syscall. 94 93 */ 95 static long sys_futex( int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)94 static long sys_futex(uint32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3) 96 95 { 97 96 errno = 0; … … 117 116 pThis->iMagic = RTSEMEVENT_MAGIC; 118 117 pThis->cWaiters = 0; 118 pThis->fSignalled = 0; 119 119 *pEventSem = pThis; 120 120 return VINF_SUCCESS; … … 141 141 if (ASMAtomicXchgS32(&pThis->cWaiters, INT32_MIN / 2) > 0) 142 142 { 143 sys_futex(&pThis-> cWaiters, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);143 sys_futex(&pThis->fSignalled, FUTEX_WAKE, INT_MAX, NULL, NULL, 0); 144 144 usleep(1000); 145 145 } … … 161 161 AssertReturn(VALID_PTR(pThis) && pThis->iMagic == RTSEMEVENT_MAGIC, 162 162 VERR_INVALID_HANDLE); 163 /* 164 * Try signal it. 165 */ 166 for (unsigned i = 0;; i++) 167 { 168 int32_t iCur; 169 if (ASMAtomicCmpXchgExS32(&pThis->cWaiters, -1, 0, &iCur)) 170 break; /* nobody is waiting */ 171 else if (iCur < 0) 172 break; /* already signaled */ 173 else 174 { 175 /* somebody is waiting, try wake up one of them. */ 176 long cWoken = sys_futex(&pThis->cWaiters, FUTEX_WAKE, 1, NULL, NULL, 0); 177 if (RT_LIKELY(cWoken == 1)) 178 { 179 ASMAtomicDecS32(&pThis->cWaiters); 180 break; 181 } 182 AssertMsg(cWoken == 0, ("%ld\n", cWoken)); 183 184 /* 185 * This path is taken in two situations: 186 * 1) A waiting thread is returning from the sys_futex call with a 187 * non-zero return value. 188 * 2) There are two threads signaling the event at the 189 * same time and only one thread waiting. 190 * 191 * At this point we know that nobody is activly waiting on the event but 192 * at the same time, we are racing someone updating the state. The current 193 * strategy is to spin till the thread racing us is done, this is kind of 194 * brain dead and need fixing of course. 195 */ 196 if (RT_UNLIKELY(i > 32)) 197 { 198 if ((i % 128) == 127) 199 usleep(1000); 200 else if (!(i % 4)) 201 pthread_yield(); 202 else 203 AssertReleaseMsg(i < 4096, ("iCur=%#x pThis=%p\n", iCur, pThis)); 204 } 205 } 206 207 /* Check the magic to fend off races with RTSemEventDestroy. */ 208 if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC)) 209 return VERR_SEM_DESTROYED; 210 } 211 return VINF_SUCCESS; 163 164 ASMAtomicWriteU32(&pThis->fSignalled, 1); 165 if (ASMAtomicReadS32(&pThis->cWaiters) < 1) 166 return VINF_SUCCESS; 167 168 /* somebody is waiting, try wake up one of them. */ 169 long cWoken = sys_futex(&pThis->fSignalled, FUTEX_WAKE, 1, NULL, NULL, 0); 170 if (RT_LIKELY(cWoken >= 0)) 171 return VINF_SUCCESS; 172 173 if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC)) 174 return VERR_SEM_DESTROYED; 175 176 return VERR_INVALID_PARAMETER; 212 177 } 213 178 … … 225 190 * Quickly check whether it's signaled. 226 191 */ 227 if (ASMAtomicCmpXchg S32(&pThis->cWaiters, 0, -1))192 if (ASMAtomicCmpXchgU32(&pThis->fSignalled, 0, 1)) 228 193 return VINF_SUCCESS; 229 194 … … 240 205 } 241 206 207 ASMAtomicIncS32(&pThis->cWaiters); 208 242 209 /* 243 210 * The wait loop. 244 211 */ 245 for (unsigned i = 0;; i++) 246 { 247 /* 248 * Announce that we're among the waiters. 249 */ 250 int32_t iNew = ASMAtomicIncS32(&pThis->cWaiters); 251 if (iNew == 0) 252 return VINF_SUCCESS; 253 if (RT_LIKELY(iNew > 0)) 254 { 255 /* 256 * Go to sleep. 257 */ 258 long rc = sys_futex(&pThis->cWaiters, FUTEX_WAIT, iNew, pTimeout, NULL, 0); 259 if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC)) 260 return VERR_SEM_DESTROYED; 261 262 /* Did somebody wake us up from RTSemEventSignal()? */ 263 if (rc == 0) 264 return VINF_SUCCESS; 265 266 /* No, then the kernel woke us up or we failed going to sleep. Adjust the accounting. */ 267 iNew = ASMAtomicDecS32(&pThis->cWaiters); 268 Assert(iNew >= 0); 269 270 /* 271 * Act on the wakup code. 272 */ 273 if (rc == -ETIMEDOUT) 212 int rc = VINF_SUCCESS; 213 for (;;) 214 { 215 long lrc = sys_futex(&pThis->fSignalled, FUTEX_WAIT, 0, pTimeout, NULL, 0); 216 if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC)) 217 { 218 rc = VERR_SEM_DESTROYED; 219 break; 220 } 221 222 if (RT_LIKELY(lrc == 0 || lrc == -EWOULDBLOCK)) 223 { 224 /* successful wakeup or fSignalled > 0 in the meantime */ 225 if (ASMAtomicCmpXchgU32(&pThis->fSignalled, 0, 1)) 226 break; 227 } 228 else if (lrc == -ETIMEDOUT) 229 { 230 rc = VERR_TIMEOUT; 231 break; 232 } 233 else if (lrc == -EINTR) 234 { 235 if (!fAutoResume) 274 236 { 275 Assert(pTimeout);276 return VERR_TIMEOUT;237 rc = VERR_INTERRUPTED; 238 break; 277 239 } 278 if (rc == -EWOULDBLOCK)279 /* retry with new value. */;280 else if (rc == -EINTR)281 {282 if (!fAutoResume)283 return VERR_INTERRUPTED;284 }285 else286 {287 /* this shouldn't happen! */288 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));289 return RTErrConvertFromErrno(rc);290 }291 240 } 292 241 else 293 242 { 294 /* this can't happen. */ 295 if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENT_MAGIC)) 296 return VERR_SEM_DESTROYED; 297 AssertReleaseMsgFailed(("iNew=%d\n", iNew)); 298 } 299 } 243 /* this shouldn't happen! */ 244 AssertMsgFailed(("rc=%ld errno=%d\n", lrc, errno)); 245 rc = RTErrConvertFromErrno(lrc); 246 break; 247 } 248 } 249 250 ASMAtomicDecS32(&pThis->cWaiters); 251 return rc; 300 252 } 301 253
Note:
See TracChangeset
for help on using the changeset viewer.