summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
authorChristopher Berner <me@cberner.com>2024-10-18 21:08:25 -0700
committerChristopher Berner <me@cberner.com>2024-10-19 13:50:19 -0700
commite0fdaa8624ee062b38372c2987947ff2dc6f7113 (patch)
tree786b55e5fad2c27fb0402c5e557b5fea5c16d1fe /library/std/src/sys
parentd2cdc76256313e8f23f585107c43badb49d5473d (diff)
downloadrust-e0fdaa8624ee062b38372c2987947ff2dc6f7113.tar.gz
rust-e0fdaa8624ee062b38372c2987947ff2dc6f7113.zip
Support lock() and lock_shared() on async IO Files
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/pal/windows/fs.rs62
1 files changed, 49 insertions, 13 deletions
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index bc728d498c3..138ac59c161 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -346,27 +346,63 @@ impl File {
         self.fsync()
     }
 
-    pub fn lock(&self) -> io::Result<()> {
-        cvt(unsafe {
-            let mut overlapped = mem::zeroed();
-            c::LockFileEx(
+    fn acquire_lock(&self, flags: c::LOCK_FILE_FLAGS) -> io::Result<()> {
+        unsafe {
+            let mut overlapped: c::OVERLAPPED = mem::zeroed();
+            let event = c::CreateEventW(ptr::null_mut(), c::FALSE, c::FALSE, ptr::null());
+            if event.is_null() {
+                return Err(io::Error::last_os_error());
+            }
+            overlapped.hEvent = event;
+            let lock_result = cvt(c::LockFileEx(
                 self.handle.as_raw_handle(),
-                c::LOCKFILE_EXCLUSIVE_LOCK,
+                flags,
                 0,
                 u32::MAX,
                 u32::MAX,
                 &mut overlapped,
-            )
-        })?;
-        Ok(())
+            ));
+
+            let final_result = match lock_result {
+                Ok(_) => Ok(()),
+                Err(err) => {
+                    if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) {
+                        // Wait for the lock to be acquired. This can happen asynchronously,
+                        // if the file handle was opened for async IO
+                        let wait_result = c::WaitForSingleObject(overlapped.hEvent, c::INFINITE);
+                        if wait_result == c::WAIT_OBJECT_0 {
+                            // Wait completed successfully, get the lock operation status
+                            let mut bytes_transferred = 0;
+                            cvt(c::GetOverlappedResult(
+                                self.handle.as_raw_handle(),
+                                &mut overlapped,
+                                &mut bytes_transferred,
+                                c::TRUE,
+                            ))
+                            .map(|_| ())
+                        } else if wait_result == c::WAIT_FAILED {
+                            // Wait failed
+                            Err(io::Error::last_os_error())
+                        } else {
+                            // WAIT_ABANDONED and WAIT_TIMEOUT should not be possible
+                            unreachable!()
+                        }
+                    } else {
+                        Err(err)
+                    }
+                }
+            };
+            c::CloseHandle(overlapped.hEvent);
+            final_result
+        }
+    }
+
+    pub fn lock(&self) -> io::Result<()> {
+        self.acquire_lock(c::LOCKFILE_EXCLUSIVE_LOCK)
     }
 
     pub fn lock_shared(&self) -> io::Result<()> {
-        cvt(unsafe {
-            let mut overlapped = mem::zeroed();
-            c::LockFileEx(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX, &mut overlapped)
-        })?;
-        Ok(())
+        self.acquire_lock(0)
     }
 
     pub fn try_lock(&self) -> io::Result<bool> {