📄 pthread_cond_wait.c
字号:
/*
* pthread_cond_wait.c
*
* Description:
* This translation unit implements condition variables and their primitives.
*
*
* --------------------------------------------------------------------------
*
* Pthreads-win32 - POSIX Threads Library for Win32
* Copyright(C) 1998 John E. Bossom
* Copyright(C) 1999,2004 Pthreads-win32 contributors
*
* Contact Email: rpj@callisto.canberra.edu.au
*
* The current list of contributors is contained
* in the file CONTRIBUTORS included with the source
* code distribution. The list can also be seen at the
* following World Wide Web location:
* http://sources.redhat.com/pthreads-win32/contributors.html
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library in the file COPYING.LIB;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* -------------------------------------------------------------
* Algorithm:
* The algorithm used in this implementation is that developed by
* Alexander Terekhov in colaboration with Louis Thomas. The bulk
* of the discussion is recorded in the file README.CV, which contains
* several generations of both colaborators original algorithms. The final
* algorithm used here is the one referred to as
*
* Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
*
* presented below in pseudo-code as it appeared:
*
*
* given:
* semBlockLock - bin.semaphore
* semBlockQueue - semaphore
* mtxExternal - mutex or CS
* mtxUnblockLock - mutex or CS
* nWaitersGone - int
* nWaitersBlocked - int
* nWaitersToUnblock - int
*
* wait( timeout ) {
*
* [auto: register int result ] // error checking omitted
* [auto: register int nSignalsWasLeft ]
* [auto: register int nWaitersWasGone ]
*
* sem_wait( semBlockLock );
* nWaitersBlocked++;
* sem_post( semBlockLock );
*
* unlock( mtxExternal );
* bTimedOut = sem_wait( semBlockQueue,timeout );
*
* lock( mtxUnblockLock );
* if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
* if ( bTimeout ) { // timeout (or canceled)
* if ( 0 != nWaitersBlocked ) {
* nWaitersBlocked--;
* }
* else {
* nWaitersGone++; // count spurious wakeups.
* }
* }
* if ( 0 == --nWaitersToUnblock ) {
* if ( 0 != nWaitersBlocked ) {
* sem_post( semBlockLock ); // open the gate.
* nSignalsWasLeft = 0; // do not open the gate
* // below again.
* }
* else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
* nWaitersGone = 0;
* }
* }
* }
* else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
* // spurious semaphore :-)
* sem_wait( semBlockLock );
* nWaitersBlocked -= nWaitersGone; // something is going on here
* // - test of timeouts? :-)
* sem_post( semBlockLock );
* nWaitersGone = 0;
* }
* unlock( mtxUnblockLock );
*
* if ( 1 == nSignalsWasLeft ) {
* if ( 0 != nWaitersWasGone ) {
* // sem_adjust( semBlockQueue,-nWaitersWasGone );
* while ( nWaitersWasGone-- ) {
* sem_wait( semBlockQueue ); // better now than spurious later
* }
* } sem_post( semBlockLock ); // open the gate
* }
*
* lock( mtxExternal );
*
* return ( bTimedOut ) ? ETIMEOUT : 0;
* }
*
* signal(bAll) {
*
* [auto: register int result ]
* [auto: register int nSignalsToIssue]
*
* lock( mtxUnblockLock );
*
* if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
* if ( 0 == nWaitersBlocked ) { // NO-OP
* return unlock( mtxUnblockLock );
* }
* if (bAll) {
* nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
* nWaitersBlocked = 0;
* }
* else {
* nSignalsToIssue = 1;
* nWaitersToUnblock++;
* nWaitersBlocked--;
* }
* }
* else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
* sem_wait( semBlockLock ); // close the gate
* if ( 0 != nWaitersGone ) {
* nWaitersBlocked -= nWaitersGone;
* nWaitersGone = 0;
* }
* if (bAll) {
* nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
* nWaitersBlocked = 0;
* }
* else {
* nSignalsToIssue = nWaitersToUnblock = 1;
* nWaitersBlocked--;
* }
* }
* else { // NO-OP
* return unlock( mtxUnblockLock );
* }
*
* unlock( mtxUnblockLock );
* sem_post( semBlockQueue,nSignalsToIssue );
* return result;
* }
* -------------------------------------------------------------
*
* Algorithm 9 / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
*
* presented below in pseudo-code; basically 8a...
* ...BUT W/O "spurious wakes" prevention:
*
*
* given:
* semBlockLock - bin.semaphore
* semBlockQueue - semaphore
* mtxExternal - mutex or CS
* mtxUnblockLock - mutex or CS
* nWaitersGone - int
* nWaitersBlocked - int
* nWaitersToUnblock - int
*
* wait( timeout ) {
*
* [auto: register int result ] // error checking omitted
* [auto: register int nSignalsWasLeft ]
*
* sem_wait( semBlockLock );
* ++nWaitersBlocked;
* sem_post( semBlockLock );
*
* unlock( mtxExternal );
* bTimedOut = sem_wait( semBlockQueue,timeout );
*
* lock( mtxUnblockLock );
* if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
* --nWaitersToUnblock;
* }
* else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
* // spurious semaphore :-)
* sem_wait( semBlockLock );
* nWaitersBlocked -= nWaitersGone; // something is going on here
* // - test of timeouts? :-)
* sem_post( semBlockLock );
* nWaitersGone = 0;
* }
* unlock( mtxUnblockLock );
*
* if ( 1 == nSignalsWasLeft ) {
* sem_post( semBlockLock ); // open the gate
* }
*
* lock( mtxExternal );
*
* return ( bTimedOut ) ? ETIMEOUT : 0;
* }
*
* signal(bAll) {
*
* [auto: register int result ]
* [auto: register int nSignalsToIssue]
*
* lock( mtxUnblockLock );
*
* if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
* if ( 0 == nWaitersBlocked ) { // NO-OP
* return unlock( mtxUnblockLock );
* }
* if (bAll) {
* nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
* nWaitersBlocked = 0;
* }
* else {
* nSignalsToIssue = 1;
* ++nWaitersToUnblock;
* --nWaitersBlocked;
* }
* }
* else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
* sem_wait( semBlockLock ); // close the gate
* if ( 0 != nWaitersGone ) {
* nWaitersBlocked -= nWaitersGone;
* nWaitersGone = 0;
* }
* if (bAll) {
* nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
* nWaitersBlocked = 0;
* }
* else {
* nSignalsToIssue = nWaitersToUnblock = 1;
* --nWaitersBlocked;
* }
* }
* else { // NO-OP
* return unlock( mtxUnblockLock );
* }
*
* unlock( mtxUnblockLock );
* sem_post( semBlockQueue,nSignalsToIssue );
* return result;
* }
* -------------------------------------------------------------
*
*/
#include "pthread.h"
#include "implement.h"
/*
* Arguments for cond_wait_cleanup, since we can only pass a
* single void * to it.
*/
typedef struct
{
pthread_mutex_t *mutexPtr;
pthread_cond_t cv;
int *resultPtr;
int signaled;
} ptw32_cond_wait_cleanup_args_t;
static void PTW32_CDECL
ptw32_cond_wait_cleanup (void *args)
{
ptw32_cond_wait_cleanup_args_t *cleanup_args =
(ptw32_cond_wait_cleanup_args_t *) args;
pthread_cond_t cv = cleanup_args->cv;
int *resultPtr = cleanup_args->resultPtr;
int nSignalsWasLeft;
int result;
/*
* Whether we got here as a result of signal/broadcast or because of
* timeout on wait or thread cancellation we indicate that we are no
* longer waiting. The waiter is responsible for adjusting waiters
* (to)unblock(ed) counts (protected by unblock lock).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -