A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 135 lines 4.3 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2002 by Björn Stenberg 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21#include "kernel-internal.h" 22#include "semaphore.h" 23 24/**************************************************************************** 25 * Simple semaphore functions ;) 26 ****************************************************************************/ 27 28/* Initialize the semaphore object. 29 * max = maximum up count the semaphore may assume (max >= 1) 30 * start = initial count of semaphore (0 <= count <= max) */ 31void semaphore_init(struct semaphore *s, int max, int start) 32{ 33 KERNEL_ASSERT(max > 0 && start >= 0 && start <= max, 34 "semaphore_init->inv arg\n"); 35 wait_queue_init(&s->queue); 36 s->max = max; 37 s->count = start; 38 corelock_init(&s->cl); 39} 40 41/* Down the semaphore's count or wait for 'timeout' ticks for it to go up if 42 * it is already 0. 'timeout' as TIMEOUT_NOBLOCK (0) will not block and may 43 * safely be used in an ISR. */ 44int semaphore_wait(struct semaphore *s, int timeout) 45{ 46 int ret = OBJ_WAIT_TIMEDOUT; 47 48 int oldlevel = disable_irq_save(); 49 corelock_lock(&s->cl); 50 51 int count = s->count; 52 if(LIKELY(count > 0)) 53 { 54 /* count is not zero; down it */ 55 s->count = count - 1; 56 ret = OBJ_WAIT_SUCCEEDED; 57 } 58 else if(timeout != 0) 59 { 60 ASSERT_CPU_MODE(CPU_MODE_THREAD_CONTEXT, oldlevel); 61 62 /* too many waits - block until count is upped... */ 63 struct thread_entry *current = __running_self_entry(); 64 65 block_thread(current, timeout, &s->queue, NULL); 66 corelock_unlock(&s->cl); 67 68 /* ...and turn control over to next thread */ 69 switch_thread(); 70 71 /* if explicit wake indicated; do no more */ 72 if(LIKELY(!wait_queue_ptr(current))) 73 return OBJ_WAIT_SUCCEEDED; 74 75 disable_irq(); 76 corelock_lock(&s->cl); 77 78 /* see if anyone got us after the expired wait */ 79 if(wait_queue_try_remove(current)) 80 { 81 count = s->count; 82 if(count > 0) 83 { 84 /* down it lately */ 85 s->count = count - 1; 86 ret = OBJ_WAIT_SUCCEEDED; 87 } 88 } 89 } 90 /* else just polling it */ 91 92 corelock_unlock(&s->cl); 93 restore_irq(oldlevel); 94 95 return ret; 96} 97 98/* Up the semaphore's count and release any thread waiting at the head of the 99 * queue. The count is saturated to the value of the 'max' parameter specified 100 * in 'semaphore_init'. */ 101void semaphore_release(struct semaphore *s) 102{ 103 unsigned int result = THREAD_NONE; 104 105 int oldlevel = disable_irq_save(); 106 corelock_lock(&s->cl); 107 108 struct thread_entry *thread = WQ_THREAD_FIRST(&s->queue); 109 if(LIKELY(thread != NULL)) 110 { 111 /* a thread was queued - wake it up and keep count at 0 */ 112 KERNEL_ASSERT(s->count == 0, 113 "semaphore_release->threads queued but count=%d!\n", s->count); 114 result = wakeup_thread(thread, WAKEUP_DEFAULT); 115 } 116 else 117 { 118 int count = s->count; 119 if(count < s->max) 120 { 121 /* nothing waiting - up it */ 122 s->count = count + 1; 123 } 124 } 125 126 corelock_unlock(&s->cl); 127 restore_irq(oldlevel); 128 129#if defined(HAVE_PRIORITY_SCHEDULING) && defined(is_thread_context) 130 /* No thread switch if not thread context */ 131 if((result & THREAD_SWITCH) && is_thread_context()) 132 switch_thread(); 133#endif 134 (void)result; 135}