add fchownat(2) system call
[dragonfly.git] / lib / libc_r / uthread / uthread_cond.c
1 /*
2  * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by John Birrell.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD: src/lib/libc_r/uthread/uthread_cond.c,v 1.22.2.8 2002/10/22 14:44:02 fjoe Exp $
33  * $DragonFly: src/lib/libc_r/uthread/uthread_cond.c,v 1.3 2005/05/30 20:50:53 joerg Exp $
34  */
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <pthread.h>
39 #include "pthread_private.h"
40
41 /*
42  * Prototypes
43  */
44 static inline pthread_t cond_queue_deq(pthread_cond_t);
45 static inline void      cond_queue_remove(pthread_cond_t, pthread_t);
46 static inline void      cond_queue_enq(pthread_cond_t, pthread_t);
47
48
49 /* Reinitialize a condition variable to defaults. */
50 int
51 _cond_reinit(pthread_cond_t *cond)
52 {
53         int ret = 0;
54
55         if (cond == NULL)
56                 ret = EINVAL;
57         else if (*cond == NULL)
58                 ret = pthread_cond_init(cond, NULL);
59         else {
60                 /*
61                  * Initialize the condition variable structure:
62                  */
63                 TAILQ_INIT(&(*cond)->c_queue);
64                 (*cond)->c_flags = COND_FLAGS_INITED;
65                 (*cond)->c_type = COND_TYPE_FAST;
66                 (*cond)->c_mutex = NULL;
67                 (*cond)->c_seqno = 0;
68                 memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
69         }
70         return (ret);
71 }
72
73 int
74 _pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
75 {
76         enum pthread_cond_type type;
77         pthread_cond_t  pcond;
78         int             rval = 0;
79
80         if (cond == NULL)
81                 rval = EINVAL;
82         else {
83                 /*
84                  * Check if a pointer to a condition variable attribute
85                  * structure was passed by the caller: 
86                  */
87                 if (cond_attr != NULL && *cond_attr != NULL) {
88                         /* Default to a fast condition variable: */
89                         type = (*cond_attr)->c_type;
90                 } else {
91                         /* Default to a fast condition variable: */
92                         type = COND_TYPE_FAST;
93                 }
94
95                 /* Process according to condition variable type: */
96                 switch (type) {
97                 /* Fast condition variable: */
98                 case COND_TYPE_FAST:
99                         /* Nothing to do here. */
100                         break;
101
102                 /* Trap invalid condition variable types: */
103                 default:
104                         /* Return an invalid argument error: */
105                         rval = EINVAL;
106                         break;
107                 }
108
109                 /* Check for no errors: */
110                 if (rval == 0) {
111                         if ((pcond = (pthread_cond_t)
112                             malloc(sizeof(struct pthread_cond))) == NULL) {
113                                 rval = ENOMEM;
114                         } else {
115                                 /*
116                                  * Initialise the condition variable
117                                  * structure:
118                                  */
119                                 TAILQ_INIT(&pcond->c_queue);
120                                 pcond->c_flags |= COND_FLAGS_INITED;
121                                 pcond->c_type = type;
122                                 pcond->c_mutex = NULL;
123                                 pcond->c_seqno = 0;
124                                 memset(&pcond->lock,0,sizeof(pcond->lock));
125                                 *cond = pcond;
126                         }
127                 }
128         }
129         /* Return the completion status: */
130         return (rval);
131 }
132
133 int
134 _pthread_cond_destroy(pthread_cond_t *cond)
135 {
136         int             rval = 0;
137
138         if (cond == NULL || *cond == NULL)
139                 rval = EINVAL;
140         else {
141                 /* Lock the condition variable structure: */
142                 _SPINLOCK(&(*cond)->lock);
143
144                 /*
145                  * Free the memory allocated for the condition
146                  * variable structure:
147                  */
148                 free(*cond);
149
150                 /*
151                  * NULL the caller's pointer now that the condition
152                  * variable has been destroyed:
153                  */
154                 *cond = NULL;
155         }
156         /* Return the completion status: */
157         return (rval);
158 }
159
160 int
161 _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
162 {
163         struct pthread  *curthread = _get_curthread();
164         int     rval = 0;
165         int     done = 0;
166         int     interrupted = 0;
167         int     seqno;
168
169         _thread_enter_cancellation_point();
170         
171         if (cond == NULL)
172                 return (EINVAL);
173
174         /*
175          * If the condition variable is statically initialized,
176          * perform the dynamic initialization:
177          */
178         if (*cond == NULL &&
179             (rval = pthread_cond_init(cond, NULL)) != 0)
180                 return (rval);
181
182         /*
183          * Enter a loop waiting for a condition signal or broadcast
184          * to wake up this thread.  A loop is needed in case the waiting
185          * thread is interrupted by a signal to execute a signal handler.
186          * It is not (currently) possible to remain in the waiting queue
187          * while running a handler.  Instead, the thread is interrupted
188          * and backed out of the waiting queue prior to executing the
189          * signal handler.
190          */
191         do {
192                 /* Lock the condition variable structure: */
193                 _SPINLOCK(&(*cond)->lock);
194
195                 /*
196                  * If the condvar was statically allocated, properly
197                  * initialize the tail queue.
198                  */
199                 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
200                         TAILQ_INIT(&(*cond)->c_queue);
201                         (*cond)->c_flags |= COND_FLAGS_INITED;
202                 }
203
204                 /* Process according to condition variable type: */
205                 switch ((*cond)->c_type) {
206                 /* Fast condition variable: */
207                 case COND_TYPE_FAST:
208                         if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
209                             ((*cond)->c_mutex != *mutex))) {
210                                 /* Unlock the condition variable structure: */
211                                 _SPINUNLOCK(&(*cond)->lock);
212
213                                 /* Return invalid argument error: */
214                                 rval = EINVAL;
215                         } else {
216                                 /* Reset the timeout and interrupted flags: */
217                                 curthread->timeout = 0;
218                                 curthread->interrupted = 0;
219
220                                 /*
221                                  * Queue the running thread for the condition
222                                  * variable:
223                                  */
224                                 cond_queue_enq(*cond, curthread);
225
226                                 /* Remember the mutex and sequence number: */
227                                 (*cond)->c_mutex = *mutex;
228                                 seqno = (*cond)->c_seqno;
229
230                                 /* Wait forever: */
231                                 curthread->wakeup_time.tv_sec = -1;
232
233                                 /* Unlock the mutex: */
234                                 if ((rval = _mutex_cv_unlock(mutex)) != 0) {
235                                         /*
236                                          * Cannot unlock the mutex, so remove
237                                          * the running thread from the condition
238                                          * variable queue:
239                                          */
240                                         cond_queue_remove(*cond, curthread);
241
242                                         /* Check for no more waiters: */
243                                         if (TAILQ_FIRST(&(*cond)->c_queue) ==
244                                             NULL)
245                                                 (*cond)->c_mutex = NULL;
246
247                                         /* Unlock the condition variable structure: */
248                                         _SPINUNLOCK(&(*cond)->lock);
249                                 } else {
250                                         /*
251                                          * Schedule the next thread and unlock
252                                          * the condition variable structure:
253                                          */
254                                         _thread_kern_sched_state_unlock(PS_COND_WAIT,
255                                             &(*cond)->lock, __FILE__, __LINE__);
256
257                                         done = (seqno != (*cond)->c_seqno);
258
259                                         interrupted = curthread->interrupted;
260
261                                         /*
262                                          * Check if the wait was interrupted
263                                          * (canceled) or needs to be resumed
264                                          * after handling a signal.
265                                          */
266                                         if (interrupted != 0) {
267                                                 /*
268                                                  * Lock the mutex and ignore any
269                                                  * errors.  Note that even
270                                                  * though this thread may have
271                                                  * been canceled, POSIX requires
272                                                  * that the mutex be reaquired
273                                                  * prior to cancellation.
274                                                  */
275                                                 (void)_mutex_cv_lock(mutex);
276                                         } else {
277                                                 /*
278                                                  * Lock the condition variable
279                                                  * while removing the thread.
280                                                  */
281                                                 _SPINLOCK(&(*cond)->lock);
282
283                                                 cond_queue_remove(*cond,
284                                                     curthread);
285
286                                                 /* Check for no more waiters: */
287                                                 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
288                                                         (*cond)->c_mutex = NULL;
289
290                                                 _SPINUNLOCK(&(*cond)->lock);
291
292                                                 /* Lock the mutex: */
293                                                 rval = _mutex_cv_lock(mutex);
294                                         }
295                                 }
296                         }
297                         break;
298
299                 /* Trap invalid condition variable types: */
300                 default:
301                         /* Unlock the condition variable structure: */
302                         _SPINUNLOCK(&(*cond)->lock);
303
304                         /* Return an invalid argument error: */
305                         rval = EINVAL;
306                         break;
307                 }
308
309                 if ((interrupted != 0) && (curthread->continuation != NULL))
310                         curthread->continuation((void *) curthread);
311         } while ((done == 0) && (rval == 0));
312
313         _thread_leave_cancellation_point();
314
315         /* Return the completion status: */
316         return (rval);
317 }
318
319 int
320 _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
321                        const struct timespec * abstime)
322 {
323         struct pthread  *curthread = _get_curthread();
324         int     rval = 0;
325         int     done = 0;
326         int     interrupted = 0;
327         int     seqno;
328
329         _thread_enter_cancellation_point();
330         
331         if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
332             abstime->tv_nsec >= 1000000000)
333                 return (EINVAL);
334         /*
335          * If the condition variable is statically initialized, perform dynamic
336          * initialization.
337          */
338         if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
339                 return (rval);
340
341         /*
342          * Enter a loop waiting for a condition signal or broadcast
343          * to wake up this thread.  A loop is needed in case the waiting
344          * thread is interrupted by a signal to execute a signal handler.
345          * It is not (currently) possible to remain in the waiting queue
346          * while running a handler.  Instead, the thread is interrupted
347          * and backed out of the waiting queue prior to executing the
348          * signal handler.
349          */
350         do {
351                 /* Lock the condition variable structure: */
352                 _SPINLOCK(&(*cond)->lock);
353
354                 /*
355                  * If the condvar was statically allocated, properly
356                  * initialize the tail queue.
357                  */
358                 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
359                         TAILQ_INIT(&(*cond)->c_queue);
360                         (*cond)->c_flags |= COND_FLAGS_INITED;
361                 }
362
363                 /* Process according to condition variable type: */
364                 switch ((*cond)->c_type) {
365                 /* Fast condition variable: */
366                 case COND_TYPE_FAST:
367                         if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
368                             ((*cond)->c_mutex != *mutex))) {
369                                 /* Return invalid argument error: */
370                                 rval = EINVAL;
371
372                                 /* Unlock the condition variable structure: */
373                                 _SPINUNLOCK(&(*cond)->lock);
374                         } else {
375                                 /* Set the wakeup time: */
376                                 curthread->wakeup_time.tv_sec =
377                                     abstime->tv_sec;
378                                 curthread->wakeup_time.tv_nsec =
379                                     abstime->tv_nsec;
380
381                                 /* Reset the timeout and interrupted flags: */
382                                 curthread->timeout = 0;
383                                 curthread->interrupted = 0;
384
385                                 /*
386                                  * Queue the running thread for the condition
387                                  * variable:
388                                  */
389                                 cond_queue_enq(*cond, curthread);
390
391                                 /* Remember the mutex and sequence number: */
392                                 (*cond)->c_mutex = *mutex;
393                                 seqno = (*cond)->c_seqno;
394
395                                 /* Unlock the mutex: */
396                                 if ((rval = _mutex_cv_unlock(mutex)) != 0) {
397                                         /*
398                                          * Cannot unlock the mutex, so remove
399                                          * the running thread from the condition
400                                          * variable queue: 
401                                          */
402                                         cond_queue_remove(*cond, curthread);
403
404                                         /* Check for no more waiters: */
405                                         if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
406                                                 (*cond)->c_mutex = NULL;
407
408                                         /* Unlock the condition variable structure: */
409                                         _SPINUNLOCK(&(*cond)->lock);
410                                 } else {
411                                         /*
412                                          * Schedule the next thread and unlock
413                                          * the condition variable structure:
414                                          */
415                                         _thread_kern_sched_state_unlock(PS_COND_WAIT,
416                                              &(*cond)->lock, __FILE__, __LINE__);
417
418                                         done = (seqno != (*cond)->c_seqno);
419
420                                         interrupted = curthread->interrupted;
421
422                                         /*
423                                          * Check if the wait was interrupted
424                                          * (canceled) or needs to be resumed
425                                          * after handling a signal.
426                                          */
427                                         if (interrupted != 0) {
428                                                 /*
429                                                  * Lock the mutex and ignore any
430                                                  * errors.  Note that even
431                                                  * though this thread may have
432                                                  * been canceled, POSIX requires
433                                                  * that the mutex be reaquired
434                                                  * prior to cancellation.
435                                                  */
436                                                 (void)_mutex_cv_lock(mutex);
437                                         } else {
438                                                 /*
439                                                  * Lock the condition variable
440                                                  * while removing the thread.
441                                                  */
442                                                 _SPINLOCK(&(*cond)->lock);
443
444                                                 cond_queue_remove(*cond,
445                                                     curthread);
446
447                                                 /* Check for no more waiters: */
448                                                 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
449                                                         (*cond)->c_mutex = NULL;
450
451                                                 _SPINUNLOCK(&(*cond)->lock);
452
453                                                 /* Lock the mutex: */
454                                                 rval = _mutex_cv_lock(mutex);
455
456                                                 /*
457                                                  * Return ETIMEDOUT if the wait
458                                                  * timed out and there wasn't an
459                                                  * error locking the mutex:
460                                                  */
461                                                 if ((curthread->timeout != 0)
462                                                     && rval == 0)
463                                                         rval = ETIMEDOUT;
464                                         }
465                                 }
466                         }
467                         break;
468
469                 /* Trap invalid condition variable types: */
470                 default:
471                         /* Unlock the condition variable structure: */
472                         _SPINUNLOCK(&(*cond)->lock);
473
474                         /* Return an invalid argument error: */
475                         rval = EINVAL;
476                         break;
477                 }
478
479                 if ((interrupted != 0) && (curthread->continuation != NULL))
480                         curthread->continuation((void *) curthread);
481         } while ((done == 0) && (rval == 0));
482
483         _thread_leave_cancellation_point();
484
485         /* Return the completion status: */
486         return (rval);
487 }
488
489 int
490 _pthread_cond_signal(pthread_cond_t * cond)
491 {
492         int             rval = 0;
493         pthread_t       pthread;
494
495         if (cond == NULL)
496                 rval = EINVAL;
497        /*
498         * If the condition variable is statically initialized, perform dynamic
499         * initialization.
500         */
501         else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
502                 /*
503                  * Defer signals to protect the scheduling queues
504                  * from access by the signal handler:
505                  */
506                 _thread_kern_sig_defer();
507
508                 /* Lock the condition variable structure: */
509                 _SPINLOCK(&(*cond)->lock);
510
511                 /* Process according to condition variable type: */
512                 switch ((*cond)->c_type) {
513                 /* Fast condition variable: */
514                 case COND_TYPE_FAST:
515                         /* Increment the sequence number: */
516                         (*cond)->c_seqno++;
517
518                         if ((pthread = cond_queue_deq(*cond)) != NULL) {
519                                 /*
520                                  * Wake up the signaled thread:
521                                  */
522                                 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
523                         }
524
525                         /* Check for no more waiters: */
526                         if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
527                                 (*cond)->c_mutex = NULL;
528                         break;
529
530                 /* Trap invalid condition variable types: */
531                 default:
532                         /* Return an invalid argument error: */
533                         rval = EINVAL;
534                         break;
535                 }
536
537                 /* Unlock the condition variable structure: */
538                 _SPINUNLOCK(&(*cond)->lock);
539
540                 /*
541                  * Undefer and handle pending signals, yielding if
542                  * necessary:
543                  */
544                 _thread_kern_sig_undefer();
545         }
546
547         /* Return the completion status: */
548         return (rval);
549 }
550
551 int
552 _pthread_cond_broadcast(pthread_cond_t * cond)
553 {
554         int             rval = 0;
555         pthread_t       pthread;
556
557         if (cond == NULL)
558                 rval = EINVAL;
559        /*
560         * If the condition variable is statically initialized, perform dynamic
561         * initialization.
562         */
563         else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
564                 /*
565                  * Defer signals to protect the scheduling queues
566                  * from access by the signal handler:
567                  */
568                 _thread_kern_sig_defer();
569
570                 /* Lock the condition variable structure: */
571                 _SPINLOCK(&(*cond)->lock);
572
573                 /* Process according to condition variable type: */
574                 switch ((*cond)->c_type) {
575                 /* Fast condition variable: */
576                 case COND_TYPE_FAST:
577                         /* Increment the sequence number: */
578                         (*cond)->c_seqno++;
579
580                         /*
581                          * Enter a loop to bring all threads off the
582                          * condition queue:
583                          */
584                         while ((pthread = cond_queue_deq(*cond)) != NULL) {
585                                 /*
586                                  * Wake up the signaled thread:
587                                  */
588                                 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
589                         }
590
591                         /* There are no more waiting threads: */
592                         (*cond)->c_mutex = NULL;
593                         break;
594         
595                 /* Trap invalid condition variable types: */
596                 default:
597                         /* Return an invalid argument error: */
598                         rval = EINVAL;
599                         break;
600                 }
601
602                 /* Unlock the condition variable structure: */
603                 _SPINUNLOCK(&(*cond)->lock);
604
605                 /*
606                  * Undefer and handle pending signals, yielding if
607                  * necessary:
608                  */
609                 _thread_kern_sig_undefer();
610         }
611
612         /* Return the completion status: */
613         return (rval);
614 }
615
616 void
617 _cond_wait_backout(pthread_t pthread)
618 {
619         pthread_cond_t  cond;
620
621         cond = pthread->data.cond;
622         if (cond != NULL) {
623                 /*
624                  * Defer signals to protect the scheduling queues
625                  * from access by the signal handler:
626                  */
627                 _thread_kern_sig_defer();
628
629                 /* Lock the condition variable structure: */
630                 _SPINLOCK(&cond->lock);
631
632                 /* Process according to condition variable type: */
633                 switch (cond->c_type) {
634                 /* Fast condition variable: */
635                 case COND_TYPE_FAST:
636                         cond_queue_remove(cond, pthread);
637
638                         /* Check for no more waiters: */
639                         if (TAILQ_FIRST(&cond->c_queue) == NULL)
640                                 cond->c_mutex = NULL;
641                         break;
642
643                 default:
644                         break;
645                 }
646
647                 /* Unlock the condition variable structure: */
648                 _SPINUNLOCK(&cond->lock);
649
650                 /*
651                  * Undefer and handle pending signals, yielding if
652                  * necessary:
653                  */
654                 _thread_kern_sig_undefer();
655         }
656 }
657
658 /*
659  * Dequeue a waiting thread from the head of a condition queue in
660  * descending priority order.
661  */
662 static inline pthread_t
663 cond_queue_deq(pthread_cond_t cond)
664 {
665         pthread_t pthread;
666
667         while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
668                 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
669                 pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
670                 if ((pthread->timeout == 0) && (pthread->interrupted == 0))
671                         /*
672                          * Only exit the loop when we find a thread
673                          * that hasn't timed out or been canceled;
674                          * those threads are already running and don't
675                          * need their run state changed.
676                          */
677                         break;
678         }
679
680         return(pthread);
681 }
682
683 /*
684  * Remove a waiting thread from a condition queue in descending priority
685  * order.
686  */
687 static inline void
688 cond_queue_remove(pthread_cond_t cond, pthread_t pthread)
689 {
690         /*
691          * Because pthread_cond_timedwait() can timeout as well
692          * as be signaled by another thread, it is necessary to
693          * guard against removing the thread from the queue if
694          * it isn't in the queue.
695          */
696         if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
697                 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
698                 pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
699         }
700 }
701
702 /*
703  * Enqueue a waiting thread to a condition queue in descending priority
704  * order.
705  */
706 static inline void
707 cond_queue_enq(pthread_cond_t cond, pthread_t pthread)
708 {
709         pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head);
710
711         PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
712
713         /*
714          * For the common case of all threads having equal priority,
715          * we perform a quick check against the priority of the thread
716          * at the tail of the queue.
717          */
718         if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
719                 TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
720         else {
721                 tid = TAILQ_FIRST(&cond->c_queue);
722                 while (pthread->active_priority <= tid->active_priority)
723                         tid = TAILQ_NEXT(tid, sqe);
724                 TAILQ_INSERT_BEFORE(tid, pthread, sqe);
725         }
726         pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
727         pthread->data.cond = cond;
728 }
729
730 __strong_reference(_pthread_cond_init, pthread_cond_init);
731 __strong_reference(_pthread_cond_destroy, pthread_cond_destroy);
732 __strong_reference(_pthread_cond_wait, pthread_cond_wait);
733 __strong_reference(_pthread_cond_timedwait, pthread_cond_timedwait);
734 __strong_reference(_pthread_cond_signal, pthread_cond_signal);
735 __strong_reference(_pthread_cond_broadcast, pthread_cond_broadcast);