A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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}