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 hamish, 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  
    11/*
    2  * Copyright 2008-2012 Haiku, Inc.
     2 * Copyright 2008-2015 Haiku, Inc.
    33 * Distributed under the terms of the MIT License.
    44 */
    55#ifndef _SEMAPHORE_H_
     
    1313
    1414
    1515typedef 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];
    1822} sem_t;
    1923
    2024#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,  
    2020status_t    _user_mutex_unlock(int32* mutex, uint32 flags);
    2121status_t    _user_mutex_switch_lock(int32* fromMutex, int32* toMutex,
    2222                const char* name, uint32 flags, bigtime_t timeout);
     23status_t    _user_mutex_sem_acquire(int32* sem, const char* name, uint32 flags,
     24                bigtime_t timeout);
     25status_t    _user_mutex_sem_release(int32* sem);
    2326
    2427#ifdef __cplusplus
    2528}
  • 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,  
    7979extern status_t     _kern_mutex_unlock(int32* mutex, uint32 flags);
    8080extern status_t     _kern_mutex_switch_lock(int32* fromMutex, int32* toMutex,
    8181                        const char* name, uint32 flags, bigtime_t timeout);
     82extern status_t     _kern_mutex_sem_acquire(int32* sem, const char* name,
     83                        uint32 flags, bigtime_t timeout);
     84extern status_t     _kern_mutex_sem_release(int32* sem);
    8285
    8386/* sem functions */
    8487extern 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  
    11/*
     2 * Copyright 2015, Hamish Morrison, hamishm53@gmail.com.
    23 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
    34 * Distributed under the terms of the MIT License.
    45 */
    remove_user_mutex_entry(UserMutexEntry* entry)  
    99100
    100101
    101102static status_t
    102 user_mutex_lock_locked(int32* mutex, addr_t physicalAddress, const char* name,
    103     uint32 flags, bigtime_t timeout, MutexLocker& locker)
     103user_mutex_wait_locked(int32* mutex, addr_t physicalAddress, const char* name,
     104    uint32 flags, bigtime_t timeout, MutexLocker& locker, bool& lastWaiter)
    104105{
    105     // mark the mutex locked + waiting
    106     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)) == 0
    111             || (oldValue & B_USER_MUTEX_DISABLED) != 0) {
    112         // clear the waiting flag and be done
    113         atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
    114         return B_OK;
    115     }
    116 
    117     // we have to wait
    118 
    119106    // add the entry to the table
    120107    UserMutexEntry entry;
    121108    entry.address = physicalAddress;
    user_mutex_lock_locked(int32* mutex, addr_t physicalAddress, const char* name,  
    131118    status_t error = waitEntry.Wait(flags, timeout);
    132119    locker.Lock();
    133120
    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;
    138131    }
    139132
    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
     137static status_t
     138user_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;
    144150    }
    145151
     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
    146159    return error;
    147160}
    148161
    user_mutex_unlock_locked(int32* mutex, addr_t physicalAddress, uint32 flags)  
    186199
    187200
    188201static status_t
     202user_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
     226static void
     227user_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
     254static status_t
    189255user_mutex_lock(int32* mutex, const char* name, uint32 flags, bigtime_t timeout)
    190256{
    191257    // wire the page and get the physical address
    _user_mutex_switch_lock(int32* fromMutex, int32* toMutex, const char* name,  
    312378    return user_mutex_switch_lock(fromMutex, toMutex, name,
    313379        flags | B_CAN_INTERRUPT, timeout);
    314380}
     381
     382
     383status_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
     410status_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:  
    150150};
    151151
    152152
    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() const
    176     {
    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() const
    226     {
    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 
    251153struct NamedSemHashDefinition {
    252154    typedef const char* KeyType;
    253155    typedef NamedSem    ValueType;
    struct NamedSemHashDefinition {  
    274176};
    275177
    276178
    277 struct UnnamedSemHashDefinition {
    278     typedef sem_id              KeyType;
    279     typedef UnnamedSharedSem    ValueType;
    280 
    281     size_t HashKey(const KeyType& key) const
    282     {
    283         return (size_t)key;
    284     }
    285 
    286     size_t Hash(UnnamedSharedSem* semaphore) const
    287     {
    288         return HashKey(semaphore->SemaphoreID());
    289     }
    290 
    291     bool Compare(const KeyType& key, UnnamedSharedSem* semaphore) const
    292     {
    293         return key == semaphore->SemaphoreID();
    294     }
    295 
    296     UnnamedSharedSem*& GetLink(UnnamedSharedSem* semaphore) const
    297     {
    298         return semaphore->HashLink();
    299     }
    300 };
    301 
    302 
    303179class GlobalSemTable {
    304180public:
    305181    GlobalSemTable()
    public:  
    316192
    317193    status_t Init()
    318194    {
    319         status_t error = fNamedSemaphores.Init();
    320         if (error != B_OK)
    321             return error;
    322         return fUnnamedSemaphores.Init();
     195        return fNamedSemaphores.Init();
    323196    }
    324197
    325198    status_t OpenNamedSem(const char* name, int openFlags, mode_t mode,
    public:  
    393266        return B_OK;
    394267    }
    395268
    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 
    444269private:
    445270    typedef BOpenHashTable<NamedSemHashDefinition, true> NamedSemTable;
    446     typedef BOpenHashTable<UnnamedSemHashDefinition, true> UnnamedSemTable;
    447271
    448272    mutex           fLock;
    449273    NamedSemTable   fNamedSemaphores;
    450     UnnamedSemTable fUnnamedSemaphores;
    451274    int32           fSemaphoreCount;
    452275};
    453276
    struct realtime_sem_context {  
    602425        return context;
    603426    }
    604427
    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 
    645428    status_t OpenSem(const char* name, int openFlags, mode_t mode,
    646429        uint32 semCount, sem_t* userSem, sem_t*& _usedUserSem, int32_t& _id,
    647430        bool& _created)
    struct realtime_sem_context {  
    706489
    707490        TeamSemInfo* sem = fSemaphores.Lookup(id);
    708491        if (sem == NULL)
    709             return sSemTable.DeleteUnnamedSem(id);
     492            return B_BAD_VALUE;
    710493
    711494        if (sem->Close()) {
    712495            // last reference closed
    struct realtime_sem_context {  
    724507        MutexLocker locker(fLock);
    725508
    726509        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
    731513            id = sem->SemaphoreID();
    732514
    733515        locker.Unlock();
    struct realtime_sem_context {  
    751533        MutexLocker locker(fLock);
    752534
    753535        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
    758539            id = sem->SemaphoreID();
    759540
    760541        locker.Unlock();
    struct realtime_sem_context {  
    768549        MutexLocker locker(fLock);
    769550
    770551        TeamSemInfo* sem = fSemaphores.Lookup(id);
    771         if (sem == NULL) {
    772             if (!sSemTable.IsUnnamedValidSem(id))
     552        if (sem == NULL)
    773553                return B_BAD_VALUE;
    774         } else
     554        else
    775555            id = sem->SemaphoreID();
    776556
    777557        locker.Unlock();
    _user_realtime_sem_open(const char* userName, int openFlagsOrShared,  
    914694    if (!IS_USER_ADDRESS(userSem))
    915695        return B_BAD_ADDRESS;
    916696
    917     // unnamed semaphores are less work -- deal with them first
    918     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 
    934697    // check user pointers
    935698    if (_usedUserSem == NULL)
    936699        return B_BAD_VALUE;
    _user_realtime_sem_open(const char* userName, int openFlagsOrShared,  
    954717        return error;
    955718
    956719    // copy results back to userland
    957     if (user_memcpy(&userSem->id, &id, sizeof(int)) != B_OK
     720    if (user_memcpy(&userSem->u.named_sem_id, &id, sizeof(int32_t)) != B_OK
    958721        || user_memcpy(_usedUserSem, &usedUserSem, sizeof(sem_t*)) != B_OK) {
    959722        if (created)
    960723            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  
    11/*
     2 * Copyright 2015, Hamish Morrison, hamishm53@gmail.com.
    23 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
    34 * Distributed under the terms of the MIT License.
    45 */
     
    1718#include <posix/realtime_sem_defs.h>
    1819#include <syscall_utils.h>
    1920#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
     28static int32
     29atomic_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}
    2040
    2141
    2242sem_t*
    sem_open(const char* name, int openFlags,...)  
    5070        __set_errno(B_NO_MEMORY);
    5171        return SEM_FAILED;
    5272    }
     73
     74    sem->type = SEM_TYPE_NAMED;
    5375    MemoryDeleter semDeleter(sem);
    5476
    5577    // ask the kernel to open the semaphore
    int  
    7294sem_close(sem_t* semaphore)
    7395{
    7496    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);
    7699    if (error == B_OK)
    77100        free(deleteSem);
    78101
    sem_unlink(const char* name)  
    90113int
    91114sem_init(sem_t* semaphore, int shared, unsigned value)
    92115{
    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;
    95119}
    96120
    97121
    98122int
    99123sem_destroy(sem_t* semaphore)
    100124{
    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
     132static int
     133unnamed_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
     143static int
     144unnamed_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
     154static int
     155unnamed_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);
    102171}
    103172
    104173
    105174int
    106175sem_post(sem_t* semaphore)
    107176{
    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);
    109184}
    110185
    111186
    112 int
    113 sem_timedwait(sem_t* semaphore, const struct timespec* timeout)
     187static int
     188named_sem_timedwait(sem_t* semaphore, const struct timespec* timeout)
    114189{
    115190    if (timeout != NULL
    116191        && (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);
    118193        if (err == B_WOULD_BLOCK)
    119194            err = EINVAL;
    120195        // do nothing, return err as it is.
    121         RETURN_AND_SET_ERRNO_TEST_CANCEL(err);
     196        return err;
    122197    }
    123198
    124199    bigtime_t timeoutMicros = B_INFINITE_TIMEOUT;
    sem_timedwait(sem_t* semaphore, const struct timespec* timeout)  
    126201        timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000
    127202            + timeout->tv_nsec / 1000;
    128203    }
    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);
    130206    if (err == B_WOULD_BLOCK)
    131207        err = ETIMEDOUT;
    132    
    133     RETURN_AND_SET_ERRNO_TEST_CANCEL(err);
     208
     209    return err;
    134210}
    135211
    136212
    137213int
    138214sem_trywait(sem_t* semaphore)
    139215{
    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);
    141223}
    142224
    143225
    144226int
    145227sem_wait(sem_t* semaphore)
    146228{
    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
     239int
     240sem_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);
    149249}
    150250
    151251
    152252int
    153253sem_getvalue(sem_t* semaphore, int* value)
    154254{
    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    }
    156262}