> For the complete documentation index, see [llms.txt](https://docs.aic-eec.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.aic-eec.com/computer-operation-systems/linux-os-dev.-engineer/ipc/signal-programming.md).

# Signal Programming

การส่งสัญญาณ (signal) ถือว่าเป็นการส่งข้อมูลขั้นพื้นฐานระหว่างโปรเซสภายใต้ระบบปฏิบัติการลีนุกซ์ โดยโปรเซสหนึ่งจะส่งสัญญาณไปยังอีกโปรเซสหนึ่ง เมื่ออีกโปรเซสที่ได้รับสัญญาณที่ถูกแทรกเข้ามา (interrupt) มันก็จะดำเนินการคำสั่งที่ถูกตั้งเอาไว้ทันที ซึ่งเมื่อเริ่มแรกของการนำสัญญาณมาใช้นั้น จะเป็นเพียงรูปแบบสัญญาณที่ไม่ได้แยกแยะชนิดหรือประเภทของสัญญาณอะไรมากมายแต่ในปัจจุบันการพัฒนาของระบบปฏิบัติการลีนุกซ์มีความซับซ้อนมากขึ้น รวมทั้งการสื่อสารระหว่างโปรเซสก็ต้องการเงื่อนไขที่หลากหลายมากขึ้นเช่นกัน จึงทำให้มีการกำหนดประเภทของสัญญาณ (signal type) ขึ้นมาโดยมีชนิดเป็นเลขจำนวนเต็ม (integer value) ตัวอย่างเช่น เลข 15 (`SIGTERM`) แทนสัญญาณสิ้นสุดการทำงาน (Terminate) ซึ่งหมายเลขสัญญาณต่างๆจะถูกกำหนดอยู่ในฟังก์ชัน  <mark style="color:blue;">**`signal.h`**</mark>

| 1) SIGHUP       | 2) SIGINT       | 3) SIGQUIT      | 4) SIGILL       | 5) SIGTRAP      |
| --------------- | --------------- | --------------- | --------------- | --------------- |
| 6) SIGABRT      | 7) SIGBUS       | 8) SIGFPE       | 9) SIGKILL      | 10) SIGUSR1     |
| 11) SIGSEGV     | 12) SIGUSR2     | 13) SIGPIPE     | 14) SIGALRM     | 15) SIGTERM     |
| 16) SIGSTKFLT   | 17) SIGCHLD     | 18) SIGCONT     | 19) SIGSTOP     | 20) SIGTSTP     |
| 21) SIGTTIN     | 22) SIGTTOU     | 23) SIGCONT     | 24) SIGXCPU     | 25) SIGXFSZ     |
| 26) SIGVTALRM   | 27) SIGPROF     | 28) SIGWINCH    | 29) SIGIO       | 30) SIGPWR      |
| 31) SIGSYS      | 34) SIGRTMIN    | 35) SIGRTMIN+1  | 36) SIGRTMIN+2  | 37) SIGRTMIN+3  |
| 38) SIGRTMIN+4  | 39) SIGRTMIN+5  | 40) SIGRTMIN+6  | 41) SIGRTMIN+7  | 42) SIGRTMIN+8  |
| 43) SIGRTMIN+9  | 44) SIGRTMIN+10 | 45) SIGRTMIN+11 | 46) SIGRTMIN+12 | 47) SIGRTMIN+13 |
| 48) SIGRTMIN+14 | 49) SIGRTMIN+15 | 50) SIGRTMAX-14 | 51) SIGRTMAX-13 | 52) SIGRTMAX-12 |
| 53) SIGRTMAX-11 | 54) SIGRTMAX-10 | 55) SIGRTMAX-9  | 56) SIGRTMAX-8  | 57) SIGRTMAX-7  |
| 58) SIGRTMAX-6  | 59) SIGRTMAX-5  | 60) SIGRTMAX-4  | 61) SIGRTMAX-3  | 62) SIGRTMAX-2  |
| 63) SIGRTMAX-1  | 64) SIGRTMAX    | <p><br></p>     | <p><br></p>     | <p><br></p>     |

{% hint style="info" %}

#### ตัวอย่างการส่งสัญญาณผ่านคีย์บอร์ด

<mark style="color:orange;">**Ctrl-C**</mark>

