fix: race condition and partial state issue on injecting signal context into user...
[lunaix-os.git] / lunaix-os / kernel / demos / signal_demo.c
1 #include <lunaix/lunistd.h>
2 #include <lunaix/proc.h>
3 #include <lunaix/signal.h>
4 #include <lunaix/spike.h>
5 #include <lunaix/syslog.h>
6 #include <lunaix/types.h>
7
8 LOG_MODULE("SIGDEMO")
9
10 void __USER__
11 sigchild_handler(int signum)
12 {
13     kprintf(KINFO "SIGCHLD received\n");
14 }
15
16 void __USER__
17 sigsegv_handler(int signum)
18 {
19     pid_t pid = getpid();
20     kprintf(KWARN "SIGSEGV received on process %d\n", pid);
21     _exit(signum);
22 }
23
24 void __USER__
25 sigalrm_handler(int signum)
26 {
27     pid_t pid = getpid();
28     kprintf(KWARN "I, pid %d, have received an alarm!\n", pid);
29 }
30
31 // FIXME: Race condition with signal (though rare!)
32 // For some reason, there is a chance that iret in soft_iret path
33 //   get unhappy when return from signal handler. Investigation is needed!
34
35 void __USER__
36 _signal_demo_main()
37 {
38     signal(_SIGCHLD, sigchild_handler);
39     signal(_SIGSEGV, sigsegv_handler);
40     signal(_SIGALRM, sigalrm_handler);
41
42     alarm(5);
43
44     int status;
45     pid_t p = 0;
46
47     kprintf(KINFO "Child sleep 3s, parent pause.\n");
48     if (!fork()) {
49         sleep(3);
50         _exit(0);
51     }
52
53     pause();
54
55     kprintf("Parent resumed on SIGCHILD\n");
56
57     for (int i = 0; i < 5; i++) {
58         pid_t pid = 0;
59         if (!(pid = fork())) {
60             signal(_SIGSEGV, sigsegv_handler);
61             sleep(i);
62             if (i == 3) {
63                 i = *(int*)0xdeadc0de; // seg fault!
64             }
65             kprintf(KINFO "%d\n", i);
66             _exit(0);
67         }
68         kprintf(KINFO "Forked %d\n", pid);
69     }
70
71     while ((p = wait(&status)) >= 0) {
72         short code = WEXITSTATUS(status);
73         if (WIFSIGNALED(status)) {
74             kprintf(KINFO "Process %d terminated by signal, exit_code: %d\n",
75                     p,
76                     code);
77         } else if (WIFEXITED(status)) {
78             kprintf(KINFO "Process %d exited with code %d\n", p, code);
79         } else {
80             kprintf(KWARN "Process %d aborted with code %d\n", p, code);
81         }
82     }
83
84     kprintf("done\n");
85
86     _exit(0);
87 }