⛏️ index : haiku.git


#include <BeOSBuildCompatibility.h>

#include <stdlib.h>
#include <string.h>

#include <OS.h>
#include <SupportDefs.h>

// We assume that everything is single-threaded, so we don't need real

// semaphores. Simple fakes are sufficient.


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;
}

// create_sem

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;
}

// delete_sem

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;
}

// acquire_sem

status_t
acquire_sem(sem_id id)
{
	return acquire_sem_etc(id, 1, 0, 0);
}

// acquire_sem_etc

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) {
		// relative timeout: get the absolute time when to time out


		// special case: on timeout == 0 we return B_WOULD_BLOCK

		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) {
		// absolute timeout

	} else {
		// no timeout given

		noTimeout = true;
	}

	// no timeout?

	if (noTimeout) {
		debugger("Would block on a semaphore without timeout in a "
			"single-threaded context!");
		return B_ERROR;
	}

	// wait for the time out time

	status_t error = snooze_until(timeout, B_SYSTEM_TIMEBASE);
	if (error != B_OK)
		return error;

	return B_TIMED_OUT;
}

// release_sem

status_t
release_sem(sem_id id)
{
	return release_sem_etc(id, 1, 0);
}

// release_sem_etc

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;
}

// get_sem_count

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;
}

// set_sem_owner

status_t
set_sem_owner(sem_id id, team_id team)
{
	if (!check_sem(id))
		return B_BAD_SEM_ID;

	return B_OK;
}

// _get_sem_info

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;
}

// _get_next_sem_info

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;
}