#include #include #include #include #include #include #include #include #include #include #include #ifndef WIN32 #include #endif #ifdef OS_UNIX #include #endif #include #include #include // // 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; }