[haiku-gsoc] Xsi semaphorses: patch #1

  • From: "Salvatore Benedetto" <emitrax@xxxxxxxxx>
  • To: haiku-gsoc@xxxxxxxxxxxxx
  • Date: Sun, 13 Jul 2008 13:43:59 +0000

Hi,

the attached is a first implementation of the xsi semaphore.
Althought not complete, it has everything it needs to get bonnie++
up and running (which by they way I already ran and it already corrupted my
haiku partition on vmware).

Regards,
-- 
Salvatore Benedetto (a.k.a. emitrax)
Student of Computer Engineer
University of Pisa
www.haiku-os.it
Index: src/system/kernel/posix/Jamfile
===================================================================
--- src/system/kernel/posix/Jamfile     (revision 26404)
+++ src/system/kernel/posix/Jamfile     (working copy)
@@ -4,6 +4,7 @@
 
 KernelMergeObject kernel_posix.o : 
        realtime_sem.cpp
+       xsi_semaphore.cpp
 
        : $(TARGET_KERNEL_PIC_CCFLAGS)
 ;
Index: src/system/kernel/posix/xsi_semaphore.cpp
===================================================================
--- src/system/kernel/posix/xsi_semaphore.cpp   (revision 0)
+++ src/system/kernel/posix/xsi_semaphore.cpp   (revision 0)
@@ -0,0 +1,735 @@
+/*
+ * Copyright 2008, Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Salvatore Benedetto <salvatore.benedetto@xxxxxxxxx>
+ */
+
+#include <posix/xsi_semaphore.h>
+#include <posix/realtime_sem_defs.h>
+
+#include <new>
+
+#include <OS.h>
+
+#include <kernel.h>
+#include <syscall_restart.h>
+
+#include <sys/ipc.h>
+#include <sys/types.h>
+
+#include <util/DoublyLinkedList.h>
+#include <util/OpenHashTable.h>
+#include <util/Vector.h>
+
+
+//#define TRACE_XSI_SEM
+#ifdef TRACE_XSI_SEM
+#      define TRACE(x)                 dprintf x
+#      define TRACE_ERROR(x)   dprintf x
+#else
+#      define TRACE(x)                 /* nothing */
+#      define TRACE_ERROR(x)   dprintf x
+#endif
+
+//#define KTRACE_XSI_SEM
+#ifdef KTRACE_XSI_SEM
+#      define KTRACE(x...) ktrace_printf(x)
+#else
+#      define KTRACE(x...)
+#endif
+
+// Queue for holding blocked threads
+struct queued_thread : DoublyLinkedListLinkImpl<queued_thread> {
+       queued_thread(struct thread *thread, int32 count)
+               :
+               thread(thread),
+               count(count),
+               queued(false)
+       {
+       }
+
+       struct thread   *thread;
+       int32                   count;
+       bool                    queued;
+       bool                    destroyed;
+};
+
+typedef DoublyLinkedList<queued_thread> ThreadQueue;
+
+
+// Xsi semaphore definition
+class XsiSemaphore {
+public:
+       XsiSemaphore()
+               : fLastPidOperation(0),
+               fProcessesWaitingToIncrease(0),
+               fProcessesWaitingToBeZero(0),
+               fValue(0)
+       {
+       }
+
+       ~XsiSemaphore()
+       {
+               // For some reason the semaphore is getting destroyed.
+               // Wake up any remaing awaiting threads
+               GRAB_THREAD_LOCK();
+               while (queued_thread *entry = 
fWaitingToIncreaseQueue.RemoveHead()) {
+                       entry->queued = false;
+                       entry->destroyed = true;
+                       thread_unblock_locked(entry->thread, EIDRM);
+               }
+               while (queued_thread *entry = 
fWaitingToBeZeroQueue.RemoveHead()) {
+                       entry->queued = false;
+                       entry->destroyed = true;
+                       thread_unblock_locked(entry->thread, EIDRM);
+               }
+               RELEASE_THREAD_LOCK();
+       }
+
+       // We return true in case the operation causes the
+       // caller to wait, so it can undo all the operations
+       // previously done, by calling the same function
+       // with force set to true, which causes the operation
+       // to take place despite the result of the algebric sum
+       bool Add(short value, bool force)
+       {
+               if (!force) {
+                       if ((int)(fValue + value) < 0) {
+                               TRACE(("XsiSemaphore::Add: going to sleep\n"));
+                               return true;
+                       } else {
+                               fValue += value;
+                               if ((fValue == 0) && (fProcessesWaitingToBeZero 
> 0))
+                                       WakeUpThread(true);
+                               else if ((fValue > 0) && 
(fProcessesWaitingToIncrease > 0))
+                                       WakeUpThread(false);
+                               return false;
+                       }
+               }
+               // We are being forced to revert our changes
+               fValue -= value;
+               return false;
+       }
+
+       pid_t GetPid() const
+       {
+               return fLastPidOperation;
+       }
+
+       ushort GetProcessesWaitingToIncrease() const
+       {
+               return fProcessesWaitingToIncrease;
+       }
+
+       ushort GetProcessesWaitingToBeZero() const
+       {
+               return fProcessesWaitingToBeZero;
+       }
+
+       ushort GetValue() const
+       {
+               return fValue;
+       }
+
+       void SetPid(pid_t pid)
+       {
+               fLastPidOperation = pid;
+       }
+
+       void SetValue(ushort value)
+       {
+               fValue = value;
+       }
+
+       status_t Wait(int32 count, bool waitForZero)
+       {
+               // enqueue the thread in the appropriate
+               // queue and get ready to wait
+               struct thread *thread = thread_get_current_thread();
+               queued_thread queueEntry(thread, count);
+               if (waitForZero) {
+                       fWaitingToBeZeroQueue.Add(&queueEntry);
+                       fProcessesWaitingToBeZero++;
+               } else {
+                       fWaitingToIncreaseQueue.Add(&queueEntry);
+                       fProcessesWaitingToIncrease++;
+               }
+               queueEntry.queued = true;
+
+               thread_prepare_to_block(thread, 0, THREAD_BLOCK_TYPE_OTHER,
+                       (void*)"xsi semaphore");
+               GRAB_THREAD_LOCK();
+               status_t result = thread_block_locked(thread);
+               RELEASE_THREAD_LOCK();
+
+               return result;
+       }
+
+       void WakeUpThread(bool waitingForZero)
+       {
+               queued_thread *entry;
+               bool unblock = false;
+
+               GRAB_THREAD_LOCK();
+               if (waitingForZero) {
+                       unblock = true;
+                       entry = fWaitingToBeZeroQueue.RemoveHead();
+               } else {
+                       entry = fWaitingToIncreaseQueue.Head();
+                       if ((entry->count + fValue) > 0) {
+                               unblock = true;
+                               entry = fWaitingToIncreaseQueue.RemoveHead();
+                       }
+               }
+               if (unblock) {
+                       entry->queued = false;
+                       entry->destroyed = true;
+                       thread_unblock_locked(entry->thread, 0);
+               }
+               RELEASE_THREAD_LOCK();
+       }
+
+private:
+       pid_t                   fLastPidOperation;                              
// sempid
+       ushort                  fProcessesWaitingToIncrease;    // semncnt
+       ushort                  fProcessesWaitingToBeZero;              // 
semzcnt
+       short                   fValue;                                         
        // semval
+
+       ThreadQueue             fWaitingToIncreaseQueue;
+       ThreadQueue             fWaitingToBeZeroQueue;
+};
+
+
+
+// Xsi semaphore set definition (semid_ds)
+class XsiSemaphoreSet {
+public:
+       XsiSemaphoreSet(int nsems, int flags)
+               :       fLastSemctlTime((time_t)real_time_clock()),
+               fLastSemopTime(0),      
+               fNumberOfSemaphores(nsems),
+               fSemaphores(0)
+       {
+               SetID();
+               SetIpcKey((key_t)-1);
+               SetPermissions(flags);
+
+               for (int i = 0; i < nsems; i++) {
+                       XsiSemaphore *current = new(std::nothrow) 
XsiSemaphore();
+                       if (current == NULL) {
+                               TRACE_ERROR(("XsiSemaphoreSet::XsiSemaphore(): 
failed to allocate "
+                                       "XsiSemaphore object\n"));
+                               return;
+                       }
+                       fSemaphores.PushBack(current);
+               }
+       }
+
+       ~XsiSemaphoreSet()
+       {
+               for (Vector<XsiSemaphore *>::Iterator i = fSemaphores.Begin();
+                               i != fSemaphores.End(); i++) {
+                       delete (*i);
+               }
+       }
+
+       int     GetID() const
+       {
+               return fID;
+       }
+
+       key_t GetIpcKey() const
+       {
+               return fPermissions.key;
+       }
+
+       ushort GetNumberOfSemaphores() const
+       {
+               return fNumberOfSemaphores;
+       }
+
+       XsiSemaphore* GetSemaphore(int nth) const
+       {
+               return fSemaphores[nth];
+       }
+
+       // Implemented after sSemaphoreHashTable is declared
+       void SetID();
+
+       void SetIpcKey(key_t key)
+       {
+               fPermissions.key = key;
+       }
+
+       void SetLastSemctlTime()
+       {
+               fLastSemctlTime = real_time_clock();
+       }
+
+       void SetLastSemopTime()
+       {
+               fLastSemopTime = real_time_clock();
+       }
+
+       void SetPermissions(int flags)
+       {
+               fPermissions.uid = fPermissions.cuid = geteuid();
+               fPermissions.gid = fPermissions.cgid = getegid();
+               fPermissions.mode = (flags & 0x01ff);
+       }
+
+       bool HasPermission() const
+       {
+               if ((fPermissions.mode & S_IWOTH) != 0)
+                       return true;
+
+               uid_t uid = geteuid();
+               if (uid == 0 || (uid == fPermissions.uid && (fPermissions.mode 
& S_IWUSR) != 0))
+                       return true;
+
+               gid_t gid = getegid();
+               if (gid == fPermissions.gid && (fPermissions.mode & S_IWGRP) != 
0)
+                       return true;
+
+               return false;
+       }
+
+       bool HasReadPermission() const
+       {
+               // TODO: fix this
+               return HasPermission();
+       }
+
+       HashTableLink<XsiSemaphoreSet>* Link()
+       {
+               return &fLink;
+       }
+
+private:
+       int                                                     fID;            
                        // semaphore set id
+       time_t                                          fLastSemctlTime;        
        // sem_ctime
+       time_t                                          fLastSemopTime;         
        // sem_otime
+       ushort                                          fNumberOfSemaphores;    
// sem_nsems
+       struct ipc_perm                         fPermissions;                   
// sem_perm
+       Vector<XsiSemaphore*>           fSemaphores;
+       
+       ::HashTableLink<XsiSemaphoreSet> fLink;
+};
+
+// Xsi semaphore set hash table
+struct SemaphoreHashTableDefinition {
+       typedef int                                     KeyType;
+       typedef XsiSemaphoreSet         ValueType;
+
+       size_t HashKey (const int key) const
+       {
+               return (size_t)key;
+       }
+       size_t Hash(XsiSemaphoreSet* variable) const
+       {
+               return (size_t)variable->GetID();
+       }
+       bool Compare(const int key, XsiSemaphoreSet* variable) const
+       {
+               return (int)key == (int)variable->GetID();
+       }
+       HashTableLink<XsiSemaphoreSet>* GetLink(XsiSemaphoreSet* variable) const
+       {
+               return variable->Link();
+       }
+};
+
+static OpenHashTable<SemaphoreHashTableDefinition> sSemaphoreHashTable;
+static int sNextAvailableID = 0;
+static spinlock xsi_semaphore_set_spinlock = B_SPINLOCK_INITIALIZER;
+#define GRAB_SEM_LOCK()         acquire_spinlock(&xsi_semaphore_set_spinlock)
+#define RELEASE_SEM_LOCK()      release_spinlock(&xsi_sempahore_set_spinlock)
+
+// Arbitrary limit
+#define        MAX_XSI_SEMAPHORE               512
+static int sTotalNumberOfXsiSemaphores = 0;
+
+void
+XsiSemaphoreSet::SetID()
+{
+       // The spinlock is held upon creation of the object
+       while (true) {
+               if (sSemaphoreHashTable.Lookup(sNextAvailableID) == NULL)
+                       break;
+               sNextAvailableID++;
+       }
+       fID = sNextAvailableID++;
+}
+
+
+// IPC class
+class Ipc {
+public:
+       Ipc(key_t key)
+               : fKey(key),
+               fSemaphoreSetId(-1)
+       {
+       }
+
+       key_t GetKey() const
+       {
+               return fKey;
+       }
+
+       int GetSemaphoreSetID() const
+       {
+               return fSemaphoreSetId;
+       }
+
+       void SetSemaphoreSetID(XsiSemaphoreSet *semaphoreSet)
+       {
+               fSemaphoreSetId = semaphoreSet->GetID();
+       }
+
+       bool HasSemaphoreSet()
+       {
+               if (fSemaphoreSetId != -1)
+                       return true;
+               return false;
+       }
+
+       HashTableLink<Ipc>* Link()
+       {
+               return &fLink;
+       }
+
+private:
+       key_t                           fKey;
+       int                                     fSemaphoreSetId;
+       HashTableLink<Ipc>      fLink;
+};
+
+
+struct IpcHashTableDefinition {
+       typedef key_t   KeyType;
+       typedef Ipc             ValueType;
+
+       size_t HashKey (const key_t key) const
+       {
+               // TODO: Define a better hash function
+               // key_t is a 32 bit integer value.
+               return (size_t)(key & 0x00000fff) % 32;
+       }
+       size_t Hash(Ipc* variable) const
+       {
+               return HashKey(variable->GetKey());
+       }
+       bool Compare(const key_t key, Ipc* variable) const
+       {
+               return (key_t)key == (key_t)variable->GetKey();
+       }
+       HashTableLink<Ipc>* GetLink(Ipc* variable) const
+       {
+               return variable->Link();
+       }
+};
+
+static OpenHashTable<IpcHashTableDefinition> sIpcHashTable;
+static spinlock ipc_spinlock = B_SPINLOCK_INITIALIZER;
+#define        GRAB_IPC_TABLE_LOCK()           acquire_spinlock(&ipc_spinlock);
+#define        RELEASE_IPC_TABLE_LOCK()        release_spinlock(&ipc_spinlock);
+
+
+status_t 
+haiku_xsi_ipc_init(struct kernel_args *args)
+{
+       // Initialize hash tables
+       status_t error = sIpcHashTable.Init();
+       if (error != B_OK)
+               return error;
+       return sSemaphoreHashTable.Init();
+}
+
+
+int
+_user_xsi_semget(key_t key, int numberOfSemaphores, int flags)
+{
+       XsiSemaphoreSet *semaphoreSet = NULL;
+       Ipc *IpcKey = NULL;
+       // Default assumptions
+       bool isPrivate = true;
+       bool create = true;
+
+       if (key != IPC_PRIVATE) {
+               isPrivate = false;
+               // Check if key already have a semaphore
+               // associated with it
+               IpcKey = sIpcHashTable.Lookup(key);
+               if (IpcKey == NULL) {
+                       // The ipc key have probably just been created
+                       // by the caller, add it to the system
+                       IpcKey = new(std::nothrow) Ipc(key);
+                       if (IpcKey == NULL) {
+                               TRACE_ERROR(("xsi_semget: failed to create new 
Ipc object "
+                                       "for key %d\n", (int)key));
+                               return ENOMEM;
+                       }
+                       sIpcHashTable.Insert(IpcKey);
+               } else if (IpcKey->HasSemaphoreSet()) {
+                       // The IPC key exist and it already has a semaphore
+                       if ((flags & IPC_CREAT) && (flags & IPC_EXCL)) {
+                               TRACE_ERROR(("xsi_semget: key %d already 
exist\n", (int)key));
+                               return EEXIST;
+                       }
+                       int semaphoreSetID = IpcKey->GetSemaphoreSetID();
+                       semaphoreSet = 
sSemaphoreHashTable.Lookup(semaphoreSetID);
+                       if (!semaphoreSet->HasPermission()) {
+                               TRACE_ERROR(("xsi_semget: calling process has 
not permission "
+                                       "on semaphore %d, key %d\n", 
semaphoreSet->GetID(),
+                                       (int)semaphoreSet->GetIpcKey()));
+                               return EACCES;
+                       }
+                       if ((semaphoreSet->GetNumberOfSemaphores() < 
numberOfSemaphores)
+                               && (numberOfSemaphores != 0)) {
+                               TRACE_ERROR(("xsi_semget: nsems greater than 
the one "
+                                       "associated with semaphore %d, key 
%d\n",
+                                       semaphoreSet->GetID(), 
(int)semaphoreSet->GetIpcKey()));
+                               return EINVAL;
+                       }
+                       create = false;
+               } else {
+                       // The IPC key exist but it has not semaphore 
associated with it
+                       if (!(flags & IPC_CREAT)) {
+                               TRACE_ERROR(("xsi_semget: key %d has not 
semaphore associated "
+                                       "with it and caller did not ask for 
creation\n",(int)key));
+                               return ENOENT;
+                       }
+               }
+
+               if (create) {
+                       // Create a new sempahore for this key
+                       if (numberOfSemaphores < 0 
+                                       || numberOfSemaphores > 
MAX_POSIX_SEMS_PER_TEAM) {
+                               TRACE_ERROR(("xsi_semget: nsems out of 
range\n"));
+                               return EINVAL;
+                       }
+                       if (sTotalNumberOfXsiSemaphores < MAX_XSI_SEMAPHORE) {
+                               TRACE_ERROR(("xsi_semget: reached limit of 
maximum number of "
+                                                       "semaphores 
allowed\n"));
+                               return ENOSPC;
+                       }
+                       sTotalNumberOfXsiSemaphores++;
+
+                       semaphoreSet = new(std::nothrow) 
XsiSemaphoreSet(numberOfSemaphores,flags);
+                       if (semaphoreSet == NULL) {
+                               TRACE_ERROR(("xsi_semget: failed to allocate a 
new xsi "
+                                                       "semaphore set\n"));
+                               sTotalNumberOfXsiSemaphores--;
+                               return ENOMEM;
+                       }
+                       if (isPrivate)
+                               semaphoreSet->SetIpcKey((key_t)-1);
+                       else {
+                               semaphoreSet->SetIpcKey(key);
+                               IpcKey->SetSemaphoreSetID(semaphoreSet);
+                       }
+               }
+       }
+
+       return semaphoreSet->GetID();
+}
+
+
+int
+_user_xsi_semctl(int semaphoreID, int semaphoreNumber, int command, union 
semun* args)
+{
+       XsiSemaphoreSet *semaphoreSet = sSemaphoreHashTable.Lookup(semaphoreID);
+       if (semaphoreSet == NULL) {
+               TRACE_ERROR(("xsi_semctl: semaphore set id %d not valid\n", 
semaphoreID));
+               return EINVAL;
+       }
+       if ((semaphoreNumber < 0)
+               || (semaphoreNumber >= semaphoreSet->GetNumberOfSemaphores())) {
+               TRACE_ERROR(("xsi_semctl: semaphore number %d not valid for "
+                       "semaphore %d\n", semaphoreNumber, semaphoreID));
+               return EINVAL;
+       }
+
+       if ((args != 0) && !(IS_USER_ADDRESS(args))) {
+               TRACE_ERROR(("xsi_semctl: semun address is not valid\n"));
+               return B_BAD_ADDRESS;
+       }
+
+       XsiSemaphore *semaphore = semaphoreSet->GetSemaphore(semaphoreNumber);
+       switch (command) {
+               case GETVAL:
+                       if (!(semaphoreSet->HasReadPermission())) {
+                               TRACE_ERROR(("xsi_semctl: calling process has 
not permission "
+                                       "on semaphore %d, key %d\n", 
semaphoreSet->GetID(),
+                                       (int)semaphoreSet->GetIpcKey()));
+                               return EACCES;
+                       }
+                       return semaphore->GetValue();
+
+               case SETVAL:
+                       if (!(semaphoreSet->HasPermission())) {
+                               TRACE_ERROR(("xsi_semctl: calling process has 
not permission "
+                                       "on semaphore %d, key %d\n", 
semaphoreSet->GetID(),
+                                       (int)semaphoreSet->GetIpcKey()));
+                               return EACCES;
+                       }
+                       int value;
+                       user_memcpy(&value, &args->val, sizeof(int));
+                       if (value > USHRT_MAX) {
+                               TRACE_ERROR(("xsi_semctl: value %d out of 
range\n", value));
+                               return ERANGE;
+                       }
+                       semaphore->SetValue(value);
+                       return 0;
+
+               case GETPID:
+                       if (!(semaphoreSet->HasReadPermission())) {
+                       TRACE_ERROR(("xsi_semctl: calling process has not 
permission "
+                               "on semaphore %d, key %d\n", 
semaphoreSet->GetID(),
+                               (int)semaphoreSet->GetIpcKey()));
+                       return EACCES;
+                       }
+                       return semaphore->GetPid();
+
+               case GETNCNT:
+                       if (!(semaphoreSet->HasReadPermission())) {
+                               TRACE_ERROR(("xsi_semctl: calling process has 
not permission "
+                                       "on semaphore %d, key %d\n", 
semaphoreSet->GetID(),
+                                       (int)semaphoreSet->GetIpcKey()));
+                               return EACCES;
+                       }
+                       return semaphore->GetProcessesWaitingToIncrease();
+
+               case GETZCNT:
+                       if (!(semaphoreSet->HasReadPermission())) {
+                               TRACE_ERROR(("xsi_semctl: calling process has 
not permission "
+                                       "on semaphore %d, key %d\n", 
semaphoreSet->GetID(),
+                                       (int)semaphoreSet->GetIpcKey()));
+                               return EACCES;
+                       }
+                       return semaphore->GetProcessesWaitingToBeZero();
+
+               case GETALL:
+               case SETALL:
+                       // TODO
+                       return -1;
+
+               case IPC_STAT:
+               case IPC_SET:
+                       // TODO
+               case IPC_RMID:
+                               if (!(semaphoreSet->HasPermission())) {
+                                       TRACE_ERROR(("xsi_semctl: calling 
process has not permission "
+                                               "on semaphore %d, key %d\n", 
semaphoreSet->GetID(),
+                                               
(int)semaphoreSet->GetIpcKey()));
+                                       return EACCES;
+                               }
+                               sSemaphoreHashTable.Remove(semaphoreSet);
+                               delete semaphoreSet;
+                               
+
+               default:
+                       TRACE_ERROR(("xsi_semctl: command %d not valid\n", 
command));
+                       return EINVAL;
+       }
+}
+
+
+status_t
+_user_xsi_semop(int semaphoreID, struct sembuf *sops, size_t nsops)
+{
+       XsiSemaphoreSet *semaphoreSet = sSemaphoreHashTable.Lookup(semaphoreID);
+       if (semaphoreSet == NULL) {
+               TRACE_ERROR(("xsi_semop: semaphore set id %d not valid\n", 
semaphoreID));
+               return EINVAL;
+       }
+
+       if (!IS_USER_ADDRESS(sops)) {
+               TRACE_ERROR(("xsi_semop: sembuf address is not valid\n"));
+               return B_BAD_ADDRESS;
+       }
+
+       struct sembuf operations[nsops];
+       user_memcpy(&operations[0], sops, (sizeof(struct sembuf) * nsops));
+       /*
+        * We won't do partial request. If we must wait on a
+        * semaphore, we undo all the operations already done
+        * and go to sleep.
+        */
+       bool notDone = true;
+       bool goToSleep = false;
+       status_t result = 0;
+       while (notDone) {
+               XsiSemaphore *semaphore = NULL;
+               short numberOfSemaphores = 
semaphoreSet->GetNumberOfSemaphores();
+
+               int i = 0;
+               for (; i < nsops; i++) {
+                       short semaphoreNumber = operations[i].sem_num;
+                       if (semaphoreNumber > numberOfSemaphores) {
+                               TRACE_ERROR(("xsi_semop: %d invalid semaphore 
number\n", i));
+                               result = EINVAL;
+                               break;
+                       }
+                       semaphore = semaphoreSet->GetSemaphore(semaphoreNumber);
+                       unsigned short value = semaphore->GetValue();
+                       short operation = operations[i].sem_op;
+                       if (operation < 0) {
+                               if (semaphore->Add(operation, false)) {
+                                       goToSleep = true;
+                                       break;
+                               }
+                       } else if (operation == 0) {
+                               if (value == 0) 
+                                       continue;
+                               else if (operations[i].sem_flg & IPC_NOWAIT) {
+                                       result = EAGAIN;
+                                       break;
+                               } else {
+                                       goToSleep = true;
+                                       break;
+                               }
+                       } else {
+                               // Operation must be greater than zero,
+                               // just add the value and continue
+                               semaphore->Add(operation, false);
+                       }
+               }
+
+               // Either we have to wait or an error occured
+               if (goToSleep || result != 0) {
+                       // Undo all previosly done operations
+                       for (int j = 0; j < i; j++) {
+                               short semaphoreNumber = operations[j].sem_num;
+                               semaphore = 
semaphoreSet->GetSemaphore(semaphoreNumber);
+                               short operation = operations[j].sem_op;
+                               if (operation != 0)
+                                       semaphore->Add(operation, true);
+                       }
+                       if (result != 0)
+                               return result;
+
+                       bool waitOnZero = true;
+                       if (operations[i].sem_op != 0)
+                               waitOnZero = false;
+
+                       result = semaphore->Wait((int32)operations[i].sem_op, 
waitOnZero);
+
+                       // We are back to life.
+                       // Find out why!
+                       semaphoreSet = sSemaphoreHashTable.Lookup(semaphoreID);
+                       if (semaphoreSet == NULL || result == EIDRM) {
+                               TRACE_ERROR(("xsi_semop: semaphore set id %d 
got destroyed\n",
+                                       semaphoreID));
+                               result = EIDRM;
+                               notDone = false;
+                       }
+               } else
+                       // everything worked like a charm
+                       notDone = false;
+                       // TODO: Handle SEM_UNDO requests
+       }
+       return result;
+}
Index: src/system/kernel/syscalls.cpp
===================================================================
--- src/system/kernel/syscalls.cpp      (revision 26404)
+++ src/system/kernel/syscalls.cpp      (working copy)
@@ -17,6 +17,7 @@
 #include <vm.h>
 #include <thread.h>
 #include <posix/realtime_sem.h>
+#include <posix/xsi_semaphore.h>
 #include <sem.h>
 #include <port.h>
 #include <cpu.h>
Index: src/system/libroot/posix/sys/ftok.c
===================================================================
--- src/system/libroot/posix/sys/ftok.c (revision 0)
+++ src/system/libroot/posix/sys/ftok.c (revision 0)
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2008, Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Salvatore Benedetto <salvatore.benedetto@xxxxxxxxx>
+ */
+
+#include <sys/ipc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+key_t
+ftok(const char *path, int id)
+{
+       struct stat st;
+
+       if (stat(path,&st) < 0)
+               return (key_t)-1;
+
+       return (key_t) (id << 24 | (st.st_dev & 0xff) << 16 | (st.st_ino & 
0xffff));
+}
Index: src/system/libroot/posix/sys/xsi_sem.c
===================================================================
--- src/system/libroot/posix/sys/xsi_sem.c      (revision 0)
+++ src/system/libroot/posix/sys/xsi_sem.c      (revision 0)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008, Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Salvatore Benedetto <salvatore.benedetto@xxxxxxxxx>
+ */
+
+#include <sys/sem.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <OS.h>
+
+#include <posix/realtime_sem_defs.h>
+#include <syscalls.h>
+
+#define RETURN_AND_SET_ERRNO(status) \
+{ \
+       if (status < 0) { \
+               errno = status; \
+               return -1; \
+       } \
+       return status; \
+}
+
+
+/*
+ * For the semctl option argument, the user
+ * should declare explicitly the following union
+ */
+union semun {
+       int                             val;
+       struct semid_ds *buf;
+       unsigned short  *array;
+};
+
+int
+semget(key_t key, int num_sems, int sem_flags)
+{
+       RETURN_AND_SET_ERRNO(_kern_xsi_semget(key, num_sems, sem_flags));
+}
+
+
+int
+semctl(int semId, int sem_num, int command, ...)
+{
+       union semun arg;
+       va_list args;
+
+       switch (command) {
+               case GETVAL:
+               case GETPID:
+               case GETNCNT:
+               case GETZCNT:
+               case IPC_RMID:
+                       RETURN_AND_SET_ERRNO(_kern_xsi_semctl(semId, sem_num, 
command, 0));
+
+               case SETVAL:
+               case GETALL:
+               case SETALL:
+               case IPC_STAT:
+               case IPC_SET:
+                       va_start(args, command);
+                       arg = va_arg(args, union semun);
+                       va_end(args);
+                       RETURN_AND_SET_ERRNO(_kern_xsi_semctl(semId, sem_num, 
command, &arg));
+               default:
+                       return EINVAL;
+       }
+}
+
+
+int
+semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops)
+{
+       RETURN_AND_SET_ERRNO(_kern_xsi_semop(sem_id, sem_ops, num_sem_ops));
+}
Index: src/system/libroot/posix/sys/Jamfile
===================================================================
--- src/system/libroot/posix/sys/Jamfile        (revision 26404)
+++ src/system/libroot/posix/sys/Jamfile        (working copy)
@@ -7,6 +7,7 @@
        chmod.c
        flock.c
        ftime.c
+       ftok.c
        getrusage.c
        gettimeofday.c
        itimer.c
@@ -23,4 +24,5 @@
        uname.c
        utimes.c
        wait.c
+       xsi_sem.c
 ;
Index: headers/posix/sys/ipc.h
===================================================================
--- headers/posix/sys/ipc.h     (revision 26404)
+++ headers/posix/sys/ipc.h     (working copy)
@@ -6,8 +6,8 @@
 #define _SYS_IPC_H
 
 
+#include <sys/cdefs.h>
 #include <sys/types.h>
-#error functionality has not yet been implemented
 
 
 /* Mode bits for msgget(), semget(), and shmget() */
@@ -17,15 +17,15 @@
 
 /* Control commands for msgctl(), semctl(), and shmctl() */
 #define IPC_RMID       0               /* remove identifier */
-#define IPC_SET                1
-#define IPC_STAT       2
+#define IPC_SET                1               /* set options */
+#define IPC_STAT       2               /* get options */
 
 /* Private key */
-#define IPC_PRIVATE    0
+#define IPC_PRIVATE            (key_t)0
 
 
 struct ipc_perm {
-       key_t   key;
+       key_t   key;                    /* IPC identifier */
        uid_t   uid;                    /* owner's user ID */
        gid_t   gid;                    /* owner's group ID */
        uid_t   cuid;                   /* creator's user ID */
@@ -34,14 +34,10 @@
 };
 
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
 
 key_t ftok(const char *path, int id);
 
-#ifdef __cplusplus
-}
-#endif
+__END_DECLS
 
 #endif /* _SYS_IPC_H */
Index: headers/posix/sys/types.h
===================================================================
--- headers/posix/sys/types.h   (revision 26404)
+++ headers/posix/sys/types.h   (working copy)
@@ -1,5 +1,6 @@
 /*
- * Distributed under the terms of the OpenBeOS license
+ * Copyright 2008, Haiku Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
  */
 #ifndef _SYS_TYPES_H
 #define _SYS_TYPES_H
Index: headers/posix/sys/sem.h
===================================================================
--- headers/posix/sys/sem.h     (revision 0)
+++ headers/posix/sys/sem.h     (revision 0)
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008, Haiku Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _SYS_SEM_H
+#define _SYS_SEM_H
+
+#include <sys/cdefs.h>
+#include <sys/ipc.h>
+#include <sys/types.h>
+
+
+// Semaphore operation flags
+#define        SEM_UNDO        10
+
+// Command definition for semctl
+#define        GETPID          3       // Get process ID of last element 
manipulating
+#define        GETVAL          4       // Get semval
+#define        GETALL          5       // Get all semval
+#define        GETNCNT         6       // Get semncnt
+#define        GETZCNT         7       // Get semzcnt
+#define        SETVAL          8       // Set semval
+#define        SETALL          9       // Set all semval
+
+struct semid_ds {
+       struct ipc_perm         sem_perm;       // Operation permission 
structure
+       unsigned short          sem_nsems;      // Number of semaphores in set
+       time_t                          sem_otime;      // Last semop
+       time_t                          sem_ctime;      // Last time changed by 
semctl
+};
+
+// Structure passed as parameter to the semop function
+struct sembuf {
+       unsigned short  sem_num;        // Semaphore number
+       short                   sem_op;         // Semaphore operation
+       short                   sem_flg;        // Operation flags
+};
+
+// Semaphore info structure. Useful for the ipcs
+// standard utily
+struct  seminfo {
+       int semmni;     // Number of semaphore identifies
+       int semmns;     // Number of semaphore in system
+       int semmnu;     // Number of undo structures in system
+       int semmsl;     // Max number of semaphores per id
+       int semopm;     // Max number of operations per semop call
+       int semume;     // Max number of undo entries per process
+       int semusz;     // Size in bytes of undo structure
+       int semvmx;     // Semaphore maximum valure
+       int semaem;     // adjust on exit max value
+};
+
+
+__BEGIN_DECLS
+
+int            semctl(int sem_id, int sem_num, int command, ...);
+int            semget(key_t key, int num_sems, int sem_flags);
+int            semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
+
+__END_DECLS
+
+
+#endif /* _SYS_SEM_H */
Index: headers/posix/sys/resource.h
===================================================================
--- headers/posix/sys/resource.h        (revision 26404)
+++ headers/posix/sys/resource.h        (working copy)
@@ -1,10 +1,11 @@
+/*
+ * Copyright 2008, Haiku Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
 #ifndef _SYS_RESOURCE_H
 #define _SYS_RESOURCE_H
-/* 
-** Distributed under the terms of the OpenBeOS License.
-*/
 
-
+#include <sys/cdefs.h>
 #include <sys/time.h>
 
 
@@ -53,9 +54,7 @@
 #define PRIO_USER              2
 
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
 
 extern int getrusage(int who, struct rusage *rusage);
 
@@ -66,8 +65,6 @@
  * int getpriority(int which, id_t who);
  * int setpriority(int which, id_t who, int priority); */
 
-#ifdef __cplusplus
-}
-#endif
+__END_DECLS
 
 #endif /* _SYS_RESOURCE_H */
Index: headers/private/kernel/posix/xsi_semaphore.h
===================================================================
--- headers/private/kernel/posix/xsi_semaphore.h        (revision 0)
+++ headers/private/kernel/posix/xsi_semaphore.h        (revision 0)
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008, Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Salvatore Benedetto <salvatore.benedetto@xxxxxxxxx>
+ */
+#ifndef        KERNEL_XSI_H
+#define KERNEL_XSI_H
+
+#include <sys/sem.h>
+#include <sys/cdefs.h>
+
+#include <OS.h>
+
+struct kernel_args;
+
+union semun {
+       int                                     val;
+       struct semid_ds         *buf;
+       unsigned short          *array;
+};
+
+__BEGIN_DECLS
+
+extern status_t haiku_xsi_ipc_init(struct kernel_args *args);
+
+/* user calls */
+int _user_xsi_semget(key_t key, int numberOfSemaphores, int flags);
+int _user_xsi_semctl(int semaphoreID, int semaphoreNumber, int command, union 
semun* args);
+status_t _user_xsi_semop(int semaphoreID, struct sembuf *sops, size_t nsops);
+
+__END_DECLS
+
+#endif /* KERNEL_XSI_H */
Index: headers/private/kernel/util/OpenHashTable.h
===================================================================
--- headers/private/kernel/util/OpenHashTable.h (revision 26404)
+++ headers/private/kernel/util/OpenHashTable.h (working copy)
@@ -30,7 +30,7 @@
                size_t HashKey(int key) const { return key >> 1; }
                size_t Hash(Foo *value) const { return HashKey(value->bar); }
                bool Compare(int key, Foo *value) const { return value->bar == 
key; }
-               HashTableLink<Foo> *GetLink(Foo *value) const { return value; }
+               HashTableLink<Foo> *GetLink(Foo *value) const { return 
&value->otherLink; }
        };
 */
 
Index: headers/private/system/syscalls.h
===================================================================
--- headers/private/system/syscalls.h   (revision 26404)
+++ headers/private/system/syscalls.h   (working copy)
@@ -27,6 +27,7 @@
 struct net_stat;
 struct pollfd;
 struct rlimit;
+struct sembuf;
 struct sigaction;
 struct stat;
 struct _sem_t;
@@ -38,6 +39,7 @@
 struct user_disk_device_job_info;
 struct user_disk_system_info;
 
+union semun;
 // This marks the beginning of the syscalls prototypes for gensyscallinfos.
 // NOTE:
 // * Nothing but those prototypes may live here.
@@ -89,6 +91,11 @@
 extern status_t                _kern_realtime_sem_post(sem_id semID);
 extern status_t                _kern_realtime_sem_wait(sem_id semID, bigtime_t 
timeout);
 
+/* POSIX XSI sem syscalls */
+extern int                     _kern_xsi_semget(key_t key, int 
numberOfSemaphores, int flags);
+extern int                     _kern_xsi_semctl(int semaphoreID, int 
semaphoreNumber, int command, union semun* args);
+extern status_t                _kern_xsi_semop(int semaphoreID, struct sembuf 
*sops, size_t nsops);
+
 /* team & thread syscalls */
 
 extern thread_id       _kern_load_image(const char* const* flatArgs,

Other related posts: