1
Fork 0

Add some features to flock.

This commit is contained in:
Michael Woerister 2016-08-15 13:52:38 -04:00
parent 6ef8198406
commit 206e7b6fc7
2 changed files with 106 additions and 22 deletions

View file

@ -15,6 +15,7 @@
//! librustdoc, it is not production quality at all.
#![allow(non_camel_case_types)]
use std::path::Path;
pub use self::imp::Lock;
@ -41,6 +42,7 @@ mod imp {
pub l_sysid: libc::c_int,
}
pub const F_RDLCK: libc::c_short = 0;
pub const F_WRLCK: libc::c_short = 1;
pub const F_UNLCK: libc::c_short = 2;
pub const F_SETLK: libc::c_int = 6;
@ -60,6 +62,7 @@ mod imp {
pub l_sysid: libc::c_int,
}
pub const F_RDLCK: libc::c_short = 1;
pub const F_UNLCK: libc::c_short = 2;
pub const F_WRLCK: libc::c_short = 3;
pub const F_SETLK: libc::c_int = 12;
@ -84,6 +87,7 @@ mod imp {
pub l_sysid: libc::c_int,
}
pub const F_RDLCK: libc::c_short = 1;
pub const F_UNLCK: libc::c_short = 2;
pub const F_WRLCK: libc::c_short = 3;
pub const F_SETLK: libc::c_int = 8;
@ -105,6 +109,7 @@ mod imp {
pub l_sysid: libc::c_int,
}
pub const F_RDLCK: libc::c_short = 1;
pub const F_UNLCK: libc::c_short = 2;
pub const F_WRLCK: libc::c_short = 3;
pub const F_SETLK: libc::c_int = 8;
@ -124,6 +129,7 @@ mod imp {
pub l_pid: libc::pid_t,
}
pub const F_RDLCK: libc::c_short = 1;
pub const F_WRLCK: libc::c_short = 2;
pub const F_UNLCK: libc::c_short = 3;
pub const F_SETLK: libc::c_int = 6;
@ -135,32 +141,53 @@ mod imp {
}
impl Lock {
pub fn new(p: &Path) -> Lock {
pub fn new(p: &Path,
wait: bool,
create: bool,
exclusive: bool)
-> io::Result<Lock> {
let os: &OsStr = p.as_ref();
let buf = CString::new(os.as_bytes()).unwrap();
let open_flags = if create {
libc::O_RDWR | libc::O_CREAT
} else {
libc::O_RDWR
};
let fd = unsafe {
libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
libc::open(buf.as_ptr(), open_flags,
libc::S_IRWXU as libc::c_int)
};
assert!(fd > 0, "failed to open lockfile: {}",
io::Error::last_os_error());
if fd < 0 {
return Err(io::Error::last_os_error());
}
let lock_type = if exclusive {
os::F_WRLCK
} else {
os::F_RDLCK
};
let flock = os::flock {
l_start: 0,
l_len: 0,
l_pid: 0,
l_whence: libc::SEEK_SET as libc::c_short,
l_type: os::F_WRLCK,
l_type: lock_type,
l_sysid: 0,
};
let cmd = if wait { os::F_SETLKW } else { os::F_SETLK };
let ret = unsafe {
libc::fcntl(fd, os::F_SETLKW, &flock)
libc::fcntl(fd, cmd, &flock)
};
if ret == -1 {
let err = io::Error::last_os_error();
unsafe { libc::close(fd); }
panic!("could not lock `{}`: {}", p.display(), err);
Err(err)
} else {
Ok(Lock { fd: fd })
}
Lock { fd: fd }
}
}
@ -191,18 +218,28 @@ mod imp {
use std::os::windows::raw::HANDLE;
use std::path::Path;
use std::fs::{File, OpenOptions};
use std::os::raw::{c_ulong, c_ulonglong, c_int};
use std::os::windows::fs::OpenOptionsExt;
pub type DWORD = c_ulong;
pub type BOOL = c_int;
pub type ULONG_PTR = c_ulonglong;
type DWORD = u32;
type LPOVERLAPPED = *mut OVERLAPPED;
type BOOL = i32;
const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002;
const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x00000001;
pub const FILE_SHARE_DELETE: DWORD = 0x4;
pub const FILE_SHARE_READ: DWORD = 0x1;
pub const FILE_SHARE_WRITE: DWORD = 0x2;
#[repr(C)]
struct OVERLAPPED {
Internal: usize,
InternalHigh: usize,
Pointer: *mut u8,
hEvent: *mut u8,
Internal: ULONG_PTR,
InternalHigh: ULONG_PTR,
Offset: DWORD,
OffsetHigh: DWORD,
hEvent: HANDLE,
}
extern "system" {
@ -219,19 +256,66 @@ mod imp {
}
impl Lock {
pub fn new(p: &Path) -> Lock {
let f = OpenOptions::new().read(true).write(true).create(true)
.open(p).unwrap();
pub fn new(p: &Path,
wait: bool,
create: bool,
exclusive: bool)
-> io::Result<Lock> {
let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
let f = {
let mut open_options = OpenOptions::new().read(true)
.share_mode(share_mode);
if create {
open_options.create(true);
}
match open_options.open(p) {
Ok(file) => file,
Err(err) => return Err(err),
}
};
let ret = unsafe {
let mut overlapped: OVERLAPPED = mem::zeroed();
LockFileEx(f.as_raw_handle(), LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
let mut dwFlags = 0;
if !wait {
dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
}
if exclusive {
dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
}
LockFileEx(f.as_raw_handle(),
dwFlags,
0,
0xFFFF_FFFF,
0xFFFF_FFFF,
&mut overlapped)
};
if ret == 0 {
let err = io::Error::last_os_error();
Err(io::Error::last_os_error())
} else {
Ok(Lock { _file: f })
}
}
}
// Note that we don't need a Drop impl on the Windows: The file is unlocked
// automatically when it's closed.
}
impl imp::Lock {
pub fn panicking_new(p: &Path,
wait: bool,
create: bool,
exclusive: bool)
-> Lock {
Lock::new(p, wait, create, exclusive).unwrap_or_else(|err| {
panic!("could not lock `{}`: {}", p.display(), err);
}
Lock { _file: f }
}
})
}
}

View file

@ -652,7 +652,7 @@ fn write_shared(cx: &Context,
// docs placed in the output directory, so this needs to be a synchronized
// operation with respect to all other rustdocs running around.
try_err!(mkdir(&cx.dst), &cx.dst);
let _lock = flock::Lock::new(&cx.dst.join(".lock"));
let _lock = flock::Lock::panicking_new(&cx.dst.join(".lock"), true, true, true);
// Add all the static files. These may already exist, but we just
// overwrite them anyway to make sure that they're fresh and up-to-date.