ส่งสัญญาณ INT (SIGINT) ไปยังโปรเซสที่ทำงานอยู่ยุติการทำงานทันที

<mark style="color:orange;">**Ctrl-Z**</mark>&#x20;

ส่งสัญญาณ TSTP (SIGTSTP) ไปยังโปรเซสที่ทำงานอยู่ให้หยุดชั่วคราว

<mark style="color:orange;">**Ctrl-\\**</mark>&#x20;

ส่งสัญญาณ ABRT (SIGABRT) ไปยังโปรเซสที่ทำงานอยู่ให้ยุติการทำงานของโปรเซสนั้นทันที เหมือน Ctrl-C แต่เป็นคำสั่งที่ดีกว่าคือสามารถแก้ไขได้
{% endhint %}

นอกจากนั้นจะมีการเรียกใช้ฟังก์ชัน kill() เพื่อทำการส่งสัญญาณออกไปยังโปรเซสปลายทาง โดยที่โปรเซสรับปลายทางจะมีการกำหนดไว้ว่าถ้าได้รับสัญญาณหมายเลขนี้ ก็ให้ดำเนินการเรียกฟังก์ชันที่กำหนดไว้ต่อไป ด้วยการเรียกใช้ฟังก์ชัน signal() อย่างไรก็ตามโปรเซสต่างๆที่อยู่ภายใต้ผู้ใช้คนเดียวกัน จะสามารถส่งสัญญาณถึงกันได้ แต่ไม่สามารถส่งสัญญาณไปยังโปรเซสอื่นๆของผู้ใช้คนอื่นได้ ยกเว้นโปรเซสของ superuser เท่านั้น

{% hint style="info" %}
**ฟังก์ชันและตัวแปรที่เกี่ยวข้อง**

* **ฟังก์ชัน&#x20;**<mark style="color:orange;">**`void signal(int sig_type, void (*sig_handler)(int signal_type))`**</mark>
  * `sig_type` แทนค่าของสัญญาณที่จะตรวจจับ (ดูจากไฟล์ <mark style="color:blue;">**`signal.h`**</mark>)
    * `sig_handles` แทนค่าตัวชี้ (pointer) ไปยังฟังก์ชันที่สร้างขึ้นมาเพื่อดำเนินการเมื่อได้รับสัญญาณที่ตรวจจับได้
* **ฟังก์ชัน&#x20;**<mark style="color:orange;">**`int kill (pid_t dest_pid, int sig_type)`**</mark>
  * เป็นฟังก์ชันที่ใช้ในการส่งสัญญาณที่ต้องการ (`sig_type`) ไปยังโปรเซสปลายทาง (`dest_pid`) นอกจากนั้นถ้ามีการกำหนดค่า `dest_pid` เป็น `0` จะหมายถึงการส่งไปยังทุกโปรเซสของผู้ใช้เดียวกัน แต่ถ้ากำหนดค่า `dest_pid` เป็น `-1` เมื่อใดจะหมายถึงการส่งไปยังทุกโปรเซสในระบบ (แต่ใช้ได้เฉพาะเป็น superuser เท่านั้น)&#x20;
* **ฟังก์ชัน&#x20;**<mark style="color:orange;">**`void raise (int sig_type)`**</mark>
  * ใช้ในกรณีที่ต้องการส่งสัญญาณ (`sig_type`) ให้ตัวเอง
    {% endhint %}

{% hint style="info" %}
&#x20;  **สิ่งที่ควรรู้**  &#x20;

* โปรเซสจะได้รับสัญญาณได้ทั้งผ่านโปรเซสในกลุ่มเดียวกันของผู้ใช้นั้นส่งมาหรือผู้ใช้ในระดับ superuser เป็นผู้ส่งมาให้เอง
* ชนิดของสัญญาณและชื่อของสัญญาณถูกกำหนดอยู่ในไฟล์ <mark style="color:blue;">**`signal.h`**</mark>&#x20;
* สัญญาณที่ถูกส่งไปจะไม่สามารถถูกเก็บเข้าคิวได้
* ตัวจัดการที่ใช้ในการสิ้นสุดโปรเซสคือ `SIG_DFL` และ `SIG_IGN` ในกรณีต้องการเพิกเฉยต่อสัญญาณที่เข้ามา  ตัวอย่างเช่น`signal (SIGINT, SIG_IGN);`
  {% endhint %}

