SemaphoreWrapper/src/ProcessSemaphore_Linux.cpp

133 lines
2.4 KiB
C++

#if (defined(__linux__)&&!defined(_TRY_POSIX)&&!defined(_C4DROID_)) /// Linux platform without trying posix.
#include "SemaphoreWrapper.h"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include "log.h"
class ProcessSemaphore::impl
{
public:
int id;
int key;
int status;
bool created;
};
static void _do_clean_up_semaphore(int key,int id)
{
if(semctl(id,0,IPC_RMID,0)<0)
{
dprintf("Failed to destroy process semaphore (call semctl failed on key: %d, id: %d)",key,id);
}
}
ProcessSemaphore::ProcessSemaphore(int key,int action,int default_value) : _p(new impl)
{
if(_p)
{
_p->key=key;
_p->status=0;
switch(action)
{
case 0:
_p->id=semget(key,1,0666);
break;
case 1:
_p->id=semget(key,1,0666|IPC_CREAT|IPC_EXCL);
break;
}
if(_p->id<0)
{
_p->status=0;
}
else
{
_p->status=1;
if(action==1) /// Created semaphore needs to be initialized
{
if(semctl(_p->id,0,SETVAL,1)>=0)
{
_p->status=2;
_p->created=true;
}
}
else /// Got a created semaphore
{
_p->status=2;
_p->created=false;
}
if(_p->status!=2) /// Semaphore does not reach ready level.
{
_do_clean_up_semaphore(key,_p->id);
_p->status=0; /// Set status to empty(0)
}
}
}
}
bool ProcessSemaphore::isReady() const
{
return _p&&_p->status==2;
}
int ProcessSemaphore::p()
{
struct sembuf b;
b.sem_num=0;
b.sem_op=-1;
b.sem_flg=SEM_UNDO;
if(semop(_p->id,&b,1)<0)
{
return -1;
}
else return 0;
}
int ProcessSemaphore::v()
{
struct sembuf b;
b.sem_num=0;
b.sem_op=1;
b.sem_flg=SEM_UNDO;
if(semop(_p->id,&b,1)<0)
{
return -1;
}
else return 0;
}
int ProcessSemaphore::wait()
{
return p();
}
int ProcessSemaphore::notify()
{
return v();
}
ProcessSemaphore::~ProcessSemaphore()
{
if(_p)
{
if(_p->created)
{
_do_clean_up_semaphore(_p->key,_p->id);
}
delete _p;
}
}
#endif /// End of Linux.