VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/semxroads-generic.cpp@ 25431

Last change on this file since 25431 was 25431, checked in by vboxsync, 15 years ago

RTSemXRoads: initial implementation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/* $Id: semxroads-generic.cpp 25431 2009-12-16 14:15:11Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTSemXRoads, generic implementation.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/semaphore.h>
36#include "internal/iprt.h"
37
38#include <iprt/asm.h>
39#include <iprt/assert.h>
40#include <iprt/err.h>
41#include <iprt/mem.h>
42#include <iprt/thread.h>
43
44#include "internal/magics.h"
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50typedef 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)
80
81
82RTDECL(int) RTSemXRoadsCreate(PRTSEMXROADS phXRoads)
83{
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;
106}
107
108
109RTDECL(int) RTSemXRoadsDestroy(RTSEMXROADS hXRoads)
110{
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 */
150DECL_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 */
228DECL_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 }
278}
279
280
281RTDECL(int) RTSemXRoadsNSEnter(RTSEMXROADS hXRoads)
282{
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);
293}
294
295
296RTDECL(int) RTSemXRoadsNSLeave(RTSEMXROADS hXRoads)
297{
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);
308}
309
310
311RTDECL(int) RTSemXRoadsEWEnter(RTSEMXROADS hXRoads)
312{
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);
323}
324
325
326RTDECL(int) RTSemXRoadsEWLeave(RTSEMXROADS hXRoads)
327{
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 TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette