SemaphoreWrapper/src/ProcessSemaphore_C4droid.cpp

236 lines
4.9 KiB
C++

#if (defined(_C4DROID_)&&!defined(_TRY_POSIX)) /// Generic Version
#include "SemaphoreWrapper.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/file.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <error.h>
#include <stdlib.h>
#include <vector>
using namespace std;
class ProcessSemaphore::impl
{
public:
char buff[256];
int fd;
int status;
bool owner;
struct LockInfo
{
public:
int total_value;
int current_value;
vector<int> waiting;
LockInfo()
{
total_value=0;
current_value=0;
}
void writeTo(int fd) const
{
lseek(fd,0L,SEEK_SET);
write(fd,&total_value,sizeof(int));
write(fd,&current_value,sizeof(int));
int num_waiting=waiting.size();
write(fd,&num_waiting,sizeof(int));
for(int i=0;i<num_waiting;i++)
{
write(fd,&waiting[i],sizeof(int));
}
}
static LockInfo getFrom(int fd)
{
lseek(fd,0L,SEEK_SET);
LockInfo x;
read(fd,&x.total_value,sizeof(int));
read(fd,&x.current_value,sizeof(int));
int num_waiting=x.waiting.size();
read(fd,&num_waiting,sizeof(int));
for(int i=0;i<num_waiting;i++)
{
int n;
read(fd,&n,sizeof(int));
x.waiting.push_back(n);
}
return x;
}
};
};
ProcessSemaphore::ProcessSemaphore(int key, int action, int default_value) : _p(new impl)
{
if(_p)
{
_p->status=0;
_p->owner=false;
memset(_p->buff,0,256);
sprintf(_p->buff,"LibSemaphoreWrapper_%d",key);
if(action==1)
{
_p->fd=open(_p->buff,O_RDWR|O_CREAT|O_EXCL,0666);
_p->owner=true;
}
else
{
_p->fd=open(_p->buff,O_RDWR,0666);
}
if(_p->fd>=0) /// Opened.
{
_p->status=2;
if(_p->owner)
{
flock(_p->fd,LOCK_EX);
impl::LockInfo x;
x.total_value=default_value;
x.current_value=default_value;
x.writeTo(_p->fd);
flock(_p->fd,LOCK_UN);
}
}
else
{
perror("Failed to open file. ");
}
if(_p->status!=0&&_p->status!=2) /// Clean up
{
close(_p->fd);
_p->status=0;
}
}
}
ProcessSemaphore::~ProcessSemaphore()
{
if(_p)
{
if(_p->status==2)
{
if(_p->owner)
{
/// Unlink it (delete on close) : Only owner will delete this file.
unlink(_p->buff);
}
/// Close on delete.
close(_p->fd);
}
delete _p;
}
}
bool ProcessSemaphore::isReady() const
{
return _p&&_p->status==2;
}
int ProcessSemaphore::p()
{
flock(_p->fd,LOCK_EX);
impl::LockInfo x=impl::LockInfo::getFrom(_p->fd);
if(x.current_value<=0)
{
int thisPid=getpid();
x.waiting.push_back(thisPid);
x.writeTo(_p->fd);
/*
/// wait for signal...
typedef void (*fnvi)(int);
_global_process_semaphore_value=0;
fnvi old=signal(SIGUSR1,_global_process_semaphore_handler);
*/
flock(_p->fd,LOCK_UN);
/// Sleep For 1 Second.
sleep(1);
while(1)
{
flock(_p->fd,LOCK_EX);
x=impl::LockInfo::getFrom(_p->fd);
if(x.current_value>0) /// Someone has released resource!
{
x.current_value=x.current_value-1;
int sz=x.waiting.size();
for(int i=0;i<sz;i++)
{
if(x.waiting[i]==thisPid)
{
x.waiting.erase(x.waiting.begin()+i);
break;
}
}
x.writeTo(_p->fd);
/// Pass!
flock(_p->fd,LOCK_UN);
break;
}
else /// Nothing happened...
{
flock(_p->fd,LOCK_UN);
/// Sleep for 1 second.
sleep(1);
}
}
return 0;
}
else
{
x.current_value=x.current_value-1;
x.writeTo(_p->fd);
flock(_p->fd,LOCK_UN);
/// Pass Operation P.
return 0;
}
}
int ProcessSemaphore::v()
{
flock(_p->fd,LOCK_EX);
impl::LockInfo x=impl::LockInfo::getFrom(_p->fd);
x.current_value=x.current_value+1;
x.writeTo(_p->fd);
flock(_p->fd,LOCK_UN);
return 0;
}
int ProcessSemaphore::wait()
{
return p();
}
int ProcessSemaphore::notify()
{
return v();
}
#endif /// End of try generic