236 lines
4.9 KiB
C++
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,¤t_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
|