static void wake_next(async_rwlock_t *const lock) { if(lock->upgrade) { if(lock->state > 0) return; lock->state = s_write; async_t *const next = lock->upgrade; lock->upgrade = NULL; async_wakeup(next); } else if(lock->wrhead) { if(lock->state > 0) return; lock->state = s_write; async_thread_list *const next = lock->wrhead; lock->wrhead = next->next; if(!lock->wrhead) lock->wrtail = NULL; async_wakeup(next->thread); } else while(lock->rdhead) { if(lock->state >= READERS_MAX) return; ++lock->state; async_thread_list *const next = lock->rdhead; lock->rdhead = next->next; if(!lock->rdhead) lock->rdtail = NULL; async_wakeup(next->thread); } }
void async_mutex_unlock(async_mutex_t *const mutex) { assert(mutex && "Mutex must not be null"); cothread_t const thread = co_active(); assert(mutex->active.thread && "Leaving empty mutex"); assert(thread == mutex->active.thread && "Leaving someone else's mutex"); assert(mutex->depth > 0 && "Mutex recursion depth going negative"); if(--mutex->depth) return; if(!mutex->active.next) return; list_entry *const next = mutex->active.next; if(!next->next) mutex->tail = &mutex->active; mutex->active.thread = next->thread; mutex->active.next = next->next; mutex->depth = 1; async_wakeup(next->thread); // Set everything up ahead of time so we aren't dependent on whether the wakeup is synchronous or not. }
void async_cancel(async_t *const thread) { if(!thread) return; thread->flags |= ASYNC_CANCELED; if(ASYNC_CANCELABLE & thread->flags) async_wakeup(thread); }