/* Up the semaphore's count and release any thread waiting at the head of the * queue. The count is saturated to the value of the 'max' parameter specified * in 'semaphore_init'. */ void semaphore_release(struct semaphore *s) { unsigned int result = THREAD_NONE; int oldlevel = disable_irq_save(); corelock_lock(&s->cl); struct thread_entry *thread = WQ_THREAD_FIRST(&s->queue); if(LIKELY(thread != NULL)) { /* a thread was queued - wake it up and keep count at 0 */ KERNEL_ASSERT(s->count == 0, "semaphore_release->threads queued but count=%d!\n", s->count); result = wakeup_thread(thread, WAKEUP_DEFAULT); } else { int count = s->count; if(count < s->max) { /* nothing waiting - up it */ s->count = count + 1; } } corelock_unlock(&s->cl); restore_irq(oldlevel); #if defined(HAVE_PRIORITY_SCHEDULING) && defined(is_thread_context) /* No thread switch if not thread context */ if((result & THREAD_SWITCH) && is_thread_context()) switch_thread(); #endif (void)result; }
/* Release ownership of a mutex object - only owning thread must call this */ void mutex_unlock(struct mutex *m) { /* unlocker not being the owner is an unlocking violation */ KERNEL_ASSERT(m->blocker.thread == __running_self_entry(), "mutex_unlock->wrong thread (%s != %s)\n", m->blocker.thread->name, __running_self_entry()->name); if(m->recursion > 0) { /* this thread still owns lock */ m->recursion--; return; } /* lock out other cores */ corelock_lock(&m->cl); /* transfer to next queued thread if any */ struct thread_entry *thread = WQ_THREAD_FIRST(&m->queue); if(LIKELY(thread == NULL)) { /* no threads waiting - open the lock */ m->blocker.thread = NULL; corelock_unlock(&m->cl); return; } const int oldlevel = disable_irq_save(); /* Tranfer of owning thread is handled in the wakeup protocol * if priorities are enabled otherwise just set it from the * queue head. */ #ifndef HAVE_PRIORITY_SCHEDULING m->blocker.thread = thread; #endif unsigned int result = wakeup_thread(thread, WAKEUP_TRANSFER); restore_irq(oldlevel); corelock_unlock(&m->cl); #ifdef HAVE_PRIORITY_SCHEDULING if(result & THREAD_SWITCH) switch_thread(); #endif (void)result; }