diff options
Diffstat (limited to 'pthreads/pthread_cond_destroy.c')
-rw-r--r-- | pthreads/pthread_cond_destroy.c | 504 |
1 files changed, 253 insertions, 251 deletions
diff --git a/pthreads/pthread_cond_destroy.c b/pthreads/pthread_cond_destroy.c index 34550f08d..40d4a0896 100644 --- a/pthreads/pthread_cond_destroy.c +++ b/pthreads/pthread_cond_destroy.c @@ -1,251 +1,253 @@ -/*
- * pthread_cond_destroy.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,2005 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
- */
-
-#include "pthread.h"
-#include "implement.h"
-
-int
-pthread_cond_destroy (pthread_cond_t * cond)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function destroys a condition variable
- *
- *
- * PARAMETERS
- * cond
- * pointer to an instance of pthread_cond_t
- *
- *
- * DESCRIPTION
- * This function destroys a condition variable.
- *
- * NOTES:
- * 1) A condition variable can be destroyed
- * immediately after all the threads that
- * are blocked on it are awakened. e.g.
- *
- * struct list {
- * pthread_mutex_t lm;
- * ...
- * }
- *
- * struct elt {
- * key k;
- * int busy;
- * pthread_cond_t notbusy;
- * ...
- * }
- *
- *
- * struct elt *
- * list_find(struct list *lp, key k)
- * {
- * struct elt *ep;
- *
- * pthread_mutex_lock(&lp->lm);
- * while ((ep = find_elt(l,k) != NULL) && ep->busy)
- * pthread_cond_wait(&ep->notbusy, &lp->lm);
- * if (ep != NULL)
- * ep->busy = 1;
- * pthread_mutex_unlock(&lp->lm);
- * return(ep);
- * }
- *
- * delete_elt(struct list *lp, struct elt *ep)
- * {
- * pthread_mutex_lock(&lp->lm);
- * assert(ep->busy);
- * ... remove ep from list ...
- * ep->busy = 0;
- * (A) pthread_cond_broadcast(&ep->notbusy);
- * pthread_mutex_unlock(&lp->lm);
- * (B) pthread_cond_destroy(&rp->notbusy);
- * free(ep);
- * }
- *
- * In this example, the condition variable
- * and its list element may be freed (line B)
- * immediately after all threads waiting for
- * it are awakened (line A), since the mutex
- * and the code ensure that no other thread
- * can touch the element to be deleted.
- *
- * RESULTS
- * 0 successfully released condition variable,
- * EINVAL 'cond' is invalid,
- * EBUSY 'cond' is in use,
- *
- * ------------------------------------------------------
- */
-{
- pthread_cond_t cv;
- int result = 0, result1 = 0, result2 = 0;
-
- /*
- * Assuming any race condition here is harmless.
- */
- if (cond == NULL || *cond == NULL)
- {
- return EINVAL;
- }
-
- if (*cond != PTHREAD_COND_INITIALIZER)
- {
- EnterCriticalSection (&ptw32_cond_list_lock);
-
- cv = *cond;
-
- /*
- * Close the gate; this will synchronize this thread with
- * all already signaled waiters to let them retract their
- * waiter status - SEE NOTE 1 ABOVE!!!
- */
- if (ptw32_semwait (&(cv->semBlockLock)) != 0) /* Non-cancelable */
- {
- result = errno;
- }
- else
- {
- /*
- * !TRY! lock mtxUnblockLock; try will detect busy condition
- * and will not cause a deadlock with respect to concurrent
- * signal/broadcast.
- */
- if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0)
- {
- (void) sem_post (&(cv->semBlockLock));
- }
- }
-
- if (result != 0)
- {
- LeaveCriticalSection (&ptw32_cond_list_lock);
- return result;
- }
-
- /*
- * Check whether cv is still busy (still has waiters)
- */
- if (cv->nWaitersBlocked > cv->nWaitersGone)
- {
- if (sem_post (&(cv->semBlockLock)) != 0)
- {
- result = errno;
- }
- result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock));
- result2 = EBUSY;
- }
- else
- {
- /*
- * Now it is safe to destroy
- */
- *cond = NULL;
-
- if (sem_destroy (&(cv->semBlockLock)) != 0)
- {
- result = errno;
- }
- if (sem_destroy (&(cv->semBlockQueue)) != 0)
- {
- result1 = errno;
- }
- if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0)
- {
- result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock));
- }
-
- /* Unlink the CV from the list */
-
- if (ptw32_cond_list_head == cv)
- {
- ptw32_cond_list_head = cv->next;
- }
- else
- {
- cv->prev->next = cv->next;
- }
-
- if (ptw32_cond_list_tail == cv)
- {
- ptw32_cond_list_tail = cv->prev;
- }
- else
- {
- cv->next->prev = cv->prev;
- }
-
- (void) free (cv);
- }
-
- LeaveCriticalSection (&ptw32_cond_list_lock);
- }
- else
- {
- /*
- * See notes in ptw32_cond_check_need_init() above also.
- */
- EnterCriticalSection (&ptw32_cond_test_init_lock);
-
- /*
- * Check again.
- */
- if (*cond == PTHREAD_COND_INITIALIZER)
- {
- /*
- * This is all we need to do to destroy a statically
- * initialised cond that has not yet been used (initialised).
- * If we get to here, another thread waiting to initialise
- * this cond will get an EINVAL. That's OK.
- */
- *cond = NULL;
- }
- else
- {
- /*
- * The cv has been initialised while we were waiting
- * so assume it's in use.
- */
- result = EBUSY;
- }
-
- LeaveCriticalSection (&ptw32_cond_test_init_lock);
- }
-
- return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
-}
+/* + * pthread_cond_destroy.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,2005 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 + */ + +#include "pthread.h" +#include "implement.h" + +int +pthread_cond_destroy (pthread_cond_t * cond) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function destroys a condition variable + * + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * + * DESCRIPTION + * This function destroys a condition variable. + * + * NOTES: + * 1) A condition variable can be destroyed + * immediately after all the threads that + * are blocked on it are awakened. e.g. + * + * struct list { + * pthread_mutex_t lm; + * ... + * } + * + * struct elt { + * key k; + * int busy; + * pthread_cond_t notbusy; + * ... + * } + * + * + * struct elt * + * list_find(struct list *lp, key k) + * { + * struct elt *ep; + * + * pthread_mutex_lock(&lp->lm); + * while ((ep = find_elt(l,k) != NULL) && ep->busy) + * pthread_cond_wait(&ep->notbusy, &lp->lm); + * if (ep != NULL) + * ep->busy = 1; + * pthread_mutex_unlock(&lp->lm); + * return(ep); + * } + * + * delete_elt(struct list *lp, struct elt *ep) + * { + * pthread_mutex_lock(&lp->lm); + * assert(ep->busy); + * ... remove ep from list ... + * ep->busy = 0; + * (A) pthread_cond_broadcast(&ep->notbusy); + * pthread_mutex_unlock(&lp->lm); + * (B) pthread_cond_destroy(&rp->notbusy); + * free(ep); + * } + * + * In this example, the condition variable + * and its list element may be freed (line B) + * immediately after all threads waiting for + * it are awakened (line A), since the mutex + * and the code ensure that no other thread + * can touch the element to be deleted. + * + * RESULTS + * 0 successfully released condition variable, + * EINVAL 'cond' is invalid, + * EBUSY 'cond' is in use, + * + * ------------------------------------------------------ + */ +{ + pthread_cond_t cv; + int result = 0, result1 = 0, result2 = 0; + + /* + * Assuming any race condition here is harmless. + */ + if (cond == NULL || *cond == NULL) + { + return EINVAL; + } + + if (*cond != PTHREAD_COND_INITIALIZER) + { + ptw32_mcs_local_node_t node; + ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node); + + cv = *cond; + + /* + * Close the gate; this will synchronize this thread with + * all already signaled waiters to let them retract their + * waiter status - SEE NOTE 1 ABOVE!!! + */ + if (ptw32_semwait (&(cv->semBlockLock)) != 0) /* Non-cancelable */ + { + result = errno; + } + else + { + /* + * !TRY! lock mtxUnblockLock; try will detect busy condition + * and will not cause a deadlock with respect to concurrent + * signal/broadcast. + */ + if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0) + { + (void) sem_post (&(cv->semBlockLock)); + } + } + + if (result != 0) + { + ptw32_mcs_lock_release(&node); + return result; + } + + /* + * Check whether cv is still busy (still has waiters) + */ + if (cv->nWaitersBlocked > cv->nWaitersGone) + { + if (sem_post (&(cv->semBlockLock)) != 0) + { + result = errno; + } + result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock)); + result2 = EBUSY; + } + else + { + /* + * Now it is safe to destroy + */ + *cond = NULL; + + if (sem_destroy (&(cv->semBlockLock)) != 0) + { + result = errno; + } + if (sem_destroy (&(cv->semBlockQueue)) != 0) + { + result1 = errno; + } + if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) + { + result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock)); + } + + /* Unlink the CV from the list */ + + if (ptw32_cond_list_head == cv) + { + ptw32_cond_list_head = cv->next; + } + else + { + cv->prev->next = cv->next; + } + + if (ptw32_cond_list_tail == cv) + { + ptw32_cond_list_tail = cv->prev; + } + else + { + cv->next->prev = cv->prev; + } + + (void) free (cv); + } + + ptw32_mcs_lock_release(&node); + } + else + { + ptw32_mcs_local_node_t node; + /* + * See notes in ptw32_cond_check_need_init() above also. + */ + ptw32_mcs_lock_acquire(&ptw32_cond_test_init_lock, &node); + + /* + * Check again. + */ + if (*cond == PTHREAD_COND_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised cond that has not yet been used (initialised). + * If we get to here, another thread waiting to initialise + * this cond will get an EINVAL. That's OK. + */ + *cond = NULL; + } + else + { + /* + * The cv has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + + ptw32_mcs_lock_release(&node); + } + + return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); +} |