xref: /haiku/src/build/libroot/sem.cpp (revision 5737b4aed826993c48bbeb190203c8fa22be92ad)
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 
13 struct semaphore {
14 	char*	name;
15 	int32	count;
16 	bool	inUse;
17 };
18 
19 static const int kSemaphoreCount = 40960;
20 static semaphore sSemaphores[kSemaphoreCount];
21 
22 
23 static bool
check_sem(sem_id id)24 check_sem(sem_id id)
25 {
26 	if (id < 0 || id >= kSemaphoreCount)
27 		return false;
28 	return sSemaphores[id].inUse;
29 }
30 
31 // create_sem
32 sem_id
create_sem(int32 count,const char * name)33 create_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
53 status_t
delete_sem(sem_id id)54 delete_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
67 status_t
acquire_sem(sem_id id)68 acquire_sem(sem_id id)
69 {
70 	return acquire_sem_etc(id, 1, 0, 0);
71 }
72 
73 // acquire_sem_etc
74 status_t
acquire_sem_etc(sem_id id,int32 count,uint32 flags,bigtime_t timeout)75 acquire_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
130 status_t
release_sem(sem_id id)131 release_sem(sem_id id)
132 {
133 	return release_sem_etc(id, 1, 0);
134 }
135 
136 // release_sem_etc
137 status_t
release_sem_etc(sem_id id,int32 count,uint32 flags)138 release_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
153 status_t
get_sem_count(sem_id id,int32 * threadCount)154 get_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
167 status_t
set_sem_owner(sem_id id,team_id team)168 set_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
177 status_t
_get_sem_info(sem_id id,struct sem_info * info,size_t infoSize)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
196 status_t
_get_next_sem_info(team_id team,int32 * cookie,struct sem_info * info,size_t infoSize)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