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