From 6d999151548fd9ae0de19f4f7d2767cca2e00448 Mon Sep 17 00:00:00 2001
From: jD91mZM2 <me@krake.one>
Date: Sun, 23 Sep 2018 20:38:55 +0200
Subject: [PATCH] Use RAII for file locking in stdio

---
 src/header/stdio/mod.rs | 106 +++++++++++++++++-----------------------
 1 file changed, 44 insertions(+), 62 deletions(-)

diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs
index 39d097fe..399a4445 100644
--- a/src/header/stdio/mod.rs
+++ b/src/header/stdio/mod.rs
@@ -3,7 +3,8 @@
 use alloc::vec::Vec;
 use core::fmt::Write as WriteFmt;
 use core::fmt::{self, Error};
-use core::sync::atomic::{AtomicBool, Ordering};
+use core::ops::{Deref, DerefMut};
+use core::sync::atomic::{self, AtomicBool, Ordering};
 use core::{ptr, str};
 use va_list::VaList as va_list;
 
@@ -187,6 +188,18 @@ impl FILE {
 }
 
 pub struct LockGuard<'a>(&'a mut FILE);
+impl<'a> Deref for LockGuard<'a> {
+    type Target = &'a mut FILE;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl<'a> DerefMut for LockGuard<'a> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
 impl<'a> Drop for LockGuard<'a> {
     fn drop(&mut self) {
         funlockfile(self.0);
@@ -286,19 +299,15 @@ pub extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE {
 /// Check for EOF
 #[no_mangle]
 pub extern "C" fn feof(stream: &mut FILE) -> c_int {
-    flockfile(stream);
-    let ret = stream.flags & F_EOF;
-    funlockfile(stream);
-    ret
+    let stream = stream.lock();
+    stream.flags & F_EOF
 }
 
 /// Check for ERR
 #[no_mangle]
 pub extern "C" fn ferror(stream: &mut FILE) -> c_int {
-    flockfile(stream);
-    let ret = stream.flags & F_ERR;
-    funlockfile(stream);
-    ret
+    let stream = stream.lock();
+    stream.flags & F_ERR
 }
 
 /// Flush output to stream, or sync read position
@@ -306,19 +315,15 @@ pub extern "C" fn ferror(stream: &mut FILE) -> c_int {
 /// itself.
 #[no_mangle]
 pub unsafe extern "C" fn fflush(stream: &mut FILE) -> c_int {
-    flockfile(stream);
-    let ret = helpers::fflush_unlocked(stream);
-    funlockfile(stream);
-    ret
+    let mut stream = stream.lock();
+    helpers::fflush_unlocked(&mut stream)
 }
 
 /// Get a single char from a stream
 #[no_mangle]
 pub extern "C" fn fgetc(stream: &mut FILE) -> c_int {
-    flockfile(stream);
-    let c = getc_unlocked(stream);
-    funlockfile(stream);
-    c
+    let mut stream = stream.lock();
+    getc_unlocked(&mut stream)
 }
 
 /// Get the position of the stream and store it in pos
@@ -340,14 +345,13 @@ pub extern "C" fn fgetpos(stream: &mut FILE, pos: Option<&mut fpos_t>) -> c_int
 #[no_mangle]
 pub extern "C" fn fgets(s: *mut c_char, n: c_int, stream: &mut FILE) -> *mut c_char {
     use core::slice;
-    flockfile(stream);
+    let mut stream = stream.lock();
     let st = unsafe { slice::from_raw_parts_mut(s as *mut u8, n as usize) };
 
     let mut len = n;
 
     // We can only fit one or less chars in
     if n <= 1 {
-        funlockfile(stream);
         if n <= 0 {
             return ptr::null_mut();
         }
@@ -360,7 +364,6 @@ pub extern "C" fn fgets(s: *mut c_char, n: c_int, stream: &mut FILE) -> *mut c_c
     {
         // We can't read from this stream
         if !stream.can_read() {
-            funlockfile(stream);
             return ptr::null_mut();
         }
     }
@@ -399,17 +402,14 @@ pub extern "C" fn fgets(s: *mut c_char, n: c_int, stream: &mut FILE) -> *mut c_c
     }
 
     st[(n - len) as usize] = 0;
-    funlockfile(stream);
     s
 }
 
 /// Get the underlying file descriptor
 #[no_mangle]
 pub extern "C" fn fileno(stream: &mut FILE) -> c_int {
-    flockfile(stream);
-    let fd = stream.fd;
-    funlockfile(stream);
-    fd
+    let stream = stream.lock();
+    stream.fd
 }
 
 /// Lock the file
@@ -417,7 +417,9 @@ pub extern "C" fn fileno(stream: &mut FILE) -> c_int {
 /// locked
 #[no_mangle]
 pub extern "C" fn flockfile(file: &mut FILE) {
-    while ftrylockfile(file) != 0 {}
+    while ftrylockfile(file) != 0 {
+        atomic::spin_loop_hint();
+    }
 }
 
 /// Open the file in mode `mode`
@@ -458,10 +460,8 @@ pub extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FI
 /// Insert a character into the stream
 #[no_mangle]
 pub extern "C" fn fputc(c: c_int, stream: &mut FILE) -> c_int {
-    flockfile(stream);
-    let c = putc_unlocked(c, stream);
-    funlockfile(stream);
-    c
+    let mut stream = stream.lock();
+    putc_unlocked(c, &mut stream)
 }
 
 /// Insert a string into a stream
@@ -480,10 +480,9 @@ pub extern "C" fn fread(ptr: *mut c_void, size: usize, nitems: usize, stream: &m
     let len = size * nitems;
     let mut l = len as isize;
 
-    flockfile(stream);
+    let mut stream = stream.lock();
 
     if !stream.can_read() {
-        funlockfile(stream);
         return 0;
     }
 
@@ -510,7 +509,6 @@ pub extern "C" fn fread(ptr: *mut c_void, size: usize, nitems: usize, stream: &m
             };
 
             if k == 0 {
-                funlockfile(stream);
                 return (len - l as usize) / 2;
             }
 
@@ -521,7 +519,6 @@ pub extern "C" fn fread(ptr: *mut c_void, size: usize, nitems: usize, stream: &m
             }
         }
 
-        funlockfile(stream);
         nitems
     } else {
         unreachable!()
@@ -545,14 +542,12 @@ pub extern "C" fn freopen(
         }
         flags &= !(fcntl::O_CREAT | fcntl::O_EXCL | fcntl::O_CLOEXEC);
         if fcntl::sys_fcntl(stream.fd, fcntl::F_SETFL, flags) < 0 {
-            funlockfile(stream);
             fclose(stream);
             return ptr::null_mut();
         }
     } else {
         let new = fopen(filename, mode);
         if new.is_null() {
-            funlockfile(stream);
             fclose(stream);
             return ptr::null_mut();
         }
@@ -563,14 +558,12 @@ pub extern "C" fn freopen(
             || fcntl::sys_fcntl(stream.fd, fcntl::F_SETFL, flags & fcntl::O_CLOEXEC) < 0
         {
             fclose(new);
-            funlockfile(stream);
             fclose(stream);
             return ptr::null_mut();
         }
         stream.flags = (stream.flags & constants::F_PERM) | new.flags;
         fclose(new);
     }
-    funlockfile(stream);
     stream
 }
 
@@ -587,7 +580,8 @@ pub extern "C" fn fseek(stream: &mut FILE, offset: c_long, whence: c_int) -> c_i
 #[no_mangle]
 pub extern "C" fn fseeko(stream: &mut FILE, offset: off_t, whence: c_int) -> c_int {
     let mut off = offset;
-    flockfile(stream);
+    let mut stream = stream.lock();
+
     // Adjust for what is currently in the buffer
     let rdiff = if let Some((rpos, rend)) = stream.read {
         rend - rpos
@@ -602,12 +596,10 @@ pub extern "C" fn fseeko(stream: &mut FILE, offset: off_t, whence: c_int) -> c_i
     }
     stream.write = None;
     if stream.seek(off, whence) < 0 {
-        funlockfile(stream);
         return -1;
     }
     stream.read = None;
     stream.flags &= !F_EOF;
-    funlockfile(stream);
     0
 }
 
@@ -630,10 +622,8 @@ pub extern "C" fn ftell(stream: &mut FILE) -> c_long {
 /// Get the current position of the cursor in the file
 #[no_mangle]
 pub extern "C" fn ftello(stream: &mut FILE) -> off_t {
-    flockfile(stream);
-    let pos = internal::ftello(stream);
-    funlockfile(stream);
-    pos
+    let mut stream = stream.lock();
+    internal::ftello(&mut stream)
 }
 
 /// Try to lock the file. Returns 0 for success, 1 for failure
@@ -658,9 +648,8 @@ pub extern "C" fn fwrite(
 ) -> usize {
     let l = size * nitems;
     let nitems = if size == 0 { 0 } else { nitems };
-    flockfile(stream);
-    let k = helpers::fwritex(ptr as *const u8, l, stream);
-    funlockfile(stream);
+    let mut stream = stream.lock();
+    let k = helpers::fwritex(ptr as *const u8, l, &mut stream);
     if k == l {
         nitems
     } else {
@@ -671,10 +660,8 @@ pub extern "C" fn fwrite(
 /// Get a single char from a stream
 #[no_mangle]
 pub extern "C" fn getc(stream: &mut FILE) -> c_int {
-    flockfile(stream);
-    let c = getc_unlocked(stream);
-    funlockfile(stream);
-    c
+    let mut stream = stream.lock();
+    getc_unlocked(&mut stream)
 }
 
 /// Get a single char from `stdin`
@@ -768,10 +755,8 @@ pub extern "C" fn popen(_command: *const c_char, _mode: *const c_char) -> *mut F
 /// Put a character `c` into `stream`
 #[no_mangle]
 pub extern "C" fn putc(c: c_int, stream: &mut FILE) -> c_int {
-    flockfile(stream);
-    let ret = putc_unlocked(c, stream);
-    funlockfile(stream);
-    ret
+    let mut stream = stream.lock();
+    putc_unlocked(c, &mut stream)
 }
 
 /// Put a character `c` into `stdout`
@@ -849,9 +834,8 @@ pub extern "C" fn rename(oldpath: *const c_char, newpath: *const c_char) -> c_in
 #[no_mangle]
 pub extern "C" fn rewind(stream: &mut FILE) {
     fseeko(stream, 0, SEEK_SET);
-    flockfile(stream);
+    let mut stream = stream.lock();
     stream.flags &= !F_ERR;
-    funlockfile(stream);
 }
 
 /// Reset `stream` to use buffer `buf`. Buffer must be `BUFSIZ` in length
@@ -935,22 +919,20 @@ pub extern "C" fn ungetc(c: c_int, stream: &mut FILE) -> c_int {
     if c < 0 {
         c
     } else {
-        flockfile(stream);
+        let mut stream = stream.lock();
+
         if stream.read.is_none() {
             stream.can_read();
         }
         if let Some((rpos, rend)) = stream.read {
             if rpos == 0 {
-                funlockfile(stream);
                 return -1;
             }
             stream.read = Some((rpos - 1, rend));
             stream.buf[rpos - 1] = c as u8;
             stream.flags &= !F_EOF;
-            funlockfile(stream);
             c
         } else {
-            funlockfile(stream);
             -1
         }
     }
-- 
GitLab