Added support for POSIX semaphores (the ones from the XSI extension

Realtime option group). The implementation should be complete, but is
totally untested yet.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25326 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-05-06 03:39:36 +00:00
parent 3bb3ab83a4
commit 5142c2ac86
13 changed files with 1010 additions and 5 deletions
+36
View File
@@ -0,0 +1,36 @@
/*
* Copyright 2008, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _SEMAPHORE_H_
#define _SEMAPHORE_H_
#include <sys/cdefs.h>
#include <time.h>
typedef struct {
int id;
} sem_t;
#define SEM_FAILED ((sem_t*)(long)-1)
__BEGIN_DECLS
sem_t* sem_open(const char* name, int openFlags,...);
int sem_close(sem_t* semaphore);
int sem_unlink(const char* name);
int sem_init(sem_t* semaphore, int shared, unsigned value);
int sem_destroy(sem_t* semaphore);
int sem_post(sem_t* semaphore);
int sem_timedwait(sem_t* semaphore, const struct timespec* timeout);
int sem_trywait(sem_t* semaphore);
int sem_wait(sem_t* semaphore);
int sem_getvalue(sem_t* semaphore, int* value);
__END_DECLS
#endif /* _SEMAPHORE_H_ */
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright 2008, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef KERNEL_REALTIME_SEM_H
#define KERNEL_REALTIME_SEM_H
#include <semaphore.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <OS.h>
struct realtime_sem_context;
__BEGIN_DECLS
void realtime_sem_init();
void delete_realtime_sem_context(struct realtime_sem_context* context);
struct realtime_sem_context* clone_realtime_sem_context(
struct realtime_sem_context* context);
status_t _user_realtime_sem_open(const char* name, int openFlags,
mode_t mode, uint32 semCount, sem_t* userSem,
sem_t** _usedUserSem);
status_t _user_realtime_sem_close(sem_id semID, sem_t** _deleteUserSem);
status_t _user_realtime_sem_unlink(const char* name);
status_t _user_realtime_sem_get_value(sem_id semID, int* value);
status_t _user_realtime_sem_post(sem_id semID);
status_t _user_realtime_sem_wait(sem_id semID, bigtime_t timeout);
__END_DECLS
#endif // KERNEL_REALTIME_SEM_H
+1 -1
View File
@@ -20,7 +20,7 @@ struct select_info;
extern "C" {
#endif
extern status_t sem_init(struct kernel_args *args);
extern status_t haiku_sem_init(struct kernel_args *args);
extern int sem_delete_owned_sems(team_id owner);
extern int32 sem_used_sems(void);
extern int32 sem_max_sems(void);
+13
View File
@@ -11,6 +11,7 @@
#include <OS.h>
#include <DiskDeviceDefs.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/socket.h>
@@ -75,6 +76,18 @@ extern status_t _kern_get_next_sem_info(team_id team, int32 *cookie,
struct sem_info *info, size_t size);
extern status_t _kern_set_sem_owner(sem_id id, team_id proc);
/* POSIX realtime sem syscalls */
extern status_t _kern_realtime_sem_open(const char* name, int openFlags,
mode_t mode, uint32 semCount, sem_t* userSem,
sem_t** _usedUserSem);
extern status_t _kern_realtime_sem_close(sem_id semID,
sem_t** _deleteUserSem);
extern status_t _kern_realtime_sem_unlink(const char* name);
extern status_t _kern_realtime_sem_get_value(sem_id semID, int* value);
extern status_t _kern_realtime_sem_post(sem_id semID);
extern status_t _kern_realtime_sem_wait(sem_id semID, bigtime_t timeout);
/* team & thread syscalls */
extern thread_id _kern_load_image(int32 argCount, const char **args,
+3 -2
View File
@@ -68,8 +68,8 @@ enum {
THREAD_BLOCK_TYPE_USER_BASE = 10000
};
struct image;
// defined in image.c
struct image; // defined in image.c
struct realtime_sem_context; // defined in realtime_sem.cpp
struct select_info;
struct death_entry {
@@ -181,6 +181,7 @@ struct team {
int state; // current team state, see above
int32 flags;
void *io_context;
struct realtime_sem_context *realtime_sem_context;
sem_id death_sem; // semaphore to wait on for dying threads
struct list dead_threads;
int dead_threads_count;
+1
View File
@@ -33,6 +33,7 @@ KernelMergeObject kernel_core.o :
Notifications.cpp
port.cpp
real_time_clock.c
realtime_sem.cpp
scheduler.cpp
sem.cpp
shutdown.c
+3 -1
View File
@@ -33,6 +33,7 @@
#include <Notifications.h>
#include <port.h>
#include <real_time_clock.h>
#include <realtime_sem.h>
#include <sem.h>
#include <smp.h>
#include <system_info.h>
@@ -137,7 +138,7 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
rtc_init(&sKernelArgs);
TRACE("init semaphores\n");
sem_init(&sKernelArgs);
haiku_sem_init(&sKernelArgs);
condition_variable_init();
// now we can create and use semaphores
@@ -158,6 +159,7 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
TRACE("init kernel daemons\n");
kernel_daemon_init();
arch_platform_init_post_thread(&sKernelArgs);
realtime_sem_init();
TRACE("init VM threads\n");
vm_init_post_thread(&sKernelArgs);
+758
View File
@@ -0,0 +1,758 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <realtime_sem.h>
#include <string.h>
#include <new>
#include <OS.h>
#include <AutoDeleter.h>
#include <fs/KPath.h>
#include <kernel.h>
#include <lock.h>
#include <syscall_restart.h>
#include <team.h>
#include <thread.h>
#include <util/atomic.h>
#include <util/AutoLock.h>
#include <util/khash.h>
#include <util/OpenHashTable.h>
class SemInfo {
public:
SemInfo()
:
fName(NULL),
fRefCount(1),
fID(-1)
{
}
~SemInfo()
{
free(fName);
if (fID >= 0)
delete_sem(fID);
}
const char* Name() const { return fName; }
sem_id ID() const { return fID; }
status_t Init(const char* name, mode_t mode, int32 semCount)
{
fName = strdup(name);
if (fName == NULL)
return B_NO_MEMORY;
fID = create_sem(semCount, name);
if (fID < 0)
return fID;
fUID = geteuid();
fGID = getegid();
fPermissions = mode;
return B_OK;
}
void AcquireReference()
{
atomic_add(&fRefCount, 1);
}
void ReleaseReference()
{
if (atomic_add(&fRefCount, -1) == 1)
delete this;
}
bool HasPermissions() const
{
if ((fPermissions & S_IWOTH) != 0)
return true;
uid_t uid = geteuid();
if (uid == 0 || (uid == fUID && (fPermissions & S_IWUSR) != 0))
return true;
gid_t gid = getegid();
if (gid == fGID && (fPermissions & S_IWGRP) != 0)
return true;
return false;
}
HashTableLink<SemInfo>* HashTableLink()
{
return &fHashLink;
}
private:
char* fName;
vint32 fRefCount;
sem_id fID;
uid_t fUID;
gid_t fGID;
mode_t fPermissions;
::HashTableLink<SemInfo> fHashLink;
};
struct NamedSemHashDefinition {
typedef const char* KeyType;
typedef SemInfo ValueType;
size_t HashKey(const KeyType& key) const
{
return hash_hash_string(key);
}
size_t Hash(SemInfo* semaphore) const
{
return HashKey(semaphore->Name());
}
bool Compare(const KeyType& key, SemInfo* semaphore) const
{
return strcmp(key, semaphore->Name()) == 0;
}
HashTableLink<SemInfo>* GetLink(SemInfo* semaphore) const
{
return semaphore->HashTableLink();
}
};
class GlobalRealtimeSemTable {
public:
GlobalRealtimeSemTable()
{
mutex_init(&fLock, "global realtime sem table");
}
~GlobalRealtimeSemTable()
{
mutex_destroy(&fLock);
}
status_t Init()
{
return fSemaphores.InitCheck();
}
status_t OpenSem(const char* name, int openFlags, mode_t mode,
uint32 semCount, SemInfo*& _sem, bool& _created)
{
MutexLocker _(fLock);
SemInfo* sem = fSemaphores.Lookup(name);
if (sem != NULL) {
if ((openFlags & O_EXCL) != 0)
return EEXIST;
if (!sem->HasPermissions())
return EACCES;
sem->AcquireReference();
_sem = sem;
_created = false;
return B_OK;
}
if ((openFlags & O_CREAT) == 0)
return ENOENT;
// does not exist yet -- create
sem = new(std::nothrow) SemInfo;
if (sem == NULL)
return B_NO_MEMORY;
status_t error = sem->Init(name, mode, semCount);
if (error != B_OK) {
delete sem;
return error;
}
error = fSemaphores.Insert(sem);
if (error != B_OK) {
delete sem;
return error;
}
// add one reference for the table
sem->AcquireReference();
_sem = sem;
_created = true;
return B_OK;
}
status_t UnlinkSem(const char* name)
{
MutexLocker _(fLock);
SemInfo* sem = fSemaphores.Lookup(name);
if (sem == NULL)
return ENOENT;
if (!sem->HasPermissions())
return EACCES;
fSemaphores.Remove(sem);
sem->ReleaseReference();
// release the table reference
return B_OK;
}
private:
typedef OpenHashTable<NamedSemHashDefinition, true> SemTable;
mutex fLock;
SemTable fSemaphores;
};
static GlobalRealtimeSemTable sSemTable;
class TeamSemInfo {
public:
TeamSemInfo(SemInfo* semaphore, sem_t* userSem)
:
fSemaphore(semaphore),
fUserSemaphore(userSem),
fOpenCount(1)
{
}
~TeamSemInfo()
{
if (fSemaphore != NULL)
fSemaphore->ReleaseReference();
}
SemInfo* Semaphore() const { return fSemaphore; }
sem_t* UserSemaphore() const { return fUserSemaphore; }
void Open()
{
fOpenCount++;
}
bool Close()
{
return --fOpenCount == 0;
}
TeamSemInfo* Clone() const
{
TeamSemInfo* sem = new(std::nothrow) TeamSemInfo(fSemaphore,
fUserSemaphore);
if (sem == NULL)
return NULL;
sem->fOpenCount = fOpenCount;
fSemaphore->AcquireReference();
return sem;
}
HashTableLink<TeamSemInfo>* HashTableLink()
{
return &fHashLink;
}
private:
SemInfo* fSemaphore;
sem_t* fUserSemaphore;
int32 fOpenCount;
::HashTableLink<TeamSemInfo> fHashLink;
};
struct TeamSemHashDefinition {
typedef sem_id KeyType;
typedef TeamSemInfo ValueType;
size_t HashKey(const KeyType& key) const
{
return (size_t)key;
}
size_t Hash(TeamSemInfo* semaphore) const
{
return HashKey(semaphore->Semaphore()->ID());
}
bool Compare(const KeyType& key, TeamSemInfo* semaphore) const
{
return key == semaphore->Semaphore()->ID();
}
HashTableLink<TeamSemInfo>* GetLink(TeamSemInfo* semaphore) const
{
return semaphore->HashTableLink();
}
};
struct realtime_sem_context {
realtime_sem_context()
{
mutex_init(&fLock, "realtime sem context");
}
~realtime_sem_context()
{
mutex_lock(&fLock);
// delete all semaphores.
SemTable::Iterator it = fSemaphores.GetIterator();
while (TeamSemInfo* sem = it.Next()) {
// Note, this uses internal knowledge about how the iterator works.
// Ugly, but there's no good alternative.
fSemaphores.RemoveUnchecked(sem);
delete sem;
}
mutex_destroy(&fLock);
}
status_t Init()
{
return fSemaphores.InitCheck();
}
realtime_sem_context* Clone()
{
// create new context
realtime_sem_context* context = new(std::nothrow) realtime_sem_context;
if (context == NULL)
return NULL;
ObjectDeleter<realtime_sem_context> contextDeleter(context);
MutexLocker _(fLock);
// clone all semaphores
SemTable::Iterator it = fSemaphores.GetIterator();
while (TeamSemInfo* sem = it.Next()) {
TeamSemInfo* clonedSem = sem->Clone();
if (clonedSem == NULL)
return NULL;
if (context->fSemaphores.Insert(clonedSem) != B_OK) {
delete clonedSem;
return NULL;
}
}
contextDeleter.Detach();
return context;
}
status_t CreateAnonymousSem(uint32 semCount, int& _id)
{
SemInfo* sem = new(std::nothrow) SemInfo;
if (sem == NULL)
return B_NO_MEMORY;
ObjectDeleter<SemInfo> semDeleter(sem);
status_t error = sem->Init(NULL, 0, semCount);
if (error != B_OK) {
delete sem;
return error;
}
TeamSemInfo* teamSem = new(std::nothrow) TeamSemInfo(sem, NULL);
if (teamSem == NULL)
return B_NO_MEMORY;
semDeleter.Detach();
MutexLocker _(fLock);
error = fSemaphores.Insert(teamSem);
if (error != B_OK) {
delete teamSem;
return error;
}
_id = teamSem->Semaphore()->ID();
return B_OK;
}
status_t OpenSem(const char* name, int openFlags, mode_t mode,
uint32 semCount, sem_t* userSem, sem_t*& _usedUserSem, int& _id,
bool& _created)
{
SemInfo* sem;
status_t error = sSemTable.OpenSem(name, openFlags, mode, semCount,
sem, _created);
if (error != B_OK)
return error;
MutexLocker _(fLock);
TeamSemInfo* teamSem = fSemaphores.Lookup(sem->ID());
if (teamSem != NULL) {
// already open -- just increment the open count
teamSem->Open();
sem->ReleaseReference();
_usedUserSem = teamSem->UserSemaphore();
_id = teamSem->Semaphore()->ID();
return B_OK;
}
// not open yet -- create a new team sem
teamSem = new(std::nothrow) TeamSemInfo(sem, NULL);
if (teamSem == NULL) {
sem->ReleaseReference();
return B_NO_MEMORY;
}
error = fSemaphores.Insert(teamSem);
if (error != B_OK) {
delete teamSem;
return error;
}
_usedUserSem = teamSem->UserSemaphore();
_id = teamSem->Semaphore()->ID();
return B_OK;
}
status_t CloseSem(sem_id id, sem_t*& deleteUserSem)
{
deleteUserSem = NULL;
MutexLocker _(fLock);
TeamSemInfo* sem = fSemaphores.Lookup(id);
if (sem == NULL)
return B_BAD_VALUE;
if (sem->Close()) {
// last reference closed
fSemaphores.Remove(sem);
deleteUserSem = sem->UserSemaphore();
delete sem;
}
return B_OK;
}
status_t AcquireSem(sem_id id, bigtime_t timeout)
{
MutexLocker locker(fLock);
if (fSemaphores.Lookup(id) == NULL)
return B_BAD_VALUE;
locker.Unlock();
status_t error;
if (timeout == 0) {
error = acquire_sem_etc(id, 1, B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT,
0);
} else if (timeout == B_INFINITE_TIMEOUT) {
error = acquire_sem_etc(id, 1, B_CAN_INTERRUPT, 0);
} else {
error = acquire_sem_etc(id, 1, B_CAN_INTERRUPT | B_ABSOLUTE_TIMEOUT,
timeout);
}
return error == B_BAD_SEM_ID ? B_BAD_VALUE : error;
}
status_t ReleaseSem(sem_id id)
{
MutexLocker locker(fLock);
if (fSemaphores.Lookup(id) == NULL)
return B_BAD_VALUE;
locker.Unlock();
status_t error = release_sem(id);
return error == B_BAD_SEM_ID ? B_BAD_VALUE : error;
}
status_t GetSemCount(sem_id id, int& _count)
{
MutexLocker locker(fLock);
if (fSemaphores.Lookup(id) == NULL)
return B_BAD_VALUE;
locker.Unlock();
int32 count;
status_t error = get_sem_count(id, &count);
if (error != B_OK)
return error;
_count = count;
return B_OK;
}
private:
typedef OpenHashTable<TeamSemHashDefinition, true> SemTable;
mutex fLock;
SemTable fSemaphores;
};
// #pragma mark - implementation private
static realtime_sem_context*
get_current_team_context()
{
struct team* team = thread_get_current_thread()->team;
// get context
realtime_sem_context* context = atomic_pointer_get(
&team->realtime_sem_context);
if (context != NULL)
return context;
// no context yet -- create a new one
context = new(std::nothrow) realtime_sem_context;
if (context == NULL || context->Init() != B_OK) {
delete context;
return NULL;
}
// set the allocated context
realtime_sem_context* oldContext = atomic_pointer_test_and_set(
&team->realtime_sem_context, context, (realtime_sem_context*)NULL);
if (oldContext == NULL)
return context;
// someone else was quicker
delete context;
return oldContext;
}
static status_t
copy_sem_name_to_kernel(const char* userName, KPath& buffer, char*& name)
{
if (userName == NULL)
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(userName))
return B_BAD_ADDRESS;
if (buffer.InitCheck() != B_OK)
return B_NO_MEMORY;
// copy userland path to kernel
name = buffer.LockBuffer();
ssize_t actualLength = user_strlcpy(name, userName, buffer.BufferSize());
if (actualLength < 0)
return B_BAD_ADDRESS;
if ((size_t)actualLength >= buffer.BufferSize())
return ENAMETOOLONG;
return B_OK;
}
// #pragma mark - kernel internal
void
realtime_sem_init()
{
new(&sSemTable) GlobalRealtimeSemTable;
if (sSemTable.Init() != B_OK)
panic("realtime_sem_init() failed to init global table");
}
void
delete_realtime_sem_context(realtime_sem_context* context)
{
delete context;
}
realtime_sem_context*
clone_realtime_sem_context(realtime_sem_context* context)
{
if (context == NULL)
return NULL;
return context->Clone();
}
// #pragma mark - syscalls
status_t
_user_realtime_sem_open(const char* userName, int openFlags, mode_t mode,
uint32 semCount, sem_t* userSem, sem_t** _usedUserSem)
{
realtime_sem_context* context = get_current_team_context();
if (context == NULL)
return B_NO_MEMORY;
// userSem must always be given
if (userSem == NULL)
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(userSem))
return B_BAD_ADDRESS;
// anonymous semaphores are less work -- deal with them first
if (userName == NULL) {
int id;
status_t error = context->CreateAnonymousSem(semCount, id);
if (error != B_OK)
return error;
if (user_memcpy(&userSem->id, &id, sizeof(int)) != B_OK) {
sem_t* dummy;
context->CloseSem(id, dummy);
return B_BAD_ADDRESS;
}
return B_OK;
}
// check user pointers
if (_usedUserSem == NULL)
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(_usedUserSem) || !IS_USER_ADDRESS(userName))
return B_BAD_ADDRESS;
// copy name to kernel
KPath nameBuffer(B_PATH_NAME_LENGTH);
char* name;
status_t error = copy_sem_name_to_kernel(userName, nameBuffer, name);
if (error != B_OK)
return error;
// open the semaphore
sem_t* usedUserSem;
bool created;
int id;
error = context->OpenSem(name, openFlags, mode, semCount, userSem,
usedUserSem, id, created);
if (error != B_OK)
return error;
// copy results back to userland
if (user_memcpy(&userSem->id, &id, sizeof(int)) != B_OK
|| user_memcpy(_usedUserSem, &usedUserSem, sizeof(sem_t*)) != B_OK) {
if (created)
sSemTable.UnlinkSem(name);
sem_t* dummy;
context->CloseSem(id, dummy);
return B_BAD_ADDRESS;
}
return B_OK;
}
status_t
_user_realtime_sem_close(sem_id semID, sem_t** _deleteUserSem)
{
if (_deleteUserSem != NULL && !IS_USER_ADDRESS(_deleteUserSem))
return B_BAD_ADDRESS;
realtime_sem_context* context = get_current_team_context();
if (context == NULL)
return B_BAD_VALUE;
// close sem
sem_t* deleteUserSem;
status_t error = context->CloseSem(semID, deleteUserSem);
if (error != B_OK)
return error;
// copy back result to userland
if (_deleteUserSem != NULL
&& user_memcpy(_deleteUserSem, &deleteUserSem, sizeof(sem_t*))
!= B_OK) {
return B_BAD_ADDRESS;
}
return B_OK;
}
status_t
_user_realtime_sem_unlink(const char* userName)
{
// copy name to kernel
KPath nameBuffer(B_PATH_NAME_LENGTH);
char* name;
status_t error = copy_sem_name_to_kernel(userName, nameBuffer, name);
if (error != B_OK)
return error;
return sSemTable.UnlinkSem(name);
}
status_t
_user_realtime_sem_get_value(sem_id semID, int* _value)
{
if (_value == NULL)
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(_value))
return B_BAD_ADDRESS;
realtime_sem_context* context = get_current_team_context();
if (context == NULL)
return B_BAD_VALUE;
// get sem count
int count;
status_t error = context->GetSemCount(semID, count);
if (error != B_OK)
return error;
// copy back result to userland
if (user_memcpy(_value, &count, sizeof(int)) != B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
status_t
_user_realtime_sem_post(sem_id semID)
{
realtime_sem_context* context = get_current_team_context();
if (context == NULL)
return B_BAD_VALUE;
return context->ReleaseSem(semID);
}
status_t
_user_realtime_sem_wait(sem_id semID, bigtime_t timeout)
{
realtime_sem_context* context = get_current_team_context();
if (context == NULL)
return B_BAD_VALUE;
return syscall_restart_handle_post(context->AcquireSem(semID, timeout));
}
+1 -1
View File
@@ -301,7 +301,7 @@ fill_sem_info(struct sem_entry *sem, sem_info *info, size_t size)
status_t
sem_init(kernel_args *args)
haiku_sem_init(kernel_args *args)
{
area_id area;
int32 i;
+1
View File
@@ -16,6 +16,7 @@
#include <vfs.h>
#include <vm.h>
#include <thread.h>
#include <realtime_sem.h>
#include <sem.h>
#include <port.h>
#include <cpu.h>
+17
View File
@@ -26,6 +26,7 @@
#include <kscheduler.h>
#include <ksignal.h>
#include <port.h>
#include <realtime_sem.h>
#include <sem.h>
#include <syscall_process_info.h>
#include <syscall_restart.h>
@@ -822,6 +823,7 @@ create_team_struct(const char *name, bool kernel)
team->num_threads = 0;
team->io_context = NULL;
team->address_space = NULL;
team->realtime_sem_context = NULL;
team->thread_list = NULL;
team->main_thread = NULL;
team->loading_info = NULL;
@@ -1365,6 +1367,8 @@ exec_team(const char *path, int32 argCount, char * const *args,
sem_delete_owned_sems(team->id);
remove_images(team);
vfs_exec_io_context(team->io_context);
delete_realtime_sem_context(team->realtime_sem_context);
team->realtime_sem_context = NULL;
user_debug_finish_after_exec();
@@ -1485,6 +1489,16 @@ fork_team(void)
goto err2;
}
// duplicate the realtime sem context
if (parentTeam->realtime_sem_context) {
team->realtime_sem_context = clone_realtime_sem_context(
parentTeam->realtime_sem_context);
if (team->realtime_sem_context == NULL) {
status = B_NO_MEMORY;
goto err25;
}
}
// create an address space for this team
status = vm_create_address_space(team->id, USER_BASE, USER_SIZE, false,
&team->address_space);
@@ -1540,6 +1554,8 @@ fork_team(void)
err4:
vm_delete_address_space(team->address_space);
err3:
delete_realtime_sem_context(team->realtime_sem_context);
err25:
vfs_free_io_context(team->io_context);
err2:
free(forkArgs);
@@ -2327,6 +2343,7 @@ team_delete_team(struct team *team)
// free team resources
vfs_free_io_context(team->io_context);
delete_realtime_sem_context(team->realtime_sem_context);
delete_owned_ports(teamID);
sem_delete_owned_sems(teamID);
remove_images(team);
+1
View File
@@ -18,6 +18,7 @@ MergeObject posix_main.o :
inttypes.c
poll.c
$(PWD_BACKEND)
semaphore.cpp
syslog.cpp
termios.c
utime.c
+137
View File
@@ -0,0 +1,137 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <semaphore.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <OS.h>
#include <AutoDeleter.h>
#include <realtime_sem.h>
#include <syscall_utils.h>
#include <syscalls.h>
sem_t*
sem_open(const char* name, int openFlags,...)
{
if (name == NULL) {
errno = B_BAD_VALUE;
return SEM_FAILED;
}
// get the mode and semaphore count parameters, if O_CREAT is specified
mode_t mode = 0;
unsigned semCount = 0;
if ((openFlags & O_CREAT) != 0) {
va_list args;
va_start(args, openFlags);
mode = va_arg(args, mode_t);
semCount = va_arg(args, unsigned);
va_end(args);
}
// Allocate a sem_t structure -- we don't know, whether this is the first
// call of this process to open the semaphore. If it is, we will keep the
// structure, otherwise we will delete it later.
sem_t* sem = (sem_t*)malloc(sizeof(sem_t));
if (sem == NULL) {
errno = B_NO_MEMORY;
return SEM_FAILED;
}
MemoryDeleter semDeleter(sem);
// ask the kernel to open the semaphore
sem_t* usedSem;
status_t error = _kern_realtime_sem_open(name, openFlags, mode, semCount,
sem, &usedSem);
if (error != B_OK) {
errno = error;
return SEM_FAILED;
}
if (usedSem == sem)
semDeleter.Detach();
return usedSem;
}
int
sem_close(sem_t* semaphore)
{
sem_t* deleteSem = NULL;
status_t error = _kern_realtime_sem_close(semaphore->id, &deleteSem);
if (error == B_OK)
free(deleteSem);
RETURN_AND_SET_ERRNO(error);
}
int
sem_unlink(const char* name)
{
RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name));
}
int
sem_init(sem_t* semaphore, int shared, unsigned value)
{
RETURN_AND_SET_ERRNO(_kern_realtime_sem_open(NULL, 0, 0, value, semaphore,
NULL));
}
int
sem_destroy(sem_t* semaphore)
{
RETURN_AND_SET_ERRNO(_kern_realtime_sem_close(semaphore->id, NULL));
}
int
sem_post(sem_t* semaphore)
{
RETURN_AND_SET_ERRNO(_kern_realtime_sem_post(semaphore->id));
}
int
sem_timedwait(sem_t* semaphore, const struct timespec* timeout)
{
bigtime_t timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000
+ timeout->tv_nsec / 1000;
RETURN_AND_SET_ERRNO(_kern_realtime_sem_wait(semaphore->id, timeoutMicros));
}
int
sem_trywait(sem_t* semaphore)
{
RETURN_AND_SET_ERRNO(_kern_realtime_sem_wait(semaphore->id, 0));
}
int
sem_wait(sem_t* semaphore)
{
RETURN_AND_SET_ERRNO(_kern_realtime_sem_wait(semaphore->id,
B_INFINITE_TIMEOUT));
}
int
sem_getvalue(sem_t* semaphore, int* value)
{
RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value(semaphore->id, value));
}