Skip to content
Advertisement

How to use SIGALARM in rust?

I have a problem using alarm from nix library in rust. I am trying to communicate two child process with alarms, the exercise consist in send a signal to child process to other every two seconds, and retun it with pipe. When I run the code it still waiting and I can’t see the message. This is my code:

use nix::sys::wait::wait;
use nix::unistd::ForkResult::{Child, Parent};
use nix::unistd::fork;
use nix::unistd::{alarm, pause};
use nix::sys::signal::*;
use std::io::prelude::*;

extern fn signal_handler(_: nix::libc::c_int) {}

fn set_alarm(sec: i32) {
    alarm::set(sec.try_into().unwrap());
}

fn main() {
    let (mut reader_2, mut writer_2) = os_pipe::pipe().unwrap();
    unsafe { 
        sigaction(
            Signal::SIGALRM, 
            &SigAction::new(
                SigHandler::Handler(signal_handler), 
                SaFlags::empty(), 
                SigSet::empty())
            ).unwrap(); 
    }
    let pid = fork();
    match pid.expect("Error during creating child") {
        Parent { child } => {
            drop(writer_2);
            let pid_2 = fork();
            match pid_2.expect("Error creating child 2") {
                Parent { child } => {}
                Child => {
                    let mut data: [u8;2] = [0;2];
                    for _ in 1..=10 {
                        set_alarm(2);
                        pause();
                        reader_2.read_exact(&mut data).unwrap();
                        println!("Data from C1, {}", std::str::from_utf8(&data).unwrap());
                    }
                }
            }
        }

        Child => {
            drop(reader_2);
            for _ in 1..=10 {
                pause();
                println!("here");
                writer_2.write("C1".as_bytes()).unwrap();
            }
        }
    }
    wait().unwrap();
}

Thanks!!!

Advertisement

Answer

Try the patch below and see if that helps.

The reader will block on the read from the pipe so there is no need for a pause on the reader.

The writer needs some event to trigger it every 2 seconds so use the alarm in the writer to create the trigger event which writes into the pipe.

That trigger will wake up the reader and show what the writer wrote into the pipe.

I am a bit weak on the use of wait so I am using waitpid instead.

Here is the output I observed after the patch:

signal_handler 14
after pause in child1
Data from C1, C1
signal_handler 14
after pause in child1
Data from C1, C1
. . .
--- main.rs 2022-11-04 20:15:22.000000000 -0700
+++ src/main.rs 2022-11-04 20:47:08.000000000 -0700
@@ -1,11 +1,13 @@
-use nix::sys::wait::wait;
+use nix::sys::wait::waitpid;
 use nix::unistd::ForkResult::{Child, Parent};
 use nix::unistd::fork;
 use nix::unistd::{alarm, pause};
 use nix::sys::signal::*;
 use std::io::prelude::*;
 
-extern fn signal_handler(_: nix::libc::c_int) {}
+extern fn signal_handler(v: nix::libc::c_int) {
+   println!{ "signal_handler {}", v }; 
+}
 
 fn set_alarm(sec: i32) {
     alarm::set(sec.try_into().unwrap());
@@ -21,19 +23,16 @@
                 SaFlags::empty(), 
                 SigSet::empty())
             ).unwrap(); 
-    }
     let pid = fork();
     match pid.expect("Error during creating child") {
         Parent { child } => {
             drop(writer_2);
             let pid_2 = fork();
             match pid_2.expect("Error creating child 2") {
-                Parent { child } => {}
+                Parent { child } => { waitpid(child,None).unwrap(); }
                 Child => {
                     let mut data: [u8;2] = [0;2];
                     for _ in 1..=10 {
-                        set_alarm(2);
-                        pause();
                         reader_2.read_exact(&mut data).unwrap();
                         println!("Data from C1, {}", std::str::from_utf8(&data).unwrap());
                     }
@@ -44,11 +43,12 @@
         Child => {
             drop(reader_2);
             for _ in 1..=10 {
+                set_alarm(2);
                 pause();
-                println!("here");
+                println!{ "after pause in child1" }; 
                 writer_2.write("C1".as_bytes()).unwrap();
             }
         }
     }
-    wait().unwrap();
+    }
 }
5 People found this is helpful
Advertisement