1 /* 2 * pthread_cond_destroy.c 3 * 4 * Description: 5 * This translation unit implements condition variables and their primitives. 6 * 7 * 8 * -------------------------------------------------------------------------- 9 * 10 * Pthreads-win32 - POSIX Threads Library for Win32 11 * Copyright(C) 1998 John E. Bossom 12 * Copyright(C) 1999,2005 Pthreads-win32 contributors 13 * 14 * Contact Email: rpj (at) callisto.canberra.edu.au 15 * 16 * The current list of contributors is contained 17 * in the file CONTRIBUTORS included with the source 18 * code distribution. The list can also be seen at the 19 * following World Wide Web location: 20 * http://sources.redhat.com/pthreads-win32/contributors.html 21 * 22 * This library is free software; you can redistribute it and/or 23 * modify it under the terms of the GNU Lesser General Public 24 * License as published by the Free Software Foundation; either 25 * version 2 of the License, or (at your option) any later version. 26 * 27 * This library is distributed in the hope that it will be useful, 28 * but WITHOUT ANY WARRANTY; without even the implied warranty of 29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 30 * Lesser General Public License for more details. 31 * 32 * You should have received a copy of the GNU Lesser General Public 33 * License along with this library in the file COPYING.LIB; 34 * if not, write to the Free Software Foundation, Inc., 35 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 36 */ 37 38 #include "pthread.h" 39 #include "implement.h" 40 41 int 42 pthread_cond_destroy (pthread_cond_t * cond) 43 /* 44 * ------------------------------------------------------ 45 * DOCPUBLIC 46 * This function destroys a condition variable 47 * 48 * 49 * PARAMETERS 50 * cond 51 * pointer to an instance of pthread_cond_t 52 * 53 * 54 * DESCRIPTION 55 * This function destroys a condition variable. 56 * 57 * NOTES: 58 * 1) A condition variable can be destroyed 59 * immediately after all the threads that 60 * are blocked on it are awakened. e.g. 61 * 62 * struct list { 63 * pthread_mutex_t lm; 64 * ... 65 * } 66 * 67 * struct elt { 68 * key k; 69 * int busy; 70 * pthread_cond_t notbusy; 71 * ... 72 * } 73 * 74 * 75 * struct elt * 76 * list_find(struct list *lp, key k) 77 * { 78 * struct elt *ep; 79 * 80 * pthread_mutex_lock(&lp->lm); 81 * while ((ep = find_elt(l,k) != NULL) && ep->busy) 82 * pthread_cond_wait(&ep->notbusy, &lp->lm); 83 * if (ep != NULL) 84 * ep->busy = 1; 85 * pthread_mutex_unlock(&lp->lm); 86 * return(ep); 87 * } 88 * 89 * delete_elt(struct list *lp, struct elt *ep) 90 * { 91 * pthread_mutex_lock(&lp->lm); 92 * assert(ep->busy); 93 * ... remove ep from list ... 94 * ep->busy = 0; 95 * (A) pthread_cond_broadcast(&ep->notbusy); 96 * pthread_mutex_unlock(&lp->lm); 97 * (B) pthread_cond_destroy(&rp->notbusy); 98 * free(ep); 99 * } 100 * 101 * In this example, the condition variable 102 * and its list element may be freed (line B) 103 * immediately after all threads waiting for 104 * it are awakened (line A), since the mutex 105 * and the code ensure that no other thread 106 * can touch the element to be deleted. 107 * 108 * RESULTS 109 * 0 successfully released condition variable, 110 * EINVAL 'cond' is invalid, 111 * EBUSY 'cond' is in use, 112 * 113 * ------------------------------------------------------ 114 */ 115 { 116 pthread_cond_t cv; 117 int result = 0, result1 = 0, result2 = 0; 118 119 /* 120 * Assuming any race condition here is harmless. 121 */ 122 if (cond == NULL || *cond == NULL) 123 { 124 return EINVAL; 125 } 126 127 if (*cond != PTHREAD_COND_INITIALIZER) 128 { 129 ptw32_mcs_local_node_t node; 130 ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node); 131 132 cv = *cond; 133 134 /* 135 * Close the gate; this will synchronize this thread with 136 * all already signaled waiters to let them retract their 137 * waiter status - SEE NOTE 1 ABOVE!!! 138 */ 139 if (ptw32_semwait (&(cv->semBlockLock)) != 0) /* Non-cancelable */ 140 { 141 result = errno; 142 } 143 else 144 { 145 /* 146 * !TRY! lock mtxUnblockLock; try will detect busy condition 147 * and will not cause a deadlock with respect to concurrent 148 * signal/broadcast. 149 */ 150 if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0) 151 { 152 (void) sem_post (&(cv->semBlockLock)); 153 } 154 } 155 156 if (result != 0) 157 { 158 ptw32_mcs_lock_release(&node); 159 return result; 160 } 161 162 /* 163 * Check whether cv is still busy (still has waiters) 164 */ 165 if (cv->nWaitersBlocked > cv->nWaitersGone) 166 { 167 if (sem_post (&(cv->semBlockLock)) != 0) 168 { 169 result = errno; 170 } 171 result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock)); 172 result2 = EBUSY; 173 } 174 else 175 { 176 /* 177 * Now it is safe to destroy 178 */ 179 *cond = NULL; 180 181 if (sem_destroy (&(cv->semBlockLock)) != 0) 182 { 183 result = errno; 184 } 185 if (sem_destroy (&(cv->semBlockQueue)) != 0) 186 { 187 result1 = errno; 188 } 189 if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) 190 { 191 result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock)); 192 } 193 194 /* Unlink the CV from the list */ 195 196 if (ptw32_cond_list_head == cv) 197 { 198 ptw32_cond_list_head = cv->next; 199 } 200 else 201 { 202 cv->prev->next = cv->next; 203 } 204 205 if (ptw32_cond_list_tail == cv) 206 { 207 ptw32_cond_list_tail = cv->prev; 208 } 209 else 210 { 211 cv->next->prev = cv->prev; 212 } 213 214 (void) free (cv); 215 } 216 217 ptw32_mcs_lock_release(&node); 218 } 219 else 220 { 221 ptw32_mcs_local_node_t node; 222 /* 223 * See notes in ptw32_cond_check_need_init() above also. 224 */ 225 ptw32_mcs_lock_acquire(&ptw32_cond_test_init_lock, &node); 226 227 /* 228 * Check again. 229 */ 230 if (*cond == PTHREAD_COND_INITIALIZER) 231 { 232 /* 233 * This is all we need to do to destroy a statically 234 * initialised cond that has not yet been used (initialised). 235 * If we get to here, another thread waiting to initialise 236 * this cond will get an EINVAL. That's OK. 237 */ 238 *cond = NULL; 239 } 240 else 241 { 242 /* 243 * The cv has been initialised while we were waiting 244 * so assume it's in use. 245 */ 246 result = EBUSY; 247 } 248 249 ptw32_mcs_lock_release(&node); 250 } 251 252 return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); 253 } 254