/* * Copyright (C) 2016 Sam Kumar * 2016 University of California, Berkeley * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @ingroup core_sync * @{ * * @file * @brief Kernel condition variable implementation * * @author Sam Kumar * * @} */ #include "cond.h" #include "irq.h" #include "mutex.h" #include "thread.h" #define ENABLE_DEBUG 0 #include "debug.h" void cond_init(cond_t *cond) { cond->queue.next = NULL; } void cond_wait(cond_t *cond, mutex_t *mutex) { unsigned irqstate = irq_disable(); thread_t *me = thread_get_active(); mutex_unlock(mutex); sched_set_status(me, STATUS_COND_BLOCKED); thread_add_to_list(&cond->queue, me); irq_restore(irqstate); thread_yield_higher(); /* * Once we reach this point, the condition variable was signalled, * and we are free to continue. */ mutex_lock(mutex); } static void _cond_signal(cond_t *cond, bool broadcast) { unsigned irqstate = irq_disable(); list_node_t *next; uint16_t min_prio = THREAD_PRIORITY_MIN + 1; while ((next = list_remove_head(&cond->queue)) != NULL) { thread_t *process = container_of((clist_node_t *)next, thread_t, rq_entry); sched_set_status(process, STATUS_PENDING); uint16_t process_priority = process->priority; if (process_priority < min_prio) { min_prio = process_priority; } if (!broadcast) { break; } } irq_restore(irqstate); if (min_prio <= THREAD_PRIORITY_MIN) { sched_switch(min_prio); } } void cond_signal(cond_t *cond) { _cond_signal(cond, false); } void cond_broadcast(cond_t *cond) { _cond_signal(cond, true); }