VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/semspingpong.cpp@ 5999

Last change on this file since 5999 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.2 KB
Line 
1/* $Id: semspingpong.cpp 5999 2007-12-07 15:05:06Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Thread Ping-Pong Construct.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/semaphore.h>
32#include <iprt/thread.h>
33#include <iprt/asm.h>
34#include <iprt/assert.h>
35#include <iprt/err.h>
36
37
38
39/**
40 * Validates a pPP handle passed to one of the PP functions.
41 *
42 * @returns true if valid, false if invalid.
43 * @param pPP Pointe to the ping-pong structure.
44 */
45inline bool rtsemPPValid(PRTPINGPONG pPP)
46{
47 if (!VALID_PTR(pPP))
48 return false;
49
50 RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker;
51 if ( enmSpeaker != RTPINGPONGSPEAKER_PING
52 && enmSpeaker != RTPINGPONGSPEAKER_PONG
53 && enmSpeaker != RTPINGPONGSPEAKER_PONG_SIGNALED
54 && enmSpeaker != RTPINGPONGSPEAKER_PING_SIGNALED)
55 return false;
56
57 return true;
58}
59
60/**
61 * Init a Ping-Pong construct.
62 *
63 * @returns iprt status code.
64 * @param pPP Pointer to the ping-pong structure which needs initialization.
65 */
66RTR3DECL(int) RTSemPingPongInit(PRTPINGPONG pPP)
67{
68 /*
69 * Init the structure.
70 */
71 pPP->enmSpeaker = RTPINGPONGSPEAKER_PING;
72
73 int rc = RTSemEventCreate(&pPP->Ping);
74 if (RT_SUCCESS(rc))
75 {
76 rc = RTSemEventCreate(&pPP->Pong);
77 if (RT_SUCCESS(rc))
78 return VINF_SUCCESS;
79 RTSemEventDestroy(pPP->Ping);
80 }
81
82 return rc;
83}
84
85
86/**
87 * Destroys a Ping-Pong construct.
88 *
89 * @returns iprt status code.
90 * @param pPP Pointer to the ping-pong structure which is to be destroyed.
91 * (I.e. put into uninitialized state.)
92 */
93RTR3DECL(int) RTSemPingPongDestroy(PRTPINGPONG pPP)
94{
95 /*
96 * Validate input
97 */
98 if (!rtsemPPValid(pPP))
99 {
100 AssertMsgFailed(("Invalid input %p\n", pPP));
101 return VERR_INVALID_PARAMETER;
102 }
103
104 /*
105 * Invalidate the ping pong handle and destroy the event semaphores.
106 */
107 ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_UNINITIALIZE);
108 int rc = RTSemEventDestroy(pPP->Ping);
109 int rc2 = RTSemEventDestroy(pPP->Pong);
110 AssertRC(rc);
111 AssertRC(rc2);
112
113 return VINF_SUCCESS;
114}
115
116
117/**
118 * Signals the pong thread in a ping-pong construct. (I.e. sends ping.)
119 * This is called by the ping thread.
120 *
121 * @returns iprt status code.
122 * @param pPP Pointer to the ping-pong structure to ping.
123 */
124RTR3DECL(int) RTSemPing(PRTPINGPONG pPP)
125{
126 /*
127 * Validate input
128 */
129 if (!rtsemPPValid(pPP))
130 {
131 AssertMsgFailed(("Invalid input %p\n", pPP));
132 return VERR_INVALID_PARAMETER;
133 }
134
135 if (pPP->enmSpeaker != RTPINGPONGSPEAKER_PING)
136 {
137 AssertMsgFailed(("Speaking out of turn!\n"));
138 return VERR_SEM_OUT_OF_TURN;
139 }
140
141 /*
142 * Signal the other thread.
143 */
144 ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PONG_SIGNALED);
145 int rc = RTSemEventSignal(pPP->Pong);
146 if (RT_SUCCESS(rc))
147 return rc;
148
149 /* restore the state. */
150 AssertMsgFailed(("Failed to signal pong sem %x. rc=%d\n", pPP->Pong, rc));
151 ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PING);
152 return rc;
153}
154
155
156/**
157 * Signals the ping thread in a ping-pong construct. (I.e. sends pong.)
158 * This is called by the pong thread.
159 *
160 * @returns iprt status code.
161 * @param pPP Pointer to the ping-pong structure to pong.
162 */
163RTR3DECL(int) RTSemPong(PRTPINGPONG pPP)
164{
165 /*
166 * Validate input
167 */
168 if (!rtsemPPValid(pPP))
169 {
170 AssertMsgFailed(("Invalid input %p\n", pPP));
171 return VERR_INVALID_PARAMETER;
172 }
173
174 if (pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG)
175 {
176 AssertMsgFailed(("Speaking out of turn!\n"));
177 return VERR_SEM_OUT_OF_TURN;
178 }
179
180 /*
181 * Signal the other thread.
182 */
183 ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PING_SIGNALED);
184 int rc = RTSemEventSignal(pPP->Ping);
185 if (RT_SUCCESS(rc))
186 return rc;
187
188 /* restore the state. */
189 AssertMsgFailed(("Failed to signal ping sem %x. rc=%d\n", pPP->Ping, rc));
190 ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PONG);
191 return rc;
192}
193
194
195/**
196 * Wait function for the ping thread.
197 *
198 * @returns iprt status code.
199 * Will not return VERR_INTERRUPTED.
200 * @param pPP Pointer to the ping-pong structure to wait on.
201 * @param cMillies Number of milliseconds to wait.
202 */
203RTR3DECL(int) RTSemPingWait(PRTPINGPONG pPP, unsigned cMillies)
204{
205 /*
206 * Validate input
207 */
208 if (!rtsemPPValid(pPP))
209 {
210 AssertMsgFailed(("Invalid input %p\n", pPP));
211 return VERR_INVALID_PARAMETER;
212 }
213
214 if ( pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG
215 && pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG_SIGNALED
216 && pPP->enmSpeaker != RTPINGPONGSPEAKER_PING_SIGNALED)
217 {
218 AssertMsgFailed(("Listening out of turn! enmSpeaker=%d\n", pPP->enmSpeaker));
219 return VERR_SEM_OUT_OF_TURN;
220 }
221
222 /*
223 * Wait.
224 */
225 int rc = RTSemEventWait(pPP->Ping, cMillies);
226 if (RT_SUCCESS(rc))
227 ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PING);
228 Assert(rc != VERR_INTERRUPTED);
229 return rc;
230}
231
232
233/**
234 * Wait function for the pong thread.
235 *
236 * @returns iprt status code.
237 * Will not return VERR_INTERRUPTED.
238 * @param pPP Pointer to the ping-pong structure to wait on.
239 * @param cMillies Number of milliseconds to wait.
240 */
241RTR3DECL(int) RTSemPongWait(PRTPINGPONG pPP, unsigned cMillies)
242{
243 /*
244 * Validate input
245 */
246 if (!rtsemPPValid(pPP))
247 {
248 AssertMsgFailed(("Invalid input %p\n", pPP));
249 return VERR_INVALID_PARAMETER;
250 }
251
252 if ( pPP->enmSpeaker != RTPINGPONGSPEAKER_PING
253 && pPP->enmSpeaker != RTPINGPONGSPEAKER_PING_SIGNALED
254 && pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG_SIGNALED)
255 {
256 AssertMsgFailed(("Listening out of turn! enmSpeaker=%d\n", pPP->enmSpeaker));
257 return VERR_SEM_OUT_OF_TURN;
258 }
259
260 /*
261 * Wait.
262 */
263 int rc = RTSemEventWait(pPP->Pong, cMillies);
264 if (RT_SUCCESS(rc))
265 ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PONG);
266 Assert(rc != VERR_INTERRUPTED);
267 return rc;
268}
269
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