1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
/*
* Copyright (c) 2017 Richard Braun.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* Semaphores are resource-counting sleeping synchronization objects.
* They are used to synchronize access to resources and signal events.
*
* The main operations supported by semaphores are locking and unlocking.
* A semaphore is implemented as an atomic integer with an initial value.
* Locking a semaphore means decrementing that integer, whereas unlocking
* means incrementing it. Locking can only succeed if the semaphore value
* is strictly greater than 0.
*
* Semaphores should not be used to implement critical sections. Instead,
* use mutexes, which are similar to binary semaphores but with additional
* restrictions that can improve debugging.
*/
#ifndef _KERN_SEMAPHORE_H
#define _KERN_SEMAPHORE_H
#include <assert.h>
#include <stdint.h>
#include <kern/atomic.h>
#include <kern/error.h>
#define SEMAPHORE_VALUE_MAX 32768
#include <kern/semaphore_i.h>
struct semaphore;
/*
* Initialize a semaphore.
*/
static inline void
semaphore_init(struct semaphore *semaphore, unsigned int value)
{
assert(value <= SEMAPHORE_VALUE_MAX);
semaphore->value = value;
}
/*
* Attempt to lock a semaphore.
*
* This function may not sleep.
*
* Return 0 on success, ERROR_AGAIN if the semaphore could not be decremented.
*/
static inline int
semaphore_trywait(struct semaphore *semaphore)
{
unsigned int prev;
prev = semaphore_dec(semaphore);
if (prev == 0) {
return ERROR_AGAIN;
}
return 0;
}
/*
* Lock a semaphore.
*
* If the semaphore value doesn't allow locking, the calling thread sleeps
* until the semaphore value is incremented.
*/
static inline void
semaphore_wait(struct semaphore *semaphore)
{
unsigned int prev;
prev = semaphore_dec(semaphore);
if (prev == 0) {
semaphore_wait_slow(semaphore);
}
}
static inline int
semaphore_timedwait(struct semaphore *semaphore, uint64_t ticks)
{
unsigned int prev;
prev = semaphore_dec(semaphore);
if (prev == 0) {
return semaphore_timedwait_slow(semaphore, ticks);
}
return 0;
}
/*
* Unlock a semaphore.
*
* If the semaphore value becomes strictly greater than 0, a thread waiting
* on the semaphore is awaken.
*
* A semaphore may be unlocked from interrupt context.
*/
static inline void
semaphore_post(struct semaphore *semaphore)
{
unsigned int prev;
prev = semaphore_inc(semaphore);
if (prev == 0) {
semaphore_post_slow(semaphore);
}
}
/*
* Get the value of a semaphore.
*/
static inline unsigned int
semaphore_getvalue(const struct semaphore *semaphore)
{
return atomic_load(&semaphore->value, ATOMIC_RELAXED);
}
#endif /* _KERN_SEMAPHORE_H */
|