1
/* $Id: semspingpong.cpp 4071 2007-08-07 17:07:59Z vboxsync $ */
3
* innotek Portable Runtime - Thread Ping-Pong Construct.
7
* Copyright (C) 2006-2007 innotek GmbH
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.
19
/*******************************************************************************
21
*******************************************************************************/
22
#include <iprt/semaphore.h>
23
#include <iprt/thread.h>
25
#include <iprt/assert.h>
31
* Validates a pPP handle passed to one of the PP functions.
33
* @returns true if valid, false if invalid.
34
* @param pPP Pointe to the ping-pong structure.
36
inline bool rtsemPPValid(PRTPINGPONG pPP)
41
RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker;
42
if ( enmSpeaker != RTPINGPONGSPEAKER_PING
43
&& enmSpeaker != RTPINGPONGSPEAKER_PONG
44
&& enmSpeaker != RTPINGPONGSPEAKER_PONG_SIGNALED
45
&& enmSpeaker != RTPINGPONGSPEAKER_PING_SIGNALED)
52
* Init a Ping-Pong construct.
54
* @returns iprt status code.
55
* @param pPP Pointer to the ping-pong structure which needs initialization.
57
RTR3DECL(int) RTSemPingPongInit(PRTPINGPONG pPP)
62
pPP->enmSpeaker = RTPINGPONGSPEAKER_PING;
64
int rc = RTSemEventCreate(&pPP->Ping);
67
rc = RTSemEventCreate(&pPP->Pong);
70
RTSemEventDestroy(pPP->Ping);
78
* Destroys a Ping-Pong construct.
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.)
84
RTR3DECL(int) RTSemPingPongDestroy(PRTPINGPONG pPP)
89
if (!rtsemPPValid(pPP))
91
AssertMsgFailed(("Invalid input %p\n", pPP));
92
return VERR_INVALID_PARAMETER;
96
* Invalidate the ping pong handle and destroy the event semaphores.
98
ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_UNINITIALIZE);
99
int rc = RTSemEventDestroy(pPP->Ping);
100
int rc2 = RTSemEventDestroy(pPP->Pong);
109
* Signals the pong thread in a ping-pong construct. (I.e. sends ping.)
110
* This is called by the ping thread.
112
* @returns iprt status code.
113
* @param pPP Pointer to the ping-pong structure to ping.
115
RTR3DECL(int) RTSemPing(PRTPINGPONG pPP)
120
if (!rtsemPPValid(pPP))
122
AssertMsgFailed(("Invalid input %p\n", pPP));
123
return VERR_INVALID_PARAMETER;
126
if (pPP->enmSpeaker != RTPINGPONGSPEAKER_PING)
128
AssertMsgFailed(("Speaking out of turn!\n"));
129
return VERR_SEM_OUT_OF_TURN;
133
* Signal the other thread.
135
ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PONG_SIGNALED);
136
int rc = RTSemEventSignal(pPP->Pong);
140
/* restore the state. */
141
AssertMsgFailed(("Failed to signal pong sem %x. rc=%d\n", pPP->Pong, rc));
142
ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PING);
148
* Signals the ping thread in a ping-pong construct. (I.e. sends pong.)
149
* This is called by the pong thread.
151
* @returns iprt status code.
152
* @param pPP Pointer to the ping-pong structure to pong.
154
RTR3DECL(int) RTSemPong(PRTPINGPONG pPP)
159
if (!rtsemPPValid(pPP))
161
AssertMsgFailed(("Invalid input %p\n", pPP));
162
return VERR_INVALID_PARAMETER;
165
if (pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG)
167
AssertMsgFailed(("Speaking out of turn!\n"));
168
return VERR_SEM_OUT_OF_TURN;
172
* Signal the other thread.
174
ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PING_SIGNALED);
175
int rc = RTSemEventSignal(pPP->Ping);
179
/* restore the state. */
180
AssertMsgFailed(("Failed to signal ping sem %x. rc=%d\n", pPP->Ping, rc));
181
ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PONG);
187
* Wait function for the ping thread.
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.
194
RTR3DECL(int) RTSemPingWait(PRTPINGPONG pPP, unsigned cMillies)
199
if (!rtsemPPValid(pPP))
201
AssertMsgFailed(("Invalid input %p\n", pPP));
202
return VERR_INVALID_PARAMETER;
205
if ( pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG
206
&& pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG_SIGNALED
207
&& pPP->enmSpeaker != RTPINGPONGSPEAKER_PING_SIGNALED)
209
AssertMsgFailed(("Listening out of turn! enmSpeaker=%d\n", pPP->enmSpeaker));
210
return VERR_SEM_OUT_OF_TURN;
216
int rc = RTSemEventWait(pPP->Ping, cMillies);
218
ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PING);
219
Assert(rc != VERR_INTERRUPTED);
225
* Wait function for the pong thread.
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.
232
RTR3DECL(int) RTSemPongWait(PRTPINGPONG pPP, unsigned cMillies)
237
if (!rtsemPPValid(pPP))
239
AssertMsgFailed(("Invalid input %p\n", pPP));
240
return VERR_INVALID_PARAMETER;
243
if ( pPP->enmSpeaker != RTPINGPONGSPEAKER_PING
244
&& pPP->enmSpeaker != RTPINGPONGSPEAKER_PING_SIGNALED
245
&& pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG_SIGNALED)
247
AssertMsgFailed(("Listening out of turn! enmSpeaker=%d\n", pPP->enmSpeaker));
248
return VERR_SEM_OUT_OF_TURN;
254
int rc = RTSemEventWait(pPP->Pong, cMillies);
256
ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PONG);
257
Assert(rc != VERR_INTERRUPTED);