blob: 219360a4128d51deb7922d8b3262f5e5537e3dd6 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/* semaphore.c
2 *
3 * Copyright 2012 Christopher Anderson <chris@nullcode.org>
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <debug.h>
18#include <err.h>
19#include <kernel/semaphore.h>
20#include <kernel/thread.h>
21
22void sem_init(semaphore_t *sem, unsigned int value)
23{
24 *sem = (semaphore_t)SEMAPHORE_INITIAL_VALUE(*sem, value);
25}
26
27void sem_destroy(semaphore_t *sem)
28{
29 THREAD_LOCK(state);
30 sem->count = 0;
31 wait_queue_destroy(&sem->wait, true);
32 THREAD_UNLOCK(state);
33}
34
35int sem_post(semaphore_t *sem, bool resched)
36{
37 int ret = 0;
38
39 THREAD_LOCK(state);
40
41 /*
42 * If the count is or was negative then a thread is waiting for a resource, otherwise
43 * it's safe to just increase the count available with no downsides
44 */
45 if (unlikely(++sem->count <= 0))
46 ret = wait_queue_wake_one(&sem->wait, resched, NO_ERROR);
47
48 THREAD_UNLOCK(state);
49
50 return ret;
51}
52
53status_t sem_wait(semaphore_t *sem)
54{
55 status_t ret = NO_ERROR;
56 THREAD_LOCK(state);
57
58 /*
59 * If there are no resources available then we need to
60 * sit in the wait queue until sem_post adds some.
61 */
62 if (unlikely(--sem->count < 0))
63 ret = wait_queue_block(&sem->wait, INFINITE_TIME);
64
65 THREAD_UNLOCK(state);
66 return ret;
67}
68
69status_t sem_trywait(semaphore_t *sem)
70{
71 status_t ret = NO_ERROR;
72 THREAD_LOCK(state);
73
74 if (unlikely(sem->count <= 0))
75 ret = ERR_NOT_READY;
76 else
77 sem->count--;
78
79 THREAD_UNLOCK(state);
80 return ret;
81}
82
83status_t sem_timedwait(semaphore_t *sem, lk_time_t timeout)
84{
85 status_t ret = NO_ERROR;
86 THREAD_LOCK(state);
87
88 if (unlikely(--sem->count < 0)) {
89 ret = wait_queue_block(&sem->wait, timeout);
90 if (ret < NO_ERROR) {
91 if (ret == ERR_TIMED_OUT) {
92 sem->count++;
93 }
94 }
95 }
96
97 THREAD_UNLOCK(state);
98 return ret;
99}
100
101/* vim: set noexpandtab: */