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