Merge branch 'flock-mutex' into 'master'
Use pthread recursive mutex for flockfile See merge request redox-os/relibc!871
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user