I'd like to call fork() from within a signal handler, where the child thread needs to wait for the parent thread to finish a task before completing its tasks. So for example:
lock=init_lock();
grab_lock(&lock);
pid_t child_pid = fork();
if (child_pid != 0) {
/* we are the parent */
build_house();
release_lock(&lock);
} else {
/* we are the child */
play_in_yard();
wait_for_lock(&lock);
enter_house();
}
In this case, you don't want the child entering the house before the parent finishes building it. (The parent would have to lock before forking, to avoid a race condition where the child enters the house before the parents have a chance to grab the lock). I'm wondering what type of lock I could use. I'm not seeing any of the locking/unlocking api's in the async-safe list of functions. Is there any way to safely do this?
Related
I am starting a bunch of joinable worker threads and main() waits for them to completed with pthread_join(). However, a user may hit CTRL+C on the terminal before the worker threads have completed their task. My understanding is that any thread could get the signal so all my worker threads call pthread_sigmask() on start up and block SIGINT (the CTRL+C signal). This causes the signal to be copied to other threads and main(). This way I know that at least main() will get definitely the signal.
I have defined a signal handler function on main() so that main() gets the signal and can kill all the worker threads and free their resources from one place. The problem is that this happens asynchronously. I call pthread_kill() from main() and then try to free() resources the worker thread is using and it's still running because the signal is dispatched asynchronously.
If I call pthread_kill(SIGTERM, ...) from main() to kill the thread main() gets killed too and do_thread_cleanup(i) is never called:
int main () {
signal (SIGINT, signal_handler);
for (i = 0; i < num_thd; i++) {
pthread_create(thread_init, ...);
}
for (i = 0; i < num_thd; i++) {
pthread_join(...);
}
return 0;
}
void signal_handler(int signal) {
for (i = 0; i < num_thd; i++) {
pthread_kill(pthread_t, SIGINT);
pthread_join(pthread_t, ...);
do_thread_cleanup(i); // Calls functions like free() and close()
}
}
void thread_init() {
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
do_stuff_in_a_loop();
}
How can I send SIGKILL to a thread without main() receiving that signal and killing itself? Alternatively, how can I wait for the thread to exit?
Having read the other SO posts the talk about using pthread_cleanup_push() and pthread_cleanup_pop() but that doesn't allow me to check form one central place that all threads are killed and their resources released.
The short answer is that you can’t; but you can do something close.
Free(), malloc() and thus all paths leading to them are not signal safe; so you can’t call them from a signal handler. It is rare that these functions would notice the signal (re)entry, so unpredictable behaviour is the likely result.
A good pattern is to have the main thread notice signals have occurred, and perform the processing for them within it. You can do this, safely, by having the main thread employ a pthread_cond_t,pthread_mutex_t pair to watch a counter, and have the signal handler use the same pair to update the counter and notify the change.
Thus the main thread can treat signals as simple inputs to transition between states, such as Normal/SIGINT -> Quitting, Quitting/SIGALRM -> HardStop.
Free() is probably a bit heavy-handed, as it can cause your program to make sporadic memory references, which may be exploitable as an attack surface.
I have come across a problem with my application and the spawnProcess.
If the main application for some reason dies/is killed then the spawned processes seem to live on and I can't reach them unless I use terminal to kill them via their PIDs. My goal is if the main application dies then the spawned processes should be killed also, somehow.
My code is like this
auto appPid = spawnProcess("path/to/process");
scope(exit){ auto exitcode = wait(appPid);
stderr.writeln(...);}
And if I use the same approach when the main process dies, using wait(thisProcessID) I get an error. "No overload matches". Any ideas how to solve this problem?
Here's some code that will do it on Linux. It doesn't have all the features of the stdlib's spawnProcess, it just shows the bare basics, but expanding it from here isn't hard if you need more.
import core.sys.posix.unistd;
version(linux) {
// this function is Linux-specific
import core.stdc.config;
import core.sys.posix.signal;
// we can tell the kernel to send our child process a signal
// when the parent dies...
extern(C) int prctl(int, c_ulong, c_ulong, c_ulong, c_ulong);
// the constant I pulled out of the C headers
enum PR_SET_PDEATHSIG = 1;
}
pid_t mySpawnProcess(string process) {
if(auto pid = fork()) {
// this branch is the parent, it can return the child pid
// you can:
// import core.sys.posix.sys.wait;
// waitpid(this_ret_value, &status, 0);
// if you want the parent to wait for the child to die
return pid;
} else {
// child
// first, tell it to terminate when the parent dies
prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
// then, exec our process
char*[2] args;
char[255] buffer;
// gotta copy the string into another buffer
// so we zero terminate it and have a C style char**...
buffer[0 .. process.length] = process[];
buffer[process.length] = 0;
args[0] = buffer.ptr;
// then call exec to run the new program
execve(args[0], args.ptr, null);
assert(0); // never reached
}
}
void main() {
mySpawnProcess("/usr/bin/cat");
// parent process sleeps for one second, then exits
usleep(1_000_000);
}
So the lower level functions need to be used, but Linux does have a function that does what you need.
Of course, since it sends a signal, your child might want to handle that to close more gracefully than the default termination, but try this program and run ps while it sleeps to see cat running, then notice the cat dies when the parent exits.
How do I return a value to a process which initiated a daemon from a signal handler inside a daemon?
sub _fork
{
my $pid = fork;
$pid;
}
sub daemonize_monitor_sigio
{
_fork and return;
SIG{IO} = sub{
print "caught sigio";
$ret = {}
...#do some processing
#wants to return $ret here;
}
while(1)
{
;
}
}
daemoniz_monitor_sigio();
The thing about signal handlers, is they're pretty simple. They're basically an interrupt from the kernel, that's passed to the process.
The handler can alter state within the process. But because you've fork()ed beforehand, you have a parent process and a child process - the two don't have any shared state. So 'signaling' from one to the other, is an completely seperate IPC - at the simplest level - you can send another kill signal to the parent process - and get this pid via getpgrp.
For more complicated IPCs though, you're looking at... well, reading the perlipc doc, and figuring out what's most appropriate.
So my program spawns a number of child processes in response to certain events, and I'm doing something ike this to keep track and kill them upon program exit (Perl syntax):
my %children = ();
# this will be called upon exit
sub kill_children {
kill 'INT' => keys %children;
exit;
}
# main code
while(1) {
...
my $child = fork();
if ($child > 0) {
$children{$child} = 1;
} elsif ($child == 0) {
# do child work ...
exit();
} else {
# handle the error
}
}
So the idea is as above. However, there's a blatant race condition there, in that a given child can start and terminate before the father has a chance to run and record its pid in the %children hash. So the father may end up thinking that a given pid belongs to an active child, even if this child has terminated.
Is there a way to do what I'm trying to accomplish in a safe way?
Edit: To better keep track of children, the code can be extended as follows (which however also suffer of the exact same race condition, so that's why I didn't write it fully in the first place):
my %children = ();
sub reap {
my $child;
while (($child = waitpid(-1, WNOHANG)) > 0) {
#print "collecting dead child $child\n";
delete $children{$child};
}
}
$SIG{CHLD} = \&reap;
# this will be called upon exit
sub kill_children {
local $SIG{CHLD} = 'IGNORE';
kill 'INT' => keys %children;
exit;
}
# main code
while(1) {
...
my $child = fork();
if ($child > 0) {
$children{$child} = 1;
} elsif ($child == 0) {
# do child work ...
exit();
} else {
# handle the error
}
}
Even in this case, the contents of %children may not reflect the actual active children.
Edit 2: I found this question, which is exactly about the same problem. I like the solution suggested in there.
On UNIX it's not a race condition. This is the standard way to handle fork(). When the child process exits, its status is changed to "terminated"; it becomes a zombie. It still has an entry in the process table until the parent process calls one of the wait functions. Only after that is the dead process really removed.
Even if the parent sets itself up to ignore SIGCHLD, it still wouldn't qualify as a race condition; the parent would just have a PID that's not valid anymore. In that case, wait() would return ECHILD. But setting SIGCHLD would free up a child's PID, possibly leading to the parent trying to kill a process that is not a child.
On Windows, which doesn't have a fork call, it is emulated by creating a thread in the perl process. See perlfork. I'm not knowlegable enough about Windows to opinionate about if that could cause a race condition, but I suspect not.
I am trying some simple code on fork. When I give code like this, it works fine. It will print
I am the child
I am the parent
and then waits for 30 seconds. I understand this is due to switching between these two process. First child executes then parent and then child...
#include<stdio.h>
#include<stdlib.h>
main()
{
int pid;
pid=fork();
if(pid==0)
{
printf("\nI am the child\n");
sleep(30);
exit(0);
}
if(pid>0)
{
printf("\nI am the parent\n");
wait();
}
}
But when I gave like (without wait in parent)
#include<stdio.h>
#include<stdlib.h>
main()
{
int pid;
pid=fork();
if(pid==0)
{
printf("\nI am the child\n");
sleep(30);
exit(0);
}
if(pid>0)
{
printf("\nI am the parent\n");
}
}
it just prints
I am the child
I am the parent
and exits ( no waiting for 30 seconds).
So is it because without wait call parent exits and child still executing? But why is it not showing up in terminal (the waiting)?
Whether parent becomes zombie here?
Your observations are correct.
The terminal waits for the original processes (which is the parent) to exit. It doesn't wait for any child processes to exit.
Zombies: A process is a zombie if it has exited but its parent has not called wait() on it.
In your case, the parent does not become a zombie because the terminal is waiting for it.
Yes.
The grandparent never waits on children; children without a parent are reparented to init.
No, it dies.
The shell is waiting for the parent to finish but not the child.
The child becomes a zombie after 30 seconds (that the shell will clean up with the next prompt).
On the second example the child becomes orphan because the parent had returned while the child is alive. Orphan process belong to init and not the shell, that's why it's not showing up. There is no zombies in your two code samples. Zombies are when a parent is alive an child is dead and the parent doesnt call wait the child becomes zombie.