* Added some padding to the sem_t structure.
* Changed the semantics of unnamed semaphores. Before parent and child of a fork() would always share an earlier created semaphore. Now we do that only, if the "shared" parameter of sem_init() was true. That's still not quite the behavior Linux and Solaris have, but should be perfectly fine with how reasonable code would use the API. * There's a global table for shared unnamed semaphores now. ATM a semaphore is leaked when no one explicitly destroys it (just as with named sems). * Enforce per-team and global semaphore number limits. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25362 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -5,12 +5,14 @@
|
|||||||
#ifndef _SEMAPHORE_H_
|
#ifndef _SEMAPHORE_H_
|
||||||
#define _SEMAPHORE_H_
|
#define _SEMAPHORE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int id;
|
int32_t id;
|
||||||
|
int32_t _padding[3];
|
||||||
} sem_t;
|
} sem_t;
|
||||||
|
|
||||||
#define SEM_FAILED ((sem_t*)(long)-1)
|
#define SEM_FAILED ((sem_t*)(long)-1)
|
||||||
|
|||||||
@@ -77,9 +77,9 @@ extern status_t _kern_get_next_sem_info(team_id team, int32 *cookie,
|
|||||||
extern status_t _kern_set_sem_owner(sem_id id, team_id proc);
|
extern status_t _kern_set_sem_owner(sem_id id, team_id proc);
|
||||||
|
|
||||||
/* POSIX realtime sem syscalls */
|
/* POSIX realtime sem syscalls */
|
||||||
extern status_t _kern_realtime_sem_open(const char* name, int openFlags,
|
extern status_t _kern_realtime_sem_open(const char* name,
|
||||||
mode_t mode, uint32 semCount, sem_t* userSem,
|
int openFlagsOrShared, mode_t mode, uint32 semCount,
|
||||||
sem_t** _usedUserSem);
|
sem_t* userSem, sem_t** _usedUserSem);
|
||||||
extern status_t _kern_realtime_sem_close(sem_id semID,
|
extern status_t _kern_realtime_sem_close(sem_id semID,
|
||||||
sem_t** _deleteUserSem);
|
sem_t** _deleteUserSem);
|
||||||
extern status_t _kern_realtime_sem_unlink(const char* name);
|
extern status_t _kern_realtime_sem_unlink(const char* name);
|
||||||
|
|||||||
@@ -29,33 +29,61 @@ class SemInfo {
|
|||||||
public:
|
public:
|
||||||
SemInfo()
|
SemInfo()
|
||||||
:
|
:
|
||||||
fName(NULL),
|
fSemaphoreID(-1)
|
||||||
fRefCount(1),
|
|
||||||
fID(-1)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
~SemInfo()
|
virtual ~SemInfo()
|
||||||
|
{
|
||||||
|
if (fSemaphoreID >= 0)
|
||||||
|
delete_sem(fSemaphoreID);
|
||||||
|
}
|
||||||
|
|
||||||
|
sem_id SemaphoreID() const { return fSemaphoreID; }
|
||||||
|
|
||||||
|
status_t Init(int32 semCount, const char* name)
|
||||||
|
{
|
||||||
|
fSemaphoreID = create_sem(semCount, name);
|
||||||
|
if (fSemaphoreID < 0)
|
||||||
|
return fSemaphoreID;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual sem_id ID() const = 0;
|
||||||
|
virtual SemInfo* Clone() = 0;
|
||||||
|
virtual void Delete() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sem_id fSemaphoreID;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class NamedSem : public SemInfo {
|
||||||
|
public:
|
||||||
|
NamedSem()
|
||||||
|
:
|
||||||
|
fName(NULL),
|
||||||
|
fRefCount(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~NamedSem()
|
||||||
{
|
{
|
||||||
free(fName);
|
free(fName);
|
||||||
if (fID >= 0)
|
|
||||||
delete_sem(fID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Name() const { return fName; }
|
const char* Name() const { return fName; }
|
||||||
sem_id ID() const { return fID; }
|
|
||||||
|
|
||||||
status_t Init(const char* name, mode_t mode, int32 semCount)
|
status_t Init(const char* name, mode_t mode, int32 semCount)
|
||||||
{
|
{
|
||||||
if (name != NULL) {
|
status_t error = SemInfo::Init(semCount, name);
|
||||||
fName = strdup(name);
|
if (error != B_OK)
|
||||||
if (fName == NULL)
|
return error;
|
||||||
return B_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
fID = create_sem(semCount, name);
|
fName = strdup(name);
|
||||||
if (fID < 0)
|
if (fName == NULL)
|
||||||
return fID;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
fUID = geteuid();
|
fUID = geteuid();
|
||||||
fGID = getegid();
|
fGID = getegid();
|
||||||
@@ -91,7 +119,23 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTableLink<SemInfo>* HashTableLink()
|
virtual sem_id ID() const
|
||||||
|
{
|
||||||
|
return SemaphoreID();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SemInfo* Clone()
|
||||||
|
{
|
||||||
|
AcquireReference();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Delete()
|
||||||
|
{
|
||||||
|
ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
HashTableLink<NamedSem>* HashTableLink()
|
||||||
{
|
{
|
||||||
return &fHashLink;
|
return &fHashLink;
|
||||||
}
|
}
|
||||||
@@ -99,64 +143,192 @@ public:
|
|||||||
private:
|
private:
|
||||||
char* fName;
|
char* fName;
|
||||||
vint32 fRefCount;
|
vint32 fRefCount;
|
||||||
sem_id fID;
|
|
||||||
uid_t fUID;
|
uid_t fUID;
|
||||||
gid_t fGID;
|
gid_t fGID;
|
||||||
mode_t fPermissions;
|
mode_t fPermissions;
|
||||||
|
|
||||||
::HashTableLink<SemInfo> fHashLink;
|
::HashTableLink<NamedSem> fHashLink;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class UnnamedSem : public SemInfo {
|
||||||
|
public:
|
||||||
|
UnnamedSem()
|
||||||
|
:
|
||||||
|
fID(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~UnnamedSem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Init(int32 semCount, const char* name)
|
||||||
|
{
|
||||||
|
return SemInfo::Init(semCount, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetID(sem_id id)
|
||||||
|
{
|
||||||
|
fID = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual sem_id ID() const
|
||||||
|
{
|
||||||
|
return fID;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SemInfo* Clone()
|
||||||
|
{
|
||||||
|
sem_info info;
|
||||||
|
if (get_sem_info(SemaphoreID(), &info) != B_OK)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
UnnamedSem* clone = new(std::nothrow) UnnamedSem;
|
||||||
|
if (clone == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (clone->Init(info.count, info.name) != B_OK) {
|
||||||
|
delete clone;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
clone->SetID(fID);
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Delete()
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sem_id fID;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class UnnamedSharedSem : public SemInfo {
|
||||||
|
public:
|
||||||
|
UnnamedSharedSem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~UnnamedSharedSem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Init(int32 semCount, const char* name)
|
||||||
|
{
|
||||||
|
return SemInfo::Init(semCount, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual sem_id ID() const
|
||||||
|
{
|
||||||
|
return SemaphoreID();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SemInfo* Clone()
|
||||||
|
{
|
||||||
|
// Can't be cloned.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Delete()
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashTableLink<UnnamedSharedSem>* HashTableLink()
|
||||||
|
{
|
||||||
|
return &fHashLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
::HashTableLink<UnnamedSharedSem> fHashLink;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct NamedSemHashDefinition {
|
struct NamedSemHashDefinition {
|
||||||
typedef const char* KeyType;
|
typedef const char* KeyType;
|
||||||
typedef SemInfo ValueType;
|
typedef NamedSem ValueType;
|
||||||
|
|
||||||
size_t HashKey(const KeyType& key) const
|
size_t HashKey(const KeyType& key) const
|
||||||
{
|
{
|
||||||
return hash_hash_string(key);
|
return hash_hash_string(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Hash(SemInfo* semaphore) const
|
size_t Hash(NamedSem* semaphore) const
|
||||||
{
|
{
|
||||||
return HashKey(semaphore->Name());
|
return HashKey(semaphore->Name());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Compare(const KeyType& key, SemInfo* semaphore) const
|
bool Compare(const KeyType& key, NamedSem* semaphore) const
|
||||||
{
|
{
|
||||||
return strcmp(key, semaphore->Name()) == 0;
|
return strcmp(key, semaphore->Name()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTableLink<SemInfo>* GetLink(SemInfo* semaphore) const
|
HashTableLink<NamedSem>* GetLink(NamedSem* semaphore) const
|
||||||
{
|
{
|
||||||
return semaphore->HashTableLink();
|
return semaphore->HashTableLink();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class GlobalRealtimeSemTable {
|
struct UnnamedSemHashDefinition {
|
||||||
public:
|
typedef sem_id KeyType;
|
||||||
GlobalRealtimeSemTable()
|
typedef UnnamedSharedSem ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(const KeyType& key) const
|
||||||
{
|
{
|
||||||
mutex_init(&fLock, "global realtime sem table");
|
return (size_t)key;
|
||||||
}
|
}
|
||||||
|
|
||||||
~GlobalRealtimeSemTable()
|
size_t Hash(UnnamedSharedSem* semaphore) const
|
||||||
|
{
|
||||||
|
return HashKey(semaphore->SemaphoreID());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(const KeyType& key, UnnamedSharedSem* semaphore) const
|
||||||
|
{
|
||||||
|
return key == semaphore->SemaphoreID();
|
||||||
|
}
|
||||||
|
|
||||||
|
HashTableLink<UnnamedSharedSem>* GetLink(UnnamedSharedSem* semaphore) const
|
||||||
|
{
|
||||||
|
return semaphore->HashTableLink();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class GlobalSemTable {
|
||||||
|
public:
|
||||||
|
GlobalSemTable()
|
||||||
|
:
|
||||||
|
fSemaphoreCount(0)
|
||||||
|
{
|
||||||
|
mutex_init(&fLock, "global named sem table");
|
||||||
|
}
|
||||||
|
|
||||||
|
~GlobalSemTable()
|
||||||
{
|
{
|
||||||
mutex_destroy(&fLock);
|
mutex_destroy(&fLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t Init()
|
status_t Init()
|
||||||
{
|
{
|
||||||
return fSemaphores.InitCheck();
|
status_t error = fNamedSemaphores.InitCheck();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
return fUnnamedSemaphores.InitCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t OpenSem(const char* name, int openFlags, mode_t mode,
|
status_t OpenNamedSem(const char* name, int openFlags, mode_t mode,
|
||||||
uint32 semCount, SemInfo*& _sem, bool& _created)
|
uint32 semCount, NamedSem*& _sem, bool& _created)
|
||||||
{
|
{
|
||||||
MutexLocker _(fLock);
|
MutexLocker _(fLock);
|
||||||
|
|
||||||
SemInfo* sem = fSemaphores.Lookup(name);
|
NamedSem* sem = fNamedSemaphores.Lookup(name);
|
||||||
if (sem != NULL) {
|
if (sem != NULL) {
|
||||||
if ((openFlags & O_EXCL) != 0)
|
if ((openFlags & O_EXCL) != 0)
|
||||||
return EEXIST;
|
return EEXIST;
|
||||||
@@ -174,8 +346,10 @@ public:
|
|||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
||||||
// does not exist yet -- create
|
// does not exist yet -- create
|
||||||
// TODO: Enforce per team semaphore limit!
|
if (fSemaphoreCount >= MAX_POSIX_SEMS)
|
||||||
sem = new(std::nothrow) SemInfo;
|
return ENOSPC;
|
||||||
|
|
||||||
|
sem = new(std::nothrow) NamedSem;
|
||||||
if (sem == NULL)
|
if (sem == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -185,7 +359,7 @@ public:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = fSemaphores.Insert(sem);
|
error = fNamedSemaphores.Insert(sem);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
delete sem;
|
delete sem;
|
||||||
return error;
|
return error;
|
||||||
@@ -194,38 +368,92 @@ public:
|
|||||||
// add one reference for the table
|
// add one reference for the table
|
||||||
sem->AcquireReference();
|
sem->AcquireReference();
|
||||||
|
|
||||||
|
fSemaphoreCount++;
|
||||||
|
|
||||||
_sem = sem;
|
_sem = sem;
|
||||||
_created = true;
|
_created = true;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t UnlinkSem(const char* name)
|
status_t UnlinkNamedSem(const char* name)
|
||||||
{
|
{
|
||||||
MutexLocker _(fLock);
|
MutexLocker _(fLock);
|
||||||
|
|
||||||
SemInfo* sem = fSemaphores.Lookup(name);
|
NamedSem* sem = fNamedSemaphores.Lookup(name);
|
||||||
if (sem == NULL)
|
if (sem == NULL)
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
||||||
if (!sem->HasPermissions())
|
if (!sem->HasPermissions())
|
||||||
return EACCES;
|
return EACCES;
|
||||||
|
|
||||||
fSemaphores.Remove(sem);
|
fNamedSemaphores.Remove(sem);
|
||||||
sem->ReleaseReference();
|
sem->ReleaseReference();
|
||||||
// release the table reference
|
// release the table reference
|
||||||
|
fSemaphoreCount--;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
status_t CreateUnnamedSem(uint32 semCount, int32_t& _id)
|
||||||
typedef OpenHashTable<NamedSemHashDefinition, true> SemTable;
|
{
|
||||||
|
MutexLocker _(fLock);
|
||||||
|
|
||||||
mutex fLock;
|
if (fSemaphoreCount >= MAX_POSIX_SEMS)
|
||||||
SemTable fSemaphores;
|
return ENOSPC;
|
||||||
|
|
||||||
|
UnnamedSharedSem* sem = new(std::nothrow) UnnamedSharedSem;
|
||||||
|
if (sem == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t error = sem->Init(semCount, "unnamed shared sem");
|
||||||
|
if (error == B_OK)
|
||||||
|
error = fUnnamedSemaphores.Insert(sem);
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete sem;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fSemaphoreCount++;
|
||||||
|
|
||||||
|
_id = sem->SemaphoreID();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t DeleteUnnamedSem(sem_id id)
|
||||||
|
{
|
||||||
|
MutexLocker _(fLock);
|
||||||
|
|
||||||
|
UnnamedSharedSem* sem = fUnnamedSemaphores.Lookup(id);
|
||||||
|
if (sem == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
fUnnamedSemaphores.Remove(sem);
|
||||||
|
delete sem;
|
||||||
|
|
||||||
|
fSemaphoreCount--;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsUnnamedValidSem(sem_id id)
|
||||||
|
{
|
||||||
|
MutexLocker _(fLock);
|
||||||
|
|
||||||
|
return fUnnamedSemaphores.Lookup(id) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef OpenHashTable<NamedSemHashDefinition, true> NamedSemTable;
|
||||||
|
typedef OpenHashTable<UnnamedSemHashDefinition, true> UnnamedSemTable;
|
||||||
|
|
||||||
|
mutex fLock;
|
||||||
|
NamedSemTable fNamedSemaphores;
|
||||||
|
UnnamedSemTable fUnnamedSemaphores;
|
||||||
|
int32 fSemaphoreCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static GlobalRealtimeSemTable sSemTable;
|
static GlobalSemTable sSemTable;
|
||||||
|
|
||||||
|
|
||||||
class TeamSemInfo {
|
class TeamSemInfo {
|
||||||
@@ -241,10 +469,11 @@ public:
|
|||||||
~TeamSemInfo()
|
~TeamSemInfo()
|
||||||
{
|
{
|
||||||
if (fSemaphore != NULL)
|
if (fSemaphore != NULL)
|
||||||
fSemaphore->ReleaseReference();
|
fSemaphore->Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
SemInfo* Semaphore() const { return fSemaphore; }
|
sem_id ID() const { return fSemaphore->ID(); }
|
||||||
|
sem_id SemaphoreID() const { return fSemaphore->SemaphoreID(); }
|
||||||
sem_t* UserSemaphore() const { return fUserSemaphore; }
|
sem_t* UserSemaphore() const { return fUserSemaphore; }
|
||||||
|
|
||||||
void Open()
|
void Open()
|
||||||
@@ -259,15 +488,19 @@ public:
|
|||||||
|
|
||||||
TeamSemInfo* Clone() const
|
TeamSemInfo* Clone() const
|
||||||
{
|
{
|
||||||
TeamSemInfo* sem = new(std::nothrow) TeamSemInfo(fSemaphore,
|
SemInfo* sem = fSemaphore->Clone();
|
||||||
fUserSemaphore);
|
|
||||||
if (sem == NULL)
|
if (sem == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
sem->fOpenCount = fOpenCount;
|
TeamSemInfo* clone = new(std::nothrow) TeamSemInfo(sem, fUserSemaphore);
|
||||||
fSemaphore->AcquireReference();
|
if (clone == NULL) {
|
||||||
|
sem->Delete();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return sem;
|
clone->fOpenCount = fOpenCount;
|
||||||
|
|
||||||
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTableLink<TeamSemInfo>* HashTableLink()
|
HashTableLink<TeamSemInfo>* HashTableLink()
|
||||||
@@ -295,12 +528,12 @@ struct TeamSemHashDefinition {
|
|||||||
|
|
||||||
size_t Hash(TeamSemInfo* semaphore) const
|
size_t Hash(TeamSemInfo* semaphore) const
|
||||||
{
|
{
|
||||||
return HashKey(semaphore->Semaphore()->ID());
|
return HashKey(semaphore->ID());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Compare(const KeyType& key, TeamSemInfo* semaphore) const
|
bool Compare(const KeyType& key, TeamSemInfo* semaphore) const
|
||||||
{
|
{
|
||||||
return key == semaphore->Semaphore()->ID();
|
return key == semaphore->ID();
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTableLink<TeamSemInfo>* GetLink(TeamSemInfo* semaphore) const
|
HashTableLink<TeamSemInfo>* GetLink(TeamSemInfo* semaphore) const
|
||||||
@@ -312,6 +545,8 @@ struct TeamSemHashDefinition {
|
|||||||
|
|
||||||
struct realtime_sem_context {
|
struct realtime_sem_context {
|
||||||
realtime_sem_context()
|
realtime_sem_context()
|
||||||
|
:
|
||||||
|
fSemaphoreCount(0)
|
||||||
{
|
{
|
||||||
mutex_init(&fLock, "realtime sem context");
|
mutex_init(&fLock, "realtime sem context");
|
||||||
}
|
}
|
||||||
@@ -334,6 +569,7 @@ struct realtime_sem_context {
|
|||||||
|
|
||||||
status_t Init()
|
status_t Init()
|
||||||
{
|
{
|
||||||
|
fNextPrivateSemID = -1;
|
||||||
return fSemaphores.InitCheck();
|
return fSemaphores.InitCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,6 +583,8 @@ struct realtime_sem_context {
|
|||||||
|
|
||||||
MutexLocker _(fLock);
|
MutexLocker _(fLock);
|
||||||
|
|
||||||
|
context->fNextPrivateSemID = fNextPrivateSemID;
|
||||||
|
|
||||||
// clone all semaphores
|
// clone all semaphores
|
||||||
SemTable::Iterator it = fSemaphores.GetIterator();
|
SemTable::Iterator it = fSemaphores.GetIterator();
|
||||||
while (TeamSemInfo* sem = it.Next()) {
|
while (TeamSemInfo* sem = it.Next()) {
|
||||||
@@ -358,21 +596,24 @@ struct realtime_sem_context {
|
|||||||
delete clonedSem;
|
delete clonedSem;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
context->fSemaphoreCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
contextDeleter.Detach();
|
contextDeleter.Detach();
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t CreateAnonymousSem(uint32 semCount, int& _id)
|
status_t CreateUnnamedSem(uint32 semCount, bool shared, int32_t& _id)
|
||||||
{
|
{
|
||||||
// TODO: Enforce per team semaphore limit!
|
if (shared)
|
||||||
SemInfo* sem = new(std::nothrow) SemInfo;
|
return sSemTable.CreateUnnamedSem(semCount, _id);
|
||||||
|
|
||||||
|
UnnamedSem* sem = new(std::nothrow) UnnamedSem;
|
||||||
if (sem == NULL)
|
if (sem == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
ObjectDeleter<SemInfo> semDeleter(sem);
|
ObjectDeleter<UnnamedSem> semDeleter(sem);
|
||||||
|
|
||||||
status_t error = sem->Init(NULL, 0, semCount);
|
status_t error = sem->Init(semCount, "unnamed sem");
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@@ -383,23 +624,31 @@ struct realtime_sem_context {
|
|||||||
|
|
||||||
MutexLocker _(fLock);
|
MutexLocker _(fLock);
|
||||||
|
|
||||||
|
if (fSemaphoreCount >= MAX_POSIX_SEMS_PER_TEAM) {
|
||||||
|
delete teamSem;
|
||||||
|
return ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
sem->SetID(_NextPrivateSemID());
|
||||||
|
|
||||||
error = fSemaphores.Insert(teamSem);
|
error = fSemaphores.Insert(teamSem);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
delete teamSem;
|
delete teamSem;
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
_id = teamSem->Semaphore()->ID();
|
fSemaphoreCount++;
|
||||||
|
|
||||||
|
_id = teamSem->ID();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t OpenSem(const char* name, int openFlags, mode_t mode,
|
status_t OpenSem(const char* name, int openFlags, mode_t mode,
|
||||||
uint32 semCount, sem_t* userSem, sem_t*& _usedUserSem, int& _id,
|
uint32 semCount, sem_t* userSem, sem_t*& _usedUserSem, int32_t& _id,
|
||||||
bool& _created)
|
bool& _created)
|
||||||
{
|
{
|
||||||
SemInfo* sem;
|
NamedSem* sem;
|
||||||
status_t error = sSemTable.OpenSem(name, openFlags, mode, semCount,
|
status_t error = sSemTable.OpenNamedSem(name, openFlags, mode, semCount,
|
||||||
sem, _created);
|
sem, _created);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
@@ -412,16 +661,25 @@ struct realtime_sem_context {
|
|||||||
teamSem->Open();
|
teamSem->Open();
|
||||||
sem->ReleaseReference();
|
sem->ReleaseReference();
|
||||||
_usedUserSem = teamSem->UserSemaphore();
|
_usedUserSem = teamSem->UserSemaphore();
|
||||||
_id = teamSem->Semaphore()->ID();
|
_id = teamSem->ID();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not open yet -- create a new team sem
|
// not open yet -- create a new team sem
|
||||||
|
|
||||||
|
// first check the semaphore limit, though
|
||||||
|
if (fSemaphoreCount >= MAX_POSIX_SEMS_PER_TEAM) {
|
||||||
|
sem->ReleaseReference();
|
||||||
|
if (_created)
|
||||||
|
sSemTable.UnlinkNamedSem(name);
|
||||||
|
return ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
teamSem = new(std::nothrow) TeamSemInfo(sem, userSem);
|
teamSem = new(std::nothrow) TeamSemInfo(sem, userSem);
|
||||||
if (teamSem == NULL) {
|
if (teamSem == NULL) {
|
||||||
sem->ReleaseReference();
|
sem->ReleaseReference();
|
||||||
if (_created)
|
if (_created)
|
||||||
sSemTable.UnlinkSem(name);
|
sSemTable.UnlinkNamedSem(name);
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,12 +687,14 @@ struct realtime_sem_context {
|
|||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
delete teamSem;
|
delete teamSem;
|
||||||
if (_created)
|
if (_created)
|
||||||
sSemTable.UnlinkSem(name);
|
sSemTable.UnlinkNamedSem(name);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fSemaphoreCount++;
|
||||||
|
|
||||||
_usedUserSem = teamSem->UserSemaphore();
|
_usedUserSem = teamSem->UserSemaphore();
|
||||||
_id = teamSem->Semaphore()->ID();
|
_id = teamSem->ID();
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -447,11 +707,12 @@ struct realtime_sem_context {
|
|||||||
|
|
||||||
TeamSemInfo* sem = fSemaphores.Lookup(id);
|
TeamSemInfo* sem = fSemaphores.Lookup(id);
|
||||||
if (sem == NULL)
|
if (sem == NULL)
|
||||||
return B_BAD_VALUE;
|
return sSemTable.DeleteUnnamedSem(id);
|
||||||
|
|
||||||
if (sem->Close()) {
|
if (sem->Close()) {
|
||||||
// last reference closed
|
// last reference closed
|
||||||
fSemaphores.Remove(sem);
|
fSemaphores.Remove(sem);
|
||||||
|
fSemaphoreCount--;
|
||||||
deleteUserSem = sem->UserSemaphore();
|
deleteUserSem = sem->UserSemaphore();
|
||||||
delete sem;
|
delete sem;
|
||||||
}
|
}
|
||||||
@@ -463,8 +724,12 @@ struct realtime_sem_context {
|
|||||||
{
|
{
|
||||||
MutexLocker locker(fLock);
|
MutexLocker locker(fLock);
|
||||||
|
|
||||||
if (fSemaphores.Lookup(id) == NULL)
|
TeamSemInfo* sem = fSemaphores.Lookup(id);
|
||||||
return B_BAD_VALUE;
|
if (sem == NULL) {
|
||||||
|
if (!sSemTable.IsUnnamedValidSem(id))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
} else
|
||||||
|
id = sem->SemaphoreID();
|
||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
@@ -487,8 +752,12 @@ struct realtime_sem_context {
|
|||||||
{
|
{
|
||||||
MutexLocker locker(fLock);
|
MutexLocker locker(fLock);
|
||||||
|
|
||||||
if (fSemaphores.Lookup(id) == NULL)
|
TeamSemInfo* sem = fSemaphores.Lookup(id);
|
||||||
return B_BAD_VALUE;
|
if (sem == NULL) {
|
||||||
|
if (!sSemTable.IsUnnamedValidSem(id))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
} else
|
||||||
|
id = sem->SemaphoreID();
|
||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
@@ -500,8 +769,12 @@ struct realtime_sem_context {
|
|||||||
{
|
{
|
||||||
MutexLocker locker(fLock);
|
MutexLocker locker(fLock);
|
||||||
|
|
||||||
if (fSemaphores.Lookup(id) == NULL)
|
TeamSemInfo* sem = fSemaphores.Lookup(id);
|
||||||
return B_BAD_VALUE;
|
if (sem == NULL) {
|
||||||
|
if (!sSemTable.IsUnnamedValidSem(id))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
} else
|
||||||
|
id = sem->SemaphoreID();
|
||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
@@ -514,11 +787,26 @@ struct realtime_sem_context {
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sem_id _NextPrivateSemID()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
if (fNextPrivateSemID >= 0)
|
||||||
|
fNextPrivateSemID = -1;
|
||||||
|
|
||||||
|
sem_id id = fNextPrivateSemID--;
|
||||||
|
if (fSemaphores.Lookup(id) == NULL)
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef OpenHashTable<TeamSemHashDefinition, true> SemTable;
|
typedef OpenHashTable<TeamSemHashDefinition, true> SemTable;
|
||||||
|
|
||||||
mutex fLock;
|
mutex fLock;
|
||||||
SemTable fSemaphores;
|
SemTable fSemaphores;
|
||||||
|
int32 fSemaphoreCount;
|
||||||
|
sem_id fNextPrivateSemID;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -585,9 +873,9 @@ copy_sem_name_to_kernel(const char* userName, KPath& buffer, char*& name)
|
|||||||
void
|
void
|
||||||
realtime_sem_init()
|
realtime_sem_init()
|
||||||
{
|
{
|
||||||
new(&sSemTable) GlobalRealtimeSemTable;
|
new(&sSemTable) GlobalSemTable;
|
||||||
if (sSemTable.Init() != B_OK)
|
if (sSemTable.Init() != B_OK)
|
||||||
panic("realtime_sem_init() failed to init global table");
|
panic("realtime_sem_init() failed to init global sem table");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -612,23 +900,27 @@ clone_realtime_sem_context(realtime_sem_context* context)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
_user_realtime_sem_open(const char* userName, int openFlags, mode_t mode,
|
_user_realtime_sem_open(const char* userName, int openFlagsOrShared,
|
||||||
uint32 semCount, sem_t* userSem, sem_t** _usedUserSem)
|
mode_t mode, uint32 semCount, sem_t* userSem, sem_t** _usedUserSem)
|
||||||
{
|
{
|
||||||
realtime_sem_context* context = get_current_team_context();
|
realtime_sem_context* context = get_current_team_context();
|
||||||
if (context == NULL)
|
if (context == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (semCount > MAX_POSIX_SEM_VALUE)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
// userSem must always be given
|
// userSem must always be given
|
||||||
if (userSem == NULL)
|
if (userSem == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
if (!IS_USER_ADDRESS(userSem))
|
if (!IS_USER_ADDRESS(userSem))
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
// anonymous semaphores are less work -- deal with them first
|
// unnamed semaphores are less work -- deal with them first
|
||||||
if (userName == NULL) {
|
if (userName == NULL) {
|
||||||
int id;
|
int32_t id;
|
||||||
status_t error = context->CreateAnonymousSem(semCount, id);
|
status_t error = context->CreateUnnamedSem(semCount, openFlagsOrShared,
|
||||||
|
id);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@@ -657,8 +949,8 @@ _user_realtime_sem_open(const char* userName, int openFlags, mode_t mode,
|
|||||||
// open the semaphore
|
// open the semaphore
|
||||||
sem_t* usedUserSem;
|
sem_t* usedUserSem;
|
||||||
bool created;
|
bool created;
|
||||||
int id;
|
int32_t id;
|
||||||
error = context->OpenSem(name, openFlags, mode, semCount, userSem,
|
error = context->OpenSem(name, openFlagsOrShared, mode, semCount, userSem,
|
||||||
usedUserSem, id, created);
|
usedUserSem, id, created);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
@@ -667,7 +959,7 @@ _user_realtime_sem_open(const char* userName, int openFlags, mode_t mode,
|
|||||||
if (user_memcpy(&userSem->id, &id, sizeof(int)) != B_OK
|
if (user_memcpy(&userSem->id, &id, sizeof(int)) != B_OK
|
||||||
|| user_memcpy(_usedUserSem, &usedUserSem, sizeof(sem_t*)) != B_OK) {
|
|| user_memcpy(_usedUserSem, &usedUserSem, sizeof(sem_t*)) != B_OK) {
|
||||||
if (created)
|
if (created)
|
||||||
sSemTable.UnlinkSem(name);
|
sSemTable.UnlinkNamedSem(name);
|
||||||
sem_t* dummy;
|
sem_t* dummy;
|
||||||
context->CloseSem(id, dummy);
|
context->CloseSem(id, dummy);
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
@@ -714,7 +1006,7 @@ _user_realtime_sem_unlink(const char* userName)
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return sSemTable.UnlinkSem(name);
|
return sSemTable.UnlinkNamedSem(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ sem_unlink(const char* name)
|
|||||||
int
|
int
|
||||||
sem_init(sem_t* semaphore, int shared, unsigned value)
|
sem_init(sem_t* semaphore, int shared, unsigned value)
|
||||||
{
|
{
|
||||||
RETURN_AND_SET_ERRNO(_kern_realtime_sem_open(NULL, 0, 0, value, semaphore,
|
RETURN_AND_SET_ERRNO(_kern_realtime_sem_open(NULL, shared, 0, value,
|
||||||
NULL));
|
semaphore, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user