C Linux Signal Handler for the Main Process Only - c

I am making a program that creates numerous processes using fork(), which then calls an exec function to the same program (this is required by the professor).
I need it to react to CTRL+C (SIGINT) and ask the user if he/she wants to leave. The problem is that the signal handler is implemented in all the child processes too, so, when the signal is sent, the user has to answer the same amount of times as the number of processes.
I only want it to ask the user once per CTRL+C.
What solutions can I implement?

When you call fork(), the parent process will get back the pid of the child. You can send a SIGTERM or SIGKILL signal to the children through the kill syscall when the parent receives the SIGINT signal.

You can set a global variable pid and populate it with the result of getpid() on launch. And inside the signal handler test getpid() against pid then execute your code. Something like, if you are the main process please proceed, if not exit!
End result: You will have a signal handler that is run once by the main process....

Related

Get signal when tid status change

There is a way to look when pid/tid status change with waitpid but this is blocking function.
I want to monitor all threads in specific pid and get signal when one of them change and print the tid.
For now I open threads as count of threads in that process and each 1 make waitpid on 1 tid and after that blocking function finish I print that tid that changed.
How can I get a signal that tid change so I can monitor all tid's in 1 thread.
I didn't want to monitor all pid in system only specific pid/tid.
Those tids/pids are not children of my process.
You can call
int status;
pid_t waitpid(-1, &status, 0);
to wait for any child process change.
So you do not have to specify in advance, which pid to monitor, and can react on any status change. This way you do not need to start one thread for each pid.
As to the signal part of your question: A SIGCHLD is sent to your process when a child process exits. This signal is ignored by default, but you can install a custom signal handler for it, of course.
If you only want to reap specific pids, linux provides the option WNOWAIT, which only reports the state, but does not really reap the child process. Now you can check, if the pid is one of those you want to monitor, and if so, call waitpid() again without the option.
If the processes are not children, waitpid() cannot be used in general. One option is, to attach with ptrace() to these 40 processes to get signalled, if one of these processes exit. This might have unwanted side-effects, however.
If you're using POSIX threads, then you could use pthread_cleanup_push and pthread_cleanup_pop to call a "cleanup" function when your thread is exiting.
This "cleanup" function could then send one of the user signals (SIGUSR1 or SIGUSR2) to the process which then catches it and treats it as a signal about thread termination.
If you use sigqueue you can add the thread-id for the signal handler so it knows which thread just exited.
You can use pthread_sigmask to block the user signal in all threads, to make sure it's only delivered to the main process thread (or use pthread_sigqueue to send to the main process thread specifically).

Don't send SIGINT on CTRL+C to child processes but don't ignore the signal itself

I'm trying to write a Task control program, very much like Supervisor.
I run some programs from a config file and let them run in the background, while in the main process I read and execute other commands.
Before fork()-ing, in the main process I call:
sigaction(SIGINT, &the_handler, NULL);
Where the_handler stores the reference of a simple print function.
When CTRL+C is pressed, the child processes are interrupted as well (which I don't want).
I could run: signal(SIGINT, SIG_IGN); after fork in child process to ignore it, but I would like to still to be able to run this command in bash: $ kill -n 2 <child_pid>, meaning, I don't want to ignore it, right?
So, how to ignore SIGINT from CTRL+C to child processes, but still be able to receive the signal in other ways? Or am I missing something?
The traditional means of doing this is to fork twice. The grand parent forks its children and then waits for them. Each child then forks and exits straight away. Because their parents have exited, the grand children become parented by pid 1. Thus signals sent to the grand parent do not get propagated to the ex-grand children.
See this answer for a bit more detail
https://stackoverflow.com/a/26418006/169346
ETA: You need to call setsid() between the two forks otherwise the grandchild is still in the same process group as the grand parent and will still receive signals that the grand parent receives.

Receiving SIGCHLD yet have spawned no child processes

I have a C program running on Linux 3.12. This program spawns several child processes. One of these processes spawns a thread that runs for a bit then terminates. While this child process is running it performs an epoll_wait(). Periodically, the epoll_wait returns with an EINTR error. I setup the child process to catch the signal doing this interruption and found it is a signal 17, which, according to everything I have read is a SIGCHLD. Thing is, the thread this child process spawned is still running. It did not terminate. I also thought that threads do not generate a SIGCHLD on termination.
Any thoughts on why my process may be getting a signal 17?
The answer is a call to system(). This function in the code spawns a process to execute the shell command being passed in. The thread was calling system() to run some shell commands. When they finished the processes that was spawned ended and generated the SIGCHLD.

zombie process created in code, and killed in another part

I want to write a 'zombie creator' and 'zombie terminator'. Main point is that I want to create zombies in one part and terminate them in other part of code. I'm using C.
Example:
create_zombie(); //let's say it's a spawn, using fork etc.
/* a houndred lines below */
kill_zombie(PID); // PID is determinated by user, I want to leave him the choice
I know how to do this using fork(), if .. else, but that's not the point. I'm looking for some kind of remote control. Is that possible? Sleeping him for a long time could be a solution?
I'm assuming Linux, but the process should be similar on other operating systems. You want to look into the kill() function declared typically declared in the signal.h header file. This will allow you to send a signal to a specific PID from your zombie killer. The easiest approach would be to send your zombie process a kill signal (SIGKILL). SIGKILL cannot be caught or ignored, and immediately kill a process dead.
If you need to do some cleanup in your zombie process, you can create a signal handler with the signal() function. This will allow you to specify a function to call when a process receives a signal. This function would implement your cleanup code and then exit().
On linux, your shell should have a kill command that mimics the functionality of kill(). The syntax is typically kill -s 9 PID. This will send a SIGKILL (signal number 9) to the process PID.
I hope this answer nudges you in the proper direction.
When you fork a process, fork returns 0 in the child process and the child's process id in the parent. You can save them in an array, write them to a file, or write them to a pipe and don't "uncap" the other end until you need it.

How to kill the parent process and its children on ctrl+C or ctrl+Z

I have the main process in my program that fork() some children processes and then goes into endless loop (Also, the children processes are endless). Now, I want to kill all processes, close a socket, de-attach shared memory, and clean all similar stuff on terminating the program with Ctrl+C or Ctrl+Z. I search the internet and I found that I could do that by sending some signals like SIGSTOP and SIGINT, but I don't know how to do it.So, how can I accomplish this in my program?
From outside the program, you can send any process a signal using the kill command.
By default, kill will send the SIGTERM signal, which will terminate a process, and free its allocated resources. You can use the ps command to find the process ids of your program's processes. Using CTRL-C will only terminate the parent process. It will not kill the child processes. If you just forked, and didn't exec a new program, then all of your child processes will have the same name as the parent, which means you can use the killall command to terminate them all in one go. If you are logged in remotely, then logging out will cause a SIGHUP signal to be sent to all of the processes you spawned during the session, which will terminate them by default.
From inside the program, there is a kill() function that operates similar to the command. You will need the process ids still, so it's important that your parent code remembers the child process id returned by fork.
When your process exits brutally, all resources are certainly freed.
However, if you want to control the behaviour (what order, etc, I don't know what) then you should install a signal handler. See sigaction(2).

Resources