Ticket #11208: 0001-Reimplement-unnamed-POSIX-semaphores-using-user_mute.patch
File 0001-Reimplement-unnamed-POSIX-semaphores-using-user_mute.patch, 21.2 KB (added by , 9 years ago) |
---|
-
headers/posix/semaphore.h
From c41b98dc79decc8e440c877194060cd277d44794 Mon Sep 17 00:00:00 2001 From: Hamish Morrison <hamishm53@gmail.com> Date: Mon, 11 May 2015 21:14:52 +0100 Subject: [PATCH] Reimplement unnamed POSIX semaphores using user_mutex * Fixes sharing semantics, so non-shared semaphores in non-shared memory do not become shared after a fork. * Adds two new system calls: _user_mutex_sem_acquire/release(), which reuse the user_mutex address-hashed wait mechanism. * Named semaphores continue to use traditional sem_id semaphores. --- headers/posix/semaphore.h | 10 +- headers/private/kernel/user_mutex.h | 3 + headers/private/system/syscalls.h | 3 + src/system/kernel/locks/user_mutex.cpp | 164 ++++++++++++++++--- src/system/kernel/posix/realtime_sem.cpp | 259 ++----------------------------- src/system/libroot/posix/semaphore.cpp | 138 ++++++++++++++-- 6 files changed, 286 insertions(+), 291 deletions(-) diff --git a/headers/posix/semaphore.h b/headers/posix/semaphore.h index 6be5f81..0501830 100644
a b 1 1 /* 2 * Copyright 2008-201 2Haiku, Inc.2 * Copyright 2008-2015 Haiku, Inc. 3 3 * Distributed under the terms of the MIT License. 4 4 */ 5 5 #ifndef _SEMAPHORE_H_ … … 13 13 14 14 15 15 typedef struct _sem_t { 16 int32_t id; 17 int32_t _padding[3]; 16 int32_t type; 17 union { 18 int32_t named_sem_id; 19 int32_t unnamed_sem; 20 } u; 21 int32_t padding[2]; 18 22 } sem_t; 19 23 20 24 #define SEM_FAILED ((sem_t*)(long)-1) -
headers/private/kernel/user_mutex.h
diff --git a/headers/private/kernel/user_mutex.h b/headers/private/kernel/user_mutex.h index a2eacd7..b0594eb 100644
a b status_t _user_mutex_lock(int32* mutex, const char* name, uint32 flags, 20 20 status_t _user_mutex_unlock(int32* mutex, uint32 flags); 21 21 status_t _user_mutex_switch_lock(int32* fromMutex, int32* toMutex, 22 22 const char* name, uint32 flags, bigtime_t timeout); 23 status_t _user_mutex_sem_acquire(int32* sem, const char* name, uint32 flags, 24 bigtime_t timeout); 25 status_t _user_mutex_sem_release(int32* sem); 23 26 24 27 #ifdef __cplusplus 25 28 } -
headers/private/system/syscalls.h
diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index 51a5213..ebfd106 100644
a b extern status_t _kern_mutex_lock(int32* mutex, const char* name, 79 79 extern status_t _kern_mutex_unlock(int32* mutex, uint32 flags); 80 80 extern status_t _kern_mutex_switch_lock(int32* fromMutex, int32* toMutex, 81 81 const char* name, uint32 flags, bigtime_t timeout); 82 extern status_t _kern_mutex_sem_acquire(int32* sem, const char* name, 83 uint32 flags, bigtime_t timeout); 84 extern status_t _kern_mutex_sem_release(int32* sem); 82 85 83 86 /* sem functions */ 84 87 extern sem_id _kern_create_sem(int count, const char *name); -
src/system/kernel/locks/user_mutex.cpp
diff --git a/src/system/kernel/locks/user_mutex.cpp b/src/system/kernel/locks/user_mutex.cpp index c89f7f5..89414ff 100644
a b 1 1 /* 2 * Copyright 2015, Hamish Morrison, hamishm53@gmail.com. 2 3 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3 4 * Distributed under the terms of the MIT License. 4 5 */ … … remove_user_mutex_entry(UserMutexEntry* entry) 99 100 100 101 101 102 static status_t 102 user_mutex_ lock_locked(int32* mutex, addr_t physicalAddress, const char* name,103 uint32 flags, bigtime_t timeout, MutexLocker& locker )103 user_mutex_wait_locked(int32* mutex, addr_t physicalAddress, const char* name, 104 uint32 flags, bigtime_t timeout, MutexLocker& locker, bool& lastWaiter) 104 105 { 105 // mark the mutex locked + waiting106 int32 oldValue = atomic_or(mutex,107 B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING);108 109 // The mutex might have been unlocked (or disabled) in the meantime.110 if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0111 || (oldValue & B_USER_MUTEX_DISABLED) != 0) {112 // clear the waiting flag and be done113 atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);114 return B_OK;115 }116 117 // we have to wait118 119 106 // add the entry to the table 120 107 UserMutexEntry entry; 121 108 entry.address = physicalAddress; … … user_mutex_lock_locked(int32* mutex, addr_t physicalAddress, const char* name, 131 118 status_t error = waitEntry.Wait(flags, timeout); 132 119 locker.Lock(); 133 120 134 // dequeue if we weren't woken up 135 if (!entry.locked && !remove_user_mutex_entry(&entry)) { 136 // no one is waiting anymore -- clear the waiting flag 137 atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 121 if (error != B_OK && entry.locked) 122 error = B_OK; 123 124 if (!entry.locked) { 125 // if nobody woke us up, we have to dequeue ourselves 126 lastWaiter = !remove_user_mutex_entry(&entry); 127 } else { 128 // otherwise the waker has done the work of marking the 129 // mutex or semaphore uncontended 130 lastWaiter = false; 138 131 } 139 132 140 if (error != B_OK 141 && (entry.locked || (*mutex & B_USER_MUTEX_DISABLED) != 0)) { 142 // timeout or interrupt, but the mutex was unlocked or disabled in time 143 error = B_OK; 133 return error; 134 } 135 136 137 static status_t 138 user_mutex_lock_locked(int32* mutex, addr_t physicalAddress, 139 const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) 140 { 141 // mark the mutex locked + waiting 142 int32 oldValue = atomic_or(mutex, 143 B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING); 144 145 if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0 146 || (oldValue & B_USER_MUTEX_DISABLED) != 0) { 147 // clear the waiting flag and be done 148 atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 149 return B_OK; 144 150 } 145 151 152 bool lastWaiter; 153 status_t error = user_mutex_wait_locked(mutex, physicalAddress, name, 154 flags, timeout, locker, lastWaiter); 155 156 if (lastWaiter) 157 atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 158 146 159 return error; 147 160 } 148 161 … … user_mutex_unlock_locked(int32* mutex, addr_t physicalAddress, uint32 flags) 186 199 187 200 188 201 static status_t 202 user_mutex_sem_acquire_locked(int32* sem, addr_t physicalAddress, 203 const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) 204 { 205 // The semaphore may have been released in the meantime, and we also 206 // need to mark it as contended if it isn't already. 207 int32 oldValue = atomic_get(sem); 208 while (oldValue > -1) { 209 int32 value = atomic_test_and_set(sem, oldValue - 1, oldValue); 210 if (value == oldValue && value > 0) 211 return B_OK; 212 oldValue = value; 213 } 214 215 bool lastWaiter; 216 status_t error = user_mutex_wait_locked(sem, physicalAddress, name, flags, 217 timeout, locker, lastWaiter); 218 219 if (lastWaiter) 220 atomic_test_and_set(sem, 0, -1); 221 222 return error; 223 } 224 225 226 static void 227 user_mutex_sem_release_locked(int32* sem, addr_t physicalAddress) 228 { 229 UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress); 230 if (!entry) { 231 // no waiters - mark as uncontended and release 232 int32 oldValue = atomic_get(sem); 233 while (true) { 234 int32 inc = oldValue < 0 ? 2 : 1; 235 int32 value = atomic_test_and_set(sem, oldValue + inc, oldValue); 236 if (value == oldValue) 237 return; 238 oldValue = value; 239 } 240 } 241 242 bool otherWaiters = remove_user_mutex_entry(entry); 243 244 entry->locked = true; 245 entry->condition.NotifyOne(); 246 247 if (!otherWaiters) { 248 // mark the semaphore uncontended 249 atomic_test_and_set(sem, 0, -1); 250 } 251 } 252 253 254 static status_t 189 255 user_mutex_lock(int32* mutex, const char* name, uint32 flags, bigtime_t timeout) 190 256 { 191 257 // wire the page and get the physical address … … _user_mutex_switch_lock(int32* fromMutex, int32* toMutex, const char* name, 312 378 return user_mutex_switch_lock(fromMutex, toMutex, name, 313 379 flags | B_CAN_INTERRUPT, timeout); 314 380 } 381 382 383 status_t 384 _user_mutex_sem_acquire(int32* sem, const char* name, uint32 flags, 385 bigtime_t timeout) 386 { 387 if (sem == NULL || !IS_USER_ADDRESS(sem) || (addr_t)sem % 4 != 0) 388 return B_BAD_ADDRESS; 389 390 syscall_restart_handle_timeout_pre(flags, timeout); 391 392 // wire the page and get the physical address 393 VMPageWiringInfo wiringInfo; 394 status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)sem, true, 395 &wiringInfo); 396 if (error != B_OK) 397 return error; 398 399 { 400 MutexLocker locker(sUserMutexTableLock); 401 error = user_mutex_sem_acquire_locked(sem, wiringInfo.physicalAddress, 402 name, flags | B_CAN_INTERRUPT, timeout, locker); 403 } 404 405 vm_unwire_page(&wiringInfo); 406 return syscall_restart_handle_timeout_post(error, timeout); 407 } 408 409 410 status_t 411 _user_mutex_sem_release(int32* sem) 412 { 413 if (sem == NULL || !IS_USER_ADDRESS(sem) || (addr_t)sem % 4 != 0) 414 return B_BAD_ADDRESS; 415 416 // wire the page and get the physical address 417 VMPageWiringInfo wiringInfo; 418 status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)sem, true, 419 &wiringInfo); 420 if (error != B_OK) 421 return error; 422 423 { 424 MutexLocker locker(sUserMutexTableLock); 425 user_mutex_sem_release_locked(sem, wiringInfo.physicalAddress); 426 } 427 428 vm_unwire_page(&wiringInfo); 429 return B_OK; 430 } -
src/system/kernel/posix/realtime_sem.cpp
diff --git a/src/system/kernel/posix/realtime_sem.cpp b/src/system/kernel/posix/realtime_sem.cpp index 41766f8..c6442ab 100644
a b private: 150 150 }; 151 151 152 152 153 class UnnamedSem : public SemInfo {154 public:155 UnnamedSem()156 :157 fID(0)158 {159 }160 161 virtual ~UnnamedSem()162 {163 }164 165 status_t Init(int32 semCount, const char* name)166 {167 return SemInfo::Init(semCount, name);168 }169 170 void SetID(sem_id id)171 {172 fID = id;173 }174 175 virtual sem_id ID() const176 {177 return fID;178 }179 180 virtual SemInfo* Clone()181 {182 sem_info info;183 if (get_sem_info(SemaphoreID(), &info) != B_OK)184 return NULL;185 186 UnnamedSem* clone = new(std::nothrow) UnnamedSem;187 if (clone == NULL)188 return NULL;189 190 if (clone->Init(info.count, info.name) != B_OK) {191 delete clone;192 return NULL;193 }194 195 clone->SetID(fID);196 197 return clone;198 }199 200 virtual void Delete()201 {202 delete this;203 }204 205 private:206 sem_id fID;207 };208 209 210 class UnnamedSharedSem : public SemInfo {211 public:212 UnnamedSharedSem()213 {214 }215 216 virtual ~UnnamedSharedSem()217 {218 }219 220 status_t Init(int32 semCount, const char* name)221 {222 return SemInfo::Init(semCount, name);223 }224 225 virtual sem_id ID() const226 {227 return SemaphoreID();228 }229 230 virtual SemInfo* Clone()231 {232 // Can't be cloned.233 return NULL;234 }235 236 virtual void Delete()237 {238 delete this;239 }240 241 UnnamedSharedSem*& HashLink()242 {243 return fHashLink;244 }245 246 private:247 UnnamedSharedSem* fHashLink;248 };249 250 251 153 struct NamedSemHashDefinition { 252 154 typedef const char* KeyType; 253 155 typedef NamedSem ValueType; … … struct NamedSemHashDefinition { 274 176 }; 275 177 276 178 277 struct UnnamedSemHashDefinition {278 typedef sem_id KeyType;279 typedef UnnamedSharedSem ValueType;280 281 size_t HashKey(const KeyType& key) const282 {283 return (size_t)key;284 }285 286 size_t Hash(UnnamedSharedSem* semaphore) const287 {288 return HashKey(semaphore->SemaphoreID());289 }290 291 bool Compare(const KeyType& key, UnnamedSharedSem* semaphore) const292 {293 return key == semaphore->SemaphoreID();294 }295 296 UnnamedSharedSem*& GetLink(UnnamedSharedSem* semaphore) const297 {298 return semaphore->HashLink();299 }300 };301 302 303 179 class GlobalSemTable { 304 180 public: 305 181 GlobalSemTable() … … public: 316 192 317 193 status_t Init() 318 194 { 319 status_t error = fNamedSemaphores.Init(); 320 if (error != B_OK) 321 return error; 322 return fUnnamedSemaphores.Init(); 195 return fNamedSemaphores.Init(); 323 196 } 324 197 325 198 status_t OpenNamedSem(const char* name, int openFlags, mode_t mode, … … public: 393 266 return B_OK; 394 267 } 395 268 396 status_t CreateUnnamedSem(uint32 semCount, int32_t& _id)397 {398 MutexLocker _(fLock);399 400 if (fSemaphoreCount >= MAX_POSIX_SEMS)401 return ENOSPC;402 403 UnnamedSharedSem* sem = new(std::nothrow) UnnamedSharedSem;404 if (sem == NULL)405 return B_NO_MEMORY;406 407 status_t error = sem->Init(semCount, "unnamed shared sem");408 if (error == B_OK)409 error = fUnnamedSemaphores.Insert(sem);410 if (error != B_OK) {411 delete sem;412 return error;413 }414 415 fSemaphoreCount++;416 417 _id = sem->SemaphoreID();418 return B_OK;419 }420 421 status_t DeleteUnnamedSem(sem_id id)422 {423 MutexLocker _(fLock);424 425 UnnamedSharedSem* sem = fUnnamedSemaphores.Lookup(id);426 if (sem == NULL)427 return B_BAD_VALUE;428 429 fUnnamedSemaphores.Remove(sem);430 delete sem;431 432 fSemaphoreCount--;433 434 return B_OK;435 }436 437 bool IsUnnamedValidSem(sem_id id)438 {439 MutexLocker _(fLock);440 441 return fUnnamedSemaphores.Lookup(id) != NULL;442 }443 444 269 private: 445 270 typedef BOpenHashTable<NamedSemHashDefinition, true> NamedSemTable; 446 typedef BOpenHashTable<UnnamedSemHashDefinition, true> UnnamedSemTable;447 271 448 272 mutex fLock; 449 273 NamedSemTable fNamedSemaphores; 450 UnnamedSemTable fUnnamedSemaphores;451 274 int32 fSemaphoreCount; 452 275 }; 453 276 … … struct realtime_sem_context { 602 425 return context; 603 426 } 604 427 605 status_t CreateUnnamedSem(uint32 semCount, bool shared, int32_t& _id)606 {607 if (shared)608 return sSemTable.CreateUnnamedSem(semCount, _id);609 610 UnnamedSem* sem = new(std::nothrow) UnnamedSem;611 if (sem == NULL)612 return B_NO_MEMORY;613 ObjectDeleter<UnnamedSem> semDeleter(sem);614 615 status_t error = sem->Init(semCount, "unnamed sem");616 if (error != B_OK)617 return error;618 619 TeamSemInfo* teamSem = new(std::nothrow) TeamSemInfo(sem, NULL);620 if (teamSem == NULL)621 return B_NO_MEMORY;622 semDeleter.Detach();623 624 MutexLocker _(fLock);625 626 if (fSemaphoreCount >= MAX_POSIX_SEMS_PER_TEAM) {627 delete teamSem;628 return ENOSPC;629 }630 631 sem->SetID(_NextPrivateSemID());632 633 error = fSemaphores.Insert(teamSem);634 if (error != B_OK) {635 delete teamSem;636 return error;637 }638 639 fSemaphoreCount++;640 641 _id = teamSem->ID();642 return B_OK;643 }644 645 428 status_t OpenSem(const char* name, int openFlags, mode_t mode, 646 429 uint32 semCount, sem_t* userSem, sem_t*& _usedUserSem, int32_t& _id, 647 430 bool& _created) … … struct realtime_sem_context { 706 489 707 490 TeamSemInfo* sem = fSemaphores.Lookup(id); 708 491 if (sem == NULL) 709 return sSemTable.DeleteUnnamedSem(id);492 return B_BAD_VALUE; 710 493 711 494 if (sem->Close()) { 712 495 // last reference closed … … struct realtime_sem_context { 724 507 MutexLocker locker(fLock); 725 508 726 509 TeamSemInfo* sem = fSemaphores.Lookup(id); 727 if (sem == NULL) { 728 if (!sSemTable.IsUnnamedValidSem(id)) 729 return B_BAD_VALUE; 730 } else 510 if (sem == NULL) 511 return B_BAD_VALUE; 512 else 731 513 id = sem->SemaphoreID(); 732 514 733 515 locker.Unlock(); … … struct realtime_sem_context { 751 533 MutexLocker locker(fLock); 752 534 753 535 TeamSemInfo* sem = fSemaphores.Lookup(id); 754 if (sem == NULL) { 755 if (!sSemTable.IsUnnamedValidSem(id)) 756 return B_BAD_VALUE; 757 } else 536 if (sem == NULL) 537 return B_BAD_VALUE; 538 else 758 539 id = sem->SemaphoreID(); 759 540 760 541 locker.Unlock(); … … struct realtime_sem_context { 768 549 MutexLocker locker(fLock); 769 550 770 551 TeamSemInfo* sem = fSemaphores.Lookup(id); 771 if (sem == NULL) { 772 if (!sSemTable.IsUnnamedValidSem(id)) 552 if (sem == NULL) 773 553 return B_BAD_VALUE; 774 }else554 else 775 555 id = sem->SemaphoreID(); 776 556 777 557 locker.Unlock(); … … _user_realtime_sem_open(const char* userName, int openFlagsOrShared, 914 694 if (!IS_USER_ADDRESS(userSem)) 915 695 return B_BAD_ADDRESS; 916 696 917 // unnamed semaphores are less work -- deal with them first918 if (userName == NULL) {919 int32_t id;920 status_t error = context->CreateUnnamedSem(semCount, openFlagsOrShared,921 id);922 if (error != B_OK)923 return error;924 925 if (user_memcpy(&userSem->id, &id, sizeof(int)) != B_OK) {926 sem_t* dummy;927 context->CloseSem(id, dummy);928 return B_BAD_ADDRESS;929 }930 931 return B_OK;932 }933 934 697 // check user pointers 935 698 if (_usedUserSem == NULL) 936 699 return B_BAD_VALUE; … … _user_realtime_sem_open(const char* userName, int openFlagsOrShared, 954 717 return error; 955 718 956 719 // copy results back to userland 957 if (user_memcpy(&userSem-> id, &id, sizeof(int)) != B_OK720 if (user_memcpy(&userSem->u.named_sem_id, &id, sizeof(int32_t)) != B_OK 958 721 || user_memcpy(_usedUserSem, &usedUserSem, sizeof(sem_t*)) != B_OK) { 959 722 if (created) 960 723 sSemTable.UnlinkNamedSem(name); -
src/system/libroot/posix/semaphore.cpp
diff --git a/src/system/libroot/posix/semaphore.cpp b/src/system/libroot/posix/semaphore.cpp index 33cb768..fc4b0fc 100644
a b 1 1 /* 2 * Copyright 2015, Hamish Morrison, hamishm53@gmail.com. 2 3 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 4 * Distributed under the terms of the MIT License. 4 5 */ … … 17 18 #include <posix/realtime_sem_defs.h> 18 19 #include <syscall_utils.h> 19 20 #include <syscalls.h> 21 #include <user_mutex_defs.h> 22 23 24 #define SEM_TYPE_NAMED 1 25 #define SEM_TYPE_UNNAMED 2 26 27 28 static int32 29 atomic_add_if_greater(int32* value, int32 amount, int32 testValue) 30 { 31 int32 current = atomic_get(value); 32 while (current > testValue) { 33 int32 old = atomic_test_and_set(value, current + amount, current); 34 if (old == current) 35 return old; 36 current = old; 37 } 38 return current; 39 } 20 40 21 41 22 42 sem_t* … … sem_open(const char* name, int openFlags,...) 50 70 __set_errno(B_NO_MEMORY); 51 71 return SEM_FAILED; 52 72 } 73 74 sem->type = SEM_TYPE_NAMED; 53 75 MemoryDeleter semDeleter(sem); 54 76 55 77 // ask the kernel to open the semaphore … … int 72 94 sem_close(sem_t* semaphore) 73 95 { 74 96 sem_t* deleteSem = NULL; 75 status_t error = _kern_realtime_sem_close(semaphore->id, &deleteSem); 97 status_t error = _kern_realtime_sem_close(semaphore->u.named_sem_id, 98 &deleteSem); 76 99 if (error == B_OK) 77 100 free(deleteSem); 78 101 … … sem_unlink(const char* name) 90 113 int 91 114 sem_init(sem_t* semaphore, int shared, unsigned value) 92 115 { 93 RETURN_AND_SET_ERRNO(_kern_realtime_sem_open(NULL, shared, 0, value, 94 semaphore, NULL)); 116 semaphore->type = SEM_TYPE_UNNAMED; 117 semaphore->u.unnamed_sem = value; 118 return 0; 95 119 } 96 120 97 121 98 122 int 99 123 sem_destroy(sem_t* semaphore) 100 124 { 101 RETURN_AND_SET_ERRNO(_kern_realtime_sem_close(semaphore->id, NULL)); 125 if (semaphore->type != SEM_TYPE_UNNAMED) 126 RETURN_AND_SET_ERRNO(EINVAL); 127 128 return 0; 129 } 130 131 132 static int 133 unnamed_sem_post(sem_t* semaphore) { 134 int32* sem = (int32*)&semaphore->u.unnamed_sem; 135 int32 oldValue = atomic_add_if_greater(sem, 1, -1); 136 if (oldValue > -1) 137 return 0; 138 139 return _kern_mutex_sem_release(sem); 140 } 141 142 143 static int 144 unnamed_sem_trywait(sem_t* semaphore) { 145 int32* sem = (int32*)&semaphore->u.unnamed_sem; 146 int32 oldValue = atomic_add_if_greater(sem, -1, 0); 147 if (oldValue > 0) 148 return 0; 149 150 return EAGAIN; 151 } 152 153 154 static int 155 unnamed_sem_timedwait(sem_t* semaphore, const struct timespec* timeout) { 156 int32* sem = (int32*)&semaphore->u.unnamed_sem; 157 158 bigtime_t timeoutMicros = B_INFINITE_TIMEOUT; 159 if (timeout != NULL) { 160 timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000 161 + timeout->tv_nsec / 1000; 162 } 163 164 int result = unnamed_sem_trywait(semaphore); 165 if (result == 0) 166 return 0; 167 168 return _kern_mutex_sem_acquire(sem, NULL, 169 timeoutMicros == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT, 170 timeoutMicros); 102 171 } 103 172 104 173 105 174 int 106 175 sem_post(sem_t* semaphore) 107 176 { 108 RETURN_AND_SET_ERRNO(_kern_realtime_sem_post(semaphore->id)); 177 status_t error; 178 if (semaphore->type == SEM_TYPE_NAMED) 179 error = _kern_realtime_sem_post(semaphore->u.named_sem_id); 180 else 181 error = unnamed_sem_post(semaphore); 182 183 RETURN_AND_SET_ERRNO(error); 109 184 } 110 185 111 186 112 int113 sem_timedwait(sem_t* semaphore, const struct timespec* timeout)187 static int 188 named_sem_timedwait(sem_t* semaphore, const struct timespec* timeout) 114 189 { 115 190 if (timeout != NULL 116 191 && (timeout->tv_nsec < 0 || timeout->tv_nsec >= 1000000000)) { 117 status_t err = _kern_realtime_sem_wait(semaphore-> id, 0);192 status_t err = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 0); 118 193 if (err == B_WOULD_BLOCK) 119 194 err = EINVAL; 120 195 // do nothing, return err as it is. 121 RETURN_AND_SET_ERRNO_TEST_CANCEL(err);196 return err; 122 197 } 123 198 124 199 bigtime_t timeoutMicros = B_INFINITE_TIMEOUT; … … sem_timedwait(sem_t* semaphore, const struct timespec* timeout) 126 201 timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000 127 202 + timeout->tv_nsec / 1000; 128 203 } 129 status_t err = _kern_realtime_sem_wait(semaphore->id, timeoutMicros); 204 status_t err = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 205 timeoutMicros); 130 206 if (err == B_WOULD_BLOCK) 131 207 err = ETIMEDOUT; 132 133 RETURN_AND_SET_ERRNO_TEST_CANCEL(err);208 209 return err; 134 210 } 135 211 136 212 137 213 int 138 214 sem_trywait(sem_t* semaphore) 139 215 { 140 RETURN_AND_SET_ERRNO(_kern_realtime_sem_wait(semaphore->id, 0)); 216 status_t error; 217 if (semaphore->type == SEM_TYPE_NAMED) 218 error = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 0); 219 else 220 error = unnamed_sem_trywait(semaphore); 221 222 RETURN_AND_SET_ERRNO(error); 141 223 } 142 224 143 225 144 226 int 145 227 sem_wait(sem_t* semaphore) 146 228 { 147 RETURN_AND_SET_ERRNO_TEST_CANCEL( 148 _kern_realtime_sem_wait(semaphore->id, B_INFINITE_TIMEOUT)); 229 status_t error; 230 if (semaphore->type == SEM_TYPE_NAMED) 231 error = named_sem_timedwait(semaphore, NULL); 232 else 233 error = unnamed_sem_timedwait(semaphore, NULL); 234 235 RETURN_AND_SET_ERRNO_TEST_CANCEL(error); 236 } 237 238 239 int 240 sem_timedwait(sem_t* semaphore, const struct timespec* timeout) 241 { 242 status_t error; 243 if (semaphore->type == SEM_TYPE_NAMED) 244 error = named_sem_timedwait(semaphore, timeout); 245 else 246 error = unnamed_sem_timedwait(semaphore, timeout); 247 248 RETURN_AND_SET_ERRNO_TEST_CANCEL(error); 149 249 } 150 250 151 251 152 252 int 153 253 sem_getvalue(sem_t* semaphore, int* value) 154 254 { 155 RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value(semaphore->id, value)); 255 if (semaphore->type == SEM_TYPE_NAMED) { 256 RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value( 257 semaphore->u.named_sem_id, value)); 258 } else { 259 *value = semaphore->u.unnamed_sem < 0 ? 0 : semaphore->u.unnamed_sem; 260 return 0; 261 } 156 262 }