mirror of
https://github.com/rui314/mold.git
synced 2026-11-09 13:01:26 -10:00
Use standard owners for the job lock and notification pipe
This commit is contained in:
1 parent
2294f1d7f7
commit
e09ce32f73
2 files changed
+43
-39
No files matched your search
+18
-25
@@ -14,10 +14,14 @@
|
||||
#[cfg(not(windows))]
|
||||
use std::ffi::CStr;
|
||||
#[cfg(not(windows))]
|
||||
use std::sync::atomic::{AtomicI32, Ordering};
|
||||
use std::fs::{File, OpenOptions};
|
||||
#[cfg(not(windows))]
|
||||
use std::os::unix::{fs::OpenOptionsExt, io::AsRawFd};
|
||||
#[cfg(not(windows))]
|
||||
use std::sync::Mutex;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
static LOCK_FD: AtomicI32 = AtomicI32::new(-1);
|
||||
static LOCK_FILE: Mutex<Option<File>> = Mutex::new(None);
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn acquire_global_lock() {
|
||||
@@ -40,27 +44,20 @@ pub fn acquire_global_lock() {
|
||||
let name = String::from_utf8_lossy(&name);
|
||||
std::path::PathBuf::from(format!("/tmp/mold-lock-{name}"))
|
||||
};
|
||||
let Ok(path) = std::ffi::CString::new(path.as_os_str().as_encoded_bytes()) else {
|
||||
let Ok(file) = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.mode(0o600)
|
||||
.open(path)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
// SAFETY: path is a valid C string and the remaining arguments have the
|
||||
// types required by open and lockf.
|
||||
unsafe {
|
||||
let fd = libc::open(
|
||||
path.as_ptr(),
|
||||
libc::O_WRONLY | libc::O_CREAT | libc::O_CLOEXEC,
|
||||
0o600,
|
||||
);
|
||||
if fd == -1 {
|
||||
return;
|
||||
}
|
||||
if libc::lockf(fd, libc::F_LOCK, 0) == -1 {
|
||||
libc::close(fd);
|
||||
return;
|
||||
}
|
||||
LOCK_FD.store(fd, Ordering::Relaxed);
|
||||
// SAFETY: file owns a valid descriptor. Keep lockf for compatibility with
|
||||
// other mold processes; flock uses a different locking protocol.
|
||||
if unsafe { libc::lockf(file.as_raw_fd(), libc::F_LOCK, 0) } == -1 {
|
||||
return;
|
||||
}
|
||||
*LOCK_FILE.lock().unwrap() = Some(file);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -68,11 +65,7 @@ pub fn acquire_global_lock() {}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn release_global_lock() {
|
||||
let fd = LOCK_FD.swap(-1, Ordering::Relaxed);
|
||||
if fd != -1 {
|
||||
// SAFETY: fd is the lock file opened by acquire_global_lock.
|
||||
unsafe { libc::close(fd) };
|
||||
}
|
||||
drop(LOCK_FILE.lock().unwrap().take());
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
||||
+25
-14
@@ -2,12 +2,14 @@
|
||||
//! handling for disk-full errors, and the `-run` subcommand.
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use std::sync::atomic::{AtomicI32, Ordering};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
|
||||
#[cfg(not(windows))]
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::fatal;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
static PIPE_WRITE_FD: AtomicI32 = AtomicI32::new(-1);
|
||||
static PIPE_WRITER: Mutex<Option<OwnedFd>> = Mutex::new(None);
|
||||
|
||||
// Exiting from a program with large memory usage is slow --
|
||||
// it may take a few hundred milliseconds. To hide the latency,
|
||||
@@ -15,12 +17,22 @@ static PIPE_WRITE_FD: AtomicI32 = AtomicI32::new(-1);
|
||||
#[cfg(not(windows))]
|
||||
pub fn fork_child() {
|
||||
let mut pipefd = [0i32; 2];
|
||||
// SAFETY: plain libc calls with valid arguments.
|
||||
unsafe {
|
||||
// Preserve pipe's descriptor inheritance across the LTO restart.
|
||||
// SAFETY: pipe initializes both descriptors on success; each then has
|
||||
// exactly one owner in this process.
|
||||
let (reader, writer) = unsafe {
|
||||
if libc::pipe(pipefd.as_mut_ptr()) == -1 {
|
||||
eprintln!("mold: pipe failed");
|
||||
std::process::exit(1);
|
||||
}
|
||||
(
|
||||
OwnedFd::from_raw_fd(pipefd[0]),
|
||||
OwnedFd::from_raw_fd(pipefd[1]),
|
||||
)
|
||||
};
|
||||
// SAFETY: this runs before the linker starts its worker threads. The
|
||||
// parent only waits for completion and exits; the child continues linking.
|
||||
unsafe {
|
||||
let pid = libc::fork();
|
||||
if pid == -1 {
|
||||
eprintln!("mold: fork failed");
|
||||
@@ -28,9 +40,9 @@ pub fn fork_child() {
|
||||
}
|
||||
if pid > 0 {
|
||||
// Parent
|
||||
libc::close(pipefd[1]);
|
||||
drop(writer);
|
||||
let mut buf = [0u8; 1];
|
||||
if libc::read(pipefd[0], buf.as_mut_ptr() as *mut libc::c_void, 1) == 1 {
|
||||
if libc::read(reader.as_raw_fd(), buf.as_mut_ptr() as *mut libc::c_void, 1) == 1 {
|
||||
libc::_exit(0);
|
||||
}
|
||||
let mut status = 0;
|
||||
@@ -43,10 +55,10 @@ pub fn fork_child() {
|
||||
}
|
||||
libc::_exit(1);
|
||||
}
|
||||
// Child
|
||||
libc::close(pipefd[0]);
|
||||
}
|
||||
PIPE_WRITE_FD.store(pipefd[1], Ordering::Relaxed);
|
||||
// Child
|
||||
drop(reader);
|
||||
*PIPE_WRITER.lock().unwrap() = Some(writer);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -55,14 +67,13 @@ pub fn fork_child() {}
|
||||
/// Tells the parent that the output is complete.
|
||||
#[cfg(not(windows))]
|
||||
pub fn notify_parent() {
|
||||
let fd = PIPE_WRITE_FD.swap(-1, Ordering::Relaxed);
|
||||
if fd == -1 {
|
||||
let Some(writer) = PIPE_WRITER.lock().unwrap().take() else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let buf = [1u8];
|
||||
// SAFETY: fd is a valid pipe write end.
|
||||
// SAFETY: writer owns a valid pipe write end.
|
||||
unsafe {
|
||||
libc::write(fd, buf.as_ptr() as *const libc::c_void, 1);
|
||||
libc::write(writer.as_raw_fd(), buf.as_ptr() as *const libc::c_void, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user