{% hint style="success" %}

### ตัวอย่างที่ 1

{% endhint %}

แสดงตัวอย่างการกำหนดฟังก์ชันที่จะให้ดำเนินการเมื่อตรวจจับสัญญาณที่กำหนดไว้ ซึ่งในตัวอย่างนี้จะตรวจสอบสัญญาณหมายเลข 2 (`SIGINT`)

<figure><img src="https://1856353139-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MClo3nC-1US0rbK8Qau%2Fuploads%2F6AMngz4tc018qiVIyJDg%2Fsignal%20definition.png?alt=media&amp;token=293aa13e-290f-4b67-8a95-80a551137f8b" alt=""><figcaption><p>กลไกการทำงานของ signalling</p></figcaption></figure>

```c
// signal1.c
#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void signalHandler(int signo) {
	if (signo == SIGINT)
		printf(" received SIGINT\n");
}

int main(void) {
	printf("My pid is %d.\n", getpid());
	if (signal(SIGINT, signalHandler) == SIG_ERR)
		printf("\n Can't catch SIGINT\n");
// A long long wait so that we can easily issue a signal to this process
	while (1)
		sleep(1);
	return 0;
}
```

{% tabs %}
{% tab title="ทดสอบแบบที่ 1" %}

```shell-session
$ gcc -o signal1 signal1.c -Wall
$ ./signal1 
My pid is 21231

(ให้กด Ctrl+C เพื่อส่งสัญญาณให้กับโปรแกรม)

^C received SIGINT
^C received SIGINT
^C received SIGINT
^C received SIGINT
^C received SIGINT
^C received SIGINT

(ให้กด Ctrl+Z เพื่อส่งสัญญาณให้กับโปรแกรม)
^Z
[1]+  Stopped                 ./signal1
```

{% endtab %}

{% tab title="ทดสอบแบบที่ 2" %}
หน้าต่าง **Terminal 1** ให้ทำการ compile และรันโปรแกรม `signal1`จะสังเกตเห็นว่าโปรแกรมจะแสดง Process ID (PID) ของตัวเอง เพื่อให้โปรเซสอื่น ๆ สามารถสื่อสารได้

```shell-session
$ gcc -o signal1 signal1.c -Wall
$ ./signal1 
My pid is 21231 
```

ให้เปิด terminal ใหม่อีกหน้าต่าง (**Terminal 2**) แล้วให้พิมพ์คำสั่ง `kill` เพื่อส่งสัญญาณ `SIGINT` ไปยัง Process ID หมายเลข `21231` ซึ่งก็คือโปรแกรม `signal1` นั่นเอง ดังแสดงข้างล่าง

```shell-session
$ kill -s SIGINT 21231
```

จะสังเกตเห็นข้อความปรากฏข้างล่างในหน้าต่าง **Terminal 1** ดังนี้

```shell-session
$ gcc -o signal1 signal1.c -Wall
$ ./signal1 
My pid is 21231
received SIGINT    <--------- แสดงข้อความเมื่อตรวจจับสัญญาณ SIGINT จาก Terminal 2
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}

### ตัวอย่างที่ 2

{% endhint %}

แสดงตัวอย่างโปรเซสลูกจะวนรอรับ signal ที่จะถูกส่งมาจากผู้ใช้เช่น `Ctrl+C` เป็นต้น โดยโปรเซสแม่จะรอโปรเซสลูกจนกว่าจะทำงานสิ้นสุด

```c
// signal2.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

void HandlerChild() {
	printf("Sigint received by child \n");
}

void HandlerParent() {
	printf("Sigint received by Parent \n");
	signal(SIGINT, HandlerParent);
}

int n, statusp;

int main(void) {
// signal(SIGINT,HandlerParent);
	n = fork();
	if (n == 0) {
		printf("Child ID %d\n", getpid());
		signal(SIGINT, HandlerChild);
		for (;;) {
		};
	} else {
		printf("Parent ID %d \n", getpid());
// signal(SIGINT,HandlerParent);
		wait(&statusp);
// kill(n,SIGKILL);
		exit(0);
	}
	return 0;
}
```

```shell-session
$ gcc -o signal2 signal2.c -Wall 
$ ./signal2
Parent ID 4564 
Child ID 4565
^CSigint received by child 
```

{% hint style="success" %}

### ตัวอย่างที่ 3

{% endhint %}

แสดงตัวอย่างการใช้ฟังก์ชัน `alarm(5)` เพื่อสร้างสัญญาณขึ้นทุกๆ 5 วินาที

```c
// signal3.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int r, count = 0, n;

