diff --git a/src/header/stdio/default.rs b/src/header/stdio/default.rs index 02a3708dd3..2e3aaa14c2 100644 --- a/src/header/stdio/default.rs +++ b/src/header/stdio/default.rs @@ -3,6 +3,7 @@ use core::{cell::UnsafeCell, ptr}; use crate::{ fs::File, + header::pthread, io::LineWriter, platform::types::*, sync::{Mutex, Once}, @@ -16,8 +17,12 @@ impl GlobalFile { fn new(file: c_int, flags: c_int) -> Self { let file = File::new(file); let writer = Box::new(LineWriter::new(unsafe { file.get_ref() })); + let mut mutex_attr = pthread::RlctMutexAttr { + ty: pthread::PTHREAD_MUTEX_RECURSIVE, + ..Default::default() + }; GlobalFile(UnsafeCell::new(FILE { - lock: Mutex::new(()), + lock: pthread::RlctMutex::new(&mutex_attr).unwrap(), file, flags: constants::F_PERM | flags, diff --git a/src/header/stdio/helpers.rs b/src/header/stdio/helpers.rs index e2822ec4c4..0abc310121 100644 --- a/src/header/stdio/helpers.rs +++ b/src/header/stdio/helpers.rs @@ -8,6 +8,7 @@ use crate::{ header::{ errno::{self, EINVAL}, fcntl::*, + pthread, }, io::BufWriter, platform::{self, types::*}, @@ -69,9 +70,12 @@ pub fn _fdopen(fd: c_int, mode: CStr) -> Result, Errno> { let file = File::new(fd); let writer = Box::new(BufWriter::new(unsafe { file.get_ref() })); - + let mut mutex_attr = pthread::RlctMutexAttr { + ty: pthread::PTHREAD_MUTEX_RECURSIVE, + ..Default::default() + }; Ok(Box::new(FILE { - lock: Mutex::new(()), + lock: pthread::RlctMutex::new(&mutex_attr).unwrap(), file, flags, diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index 8470c59887..ac99bbfebd 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -23,7 +23,9 @@ use crate::{ fs::File, header::{ errno::{self, STR_ERROR}, - fcntl, pwd, stdlib, + fcntl, + pthread::RlctMutex, + pwd, stdlib, string::{self, strlen, strncpy}, unistd, }, @@ -112,7 +114,7 @@ impl Writer for LineWriter { /// This struct gets exposed to the C API. pub struct FILE { - lock: Mutex<()>, + lock: RlctMutex, file: File, // pub for stdio_ext @@ -535,7 +537,9 @@ pub unsafe extern "C" fn fileno(stream: *mut FILE) -> c_int { /// locked #[unsafe(no_mangle)] pub unsafe extern "C" fn flockfile(file: *mut FILE) { - (*file).lock.manual_lock(); + if let Err(e) = (*file).lock.lock() { + println!("RELIBC: flockfile error {}", e) + } } /// See . @@ -794,7 +798,7 @@ pub unsafe extern "C" fn ftell_locked(stream: &mut FILE) -> off_t { /// Try to lock the file. Returns 0 for success, 1 for failure #[unsafe(no_mangle)] pub unsafe extern "C" fn ftrylockfile(file: *mut FILE) -> c_int { - if (*file).lock.manual_try_lock().is_ok() { + if (*file).lock.try_lock().is_ok() { 0 } else { 1 @@ -806,7 +810,9 @@ pub unsafe extern "C" fn ftrylockfile(file: *mut FILE) -> c_int { /// Unlock the file #[unsafe(no_mangle)] pub unsafe extern "C" fn funlockfile(file: *mut FILE) { - (*file).lock.manual_unlock(); + if let Err(e) = (*file).lock.unlock() { + println!("RELIBC: funlockfile error {}", e) + } } /// See . diff --git a/tests/stdio/mutex.c b/tests/stdio/mutex.c index 3d9be9d8db..dc729d3c5f 100644 --- a/tests/stdio/mutex.c +++ b/tests/stdio/mutex.c @@ -1,30 +1,47 @@ #include #include +#include #include "test_helpers.h" -int main(void) { - FILE *f = fopen("stdio/stdio.in", "r"); - ERROR_IF(fopen, f, == NULL); +FILE *f; - flockfile(f); +void* thread_wontlock(void* arg) { + (void)arg; - // Commenting this out should cause a deadlock: - // flockfile(f); + int result = ftrylockfile(f); + UNEXP_IF(ftrylockfile, result, == 0); - if (!ftrylockfile(f)) { - puts("Mutex unlocked but it shouldn't be"); - exit(EXIT_FAILURE); - } - funlockfile(f); - - if (ftrylockfile(f)) { - puts("Mutex locked but it shouldn't be"); - exit(EXIT_FAILURE); - } - if (!ftrylockfile(f)) { - puts("Mutex unlocked but it shouldn't be"); - exit(EXIT_FAILURE); - } - funlockfile(f); + return NULL; +} + +void* thread_willlock(void* arg) { + (void)arg; + + int result = ftrylockfile(f); + UNEXP_IF(ftrylockfile, result, != 0); + + return NULL; +} + +int main(void) { + f = fopen("stdio/stdio.in", "r"); + ERROR_IF(fopen, f, == NULL); + flockfile(f); + flockfile(f); + thread_willlock(NULL); + + pthread_t thread; + for (int i = 1; i <= 3; i++) { + pthread_create(&thread, NULL, thread_wontlock, NULL); + pthread_join(thread, NULL); + funlockfile(f); + } + + pthread_create(&thread, NULL, thread_willlock, NULL); + pthread_join(thread, NULL); + + // TODO: glibc refuses to quit test without this + // but in relibc, it will result in EPERM + // funlockfile(f); } diff --git a/tests/stdio/putc_unlocked.c b/tests/stdio/putc_unlocked.c index d38a80f32b..693bdafafe 100644 --- a/tests/stdio/putc_unlocked.c +++ b/tests/stdio/putc_unlocked.c @@ -11,9 +11,8 @@ int main(void) int c = 'c', r = 0; r = putc_unlocked(c, fp); ERROR_IF(putc_unlocked, r, == EOF); - // TODO: hang - // r = fflush(fp); - // ERROR_IF(fflush, r, == EOF); + r = fflush(fp); + ERROR_IF(fflush, r, == EOF); funlockfile(fp); // make sure unlock works r = putc(c, fp);