From 98076ff792e623922431c447c615362ff9679109 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 1 Feb 2022 15:04:36 +0100 Subject: [PATCH] Use a custom .spawn_unchecked without nightly req Courtesy of Yandros on the Rust Discord. --- src/context/linux.rs | 13 ++++++++----- src/lib.rs | 3 --- src/util.rs | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/context/linux.rs b/src/context/linux.rs index 2c89c6fe..906b475b 100644 --- a/src/context/linux.rs +++ b/src/context/linux.rs @@ -22,9 +22,9 @@ use crossbeam::channel; use std::sync::Arc; use std::thread::{self, JoinHandle, ThreadId}; -use crate::nih_log; - use super::{EventLoop, MainThreadExecutor}; +use crate::nih_log; +use crate::util::ThreadSpawnUnchecked; /// See [super::EventLoop]. pub(crate) struct LinuxEventLoop { @@ -69,9 +69,12 @@ where worker_thread: Some(unsafe { thread::Builder::new() .name(String::from("worker")) - // FIXME: Find another way to bind a thread lifetime to this struct without a - // nightly-only fature - .spawn_unchecked(move || worker_thread(receiver, executor)) + // The worker thread gets joined when this struct gets dropped, and if this + // struct never gets dropped it just sits there idly. Panics cannot be unwound, + // but in plugin-land we have bigger worries than that. + // This is the same as the `.spawn_unchecked()` function, but without requiring + // a nightly compiler. + .spawn_unchecked_2(move || worker_thread(receiver, executor)) .expect("Could not spawn worker thread") }), worker_thread_channel: sender, diff --git a/src/lib.rs b/src/lib.rs index d163b628..eb133eea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,9 +16,6 @@ // TODO: Once everything is more fleshed out, document the basic usage of this library -// FIXME: Find an alternative for this -#![feature(thread_spawn_unchecked)] - pub mod context; #[macro_use] pub mod debug; diff --git a/src/util.rs b/src/util.rs index d93ebdae..80810974 100644 --- a/src/util.rs +++ b/src/util.rs @@ -35,6 +35,31 @@ pub fn gain_to_db(gain: f32) -> f32 { } } +/// A version of [std::thread::Builder::spawn_unchecked] that works on the stable compiler. +/// Implementation courtesy of Yandros on the Rust Discord. +pub(crate) trait ThreadSpawnUnchecked { + unsafe fn spawn_unchecked_2(self, f: F) -> std::io::Result> + where + F: FnOnce() -> R + Send, + R: 'static + Send; +} + +impl ThreadSpawnUnchecked for std::thread::Builder { + unsafe fn spawn_unchecked_2(self, f: F) -> std::io::Result> + where + F: FnOnce() -> R + Send, + R: 'static + Send, + { + let f: Box R> = Box::new(f); + // ^ No need for `'_` inside function bodies + // v but this is more readable + let _: &Box R> = &f; + // Safety: same-layout since only a lifetime difference + let f: Box R> = std::mem::transmute(f); + self.spawn(f) + } +} + #[cfg(test)] mod tests { use super::*;