void HL_AlarmSig(int al) {
	printf(" I am active every 5 sec ");

	signal(SIGALRM, HL_AlarmSig);
	r = alarm(5);
	count++;
	printf(" .... Now the time is %d sec \n", count * 5);
}

void HL_AllSig(int s) {
	printf(" Oh ! I just received signal number %d \n", s);
	signal(s, HL_AllSig);
}

int main(void) {
	for (n = 1; n <= 31; n++) {
		signal(n, HL_AllSig);
	}
	signal(SIGALRM, HL_AlarmSig);
	r = alarm(5);
	while (count < 12) {
	};
	printf(" Program Terminate !! ");
	return 0;
}
```

```shell-session
$ gcc -o signal3 signal3.c -Wall 

$ ./signal3
^C Oh ! I just received signal number 2 
^C Oh ! I just received signal number 2 
^C Oh ! I just received signal number 2 
 I am active every 5 sec  .... Now the time is 5 sec 
^Z Oh ! I just received signal number 20 
^\ Oh ! I just received signal number 3 
 I am active every 5 sec  .... Now the time is 10 sec 
 I am active every 5 sec  .... Now the time is 15 sec 
^C Oh ! I just received signal number 2 
^C Oh ! I just received signal number 2 
^C Oh ! I just received signal number 2 
^Z Oh ! I just received signal number 20 
^Z Oh ! I just received signal number 20 
 I am active every 5 sec  .... Now the time is 20 sec 
 I am active every 5 sec  .... Now the time is 25 sec 
 I am active every 5 sec  .... Now the time is 30 sec 


 I am active every 5 sec  .... Now the time is 35 sec 
 I am active every 5 sec  .... Now the time is 40 sec 
 I am active every 5 sec  .... Now the time is 45 sec 
 I am active every 5 sec  .... Now the time is 50 sec 
 I am active every 5 sec  .... Now the time is 55 sec 
 I am active every 5 sec  .... Now the time is 60 sec 
```

จากผลการทำงานของโปรแกรมข้างต้นเมื่อมีการทำงานของคำสั่ง `alarm(5)` ที่มีการสร้างสัญญาณขึ้นทุกๆ 5 วินาที แล้วทำให้มีการเรียกฟังก์ชัน `HL_AlarmSig()` เพื่อแสดงข้อความนับเวลา แล้วเพิ่มค่าตัวแปร `count` ขึ้นไปเรื่อยๆ จนกระทั่งเมื่อค่าในตัวแปร `count` เพิ่มขึ้นจนเท่ากับหรือมากกว่า 12 โปรเซสแม่ก็จะสิ้นสุดการทำงานของตัวเอง ดังนั้นเมื่อรวมเวลาที่นับแล้วเท่ากับ 60 วินาที (12 x 5) นั่นเอง

{% hint style="success" %}

### ตัวอย่างที่ 4

{% endhint %}

แสดงตัวอย่างโปรแกรมตรวจสอบสัญญาณตามที่กำหนดเพื่อเรียกไปยังฟังก์ชันที่กำหนดไว้

```c
// signal4.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int r, n;

void HL_AlarmSig(int al) {
	printf(" Every 5 sec I have to tell you this PID \n");
	printf(" ....... THIS PROCESS ID = %d ....... \n", getpid());
	signal(SIGALRM, HL_AlarmSig);
	r = alarm(5);

}
void Nothing(int s) {
	signal(s, Nothing);
}

void InfiniteLoop(int s) {
	printf(" No ! I don't care signal number %d  \n", s);
	printf("If you want to stop this process send signal number 9 ONLY!!!\n");

	signal(s, InfiniteLoop);
	for (;;) {
		printf("Loop\n");
	}; /* infinite loop */

}

