Repository: RustPython/RustPython (language: rust)

Issue:
Missing `_signal` module on WASI
## Summary

If you try to import `platform` you get the following error:

```
>>>>> import platform
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "platform", line 119, in <module>
  File "subprocess", line 49, in <module>
  File "signal", line 1, in <module>
ModuleNotFoundError: No module named '_signal'
```

It seems that the `_signal` module is missing. Any idea what this could be or how we could resolve this?


Discussion / hints:
What is your platform? I cannot reproduce on macOS (Ventura, M1) or Linux (Arch Linux, x86_64).

```text
Welcome to the magnificent Rust Python 0.2.0 interpreter 😱 🖖
>>>>> import platform
>>>>> exit()
```
Oh sorry, I should have said it's when you compile to WASI. I have updated the title.
CC @youknowone 
#4964 is similar issue.
I believe `_signal` is not mendatory for platform. Implementing `_signal` will be the long term correct goal, but patching python library will also make it working.

What do you mean by patching? Is that something we can do?
Oh, I was not talking about about user-side, but about updating `Lib/platform.py` from RustPython project to not to refer `_signal`.
Another point. I think WASI anyway will not support `_signal`, right? Then maybe a fake `_signal` module with empty functions like `gc` will be enough.

I also found `platform` is updated in python 3.11 not to require `_signal` when importing. #5060
But still there are encodings problem, so it doesn't work.
oh, it was my mistake. platform will be fixed by #5060
It depends what that signal module does but WASI has a syscall to send signals to the host process, it's `proc_raise`.
But I think as long as it's mostly empty that's fine or at least if we add what we can support.
Can confirm that importing `platform` now works 👍 Where would we go to implement things like `platform.release()`?

Fix patch:
diff --git a/vm/src/stdlib/mod.rs b/vm/src/stdlib/mod.rs
index 5b177b4b0b..a6046ac72a 100644
--- a/vm/src/stdlib/mod.rs
+++ b/vm/src/stdlib/mod.rs
@@ -40,7 +40,6 @@ pub mod posix;
 pub(crate) mod msvcrt;
 #[cfg(all(unix, not(any(target_os = "android", target_os = "redox"))))]
 mod pwd;
-#[cfg(not(target_arch = "wasm32"))]
 pub(crate) mod signal;
 pub mod sys;
 #[cfg(windows)]
