shadowsocks/shadowsocks-rust · error

signal

Error message

signal

What it means

`launch_signal_reload_server_task` registers a SIGUSR1 handler via `tokio::signal::unix::signal(SignalKind::user_defined1()).expect("signal")`. The expect panics when the OS refuses to install the signal handler, e.g. signal limits (RLIMIT_SIGPENDING) exhausted or an unsupported/invalid signal kind on the platform. This only runs on Unix (`#[cfg(unix)]`).

Source

Thrown at src/service/local.rs:1122

        let total_end_time = Instant::now();

        info!(
            "server-loader task load from {} with {} servers, fetch costs: {:?}, total costs: {:?}",
            self.config_path.display(),
            server_len,
            fetch_end_time - start_time,
            total_end_time - start_time,
        );

        Ok(())
    }

    #[cfg(unix)]
    async fn launch_signal_reload_server_task(self: Arc<Self>) {
        use log::debug;
        use tokio::signal::unix::{SignalKind, signal};

        let mut sigusr1 = signal(SignalKind::user_defined1()).expect("signal");

        debug!("server-loader task is now listening USR1");

        while sigusr1.recv().await.is_some() {
            let _ = self.run_once().await;
        }
    }

    #[cfg(unix)]
    async fn launch_reload_server_task(self) {
        let arc_self = Arc::new(self);
        arc_self.launch_signal_reload_server_task().await
    }

    #[cfg(windows)]
    async fn launch_reload_server_task(self) {
        let _ = self.config_path;
        let _ = self.balancer;

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Check and raise RLIMIT_SIGPENDING / process signal limits
  2. Review sandbox/seccomp policies allowing rt_sigaction for SIGUSR1
  3. Make signal registration non-fatal (log a warning and skip hot-reload support)
  4. Restart the host/container if signal limits are leaked

Example fix

// before
let mut sigusr1 = signal(SignalKind::user_defined1()).expect("signal");
// after
let sigusr1 = match signal(SignalKind::user_defined1()) {
    Ok(s) => s,
    Err(err) => { log::warn!("SIGUSR1 reload disabled: {err}"); return; }
};
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

// avoid .expect on signal registration; degrade gracefully
let mut sigusr1 = match tokio::signal::unix::signal(SignalKind::user_defined1()) {
    Ok(s) => s,
    Err(e) => { log::warn!("hot-reload disabled: {e}"); return; }
};

Prevention

When it happens

Trigger: Calling `signal(SignalKind::user_defined1())` when the kernel/OS rejects handler registration — resource limits reached, or running in an environment that blocks signal handler installation (some sandboxes/seccomp profiles).

Common situations: Heavily loaded containers that exhausted the per-user pending-signal limit; seccomp filters blocking rt_sigaction; non-Unix platforms (excluded by cfg, so practically Unix sandboxes only).

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09). Data as JSON: /api/errors/65528877153b7df9. Report an issue: GitHub.