int main(void) {

	for (n = 1; n <= 31; n++) {
		signal(n, Nothing);
	}
	signal(SIGINT, InfiniteLoop);
	signal(SIGALRM, HL_AlarmSig);
	printf(" If you want to go into the infinite loop \n");
	printf("  .......press  ^C within 5 sec...... \n ");
	r = alarm(5);
	for (;;) {
	};
	printf(" Program Terminate !! \n");
	return 0;
}
```

```shell-session
$ gcc -o signal4 signal4.c -Wall
$ ./signal4 
If you want to go into the infinite loop
  .......press  ^C within 5 sec......
  Every 5 sec I have to tell you this PID
 ....... THIS PROCESS ID = 21538 .......
 Every 5 sec I have to tell you this PID
 ....... THIS PROCESS ID = 21538 .......

(ถ้ากด Ctrl+C โปรแกรมจะเข้าลูปอนันต์)
```

{% hint style="success" %}

### ตัวอย่างที่ 5

{% endhint %}

แสดงตัวอย่างโปรแกรม

```c
// signal5.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>

int n, status;

void HL_Child(int s) {
	printf("**Child**I received signal No. %d .. you can't kill me \n", s);
	signal(s, HL_Child);
}

void HL_Parent(int s) {
	printf("***Parent*** I received signal number %d \n", s);
	signal(s, HL_Parent);
}
void HL_Parent14(int s) {
	printf("***Parent*** I received signal No. %d == Alarm Signal \n", s);
	signal(s, HL_Parent14);

}

void HL_Child14(int s) {
	printf("***Child*** I received signal No %d == Alarm Signal \n", s);
	signal(s, HL_Child14);
}
void HL_Child3(int s) {
	printf("***Child*** I received signal No %d  .. I will exit \n", s);
	exit(5);
}

int main(void) {
	int i;
	for (i = 1; i <= 31; i++)
		signal(i, HL_Parent);
	n = fork();
	if (n == 0) /* Child Process */
	{
		for (i = 1; i <= 31; i++)
			signal(i, HL_Child);
		signal(SIGALRM, HL_Child14);
		signal(3, HL_Child3);
		alarm(2);
		printf("--c--  Child ID  = %d  \n", getpid());
		printf("--c--  Child Process goes into the infinite loop \n");
		printf("--c--  Signal number 3 (^\\) can kill me \n");
		for (;;) {
		};
	} else /* Parent Process */
	{
		printf("--p--  Parent ID  = %d  \n", getpid());
		signal(SIGALRM, HL_Parent14);
		/* alarm(2);  */
		printf("--p--  I am waiting for child exit or any signal \n");
		wait(&status);
		printf("--p--  Wait completed !!  and I am waiting again ...\n");
		wait(&status);
		printf("--p--  Wait completed !! ...exit status = %d\n", status >> 8);
		printf("--p-- I am pausing for check signal from child exit ... \n");
		pause();
		wait(&status);
		printf("--p-- Wait completed !! ...exit status = %d \n", status >> 8);
		printf("--p-- I will execute newprog now !! \n");
		for (i = 1; i <= 31; i++)
			signal(i, SIG_IGN);
		signal(3, SIG_DFL);
		signal(2, HL_Parent);
		i = execl("newprog", "newprog", 0);
		printf("--p-- Parent Process terminated !!\n");
		exit(0);

	}
	return 0;
}

```

```shell-session
$ gcc -o signal5 signal5.c -Wall
$ ./signal5 
--p--  Parent ID  = 22119
--p--  I am waiting for child exit or any signal
--c--  Child ID  = 22120
--c--  Child Process goes into the infinite loop
--c--  Signal number 3 (^\) can kill me

(กด Ctrl+C เพื่อส่งสัญญาณให้ child process)
^C***Parent*** I received signal number 2
**Child**I received signal No. 2 .. you can't kill me

(กด Ctrl+C เพื่อส่งสัญญาณให้ child process)
^C***Parent*** I received signal number 2
**Child**I received signal No. 2 .. you can't kill me
***Child*** I received signal No 14 == Alarm Signal

(กด Ctrl+Z เพื่อส่งสัญญาณให้ child process)
^Z**Child**I received signal No. 18 .. you can't kill me
***Parent*** I received signal number 18

