xref: /relibc/pthreads-emb/pthread_cond_destroy.c (revision 062c5bc4dfeed2c1bed58ed4810dd27adb32c68d)
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