diff --git a/headers/posix/semaphore.h b/headers/posix/semaphore.h new file mode 100644 index 0000000000..e8013f5ddb --- /dev/null +++ b/headers/posix/semaphore.h @@ -0,0 +1,36 @@ +/* + * Copyright 2008, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _SEMAPHORE_H_ +#define _SEMAPHORE_H_ + +#include +#include + + +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_ */ diff --git a/headers/private/kernel/realtime_sem.h b/headers/private/kernel/realtime_sem.h new file mode 100644 index 0000000000..04a5dd5033 --- /dev/null +++ b/headers/private/kernel/realtime_sem.h @@ -0,0 +1,38 @@ +/* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_REALTIME_SEM_H +#define KERNEL_REALTIME_SEM_H + +#include +#include +#include + +#include + + +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 diff --git a/headers/private/kernel/sem.h b/headers/private/kernel/sem.h index 6132125167..e6e51cd75d 100644 --- a/headers/private/kernel/sem.h +++ b/headers/private/kernel/sem.h @@ -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); diff --git a/headers/private/kernel/syscalls.h b/headers/private/kernel/syscalls.h index 4a3d622cbe..227ac2bfb7 100644 --- a/headers/private/kernel/syscalls.h +++ b/headers/private/kernel/syscalls.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -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, diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index bba4fee42e..ec88ba8fab 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -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; diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile index bc311f0fd1..af9f2a93cb 100644 --- a/src/system/kernel/Jamfile +++ b/src/system/kernel/Jamfile @@ -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 diff --git a/src/system/kernel/main.c b/src/system/kernel/main.c index 4170cfe1ac..fcd9d9510e 100644 --- a/src/system/kernel/main.c +++ b/src/system/kernel/main.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/src/system/kernel/realtime_sem.cpp b/src/system/kernel/realtime_sem.cpp new file mode 100644 index 0000000000..51d6314230 --- /dev/null +++ b/src/system/kernel/realtime_sem.cpp @@ -0,0 +1,758 @@ +/* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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* HashTableLink() + { + return &fHashLink; + } + +private: + char* fName; + vint32 fRefCount; + sem_id fID; + uid_t fUID; + gid_t fGID; + mode_t fPermissions; + + ::HashTableLink 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* 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 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* HashTableLink() + { + return &fHashLink; + } + +private: + SemInfo* fSemaphore; + sem_t* fUserSemaphore; + int32 fOpenCount; + + ::HashTableLink 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* 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 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 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 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)); +} diff --git a/src/system/kernel/sem.cpp b/src/system/kernel/sem.cpp index fdcaeda3e6..732d81b647 100644 --- a/src/system/kernel/sem.cpp +++ b/src/system/kernel/sem.cpp @@ -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; diff --git a/src/system/kernel/syscalls.cpp b/src/system/kernel/syscalls.cpp index 079d4b7376..1fab5e86ff 100644 --- a/src/system/kernel/syscalls.cpp +++ b/src/system/kernel/syscalls.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index 27265ebbfe..fcbccfc826 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/src/system/libroot/posix/Jamfile b/src/system/libroot/posix/Jamfile index 81b0fc1a47..087de76200 100644 --- a/src/system/libroot/posix/Jamfile +++ b/src/system/libroot/posix/Jamfile @@ -18,6 +18,7 @@ MergeObject posix_main.o : inttypes.c poll.c $(PWD_BACKEND) + semaphore.cpp syslog.cpp termios.c utime.c diff --git a/src/system/libroot/posix/semaphore.cpp b/src/system/libroot/posix/semaphore.cpp new file mode 100644 index 0000000000..40f0788ae4 --- /dev/null +++ b/src/system/libroot/posix/semaphore.cpp @@ -0,0 +1,137 @@ +/* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + + +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)); +}