Changeset 25549 in vbox for trunk/src/VBox/Runtime/generic
- Timestamp:
- Dec 21, 2009 5:16:59 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 56225
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/generic/semxroads-generic.cpp
r25431 r25549 33 33 * Header Files * 34 34 *******************************************************************************/ 35 #define RTASSERT_QUIET 35 36 #include <iprt/semaphore.h> 36 37 #include "internal/iprt.h" … … 44 45 #include "internal/magics.h" 45 46 47 #include <stdio.h>//debug 48 46 49 47 50 /******************************************************************************* … … 52 55 /** Magic value (RTSEMXROADS_MAGIC). */ 53 56 uint32_t volatile u32Magic; 54 /** The state variable. 57 uint32_t u32Padding; /**< alignment padding.*/ 58 /* The state variable. 55 59 * All accesses are atomic and it bits are defined like this: 56 60 * Bits 0..14 - cNorthSouth. 57 * Bits 15..30 - cEastWest. 58 * Bit 30 - fDirection; 0=NS, 1=EW. 59 * Bit 31 - Unused. 60 */ 61 uint32_t volatile u32State; 62 /** What the north/south bound threads are blocking on when waiting for 63 * east/west traffic to stop. */ 64 RTSEMEVENTMULTI hEvtNS; 65 /** What the east/west bound threads are blocking on when waiting for 66 * north/south traffic to stop. */ 67 RTSEMEVENTMULTI hEvtEW; 61 * Bit 15 - Unused. 62 * Bits 16..31 - cEastWest. 63 * Bit 31 - fDirection; 0=NS, 1=EW. 64 * Bits 32..46 - cWaitingNS 65 * Bit 47 - Unused. 66 * Bits 48..62 - cWaitingEW 67 * Bit 63 - Unused. 68 */ 69 uint64_t volatile u64State; 70 /** Per-direction data. */ 71 struct 72 { 73 /** What the north/south bound threads are blocking on when waiting for 74 * east/west traffic to stop. */ 75 RTSEMEVENTMULTI hEvt; 76 /** Indicates whether the semaphore needs resetting. */ 77 bool volatile fNeedReset; 78 } aDirs[2]; 68 79 } RTSEMXROADSINTERNAL; 69 80 … … 72 83 * Defined Constants And Macros * 73 84 *******************************************************************************/ 74 #define RTSEMXROADS_CNT_NS_SHIFT 0 75 #define RTSEMXROADS_CNT_NS_MASK UINT32_C(0x00007fff) 76 #define RTSEMXROADS_CNT_EW_SHIFT 15 77 #define RTSEMXROADS_CNT_EW_MASK UINT32_C(0x3fff8000) 78 #define RTSEMXROADS_DIR_SHIFT 30 79 #define RTSEMXROADS_DIR_MASK UINT32_C(0x40000000) 85 #define RTSEMXROADS_CNT_BITS 15 86 #define RTSEMXROADS_CNT_MASK UINT64_C(0x00007fff) 87 88 #define RTSEMXROADS_CNT_NS_SHIFT 0 89 #define RTSEMXROADS_CNT_NS_MASK (RTSEMXROADS_CNT_MASK << RTSEMXROADS_CNT_NS_SHIFT) 90 #define RTSEMXROADS_CNT_EW_SHIFT 16 91 #define RTSEMXROADS_CNT_EW_MASK (RTSEMXROADS_CNT_MASK << RTSEMXROADS_CNT_EW_SHIFT) 92 #define RTSEMXROADS_DIR_SHIFT 31 93 #define RTSEMXROADS_DIR_MASK RT_BIT_64(RTSEMXROADS_DIR_SHIFT) 94 95 #define RTSEMXROADS_WAIT_CNT_NS_SHIFT 32 96 #define RTSEMXROADS_WAIT_CNT_NS_MASK (RTSEMXROADS_CNT_MASK << RTSEMXROADS_WAIT_CNT_NS_SHIFT) 97 #define RTSEMXROADS_WAIT_CNT_EW_SHIFT 48 98 #define RTSEMXROADS_WAIT_CNT_EW_MASK (RTSEMXROADS_CNT_MASK << RTSEMXROADS_WAIT_CNT_EW_SHIFT) 99 100 101 #if 0 /* debugging aid */ 102 static uint32_t volatile g_iHist = 0; 103 static struct 104 { 105 void *tsc; 106 RTTHREAD hThread; 107 uint32_t line; 108 bool fDir; 109 void *u64State; 110 void *u64OldState; 111 bool fNeedResetNS; 112 bool fNeedResetEW; 113 const char *psz; 114 } g_aHist[256]; 115 116 # define add_hist(ns, os, dir, what) \ 117 do \ 118 { \ 119 uint32_t i = (ASMAtomicIncU32(&g_iHist) - 1) % RT_ELEMENTS(g_aHist);\ 120 g_aHist[i].line = __LINE__; \ 121 g_aHist[i].u64OldState = (void *)(os); \ 122 g_aHist[i].u64State = (void *)(ns); \ 123 g_aHist[i].fDir = (dir); \ 124 g_aHist[i].psz = (what); \ 125 g_aHist[i].fNeedResetNS = pThis->aDirs[0].fNeedReset; \ 126 g_aHist[i].fNeedResetEW = pThis->aDirs[1].fNeedReset; \ 127 g_aHist[i].hThread = RTThreadSelf(); \ 128 g_aHist[i].tsc = (void *)ASMReadTSC(); \ 129 } while (0) 130 131 # undef DECL_FORCE_INLINE 132 # define DECL_FORCE_INLINE(type) static type 133 #else 134 # define add_hist(ns, os, dir, what) do { } while (0) 135 #endif 80 136 81 137 … … 86 142 return VERR_NO_MEMORY; 87 143 88 int rc = RTSemEventMultiCreate(&pThis-> hEvtNS);144 int rc = RTSemEventMultiCreate(&pThis->aDirs[0].hEvt); 89 145 if (RT_SUCCESS(rc)) 90 146 { 91 rc = RTSemEventMulti Signal(pThis->hEvtNS);147 rc = RTSemEventMultiCreate(&pThis->aDirs[1].hEvt); 92 148 if (RT_SUCCESS(rc)) 93 149 { 94 rc = RTSemEventMultiCreate(&pThis->hEvtEW); 95 if (RT_SUCCESS(rc)) 96 { 97 pThis->u32Magic = RTSEMXROADS_MAGIC; 98 pThis->u32State = 0; 99 *phXRoads = pThis; 100 return VINF_SUCCESS; 101 } 102 } 103 RTSemEventMultiDestroy(pThis->hEvtNS); 150 pThis->u32Magic = RTSEMXROADS_MAGIC; 151 pThis->u32Padding = 0; 152 pThis->u64State = 0; 153 pThis->aDirs[0].fNeedReset = false; 154 pThis->aDirs[1].fNeedReset = false; 155 *phXRoads = pThis; 156 return VINF_SUCCESS; 157 } 158 RTSemEventMultiDestroy(pThis->aDirs[0].hEvt); 104 159 } 105 160 return rc; … … 117 172 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 118 173 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 119 Assert(!(ASMAtomicReadU 32(&pThis->u32State) & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK)));174 Assert(!(ASMAtomicReadU64(&pThis->u64State) & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK))); 120 175 121 176 /* … … 125 180 126 181 RTSEMEVENTMULTI hEvt; 127 ASMAtomicXchgHandle(&pThis-> hEvtNS, NIL_RTSEMEVENTMULTI, &hEvt);182 ASMAtomicXchgHandle(&pThis->aDirs[0].hEvt, NIL_RTSEMEVENTMULTI, &hEvt); 128 183 int rc = RTSemEventMultiDestroy(hEvt); 129 184 AssertRC(rc); 130 185 131 ASMAtomicXchgHandle(&pThis-> hEvtEW, NIL_RTSEMEVENTMULTI, &hEvt);186 ASMAtomicXchgHandle(&pThis->aDirs[1].hEvt, NIL_RTSEMEVENTMULTI, &hEvt); 132 187 rc = RTSemEventMultiDestroy(hEvt); 133 188 AssertRC(rc); 134 189 190 RTMemFree(pThis); 135 191 return VINF_SUCCESS; 136 192 } … … 142 198 * @returns IPRT status code. 143 199 * @param pThis The semaphore instace. 144 * @param hEvtBlock Which semaphore to wait on. 145 * @param hEvtReset Which semaphore to reset. 200 * @param fDir The direction. 146 201 * @param uCountShift The shift count for getting the count. 147 202 * @param fCountMask The mask for getting the count. 148 * @param fDirection The direction state value. 203 * @param uWaitCountShift The shift count for getting the wait count. 204 * @param fWaitCountMask The mask for getting the wait count. 149 205 */ 150 DECL_FORCE_INLINE(int) rtSemXRoadsEnter(RTSEMXROADSINTERNAL *pThis, 151 RTSEMEVENTMULTI hEvtBlock, RTSEMEVENTMULTI hEvtReset, 152 uint32_t uCountShift, uint32_t fCountMask, uint32_t fDirection) 153 { 206 DECL_FORCE_INLINE(int) rtSemXRoadsEnter(RTSEMXROADSINTERNAL *pThis, uint64_t fDir, 207 uint64_t uCountShift, uint64_t fCountMask, 208 uint64_t uWaitCountShift, uint64_t fWaitCountMask) 209 { 210 uint64_t u64OldState; 211 uint64_t u64State; 212 213 u64State = ASMAtomicReadU64(&pThis->u64State); 214 u64OldState = u64State; 215 add_hist(u64State, u64OldState, fDir, "enter"); 216 154 217 for (;;) 155 218 { 156 uint32_t u32OldState; 157 uint32_t u32State; 158 159 u32State = ASMAtomicReadU32(&pThis->u32State); 160 u32OldState = u32State; 161 162 if ((u32State & RTSEMXROADS_DIR_MASK) == (fDirection << RTSEMXROADS_DIR_SHIFT)) 163 { 164 /* It's flows in the right direction, try add ourselves to the flow before it changes. */ 165 uint32_t c = (u32State & fCountMask) >> uCountShift; 219 if ((u64State & RTSEMXROADS_DIR_MASK) == (fDir << RTSEMXROADS_DIR_SHIFT)) 220 { 221 /* It flows in the right direction, try follow it before it changes. */ 222 uint64_t c = (u64State & fCountMask) >> uCountShift; 166 223 c++; 167 224 Assert(c < 8*_1K); 168 u32State &= ~fCountMask; 169 u32State |= c << uCountShift; 170 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState)) 171 return VINF_SUCCESS; 172 } 173 else if ((u32State & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK)) == 0) 225 u64State &= ~fCountMask; 226 u64State |= c << uCountShift; 227 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState)) 228 { 229 add_hist(u64State, u64OldState, fDir, "enter-simple"); 230 break; 231 } 232 } 233 else if ((u64State & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK)) == 0) 174 234 { 175 235 /* Wrong direction, but we're alone here and can simply try switch the direction. */ 176 RTSemEventMultiReset(hEvtReset); 177 if (pThis->u32Magic != RTSEMXROADS_MAGIC) 178 return VERR_SEM_DESTROYED; 179 180 u32State = (UINT32_C(1) << uCountShift) | (fDirection << RTSEMXROADS_DIR_SHIFT); 181 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState)) 182 return VINF_SUCCESS; 236 u64State &= ~(RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK | RTSEMXROADS_DIR_MASK); 237 u64State |= (UINT64_C(1) << uCountShift) | (fDir << RTSEMXROADS_DIR_SHIFT); 238 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState)) 239 { 240 Assert(!pThis->aDirs[fDir].fNeedReset); 241 add_hist(u64State, u64OldState, fDir, "enter-switch"); 242 break; 243 } 183 244 } 184 245 else 185 246 { 186 /* Add ourselves to the waiting threadsand wait for the direction to change. */187 uint 32_t c = (u32State & fCountMask) >> uCountShift;247 /* Add ourselves to the queue and wait for the direction to change. */ 248 uint64_t c = (u64State & fCountMask) >> uCountShift; 188 249 c++; 189 Assert(c < 8*_1K); 190 u32State &= ~fCountMask; 191 u32State |= c << uCountShift; 192 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState)) 250 Assert(c < RTSEMXROADS_CNT_MASK / 2); 251 252 uint64_t cWait = (u64State & fWaitCountMask) >> uWaitCountShift; 253 cWait++; 254 Assert(cWait <= c); 255 Assert(cWait < RTSEMXROADS_CNT_MASK / 2); 256 257 u64State &= ~(fCountMask | fWaitCountMask); 258 u64State |= (c << uCountShift) | (cWait << uWaitCountShift); 259 260 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState)) 193 261 { 262 add_hist(u64State, u64OldState, fDir, "enter-wait"); 194 263 for (uint32_t iLoop = 0; ; iLoop++) 195 264 { 196 int rc = RTSemEventMultiWait( hEvtBlock, RT_INDEFINITE_WAIT);265 int rc = RTSemEventMultiWait(pThis->aDirs[fDir].hEvt, RT_INDEFINITE_WAIT); 197 266 AssertRCReturn(rc, rc); 198 267 … … 200 269 return VERR_SEM_DESTROYED; 201 270 202 if ((ASMAtomicReadU32(&pThis->u32State) & RTSEMXROADS_DIR_MASK) == (fDirection << RTSEMXROADS_DIR_SHIFT)) 203 return VINF_SUCCESS; 204 205 AssertMsgFailed(("%u\n", iLoop)); 271 Assert(pThis->aDirs[fDir].fNeedReset); 272 u64State = ASMAtomicReadU64(&pThis->u64State); 273 add_hist(u64State, u64OldState, fDir, "enter-wakeup"); 274 if ((u64State & RTSEMXROADS_DIR_MASK) == (fDir << RTSEMXROADS_DIR_SHIFT)) 275 break; 276 AssertMsg(iLoop < 1, ("%u\n", iLoop)); 206 277 } 278 279 /* Decrement the wait count and maybe reset the semaphore (if we're last). */ 280 for (;;) 281 { 282 u64OldState = u64State; 283 284 cWait = (u64State & fWaitCountMask) >> uWaitCountShift; 285 Assert(cWait > 0); 286 cWait--; 287 u64State &= ~fWaitCountMask; 288 u64State |= cWait << uWaitCountShift; 289 290 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState)) 291 { 292 if (cWait == 0) 293 { 294 if (ASMAtomicXchgBool(&pThis->aDirs[fDir].fNeedReset, false)) 295 { 296 add_hist(u64State, u64OldState, fDir, fDir ? "enter-reset-EW" : "enter-reset-NS"); 297 int rc = RTSemEventMultiReset(pThis->aDirs[fDir].hEvt); 298 AssertRCReturn(rc, rc); 299 } 300 else 301 add_hist(u64State, u64OldState, fDir, "enter-dec-no-need"); 302 } 303 break; 304 } 305 u64State = ASMAtomicReadU64(&pThis->u64State); 306 } 307 break; 207 308 } 208 } 209 210 ASMNopPause(); 309 310 add_hist(u64State, u64OldState, fDir, "enter-wait-failed"); 311 } 312 211 313 if (pThis->u32Magic != RTSEMXROADS_MAGIC) 212 314 return VERR_SEM_DESTROYED; 315 316 ASMNopPause(); 317 u64State = ASMAtomicReadU64(&pThis->u64State); 318 u64OldState = u64State; 213 319 } 320 321 /* got it! */ 322 Assert((ASMAtomicReadU64(&pThis->u64State) & RTSEMXROADS_DIR_MASK) == (fDir << RTSEMXROADS_DIR_SHIFT)); 323 return VINF_SUCCESS; 214 324 } 215 325 … … 220 330 * @returns IPRT status code. 221 331 * @param pThis The semaphore instace. 222 * @param hEvtReset Which semaphore to reset. 223 * @param hEvtSignal Which semaphore to signal. 332 * @param fDir The direction. 224 333 * @param uCountShift The shift count for getting the count. 225 334 * @param fCountMask The mask for getting the count. 226 * @param fDirection The direction state value.227 335 */ 228 DECL_FORCE_INLINE(int) rtSemXRoadsLeave(RTSEMXROADSINTERNAL *pThis, 229 RTSEMEVENTMULTI hEvtReset, RTSEMEVENTMULTI hEvtSignal, 230 uint32_t uCountShift, uint32_t fCountMask, uint32_t fDirection) 336 DECL_FORCE_INLINE(int) rtSemXRoadsLeave(RTSEMXROADSINTERNAL *pThis, uint64_t fDir, uint64_t uCountShift, uint64_t fCountMask) 231 337 { 232 338 for (;;) 233 339 { 234 uint 32_t u32OldState;235 uint 32_t u32State;236 uint 32_t c;237 238 u 32State = ASMAtomicReadU32(&pThis->u32State);239 u 32OldState = u32State;340 uint64_t u64OldState; 341 uint64_t u64State; 342 uint64_t c; 343 344 u64State = ASMAtomicReadU64(&pThis->u64State); 345 u64OldState = u64State; 240 346 241 347 /* The direction cannot change until we've left or we'll crash. */ 242 Assert((u 32State & RTSEMXROADS_DIR_MASK) == (fDirection<< RTSEMXROADS_DIR_SHIFT));243 244 c = (u 32State & fCountMask) >> uCountShift;348 Assert((u64State & RTSEMXROADS_DIR_MASK) == (fDir << RTSEMXROADS_DIR_SHIFT)); 349 350 c = (u64State & fCountMask) >> uCountShift; 245 351 Assert(c > 0); 246 352 c--; 247 353 248 354 if ( c > 0 249 || (u 32State & ((RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK) & ~fCountMask)) == 0)355 || (u64State & ((RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK) & ~fCountMask)) == 0) 250 356 { 251 357 /* We're not the last one across or there aren't any one waiting in the other direction. */ 252 u32State &= ~fCountMask; 253 u32State |= c << uCountShift; 254 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState)) 358 u64State &= ~fCountMask; 359 u64State |= c << uCountShift; 360 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState)) 361 { 362 add_hist(u64State, u64OldState, fDir, "leave-simple"); 255 363 return VINF_SUCCESS; 364 } 256 365 } 257 366 else 258 367 { 259 /* Reverse the direction. */ 260 RTSemEventMultiReset(hEvtReset); 261 if (pThis->u32Magic != RTSEMXROADS_MAGIC) 262 return VERR_SEM_DESTROYED; 263 264 u32State &= ~(fCountMask | RTSEMXROADS_DIR_MASK); 265 u32State |= !fDirection << RTSEMXROADS_DIR_SHIFT; 266 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState)) 368 /* Reverse the direction and signal the threads in the other direction. */ 369 u64State &= ~(fCountMask | RTSEMXROADS_DIR_MASK); 370 u64State |= (uint64_t)!fDir << RTSEMXROADS_DIR_SHIFT; 371 if (ASMAtomicCmpXchgU64(&pThis->u64State, u64State, u64OldState)) 267 372 { 268 int rc = RTSemEventMultiSignal(hEvtSignal); 373 add_hist(u64State, u64OldState, fDir, fDir ? "leave-signal-NS" : "leave-signal-EW"); 374 Assert(!pThis->aDirs[!fDir].fNeedReset); 375 ASMAtomicWriteBool(&pThis->aDirs[!fDir].fNeedReset, true); 376 int rc = RTSemEventMultiSignal(pThis->aDirs[!fDir].hEvt); 269 377 AssertRC(rc); 270 378 return VINF_SUCCESS; … … 290 398 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 291 399 292 return rtSemXRoadsEnter(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0);400 return rtSemXRoadsEnter(pThis, 0, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, RTSEMXROADS_WAIT_CNT_NS_SHIFT, RTSEMXROADS_WAIT_CNT_NS_MASK); 293 401 } 294 402 … … 305 413 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 306 414 307 return rtSemXRoadsLeave(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0);415 return rtSemXRoadsLeave(pThis, 0, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK); 308 416 } 309 417 … … 320 428 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 321 429 322 return rtSemXRoadsEnter(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1);430 return rtSemXRoadsEnter(pThis, 1, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, RTSEMXROADS_WAIT_CNT_EW_SHIFT, RTSEMXROADS_WAIT_CNT_EW_MASK); 323 431 } 324 432 … … 335 443 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 336 444 337 return rtSemXRoadsLeave(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1);338 } 339 445 return rtSemXRoadsLeave(pThis, 1, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK); 446 } 447
Note:
See TracChangeset
for help on using the changeset viewer.