Changeset 25431 in vbox for trunk/src/VBox/Runtime/generic/semxroads-generic.cpp
- Timestamp:
- Dec 16, 2009 2:15:11 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/generic/semxroads-generic.cpp
r25426 r25431 39 39 #include <iprt/assert.h> 40 40 #include <iprt/err.h> 41 #include <iprt/mem.h> 41 42 #include <iprt/thread.h> 42 43 … … 47 48 * Structures and Typedefs * 48 49 *******************************************************************************/ 50 typedef struct RTSEMXROADSINTERNAL 51 { 52 /** Magic value (RTSEMXROADS_MAGIC). */ 53 uint32_t volatile u32Magic; 54 /** The state variable. 55 * All accesses are atomic and it bits are defined like this: 56 * 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; 68 } RTSEMXROADSINTERNAL; 69 70 71 /******************************************************************************* 72 * Defined Constants And Macros * 73 *******************************************************************************/ 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) 49 80 50 81 51 82 RTDECL(int) RTSemXRoadsCreate(PRTSEMXROADS phXRoads) 52 83 { 53 return VERR_NOT_IMPLEMENTED; 84 RTSEMXROADSINTERNAL *pThis = (RTSEMXROADSINTERNAL *)RTMemAlloc(sizeof(*pThis)); 85 if (!pThis) 86 return VERR_NO_MEMORY; 87 88 int rc = RTSemEventMultiCreate(&pThis->hEvtNS); 89 if (RT_SUCCESS(rc)) 90 { 91 rc = RTSemEventMultiSignal(pThis->hEvtNS); 92 if (RT_SUCCESS(rc)) 93 { 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); 104 } 105 return rc; 54 106 } 55 107 … … 57 109 RTDECL(int) RTSemXRoadsDestroy(RTSEMXROADS hXRoads) 58 110 { 59 return VERR_NOT_IMPLEMENTED; 111 /* 112 * Validate input. 113 */ 114 RTSEMXROADSINTERNAL *pThis = hXRoads; 115 if (pThis == NIL_RTSEMXROADS) 116 return VINF_SUCCESS; 117 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 118 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 119 Assert(!(ASMAtomicReadU32(&pThis->u32State) & (RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK))); 120 121 /* 122 * Invalidate the object and free up the resources. 123 */ 124 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMXROADS_MAGIC_DEAD, RTSEMXROADS_MAGIC), VERR_INVALID_HANDLE); 125 126 RTSEMEVENTMULTI hEvt; 127 ASMAtomicXchgHandle(&pThis->hEvtNS, NIL_RTSEMEVENTMULTI, &hEvt); 128 int rc = RTSemEventMultiDestroy(hEvt); 129 AssertRC(rc); 130 131 ASMAtomicXchgHandle(&pThis->hEvtEW, NIL_RTSEMEVENTMULTI, &hEvt); 132 rc = RTSemEventMultiDestroy(hEvt); 133 AssertRC(rc); 134 135 return VINF_SUCCESS; 136 } 137 138 139 /** 140 * Internal worker for RTSemXRoadsNSEnter and RTSemXRoadsEWEnter. 141 * 142 * @returns IPRT status code. 143 * @param pThis The semaphore instace. 144 * @param hEvtBlock Which semaphore to wait on. 145 * @param hEvtReset Which semaphore to reset. 146 * @param uCountShift The shift count for getting the count. 147 * @param fCountMask The mask for getting the count. 148 * @param fDirection The direction state value. 149 */ 150 DECL_FORCE_INLINE(int) rtSemXRoadsEnter(RTSEMXROADSINTERNAL *pThis, 151 RTSEMEVENTMULTI hEvtBlock, RTSEMEVENTMULTI hEvtReset, 152 uint32_t uCountShift, uint32_t fCountMask, uint32_t fDirection) 153 { 154 for (;;) 155 { 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; 166 c++; 167 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) 174 { 175 /* 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; 183 } 184 else 185 { 186 /* Add ourselves to the waiting threads and wait for the direction to change. */ 187 uint32_t c = (u32State & fCountMask) >> uCountShift; 188 c++; 189 Assert(c < 8*_1K); 190 u32State &= ~fCountMask; 191 u32State |= c << uCountShift; 192 if (ASMAtomicCmpXchgU32(&pThis->u32State, u32State, u32OldState)) 193 { 194 for (uint32_t iLoop = 0; ; iLoop++) 195 { 196 int rc = RTSemEventMultiWait(hEvtBlock, RT_INDEFINITE_WAIT); 197 AssertRCReturn(rc, rc); 198 199 if (pThis->u32Magic != RTSEMXROADS_MAGIC) 200 return VERR_SEM_DESTROYED; 201 202 if ((ASMAtomicReadU32(&pThis->u32State) & RTSEMXROADS_DIR_MASK) == (fDirection << RTSEMXROADS_DIR_SHIFT)) 203 return VINF_SUCCESS; 204 205 AssertMsgFailed(("%u\n", iLoop)); 206 } 207 } 208 } 209 210 ASMNopPause(); 211 if (pThis->u32Magic != RTSEMXROADS_MAGIC) 212 return VERR_SEM_DESTROYED; 213 } 214 } 215 216 217 /** 218 * Internal worker for RTSemXRoadsNSLeave and RTSemXRoadsEWLeave. 219 * 220 * @returns IPRT status code. 221 * @param pThis The semaphore instace. 222 * @param hEvtReset Which semaphore to reset. 223 * @param hEvtSignal Which semaphore to signal. 224 * @param uCountShift The shift count for getting the count. 225 * @param fCountMask The mask for getting the count. 226 * @param fDirection The direction state value. 227 */ 228 DECL_FORCE_INLINE(int) rtSemXRoadsLeave(RTSEMXROADSINTERNAL *pThis, 229 RTSEMEVENTMULTI hEvtReset, RTSEMEVENTMULTI hEvtSignal, 230 uint32_t uCountShift, uint32_t fCountMask, uint32_t fDirection) 231 { 232 for (;;) 233 { 234 uint32_t u32OldState; 235 uint32_t u32State; 236 uint32_t c; 237 238 u32State = ASMAtomicReadU32(&pThis->u32State); 239 u32OldState = u32State; 240 241 /* The direction cannot change until we've left or we'll crash. */ 242 Assert((u32State & RTSEMXROADS_DIR_MASK) == (fDirection << RTSEMXROADS_DIR_SHIFT)); 243 244 c = (u32State & fCountMask) >> uCountShift; 245 Assert(c > 0); 246 c--; 247 248 if ( c > 0 249 || (u32State & ((RTSEMXROADS_CNT_NS_MASK | RTSEMXROADS_CNT_EW_MASK) & ~fCountMask)) == 0) 250 { 251 /* 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)) 255 return VINF_SUCCESS; 256 } 257 else 258 { 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)) 267 { 268 int rc = RTSemEventMultiSignal(hEvtSignal); 269 AssertRC(rc); 270 return VINF_SUCCESS; 271 } 272 } 273 274 ASMNopPause(); 275 if (pThis->u32Magic != RTSEMXROADS_MAGIC) 276 return VERR_SEM_DESTROYED; 277 } 60 278 } 61 279 … … 63 281 RTDECL(int) RTSemXRoadsNSEnter(RTSEMXROADS hXRoads) 64 282 { 65 return VERR_NOT_IMPLEMENTED; 283 /* 284 * Validate input. 285 */ 286 RTSEMXROADSINTERNAL *pThis = hXRoads; 287 if (pThis == NIL_RTSEMXROADS) 288 return VINF_SUCCESS; 289 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 290 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 291 292 return rtSemXRoadsEnter(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0); 66 293 } 67 294 … … 69 296 RTDECL(int) RTSemXRoadsNSLeave(RTSEMXROADS hXRoads) 70 297 { 71 return VERR_NOT_IMPLEMENTED; 298 /* 299 * Validate input. 300 */ 301 RTSEMXROADSINTERNAL *pThis = hXRoads; 302 if (pThis == NIL_RTSEMXROADS) 303 return VINF_SUCCESS; 304 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 305 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 306 307 return rtSemXRoadsLeave(pThis, pThis->hEvtNS, pThis->hEvtEW, RTSEMXROADS_CNT_NS_SHIFT, RTSEMXROADS_CNT_NS_MASK, 0); 72 308 } 73 309 … … 75 311 RTDECL(int) RTSemXRoadsEWEnter(RTSEMXROADS hXRoads) 76 312 { 77 return VERR_NOT_IMPLEMENTED; 313 /* 314 * Validate input. 315 */ 316 RTSEMXROADSINTERNAL *pThis = hXRoads; 317 if (pThis == NIL_RTSEMXROADS) 318 return VINF_SUCCESS; 319 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 320 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 321 322 return rtSemXRoadsEnter(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1); 78 323 } 79 324 … … 81 326 RTDECL(int) RTSemXRoadsEWLeave(RTSEMXROADS hXRoads) 82 327 { 83 return VERR_NOT_IMPLEMENTED; 84 } 85 328 /* 329 * Validate input. 330 */ 331 RTSEMXROADSINTERNAL *pThis = hXRoads; 332 if (pThis == NIL_RTSEMXROADS) 333 return VINF_SUCCESS; 334 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 335 AssertReturn(pThis->u32Magic == RTSEMXROADS_MAGIC, VERR_INVALID_HANDLE); 336 337 return rtSemXRoadsLeave(pThis, pThis->hEvtEW, pThis->hEvtNS, RTSEMXROADS_CNT_EW_SHIFT, RTSEMXROADS_CNT_EW_MASK, 1); 338 } 339
Note:
See TracChangeset
for help on using the changeset viewer.