1 /* semaphore.c
2 *
3 * Copyright 2012 Christopher Anderson <[email protected]>
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
sem_init(semaphore_t * sem,unsigned int value)22 void sem_init(semaphore_t *sem, unsigned int value)
23 {
24 *sem = (semaphore_t)SEMAPHORE_INITIAL_VALUE(*sem, value);
25 }
26
sem_destroy(semaphore_t * sem)27 void 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
sem_post(semaphore_t * sem,bool resched)35 int 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 assert(sem->count < INT_MAX);
46 if (unlikely(++sem->count <= 0))
47 ret = wait_queue_wake_one(&sem->wait, resched, NO_ERROR);
48
49 THREAD_UNLOCK(state);
50
51 return ret;
52 }
53
sem_wait(semaphore_t * sem)54 status_t sem_wait(semaphore_t *sem)
55 {
56 status_t ret = NO_ERROR;
57 THREAD_LOCK(state);
58
59 /*
60 * If there are no resources available then we need to
61 * sit in the wait queue until sem_post adds some.
62 */
63 if (unlikely(--sem->count < 0))
64 ret = wait_queue_block(&sem->wait, INFINITE_TIME);
65
66 THREAD_UNLOCK(state);
67 return ret;
68 }
69
sem_trywait(semaphore_t * sem)70 status_t sem_trywait(semaphore_t *sem)
71 {
72 status_t ret = NO_ERROR;
73 THREAD_LOCK(state);
74
75 if (unlikely(sem->count <= 0))
76 ret = ERR_NOT_READY;
77 else
78 sem->count--;
79
80 THREAD_UNLOCK(state);
81 return ret;
82 }
83
sem_timedwait(semaphore_t * sem,lk_time_t timeout)84 status_t sem_timedwait(semaphore_t *sem, lk_time_t timeout)
85 {
86 status_t ret = NO_ERROR;
87 THREAD_LOCK(state);
88
89 if (unlikely(--sem->count < 0)) {
90 ret = wait_queue_block(&sem->wait, timeout);
91 if (ret < NO_ERROR) {
92 if (ret == ERR_TIMED_OUT) {
93 sem->count++;
94 }
95 }
96 }
97
98 THREAD_UNLOCK(state);
99 return ret;
100 }
101