mirror of https://github.com/cirruslabs/tart.git
53 lines
1.2 KiB
Swift
53 lines
1.2 KiB
Swift
import Foundation
|
|
import System
|
|
|
|
class PIDLock {
|
|
let url: URL
|
|
let fd: Int32
|
|
|
|
init(lockURL: URL) throws {
|
|
url = lockURL
|
|
fd = open(lockURL.path, O_RDWR)
|
|
}
|
|
|
|
deinit {
|
|
close(fd)
|
|
}
|
|
|
|
func trylock() throws -> Bool {
|
|
let (locked, _) = try lockWrapper(F_SETLK, F_WRLCK, "failed to lock \(url)")
|
|
return locked
|
|
}
|
|
|
|
func lock() throws {
|
|
_ = try lockWrapper(F_SETLKW, F_WRLCK, "failed to lock \(url)")
|
|
}
|
|
|
|
func unlock() throws {
|
|
_ = try lockWrapper(F_SETLK, F_UNLCK, "failed to unlock \(url)")
|
|
}
|
|
|
|
func pid() throws -> pid_t {
|
|
let (_, result) = try lockWrapper(F_GETLK, F_RDLCK, "failed to get lock \(url) status")
|
|
|
|
return result.l_pid
|
|
}
|
|
|
|
func lockWrapper(_ operation: Int32, _ type: Int32, _ message: String) throws -> (Bool, flock) {
|
|
var result = flock(l_start: 0, l_len: 0, l_pid: 0, l_type: Int16(type), l_whence: Int16(SEEK_SET))
|
|
|
|
let ret = fcntl(fd, operation, &result)
|
|
if ret != 0 {
|
|
if operation == F_SETLK && errno == EAGAIN {
|
|
return (false, result)
|
|
}
|
|
|
|
let details = Errno(rawValue: CInt(errno))
|
|
|
|
throw RuntimeError.PIDLockFailed("\(message): \(details)")
|
|
}
|
|
|
|
return (true, result)
|
|
}
|
|
}
|