xref: /relibc/pthreads-emb/pthread_cond_signal.c (revision 062c5bc4dfeed2c1bed58ed4810dd27adb32c68d)
1 /*
2  * pthread_cond_signal.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  * Algorithm:
45  * See the comments at the top of pthread_cond_wait.c.
46  */
47 
48 #include "pthread.h"
49 #include "implement.h"
50 
51 static int
pte_cond_unblock(pthread_cond_t * cond,int unblockAll)52 pte_cond_unblock (pthread_cond_t * cond, int unblockAll)
53 /*
54  * Notes.
55  *
56  * Does not use the external mutex for synchronisation,
57  * therefore semBlockLock is needed.
58  * mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the
59  * state where the external mutex is not necessarily locked by
60  * any thread, ie. between cond_wait unlocking and re-acquiring
61  * the lock after having been signaled or a timeout or
62  * cancellation.
63  *
64  * Uses the following CV elements:
65  *   nWaitersBlocked
66  *   nWaitersToUnblock
67  *   nWaitersGone
68  *   mtxUnblockLock
69  *   semBlockLock
70  *   semBlockQueue
71  */
72 {
73   int result;
74   pthread_cond_t cv;
75   int nSignalsToIssue;
76 
77   if (cond == NULL || *cond == NULL)
78     {
79       return EINVAL;
80     }
81 
82   cv = *cond;
83 
84   /*
85    * No-op if the CV is static and hasn't been initialised yet.
86    * Assuming that any race condition is harmless.
87    */
88   if (cv == PTHREAD_COND_INITIALIZER)
89     {
90       return 0;
91     }
92 
93   if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0)
94     {
95       return result;
96     }
97 
98   if (0 != cv->nWaitersToUnblock)
99     {
100       if (0 == cv->nWaitersBlocked)
101         {
102           return pthread_mutex_unlock (&(cv->mtxUnblockLock));
103         }
104       if (unblockAll)
105         {
106           cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked);
107           cv->nWaitersBlocked = 0;
108         }
109       else
110         {
111           nSignalsToIssue = 1;
112           cv->nWaitersToUnblock++;
113           cv->nWaitersBlocked--;
114         }
115     }
116   else if (cv->nWaitersBlocked > cv->nWaitersGone)
117     {
118       /* Use the non-cancellable version of sem_wait() */
119 //      if (sem_wait_nocancel (&(cv->semBlockLock)) != 0)
120       if (sem_wait (&(cv->semBlockLock)) != 0)
121         {
122           result = errno;
123           (void) pthread_mutex_unlock (&(cv->mtxUnblockLock));
124           return result;
125         }
126       if (0 != cv->nWaitersGone)
127         {
128           cv->nWaitersBlocked -= cv->nWaitersGone;
129           cv->nWaitersGone = 0;
130         }
131       if (unblockAll)
132         {
133           nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked;
134           cv->nWaitersBlocked = 0;
135         }
136       else
137         {
138           nSignalsToIssue = cv->nWaitersToUnblock = 1;
139           cv->nWaitersBlocked--;
140         }
141     }
142   else
143     {
144       return pthread_mutex_unlock (&(cv->mtxUnblockLock));
145     }
146 
147   if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0)
148     {
149       if (sem_post_multiple (&(cv->semBlockQueue), nSignalsToIssue) != 0)
150         {
151           result = errno;
152         }
153     }
154 
155   return result;
156 
157 }				/* pte_cond_unblock */
158 
159 int
pthread_cond_signal(pthread_cond_t * cond)160 pthread_cond_signal (pthread_cond_t * cond)
161 /*
162  * ------------------------------------------------------
163  * DOCPUBLIC
164  *      This function signals a condition variable, waking
165  *      one waiting thread.
166  *      If SCHED_FIFO or SCHED_RR policy threads are waiting
167  *      the highest priority waiter is awakened; otherwise,
168  *      an unspecified waiter is awakened.
169  *
170  * PARAMETERS
171  *      cond
172  *              pointer to an instance of pthread_cond_t
173  *
174  *
175  * DESCRIPTION
176  *      This function signals a condition variable, waking
177  *      one waiting thread.
178  *      If SCHED_FIFO or SCHED_RR policy threads are waiting
179  *      the highest priority waiter is awakened; otherwise,
180  *      an unspecified waiter is awakened.
181  *
182  *      NOTES:
183  *
184  *      1)      Use when any waiter can respond and only one need
185  *              respond (all waiters being equal).
186  *
187  * RESULTS
188  *              0               successfully signaled condition,
189  *              EINVAL          'cond' is invalid,
190  *
191  * ------------------------------------------------------
192  */
193 {
194   /*
195    * The '0'(FALSE) unblockAll arg means unblock ONE waiter.
196    */
197   return (pte_cond_unblock (cond, 0));
198 
199 }				/* pthread_cond_signal */
200 
201 int
pthread_cond_broadcast(pthread_cond_t * cond)202 pthread_cond_broadcast (pthread_cond_t * cond)
203 /*
204  * ------------------------------------------------------
205  * DOCPUBLIC
206  *      This function broadcasts the condition variable,
207  *      waking all current waiters.
208  *
209  * PARAMETERS
210  *      cond
211  *              pointer to an instance of pthread_cond_t
212  *
213  *
214  * DESCRIPTION
215  *      This function signals a condition variable, waking
216  *      all waiting threads.
217  *
218  *      NOTES:
219  *
220  *      1)      Use when more than one waiter may respond to
221  *              predicate change or if any waiting thread may
222  *              not be able to respond
223  *
224  * RESULTS
225  *              0               successfully signalled condition to all
226  *                              waiting threads,
227  *              EINVAL          'cond' is invalid
228  *              ENOSPC          a required resource has been exhausted,
229  *
230  * ------------------------------------------------------
231  */
232 {
233   /*
234    * The TRUE unblockAll arg means unblock ALL waiters.
235    */
236   return (pte_cond_unblock (cond, PTE_TRUE));
237 
238 }				/* pthread_cond_broadcast */
239