1
2#include <BeOSBuildCompatibility.h>
3
4#include <stdlib.h>
5#include <string.h>
6
7#include <OS.h>
8#include <SupportDefs.h>
9
10// We assume that everything is single-threaded, so we don't need real
11// semaphores. Simple fakes are sufficient.
12
13struct semaphore {
14	char*	name;
15	int32	count;
16	bool	inUse;
17};
18
19static const int kSemaphoreCount = 40960;
20static semaphore sSemaphores[kSemaphoreCount];
21
22
23static bool
24check_sem(sem_id id)
25{
26	if (id < 0 || id >= kSemaphoreCount)
27		return false;
28	return sSemaphores[id].inUse;
29}
30
31// create_sem
32sem_id
33create_sem(int32 count, const char *name)
34{
35	for (int i = 0; i < kSemaphoreCount; i++) {
36		semaphore &sem = sSemaphores[i];
37		if (!sem.inUse) {
38			sem.name = strdup(name ? name : "unnamed sem");
39			if (!sem.name)
40				return B_NO_MEMORY;
41
42			sem.inUse = true;
43			sem.count = count;
44
45			return i;
46		}
47	}
48
49	return B_NO_MORE_SEMS;
50}
51
52// delete_sem
53status_t
54delete_sem(sem_id id)
55{
56	if (!check_sem(id))
57		return B_BAD_SEM_ID;
58
59	sSemaphores[id].inUse = false;
60	free(sSemaphores[id].name);
61	sSemaphores[id].name = NULL;
62
63	return B_OK;
64}
65
66// acquire_sem
67status_t
68acquire_sem(sem_id id)
69{
70	return acquire_sem_etc(id, 1, 0, 0);
71}
72
73// acquire_sem_etc
74status_t
75acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
76{
77	if (!check_sem(id))
78		return B_BAD_SEM_ID;
79
80	if (count <= 0)
81		return B_BAD_VALUE;
82
83	semaphore &sem = sSemaphores[id];
84	if (sem.count >= count) {
85		sem.count -= count;
86		return B_OK;
87	}
88
89	if (timeout < 0)
90		timeout = 0;
91
92	bool noTimeout = false;
93	if (flags & B_RELATIVE_TIMEOUT) {
94		// relative timeout: get the absolute time when to time out
95
96		// special case: on timeout == 0 we return B_WOULD_BLOCK
97		if (timeout == 0)
98			return B_WOULD_BLOCK;
99
100		bigtime_t currentTime = system_time();
101		if (timeout > B_INFINITE_TIMEOUT || currentTime >= B_INFINITE_TIMEOUT - timeout) {
102			noTimeout = true;
103		} else {
104			timeout += currentTime;
105		}
106
107	} else if (flags & B_ABSOLUTE_TIMEOUT) {
108		// absolute timeout
109	} else {
110		// no timeout given
111		noTimeout = true;
112	}
113
114	// no timeout?
115	if (noTimeout) {
116		debugger("Would block on a semaphore without timeout in a "
117			"single-threaded context!");
118		return B_ERROR;
119	}
120
121	// wait for the time out time
122	status_t error = snooze_until(timeout, B_SYSTEM_TIMEBASE);
123	if (error != B_OK)
124		return error;
125
126	return B_TIMED_OUT;
127}
128
129// release_sem
130status_t
131release_sem(sem_id id)
132{
133	return release_sem_etc(id, 1, 0);
134}
135
136// release_sem_etc
137status_t
138release_sem_etc(sem_id id, int32 count, uint32 flags)
139{
140	if (!check_sem(id))
141		return B_BAD_SEM_ID;
142
143	if (count <= 0)
144		return B_BAD_VALUE;
145
146	semaphore &sem = sSemaphores[id];
147	sem.count += count;
148
149	return B_OK;
150}
151
152// get_sem_count
153status_t
154get_sem_count(sem_id id, int32 *threadCount)
155{
156	if (!check_sem(id))
157		return B_BAD_SEM_ID;
158
159	if (!threadCount)
160		return B_BAD_VALUE;
161
162	*threadCount = sSemaphores[id].count;
163	return B_OK;
164}
165
166// set_sem_owner
167status_t
168set_sem_owner(sem_id id, team_id team)
169{
170	if (!check_sem(id))
171		return B_BAD_SEM_ID;
172
173	return B_OK;
174}
175
176// _get_sem_info
177status_t
178_get_sem_info(sem_id id, struct sem_info *info, size_t infoSize)
179{
180	if (!check_sem(id))
181		return B_BAD_SEM_ID;
182
183	if (!info)
184		return B_BAD_VALUE;
185
186	info->sem = id;
187	info->team = 1;
188	strlcpy(info->name, sSemaphores[id].name, sizeof(info->name));
189	info->count = sSemaphores[id].count;
190	info->latest_holder = -1;
191
192	return B_OK;
193}
194
195// _get_next_sem_info
196status_t
197_get_next_sem_info(team_id team, int32 *cookie, struct sem_info *info,
198	size_t infoSize)
199{
200	if (team < 0 || team > 2)
201		return B_BAD_TEAM_ID;
202
203	for (int i = *cookie; i < kSemaphoreCount; i++) {
204		if (sSemaphores[i].inUse) {
205			*cookie = i + 1;
206			return _get_sem_info(i, info, infoSize);
207		}
208	}
209
210	return B_ENTRY_NOT_FOUND;
211}
212