Merge branch 'flock-mutex' into 'master'

Use pthread recursive mutex for flockfile

See merge request redox-os/relibc!871
This commit is contained in:
Jeremy Soller
2026-01-07 07:02:35 -07:00
5 changed files with 63 additions and 32 deletions
+6 -1
View File
@@ -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,
+6 -2
View File
@@ -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<Box<FILE>, 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,
+11 -5
View File
@@ -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<W: crate::io::Write> Writer for LineWriter<W> {
/// 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 <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fopen.html>.
@@ -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 <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fwrite.html>.
+38 -21
View File
@@ -1,30 +1,47 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#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);
}
+2 -3
View File
@@ -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);