• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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