9 static const char rcsid[] __attribute__((used)) =
"$Id: LockFile.cpp 1653 2016-02-28 19:54:59Z sella $";
12 #include "CommonMacro.h"
18 using namespace sella::util;
20 LockFile::LockFile(
const std::string &fullpath, useconds_t stale,
bool removeStale, uid_t uid, gid_t gid,
int mode)
throw () :
23 removeStale(removeStale),
30 LockFile::~LockFile() {
38 void LockFile::setStaleAge(useconds_t stale)
throw () {
46 void LockFile::setUID(uid_t uid)
throw () {
47 if (uid > (__UID_T_TYPE) -1) {
50 this->uid = (__UID_T_TYPE) -1;
54 void LockFile::setGID(gid_t gid)
throw () {
55 if (gid > (__GID_T_TYPE) -1) {
58 this->gid = (__GID_T_TYPE) -1;
62 void LockFile::setMode(
int mode)
throw () {
63 if (mode > -1 && mode < 7777) {
70 bool LockFile::lock(useconds_t interval)
throw (FileException) {
71 return tryLockCount(-1, interval);
74 bool LockFile::tryLock(
void) throw (FileException) {
75 std::lock_guard<std::mutex> lg(mutex);
77 return lock_nonblock();
80 bool LockFile::tryLockUntil(time_t timeout, useconds_t interval)
throw (FileException) {
81 time_t now = time(NULL);
82 std::lock_guard<std::mutex> lg(mutex);
85 if (lock_nonblock()) {
90 }
while (now < timeout);
95 bool LockFile::tryLockFor(time_t duration, useconds_t interval)
throw (FileException) {
96 time_t now = time(NULL);
97 time_t timeout = now + duration;
98 std::lock_guard<std::mutex> lg(mutex);
101 if (lock_nonblock()) {
106 }
while (now < timeout);
111 bool LockFile::tryLockCount(int64_t retries, useconds_t interval)
throw (FileException) {
113 std::lock_guard<std::mutex> lg(mutex);
116 if (lock_nonblock()) {
121 }
while (fd < 1 && (retries < 1 || r++ < retries));
127 bool LockFile::unlock(
void) throw (FileException) {
128 std::lock_guard<std::mutex> lg(mutex);
134 THROW2(FileException,
"Failed to remove lockfile '%s'", fullpath.c_str());
145 bool LockFile::remove(
void) throw () {
146 std::lock_guard<std::mutex> lg(mutex);
155 bool LockFile::ownLock(
void) throw () {
159 bool LockFile::isLocked(
void) throw () {
164 return File::exists(fullpath,
false) && File::isRegularFile(fullpath,
false);
167 bool LockFile::isStale(
void) throw () {
170 if (File::exists(fullpath,
false) && File::isRegularFile(fullpath,
false)) {
171 return (time(NULL) - File::getCTime(fullpath,
false) > stale);
179 bool LockFile::lock_nonblock() throw (FileException) {
181 struct stat st0, st1;
182 const std::string directory = File::getDirName(fullpath);
184 if (removeStale && isStale()) {
194 if (File::exists(fullpath,
false) && !File::isRegularFile(fullpath,
false)) {
195 THROW(FileException,
"Lockfile '%s' must be a regular file or not exist", fullpath.c_str());
196 }
else if (!File::exists(directory,
false) || !File::isDirectory(directory,
false)) {
197 THROW(FileException,
"Path to lockfile '%s' must exist and be a directory", fullpath.c_str());
200 if ((fd = open(fullpath.c_str(), O_WRONLY|O_CREAT|O_DSYNC, mode)) < 0) {
201 THROW2(FileException,
"Failed to open or create lockfile '%s'", fullpath.c_str());
204 if (flock(fd, LOCK_EX|LOCK_NB) != 0) {
207 if (errno == EWOULDBLOCK) {
211 THROW2(FileException,
"Failed to lock '%s'", fullpath.c_str());
214 if (fstat(fd, &st0) < 0 || stat(fullpath.c_str(), &st1) < 0) {
216 }
else if (st0.st_ino == st1.st_ino) {
223 char buf[16] = { 0 };
224 snprintf(buf,
sizeof(buf),
"%d\n", pid);
226 if (write(fd, buf, strlen(buf)) < 1) {
230 THROW2(FileException,
"Failed to write pid %d to lockfile '%s'", pid, fullpath.c_str());
233 if (uid != (__UID_T_TYPE) -1 || gid != (__GID_T_TYPE) -1) {
234 if (fchown(fd, uid, gid) != 0) {
238 THROW2(FileException,
"Failed to change owner of lockfile '%s' to %d:%d", fullpath.c_str(), uid, gid);
245 bool LockFile::unlink(
void) throw () {
249 if (File::exists(fullpath,
false) && File::isRegularFile(fullpath,
false)) {
250 res = (::unlink(fullpath.c_str()) == 0);
258 void LockFile::close(
void) throw () {