VirtualBox

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

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

various stray files -> common/misc/

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