@@ -82,6 +81,7 @@ pub fn get_module_inits() -> StdlibMap {
             "_io" => io::make_module,
             "marshal" => marshal::make_module,
             "_operator" => operator::make_module,
+            "_signal" => signal::make_module,
             "_sre" => sre::make_module,
             "_string" => string::make_module,
             "time" => time::make_module,
@@ -105,11 +105,6 @@ pub fn get_module_inits() -> StdlibMap {
             "posix" => posix::make_module,
             // "fcntl" => fcntl::make_module,
         }
-        // disable some modules on WASM
-        #[cfg(not(target_arch = "wasm32"))]
-        {
-            "_signal" => signal::make_module,
-        }
         #[cfg(feature = "threading")]
         {
             "_thread" => thread::make_module,
diff --git a/vm/src/stdlib/signal.rs b/vm/src/stdlib/signal.rs
index cc332b08be..2f421ae07b 100644
--- a/vm/src/stdlib/signal.rs
+++ b/vm/src/stdlib/signal.rs
@@ -3,6 +3,7 @@ use crate::{builtins::PyModule, PyRef, VirtualMachine};
 pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
     let module = _signal::make_module(vm);
 
+    #[cfg(any(unix, windows))]
     _signal::init_signal_handlers(&module, vm);
 
     module
@@ -11,12 +12,17 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
 #[pymodule]
 pub(crate) mod _signal {
     use crate::{
-        builtins::PyModule,
         convert::{IntoPyException, TryFromBorrowedObject},
         signal, Py, PyObjectRef, PyResult, VirtualMachine,
     };
     use std::sync::atomic::{self, Ordering};
 
+    #[cfg(any(unix, windows))]
+    use libc::sighandler_t;
+    #[allow(non_camel_case_types)]
+    #[cfg(not(any(unix, windows)))]
+    type sighandler_t = usize;
+
     cfg_if::cfg_if! {
         if #[cfg(windows)] {
             type WakeupFd = libc::SOCKET;
@@ -33,23 +39,23 @@ pub(crate) mod _signal {
     }
 
     #[cfg(unix)]
-    pub use nix::unistd::alarm as sig_alarm;
-
-    #[cfg(not(windows))]
     pub use libc::SIG_ERR;
+    #[cfg(unix)]
+    pub use nix::unistd::alarm as sig_alarm;
 
-    #[cfg(not(windows))]
+    #[cfg(unix)]
     #[pyattr]
     pub use libc::{SIG_DFL, SIG_IGN};
 
-    #[cfg(windows)]
+    #[cfg(not(unix))]
     #[pyattr]
-    pub const SIG_DFL: libc::sighandler_t = 0;
-    #[cfg(windows)]
+    pub const SIG_DFL: sighandler_t = 0;
+    #[cfg(not(unix))]
     #[pyattr]
-    pub const SIG_IGN: libc::sighandler_t = 1;
-    #[cfg(windows)]
-    pub const SIG_ERR: libc::sighandler_t = !0;
+    pub const SIG_IGN: sighandler_t = 1;
+    #[cfg(not(unix))]
+    #[allow(dead_code)]
+    pub const SIG_ERR: sighandler_t = -1 as _;
 
     #[cfg(all(unix, not(target_os = "redox")))]
     extern "C" {
@@ -59,6 +65,7 @@ pub(crate) mod _signal {
     #[pyattr]
     use crate::signal::NSIG;
 
+    #[cfg(any(unix, windows))]
     #[pyattr]
     pub use libc::{SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM};
 
@@ -80,7 +87,11 @@ pub(crate) mod _signal {
     #[pyattr]
     use libc::{SIGPWR, SIGSTKFLT};
 
-    pub(super) fn init_signal_handlers(module: &Py<PyModule>, vm: &VirtualMachine) {
+    #[cfg(any(unix, windows))]
+    pub(super) fn init_signal_handlers(
+        module: &Py<crate::builtins::PyModule>,
+        vm: &VirtualMachine,
+    ) {
         let sig_dfl = vm.new_pyobj(SIG_DFL as u8);
         let sig_ign = vm.new_pyobj(SIG_IGN as u8);
 
@@ -107,6 +118,17 @@ pub(crate) mod _signal {
         }
     }
 
+    #[cfg(not(any(unix, windows)))]
+    #[pyfunction]
+    pub fn signal(
+        _signalnum: i32,
+        _handler: PyObjectRef,
+        vm: &VirtualMachine,
+    ) -> PyResult<Option<PyObjectRef>> {
+        Err(vm.new_not_implemented_error("signal is not implemented on this platform".to_owned()))
+    }
+
+    #[cfg(any(unix, windows))]
     #[pyfunction]
     pub fn signal(
         signalnum: i32,
@@ -123,7 +145,7 @@ pub(crate) mod _signal {
             match usize::try_from_borrowed_object(vm, &handler).ok() {
                 Some(SIG_DFL) => SIG_DFL,
                 Some(SIG_IGN) => SIG_IGN,
-                None if handler.is_callable() => run_signal as libc::sighandler_t,
+                None if handler.is_callable() => run_signal as sighandler_t,
                 _ => return Err(vm.new_type_error(
                     "signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object"
                         .to_owned(),
@@ -226,7 +248,7 @@ pub(crate) mod _signal {
         } else {
             false
         };
-        #[cfg(not(windows))]
+        #[cfg(unix)]
         if fd != INVALID_WAKEUP {
             use nix::fcntl;
             let oflags = fcntl::fcntl(fd, fcntl::F_GETFL).map_err(|e| e.into_pyexception(vm))?;
@@ -256,6 +278,7 @@ pub(crate) mod _signal {
         }
     }
 
+    #[cfg(any(unix, windows))]
     pub extern "C" fn run_signal(signum: i32) {
         signal::TRIGGERS[signum as usize].store(true, Ordering::Relaxed);
         signal::set_triggered();


Test patch: