#include <BeOSBuildCompatibility.h>
#include <stdlib.h>
#include <string.h>
#include <OS.h>
#include <SupportDefs.h>
struct semaphore {
char* name;
int32 count;
bool inUse;
};
static const int kSemaphoreCount = 40960;
static semaphore sSemaphores[kSemaphoreCount];
static bool
check_sem(sem_id id)
{
if (id < 0 || id >= kSemaphoreCount)
return false;
return sSemaphores[id].inUse;
}
sem_id
create_sem(int32 count, const char *name)
{
for (int i = 0; i < kSemaphoreCount; i++) {
semaphore &sem = sSemaphores[i];
if (!sem.inUse) {
sem.name = strdup(name ? name : "unnamed sem");
if (!sem.name)
return B_NO_MEMORY;
sem.inUse = true;
sem.count = count;
return i;
}
}
return B_NO_MORE_SEMS;
}
status_t
delete_sem(sem_id id)
{
if (!check_sem(id))
return B_BAD_SEM_ID;
sSemaphores[id].inUse = false;
free(sSemaphores[id].name);
sSemaphores[id].name = NULL;
return B_OK;
}
status_t
acquire_sem(sem_id id)
{
return acquire_sem_etc(id, 1, 0, 0);
}
status_t
acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
{
if (!check_sem(id))
return B_BAD_SEM_ID;
if (count <= 0)
return B_BAD_VALUE;
semaphore &sem = sSemaphores[id];
if (sem.count >= count) {
sem.count -= count;
return B_OK;
}
if (timeout < 0)
timeout = 0;
bool noTimeout = false;
if (flags & B_RELATIVE_TIMEOUT) {
if (timeout == 0)
return B_WOULD_BLOCK;
bigtime_t currentTime = system_time();
if (timeout > B_INFINITE_TIMEOUT || currentTime >= B_INFINITE_TIMEOUT - timeout) {
noTimeout = true;
} else {
timeout += currentTime;
}
} else if (flags & B_ABSOLUTE_TIMEOUT) {
} else {
noTimeout = true;
}
if (noTimeout) {
debugger("Would block on a semaphore without timeout in a "
"single-threaded context!");
return B_ERROR;
}
status_t error = snooze_until(timeout, B_SYSTEM_TIMEBASE);
if (error != B_OK)
return error;
return B_TIMED_OUT;
}
status_t
release_sem(sem_id id)
{
return release_sem_etc(id, 1, 0);
}
status_t
release_sem_etc(sem_id id, int32 count, uint32 flags)
{
if (!check_sem(id))
return B_BAD_SEM_ID;
if (count <= 0)
return B_BAD_VALUE;
semaphore &sem = sSemaphores[id];
sem.count += count;
return B_OK;
}
status_t
get_sem_count(sem_id id, int32 *threadCount)
{
if (!check_sem(id))
return B_BAD_SEM_ID;
if (!threadCount)
return B_BAD_VALUE;
*threadCount = sSemaphores[id].count;
return B_OK;
}
status_t
set_sem_owner(sem_id id, team_id team)
{
if (!check_sem(id))
return B_BAD_SEM_ID;
return B_OK;
}
status_t
_get_sem_info(sem_id id, struct sem_info *info, size_t infoSize)
{
if (!check_sem(id))
return B_BAD_SEM_ID;
if (!info)
return B_BAD_VALUE;
info->sem = id;
info->team = 1;
strlcpy(info->name, sSemaphores[id].name, sizeof(info->name));
info->count = sSemaphores[id].count;
info->latest_holder = -1;
return B_OK;
}
status_t
_get_next_sem_info(team_id team, int32 *cookie, struct sem_info *info,
size_t infoSize)
{
if (team < 0 || team > 2)
return B_BAD_TEAM_ID;
for (int i = *cookie; i < kSemaphoreCount; i++) {
if (sSemaphores[i].inUse) {
*cookie = i + 1;
return _get_sem_info(i, info, infoSize);
}
}
return B_ENTRY_NOT_FOUND;
}