(ถ้ากด Ctrl+\ เพื่อส่งสัญญาณให้ child process เพื่อเรียกฟังก์ชัน HL_Child3() )
^\***Parent*** I received signal number 3
***Child*** I received signal No 3  .. I will exit
***Parent*** I received signal number 20
--p--  Wait completed !!  and I am waiting again ...
--p--  Wait completed !! ...exit status = 5
--p-- I am pausing for check signal from child exit ...

(กด Ctrl+C เพื่อสั่งหยุดโปรแกรม)
^C***Parent*** I received signal number 2
--p-- Wait completed !! ...exit status = 5
--p-- I will execute newprog now !!
--p-- Parent Process terminated !!
```

{% hint style="success" %}

### ตัวอย่างที่ 6

{% endhint %}

แสดงตัวอย่างโปรแกรมที่ใช้สำหรับแก้ปัญหาการจัดการคิวของการสิ้นสุดของโปรเซสลูกที่แตกต่างกรณีกัน (exit statues) ซึ่งเมื่อไหร่ก็ตามที่สถานะของโปรเซสลูกเปลี่ยนแปลงโปรเซสแม่ก็จะได้รับสัญญาณ `SIGCHLD`&#x20;

```c
/*
 *  signal6.c
 *  
 *  The parent process pulls a child exit status whenever the OS notifies
 *  a child status change.
 *
 *  Created by Mij <mij@bitchx.it> on 04/01/05.
 *  Original source file available at http://mij.oltrelinux.com/devel/unixprg/
 *
 */

/* for printf() and fgetc() */
#include <stdio.h>
/* for fork() */
#include <sys/types.h>
#include <unistd.h>
/* for srandom() and random() */
#include <stdlib.h>
/* for time() [seeding srandom()] */
#include <time.h>
/* for waitpid() */
#include <sys/wait.h>
/* for signal(), kill() and raise() */
#include <signal.h>

/* how many childs to raise */
#define NUM_PROCS   5

/* handler prototype for SIGCHLD */
void child_handler(int);

int main(int argc, char *argv[]) {
	int i, exit_status;

	/* execute child_handler() when receiving a signal of type SIGCHLD */
	signal(SIGCHLD, &child_handler);

	/* initialize the random num generator */
	srandom(time(NULL));

	printf("Try to issue a \'ps\' while the process is running...\n");

	/* produce NUM_PROCS childs */
	for (i = 0; i < NUM_PROCS; i++) {
		if (!fork()) {
			/* child */

			/* choosing a random exit status between 0 and 99 */
			exit_status = (int) (random() % 100);
			printf(" -> New child %d, will exit with %d.\n", (int) getpid(),
					exit_status);

			/* try to skip signals overlapping */
			sleep((unsigned int) (random() % 3));

			/* choosing a value to exit between 0 and 99 */
			exit(exit_status);
		}

		/* father */
		sleep((unsigned int) (random() % 2));
	}

	/* checkpoint */
	printf("parent: done with fork()ing.\n");

	/* why this is not equivalent to sleep(20) here? */
	for (i = 0; i < 10; i++) {
		sleep(1);
	}
	/* all the child processes should be done now */
	printf("I did not purge all the childs. Timeout; exiting.\n");

	/* terminate myself => exit */
	kill(getpid(), 15);

	/* this won't be actually executed */
	return 0;
}

/* handler definition for SIGCHLD */
void child_handler(int sig_type) {
	int child_status;
	pid_t child;
	static int call_num = 0;

	/* getting the child's exit status */
	child = waitpid(0, &child_status, 0);

	printf("<-  Child %d exited with status %d.\n", child,
			WEXITSTATUS(child_status));

	/* did we get all the childs? */
	if (++call_num >= NUM_PROCS) {
		printf("I got all the childs this time. Going to exit.\n");
		exit(0);
	}

	return;
}
```

```shell-session
$ gcc -o signal6 signal6.c -Wall

$ ./signal6 
Try to issue a 'ps' while the process is running...
 -> New child 12274, will exit with 68.
 -> New child 12275, will exit with 57.
 -> New child 12276, will exit with 96.
parent: done with fork()ing.
 -> New child 12277, will exit with 18.
 -> New child 12278, will exit with 72.
<-  Child 12275 exited with status 57.
<-  Child 12274 exited with status 68.
<-  Child 12277 exited with status 18.
<-  Child 12276 exited with status 96.
<-  Child 12278 exited with status 72.
I got all the childs this time. Going to exit.
```
