First version
[3rdparty/ote_partner/tlk.git] / kernel / semaphore.c
1 /* 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
22 void sem_init(semaphore_t *sem, unsigned int value)
23 {
24         sem->magic = SEMAPHORE_MAGIC;
25         sem->count = value;
26         wait_queue_init(&sem->wait);
27 }
28
29 void sem_destroy(semaphore_t *sem)
30 {
31         enter_critical_section();
32         sem->count = 0;
33         wait_queue_destroy(&sem->wait, true);
34         exit_critical_section();
35 }
36
37 status_t sem_post(semaphore_t *sem)
38 {
39         status_t ret = NO_ERROR;
40         enter_critical_section();
41
42         /*
43          * If the count is or was negative then a thread is waiting for a resource, otherwise
44          * it's safe to just increase the count available with no downsides
45          */
46         if (unlikely(++sem->count <= 0))
47                 wait_queue_wake_one(&sem->wait, true, NO_ERROR);
48
49         exit_critical_section();
50         return ret;
51 }
52
53 status_t sem_wait(semaphore_t *sem)
54 {
55         status_t ret = NO_ERROR;
56         enter_critical_section();
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         exit_critical_section();
66         return ret;
67 }
68
69 status_t sem_trywait(semaphore_t *sem)
70 {
71         status_t ret = NO_ERROR;
72         enter_critical_section();
73
74         if (unlikely(sem->count <= 0))
75                 ret = ERR_NOT_READY;
76         else
77                 sem->count--;
78         
79         exit_critical_section();
80         return ret;
81 }
82
83 status_t sem_timedwait(semaphore_t *sem, lk_time_t timeout)
84 {
85         status_t ret = NO_ERROR;
86         enter_critical_section();
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         exit_critical_section();
98         return ret;
99 }