// Copyright (c) 1999-2002 David Muse
// See the COPYING file for more information
#include <rudiments/semaphoreset.h>
#include <rudiments/passwdentry.h>
#include <rudiments/groupentry.h>
#include <rudiments/error.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#ifdef RUDIMENTS_NAMESPACE
namespace rudiments {
#endif
class semaphoresetprivate {
public:
int _semid;
bool _created;
int _semcount;
struct sembuf **_waitop;
struct sembuf **_waitwithundoop;
struct sembuf **_signalop;
struct sembuf **_signalwithundoop;
};
#ifndef RUDIMENTS_HAVE_SEMUN
union semun {
int val;
struct semid_ds *buf;
ushort *array;
};
#endif
// lame that this isn't part of the class, but I can't think of another way to
// keep #ifndef RUDIMENTS_HAVE_SEMUN out of the header file
static int semControl(semaphoresetprivate *pvt, int semnum,
int cmd, semun semctlun) {
int result;
do {
result=semctl(pvt->_semid,semnum,cmd,semctlun);
} while (result==-1 && error::getErrorNumber()==EINTR);
return result;
}
semaphoreset::semaphoreset() {
pvt=new semaphoresetprivate;
pvt->_semid=-1;
pvt->_created=false;
pvt->_waitop=NULL;
pvt->_waitwithundoop=NULL;
pvt->_signalop=NULL;
pvt->_signalwithundoop=NULL;
}
semaphoreset::~semaphoreset() {
if (pvt->_waitop) {
for (int i=0; i<pvt->_semcount; i++) {
delete[] pvt->_waitop[i];
delete[] pvt->_waitwithundoop[i];
delete[] pvt->_signalop[i];
delete[] pvt->_signalwithundoop[i];
}
delete[] pvt->_waitop;
delete[] pvt->_waitwithundoop;
delete[] pvt->_signalop;
delete[] pvt->_signalwithundoop;
}
if (pvt->_created) {
forceRemove();
}
delete pvt;
}
bool semaphoreset::forceRemove() {
semun semctlun;
return !semControl(pvt,0,IPC_RMID,semctlun);
}
void semaphoreset::dontRemove() {
pvt->_created=false;
}
int semaphoreset::getId() const {
return pvt->_semid;
}
bool semaphoreset::wait(int index) {
return semOp(pvt->_waitop[index]);
}
bool semaphoreset::wait(int index, long seconds, long nanoseconds) {
timespec ts;
ts.tv_sec=seconds;
ts.tv_nsec=nanoseconds;
return semTimedOp(pvt->_waitop[index],&ts);
}
bool semaphoreset::waitWithUndo(int index) {
return semOp(pvt->_waitwithundoop[index]);
}
bool semaphoreset::waitWithUndo(int index, long seconds, long nanoseconds) {
timespec ts;
ts.tv_sec=seconds;
ts.tv_nsec=nanoseconds;
return semTimedOp(pvt->_waitwithundoop[index],&ts);
}
bool semaphoreset::signal(int index) {
return semOp(pvt->_signalop[index]);
}
bool semaphoreset::signalWithUndo(int index) {
return semOp(pvt->_signalwithundoop[index]);
}
int semaphoreset::getValue(int index) {
semun semctlun;
return semControl(pvt,index,GETVAL,semctlun);
}
bool semaphoreset::setValue(int index, int value) {
semun semctlun;
semctlun.val=value;
return !semControl(pvt,index,SETVAL,semctlun);
}
int semaphoreset::getWaitingForZero(int index) {
semun semctlun;
return semControl(pvt,index,GETZCNT,semctlun);
}
int semaphoreset::getWaitingForIncrement(int index) {
semun semctlun;
return semControl(pvt,index,GETNCNT,semctlun);
}
bool semaphoreset::create(key_t key, mode_t permissions,
int semcount, const int *values) {
pvt->_semcount=semcount;
// create the semaphore
if ((pvt->_semid=semGet(key,semcount,
IPC_CREAT|IPC_EXCL|permissions))!=-1) {
// if creation succeeded, initialize the semaphore
if (values) {
for (int i=0; i<semcount; i++) {
setValue(i,values[i]);
}
}
// mark for removal
pvt->_created=true;
createOperations();
return true;
}
return false;
}
bool semaphoreset::attach(key_t key, int semcount) {
pvt->_semcount=semcount;
if ((pvt->_semid=semGet(key,semcount,0))!=-1) {
createOperations();
return true;
}
return false;
}
bool semaphoreset::createOrAttach(key_t key, mode_t permissions,
int semcount, const int *values) {
pvt->_semcount=semcount;
// create the semaphore
if ((pvt->_semid=semGet(key,semcount,
IPC_CREAT|IPC_EXCL|permissions))!=-1) {
// if creation succeeded, initialize the semaphore
if (values) {
for (int i=0; i<semcount; i++) {
setValue(i,values[i]);
}
}
// mark for removal
pvt->_created=true;
} else if (!(error::getErrorNumber()==EEXIST &&
(pvt->_semid=semGet(key,semcount,permissions))!=-1)) {
return false;
}
createOperations();
return true;
}
void semaphoreset::createOperations() {
pvt->_waitop=new sembuf *[pvt->_semcount];
pvt->_waitwithundoop=new sembuf *[pvt->_semcount];
pvt->_signalop=new sembuf *[pvt->_semcount];
pvt->_signalwithundoop=new sembuf *[pvt->_semcount];
for (int i=0; i<pvt->_semcount; i++) {
// wait without undo
pvt->_waitop[i]=new sembuf[1];
pvt->_waitop[i][0].sem_num=(short)i;
pvt->_waitop[i][0].sem_op=-1;
pvt->_waitop[i][0].sem_flg=0;
// wait with undo
pvt->_waitwithundoop[i]=new sembuf[1];
pvt->_waitwithundoop[i][0].sem_num=(short)i;
pvt->_waitwithundoop[i][0].sem_op=-1;
pvt->_waitwithundoop[i][0].sem_flg=SEM_UNDO;
// signal without undo
pvt->_signalop[i]=new sembuf[1];
pvt->_signalop[i][0].sem_num=(short)i;
pvt->_signalop[i][0].sem_op=1;
pvt->_signalop[i][0].sem_flg=0;
// signal with undo
pvt->_signalwithundoop[i]=new sembuf[1];
pvt->_signalwithundoop[i][0].sem_num=(short)i;
pvt->_signalwithundoop[i][0].sem_op=1;
pvt->_signalwithundoop[i][0].sem_flg=SEM_UNDO;
}
}
bool semaphoreset::setUserId(uid_t uid) {
semid_ds setds;
setds.sem_perm.uid=uid;
semun semctlun;
semctlun.buf=&setds;
return !semControl(pvt,0,IPC_SET,semctlun);
}
bool semaphoreset::setGroupId(gid_t gid) {
semid_ds setds;
setds.sem_perm.gid=gid;
semun semctlun;
semctlun.buf=&setds;
return !semControl(pvt,0,IPC_SET,semctlun);
}
bool semaphoreset::setUserName(const char *username) {
uid_t userid;
return passwdentry::getUserId(username,&userid) &&
setUserId(userid);
}
bool semaphoreset::setGroupName(const char *groupname) {
gid_t groupid;
return groupentry::getGroupId(groupname,&groupid) &&
setGroupId(groupid);
}
bool semaphoreset::setPermissions(mode_t permissions) {
semid_ds setds;
setds.sem_perm.mode=permissions;
semun semctlun;
semctlun.buf=&setds;
return !semControl(pvt,0,IPC_SET,semctlun);
}
const char *semaphoreset::getUserName() {
semid_ds getds;
semun semctlun;
semctlun.buf=&getds;
char *name;
if (!semControl(pvt,0,IPC_STAT,semctlun) &&
passwdentry::getName(getds.sem_perm.uid,&name)) {
return name;
}
return NULL;
}
uid_t semaphoreset::getUserId() {
semid_ds getds;
semun semctlun;
semctlun.buf=&getds;
if (!semControl(pvt,0,IPC_STAT,semctlun)) {
return (short)getds.sem_perm.uid;
}
return 0;
}
const char *semaphoreset::getGroupName() {
semid_ds getds;
semun semctlun;
semctlun.buf=&getds;
char *name;
if (!semControl(pvt,0,IPC_STAT,semctlun) &&
groupentry::getName(getds.sem_perm.gid,&name)) {
return name;
}
return NULL;
}
gid_t semaphoreset::getGroupId() {
semid_ds getds;
semun semctlun;
semctlun.buf=&getds;
if (!semControl(pvt,0,IPC_STAT,semctlun)) {
return (short)getds.sem_perm.gid;
}
return 0;
}
mode_t semaphoreset::getPermissions() {
semid_ds getds;
semun semctlun;
semctlun.buf=&getds;
if (!semControl(pvt,0,IPC_STAT,semctlun)) {
return getds.sem_perm.mode;
}
return 0;
}
int semaphoreset::semGet(key_t key, int nsems, int semflg) {
int result;
do {
result=semget(key,nsems,semflg);
} while (result==-1 && error::getErrorNumber()==EINTR);
return result;
}
bool semaphoreset::semOp(struct sembuf *sops) {
int result;
do {
result=semop(pvt->_semid,sops,1);
} while (result==-1 && error::getErrorNumber()==EINTR);
return !result;
}
bool semaphoreset::semTimedOp(struct sembuf *sops, timespec *ts) {
#ifdef RUDIMENTS_HAVE_SEMTIMEDOP
int result;
do {
result=semtimedop(pvt->_semid,sops,1,ts);
} while (result==-1 && error::getErrorNumber()==EINTR);
return !result;
#else
return false;
#endif
}
bool semaphoreset::supportsTimedSemaphoreOperations() {
#ifdef RUDIMENTS_HAVE_SEMTIMEDOP
return true;
#else
return false;
#endif
}
#ifdef RUDIMENTS_NAMESPACE
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1