]> git.lizzy.rs Git - rust.git/commitdiff
Add some features to flock.
authorMichael Woerister <michaelwoerister@posteo.net>
Mon, 15 Aug 2016 17:52:38 +0000 (13:52 -0400)
committerMichael Woerister <michaelwoerister@posteo.net>
Mon, 29 Aug 2016 18:27:40 +0000 (14:27 -0400)
src/librustc_data_structures/flock.rs
src/librustdoc/html/render.rs

index 41bcfdb7cb0f03b86fe21efdc0c85a8fc3fa0639..adfeaae847537b6ed55b18f228d2af12a5f7ee41 100644 (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 @@ pub struct flock {
             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 @@ pub struct flock {
             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 @@ pub struct flock {
             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 @@ pub struct flock {
             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 @@ pub struct flock {
             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 @@ pub struct Lock {
     }
 
     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 @@ pub struct Lock {
     }
 
     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();
-                panic!("could not lock `{}`: {}", p.display(), err);
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(Lock { _file: f })
             }
-            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);
+        })
+    }
 }
index d3b9ca737b990336d7427ea2df38fbbef4e6252d..6d523ff381556799d5715fdbcdaa18eb45fdf98b 100644 (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.