if_vtnet - Default to link up, when VIRTIO_NET_F_STATUS is not negotiated.
[dragonfly.git] / lib / libc_r / uthread / uthread_cond.c
blob07732e16cffe887d047773650be59270294b3790
1 /*
2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3 * All rights reserved.
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.
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.
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 $
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <pthread.h>
39 #include "pthread_private.h"
42 * Prototypes
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);
49 /* Reinitialize a condition variable to defaults. */
50 int
51 _cond_reinit(pthread_cond_t *cond)
53 int ret = 0;
55 if (cond == NULL)
56 ret = EINVAL;
57 else if (*cond == NULL)
58 ret = pthread_cond_init(cond, NULL);
59 else {
61 * Initialize the condition variable structure:
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));
70 return (ret);
73 int
74 _pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
76 enum pthread_cond_type type;
77 pthread_cond_t pcond;
78 int rval = 0;
80 if (cond == NULL)
81 rval = EINVAL;
82 else {
84 * Check if a pointer to a condition variable attribute
85 * structure was passed by the caller:
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;
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;
102 /* Trap invalid condition variable types: */
103 default:
104 /* Return an invalid argument error: */
105 rval = EINVAL;
106 break;
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 {
116 * Initialise the condition variable
117 * structure:
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;
129 /* Return the completion status: */
130 return (rval);
134 _pthread_cond_destroy(pthread_cond_t *cond)
136 int rval = 0;
138 if (cond == NULL || *cond == NULL)
139 rval = EINVAL;
140 else {
141 /* Lock the condition variable structure: */
142 _SPINLOCK(&(*cond)->lock);
145 * Free the memory allocated for the condition
146 * variable structure:
148 free(*cond);
151 * NULL the caller's pointer now that the condition
152 * variable has been destroyed:
154 *cond = NULL;
156 /* Return the completion status: */
157 return (rval);
161 _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
163 struct pthread *curthread = _get_curthread();
164 int rval = 0;
165 int done = 0;
166 int interrupted = 0;
167 int seqno;
169 _thread_enter_cancellation_point();
171 if (cond == NULL)
172 return (EINVAL);
175 * If the condition variable is statically initialized,
176 * perform the dynamic initialization:
178 if (*cond == NULL &&
179 (rval = pthread_cond_init(cond, NULL)) != 0)
180 return (rval);
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.
191 do {
192 /* Lock the condition variable structure: */
193 _SPINLOCK(&(*cond)->lock);
196 * If the condvar was statically allocated, properly
197 * initialize the tail queue.
199 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
200 TAILQ_INIT(&(*cond)->c_queue);
201 (*cond)->c_flags |= COND_FLAGS_INITED;
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);
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;
221 * Queue the running thread for the condition
222 * variable:
224 cond_queue_enq(*cond, curthread);
226 /* Remember the mutex and sequence number: */
227 (*cond)->c_mutex = *mutex;
228 seqno = (*cond)->c_seqno;
230 /* Wait forever: */
231 curthread->wakeup_time.tv_sec = -1;
233 /* Unlock the mutex: */
234 if ((rval = _mutex_cv_unlock(mutex)) != 0) {
236 * Cannot unlock the mutex, so remove
237 * the running thread from the condition
238 * variable queue:
240 cond_queue_remove(*cond, curthread);
242 /* Check for no more waiters: */
243 if (TAILQ_FIRST(&(*cond)->c_queue) ==
244 NULL)
245 (*cond)->c_mutex = NULL;
247 /* Unlock the condition variable structure: */
248 _SPINUNLOCK(&(*cond)->lock);
249 } else {
251 * Schedule the next thread and unlock
252 * the condition variable structure:
254 _thread_kern_sched_state_unlock(PS_COND_WAIT,
255 &(*cond)->lock, __FILE__, __LINE__);
257 done = (seqno != (*cond)->c_seqno);
259 interrupted = curthread->interrupted;
262 * Check if the wait was interrupted
263 * (canceled) or needs to be resumed
264 * after handling a signal.
266 if (interrupted != 0) {
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 reacquired
273 * prior to cancellation.
275 (void)_mutex_cv_lock(mutex);
276 } else {
278 * Lock the condition variable
279 * while removing the thread.
281 _SPINLOCK(&(*cond)->lock);
283 cond_queue_remove(*cond,
284 curthread);
286 /* Check for no more waiters: */
287 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
288 (*cond)->c_mutex = NULL;
290 _SPINUNLOCK(&(*cond)->lock);
292 /* Lock the mutex: */
293 rval = _mutex_cv_lock(mutex);
297 break;
299 /* Trap invalid condition variable types: */
300 default:
301 /* Unlock the condition variable structure: */
302 _SPINUNLOCK(&(*cond)->lock);
304 /* Return an invalid argument error: */
305 rval = EINVAL;
306 break;
309 if ((interrupted != 0) && (curthread->continuation != NULL))
310 curthread->continuation((void *) curthread);
311 } while ((done == 0) && (rval == 0));
313 _thread_leave_cancellation_point();
315 /* Return the completion status: */
316 return (rval);
320 _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
321 const struct timespec * abstime)
323 struct pthread *curthread = _get_curthread();
324 int rval = 0;
325 int done = 0;
326 int interrupted = 0;
327 int seqno;
329 _thread_enter_cancellation_point();
331 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
332 abstime->tv_nsec >= 1000000000)
333 return (EINVAL);
335 * If the condition variable is statically initialized, perform dynamic
336 * initialization.
338 if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
339 return (rval);
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.
350 do {
351 /* Lock the condition variable structure: */
352 _SPINLOCK(&(*cond)->lock);
355 * If the condvar was statically allocated, properly
356 * initialize the tail queue.
358 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
359 TAILQ_INIT(&(*cond)->c_queue);
360 (*cond)->c_flags |= COND_FLAGS_INITED;
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;
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;
381 /* Reset the timeout and interrupted flags: */
382 curthread->timeout = 0;
383 curthread->interrupted = 0;
386 * Queue the running thread for the condition
387 * variable:
389 cond_queue_enq(*cond, curthread);
391 /* Remember the mutex and sequence number: */
392 (*cond)->c_mutex = *mutex;
393 seqno = (*cond)->c_seqno;
395 /* Unlock the mutex: */
396 if ((rval = _mutex_cv_unlock(mutex)) != 0) {
398 * Cannot unlock the mutex, so remove
399 * the running thread from the condition
400 * variable queue:
402 cond_queue_remove(*cond, curthread);
404 /* Check for no more waiters: */
405 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
406 (*cond)->c_mutex = NULL;
408 /* Unlock the condition variable structure: */
409 _SPINUNLOCK(&(*cond)->lock);
410 } else {
412 * Schedule the next thread and unlock
413 * the condition variable structure:
415 _thread_kern_sched_state_unlock(PS_COND_WAIT,
416 &(*cond)->lock, __FILE__, __LINE__);
418 done = (seqno != (*cond)->c_seqno);
420 interrupted = curthread->interrupted;
423 * Check if the wait was interrupted
424 * (canceled) or needs to be resumed
425 * after handling a signal.
427 if (interrupted != 0) {
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 reacquired
434 * prior to cancellation.
436 (void)_mutex_cv_lock(mutex);
437 } else {
439 * Lock the condition variable
440 * while removing the thread.
442 _SPINLOCK(&(*cond)->lock);
444 cond_queue_remove(*cond,
445 curthread);
447 /* Check for no more waiters: */
448 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
449 (*cond)->c_mutex = NULL;
451 _SPINUNLOCK(&(*cond)->lock);
453 /* Lock the mutex: */
454 rval = _mutex_cv_lock(mutex);
457 * Return ETIMEDOUT if the wait
458 * timed out and there wasn't an
459 * error locking the mutex:
461 if ((curthread->timeout != 0)
462 && rval == 0)
463 rval = ETIMEDOUT;
467 break;
469 /* Trap invalid condition variable types: */
470 default:
471 /* Unlock the condition variable structure: */
472 _SPINUNLOCK(&(*cond)->lock);
474 /* Return an invalid argument error: */
475 rval = EINVAL;
476 break;
479 if ((interrupted != 0) && (curthread->continuation != NULL))
480 curthread->continuation((void *) curthread);
481 } while ((done == 0) && (rval == 0));
483 _thread_leave_cancellation_point();
485 /* Return the completion status: */
486 return (rval);
490 _pthread_cond_signal(pthread_cond_t * cond)
492 int rval = 0;
493 pthread_t pthread;
495 if (cond == NULL)
496 rval = EINVAL;
498 * If the condition variable is statically initialized, perform dynamic
499 * initialization.
501 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
503 * Defer signals to protect the scheduling queues
504 * from access by the signal handler:
506 _thread_kern_sig_defer();
508 /* Lock the condition variable structure: */
509 _SPINLOCK(&(*cond)->lock);
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++;
518 if ((pthread = cond_queue_deq(*cond)) != NULL) {
520 * Wake up the signaled thread:
522 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
525 /* Check for no more waiters: */
526 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
527 (*cond)->c_mutex = NULL;
528 break;
530 /* Trap invalid condition variable types: */
531 default:
532 /* Return an invalid argument error: */
533 rval = EINVAL;
534 break;
537 /* Unlock the condition variable structure: */
538 _SPINUNLOCK(&(*cond)->lock);
541 * Undefer and handle pending signals, yielding if
542 * necessary:
544 _thread_kern_sig_undefer();
547 /* Return the completion status: */
548 return (rval);
552 _pthread_cond_broadcast(pthread_cond_t * cond)
554 int rval = 0;
555 pthread_t pthread;
557 if (cond == NULL)
558 rval = EINVAL;
560 * If the condition variable is statically initialized, perform dynamic
561 * initialization.
563 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
565 * Defer signals to protect the scheduling queues
566 * from access by the signal handler:
568 _thread_kern_sig_defer();
570 /* Lock the condition variable structure: */
571 _SPINLOCK(&(*cond)->lock);
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++;
581 * Enter a loop to bring all threads off the
582 * condition queue:
584 while ((pthread = cond_queue_deq(*cond)) != NULL) {
586 * Wake up the signaled thread:
588 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
591 /* There are no more waiting threads: */
592 (*cond)->c_mutex = NULL;
593 break;
595 /* Trap invalid condition variable types: */
596 default:
597 /* Return an invalid argument error: */
598 rval = EINVAL;
599 break;
602 /* Unlock the condition variable structure: */
603 _SPINUNLOCK(&(*cond)->lock);
606 * Undefer and handle pending signals, yielding if
607 * necessary:
609 _thread_kern_sig_undefer();
612 /* Return the completion status: */
613 return (rval);
616 void
617 _cond_wait_backout(pthread_t pthread)
619 pthread_cond_t cond;
621 cond = pthread->data.cond;
622 if (cond != NULL) {
624 * Defer signals to protect the scheduling queues
625 * from access by the signal handler:
627 _thread_kern_sig_defer();
629 /* Lock the condition variable structure: */
630 _SPINLOCK(&cond->lock);
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);
638 /* Check for no more waiters: */
639 if (TAILQ_FIRST(&cond->c_queue) == NULL)
640 cond->c_mutex = NULL;
641 break;
643 default:
644 break;
647 /* Unlock the condition variable structure: */
648 _SPINUNLOCK(&cond->lock);
651 * Undefer and handle pending signals, yielding if
652 * necessary:
654 _thread_kern_sig_undefer();
659 * Dequeue a waiting thread from the head of a condition queue in
660 * descending priority order.
662 static inline pthread_t
663 cond_queue_deq(pthread_cond_t cond)
665 pthread_t pthread;
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))
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.
677 break;
680 return(pthread);
684 * Remove a waiting thread from a condition queue in descending priority
685 * order.
687 static inline void
688 cond_queue_remove(pthread_cond_t cond, pthread_t pthread)
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.
696 if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
697 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
698 pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
703 * Enqueue a waiting thread to a condition queue in descending priority
704 * order.
706 static inline void
707 cond_queue_enq(pthread_cond_t cond, pthread_t pthread)
709 pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head);
711 PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
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.
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);
726 pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
727 pthread->data.cond = cond;
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);