#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#include <string>
#include <fstream>
#ifndef WIN32
#include <unistd.h>
#endif
#ifdef OS_UNIX
#include <sched.h>
#endif
#include <dboxpath.h>
#include <lock.h>
#include <logf.h>
//
// Locking Services
//
// The types/name combinations used should be unique
//
// Todo: This locking does not work over NFS
// This locking probably does not work with Win32
// Automatic stale lock detection has a race condition
//
static void mklockname(std::string &filename,
const char *type, const char *name, const char *boxname)
{
char tmpname[TEXTLEN], *tptr;
char boxdir[DIRLEN];
mkboxdir(boxdir, boxname);
strmaxcpy(tmpname, name, TEXTLEN-1);
for(tptr=tmpname; tptr[0]!=0; tptr++)
if(tptr[0]==DIRCHAR[0])
tptr[0]='_';
getboxlockdir(filename, boxdir);
filename+=type;
filename+='.';
filename+=tmpname;
}
bool stale_lock(const std::string &filename)
{
std::string line1, line2, line3;
char ch;
std::ifstream infile(filename.c_str());
infile >> line1;
infile >> ch; // read newline
infile >> line2;
infile >> ch; // read newline
infile >> line3;
infile >> ch; // read newline
logf.printf("stale_lock", "warning: stale lock %s detected: %s@%s module %s",
filename.c_str(), line2.c_str(), line1.c_str(), line3.c_str());
char tempstr[TEXTLEN*2];
gethostname(tempstr, TEXTLEN-1);
if(line1==tempstr) // local machine?
{
if(kill(atoi(line2.c_str()), 0)!=0 && errno==ESRCH) // process dead
{
logf.printf("stale_lock", "%s@%s dead, removing lock",
line2.c_str(), line1.c_str());
unlink(filename.c_str()); // race: another process might do the same
return FALSE;
}
else // process not dead
{
logf.printf("stale_lock", "%s@%s is blocking resource %s",
line2.c_str(), line1.c_str(), filename.c_str());
return FALSE;
}
}
else // remote machine
{
logf.printf("stale_lock", "warning: removing remote lock (unsafe)");
unlink(filename.c_str());
return FALSE;
}
return TRUE;
}
bool lock(const char *type, const char *name,
const char *boxname, const char *module)
{
std::string filename;
char tempstr[TEXTLEN*2];
int handle, attempt=0;
mklockname(filename, type, name, boxname);
while(TRUE)
{
attempt++;
handle=open(filename.c_str(), O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0600);
if(handle<0)
{
if(attempt>=2)
sleep(1);
else
{
#ifdef WIN32
sleep(1);
#else
#ifdef OS_WIN32
sleep(1);
#endif
#endif
sched_yield();
}
if(attempt>20)
{
if(stale_lock(filename)) return TRUE;
attempt=0;
}
}
else
break;
}
gethostname(tempstr, TEXTLEN-1);
write(handle, tempstr, strlen(tempstr));
snprintf(tempstr, TEXTLEN, "\n%d\n", getpid());
if(module!=NULL && module[0]!=0)
{
write(handle, module, strlen(module));
strmaxcpy(tempstr, "\n", TEXTLEN-1);
write(handle, tempstr, strlen(tempstr));
}
close(handle);
return FALSE;
}
bool unlock(const char *type, const char *name, const char *boxname)
{
std::string filename;
mklockname(filename, type, name, boxname);
unlink(filename.c_str());
return FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1