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@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
pthread_cond_destroy(pthread_cond_t * cond)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