Skip to content
Snippets Groups Projects
Verified Commit 6d999151 authored by jD91mZM2's avatar jD91mZM2
Browse files

Use RAII for file locking in stdio

parent 7e4a60f7
No related branches found
No related tags found
No related merge requests found
......@@ -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
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment