Perl: Installing signal handlers in forked child which execs - perl

I found the answer in Managing Signal Handling for daemons that fork() very helpful for what I'm doing. I'm unsure about how to solve
"You will therefore need to install any signal handling in the execed process when it starts up"
I don't have control over the process that start up. Is there any way for me to force some signal handles on the execed from the parent of the fork?
Edit:{
I'm writing a Perl module that monitors long-running processes. Instead of
system(<long-running cmd>);
you'd use
my_system(<ID>, <long-running cmd>);
I create a lock file for the <ID> and don't let another my_system(<ID>...) call through if there is one currently running with a matching ID.
The parent fork/execs <long-running cmd> and is in change of cleaning up the lock file when it terminates. I'd like to have the child self-sufficient so the parent can exit (or so the child can take care of itself if the parent gets a kill -9).
}

On Unix systems, you can make an exec'd process ignore signals (unless the process chooses to override what you say), but you can't force it to set a handler for it. The most you can do is leave the relevant signal being handled by the default handler.
If you think about it, you'll realize why. To install a signal handler, you have to provide a function pointer - but the process that does the exec() can't specify one of its functions because they won't exist as part of the exec'd process, and it can't specify one of the exec'd processes functions because they don't exist as part of the exec'ing process. Similarly, you can't register atexit() handlers in the exec'ing process that will be honoured by the exec'd process.
As to your programming problem, there's a good reason that the lock file normally contains the process ID (pid) of the process that holds the lock; it allows you to check whether that process is still around, even if it isn't your child. You can read the pid from the lock file, and then use kill(pid, 0) which will tell you if the process exists and you can signal it without actually sending any signal.

One approach would be to use two forks.
The first fork would create a child process responsible for cleaning up the lock file if the parent dies. This process will also fork a grandchild which would exec the long running command.

Related

Handle signals of child processes

Is it possible to catch signals received (specifically SIGSEGV, SIGABRT) by child processes of a program without actually modifying it (or with minimal modification)?
The program I'm talking about is a pretty complex tool of which I don't have low-level (implementation details) knowledge of. I do have access to its source code. I can start it using a command like:
$ ./tool_name start # tool_name is an executable created after compiling and building its source code
It forks many child processes and I want to see if those child processes are being killed by a signal or not.
What I have thought about is to create a simple C program and call above command through that (using system()). Write a signal handler for above signals I'm looking for, and do other stuffs. Is it a right way to keep track of signals received by child processes? Is there a better way to do the same?

Running perl function in background or separate process

I'm running in circles. I have webpage that creates a huge file. This file takes forever to be created and is in a subroutine.
What is the best way for my page to run this subroutine but not wait for it to be created/processed? Are there any issues with apache processes since I'm doing this from a webpage?
The simplest way to perform this task is to simply use fork() and have the long-running subroutine run in the child process. Meanwhile, have the parent return to Apache. You indicate that you've tried this already, but absent more information on exactly what the code looks like and what is failing it's hard to help you move forward on this path.
Another option is to have run a separate process that is responsible for managing the long-running task. Have the webpage send a unit of work to the long-running process using a local socket (or by creating a file with the necessary input data), and then your web script can return immediately while the separate process takes care of completing the long running task.
This method of decoupling the execution is fairly common and is often called a "task queue" (if there is some mechanism in place for queuing requests as they come in). There are a number of tools out there that will help you design this sort of solution (but for simple cases with filesystem-based communication you may be fine without them).
I think you want to create a worker grandchild of Apache -- that is:
Apache -> child -> grandchild
where the child dies right after forking the grandchild, and the grandchild closes STDIN, STDOUT, and STDERR. (The grandchild then creates the file.) These are the basic steps in creating a zombie daemon (a parent-less worker process unconnected with the webserver).

vfork:Understanding Issue:

I have a confusion around the functionality of vfork(). I read that in case of vfork(), parent and the child process used to share pages between them. It doesn't support any copy on write functionality. This means, if during its timeslice child process makes some changes, all these changes would be visible to the parent process when it will return. It was also mentioned, that the vfork() syscall is only been useful when the child process just executes the exec system call after its creation.
Let us say, that the child process executes the exec system call with ls. Now, according to the exec calls, the ls program will be loaded on to the address space of the child process. Now, when the parent process' timeslice will start, it might have a different intruction to execute on its PC, which might cause this process to behave differently.
Can somebody please make this scenario clear to me, how the vfork() call is helpful in such situations?
The point of vfork() is not to allocate a new address space for a child which is going to immediately throw it away again. As such, vfork() omits the part of fork() which creates a new address space (page tables and allocations) for the child, and instead sets a flag which execve() interprets as meaning that it should allocate a new page table and stack for the process before populating it with the new executable and its requested initial heap (BSS).
execve() releases the current process' memory mappings and allocates new ones. Exiting a process also ends up releasing that process' memory mappings.
Traditionally, vfork() suspends the parent process until the child stops using the parent's memory mappings. The only way to do that safely is via execve() or _exit().
Let us say, that the child process executes the exec system call with
ls. Now, according to the exec calls, the ls program will be loaded on
to the address space of the child process.
Actually, ls will be loaded in a new address space, the parent's address space is released on the child.

Perl system() command failing after fork

I have a perl script which calls fork() a few times to create 4 child processes. The parent process then uses waitpid() to wait for all of the children to finish.
The problem occurs when I try to call system() from within the child processes (I'm using it to create directories). Even something as simple as system("dir") fails (yes, I'm on Windows).
By "fails", I mean that one of the child threads goes past it no problem, but the other child processes so far as I can tell simply cease to exist.
trace INFO, "Thread $thread_id still alive at 2.62";
system("dir");
trace INFO, "Thread $thread_id still alive at 2.65";
I get messages such as "Thread 3 still alive at 2.62", but only 1 of the child threads ever gets to 2.65.
At the bottom of the log, I can see "Command exited with non-zero status 127", which I think may have something to do with it.
I've considered using some sort of a mutex lock to make sure that only 1 processes at a time goes through the system calls, but how can I do that with fork()? Also, this problem doesn't really make any sense in the first place, why would several independent processes have trouble doing system("dir") at the same time?
The problem here is that fork() is emulated under windows using threads. So there is no real processes created.
If you are only use system call to create folders, then you'd better use perl function mkdir or File::Path's make_path instead.

Managing Signal Handling for daemons that fork()

I want to write a robust daemon in perl that will run on Linux and am following the template described in this excellent answer. However there are a few differences in my situation: First I am using Parallel::ForkManager start() and next; to fork on an event immediately followed by exec('handle_event.pl')
In such a situation, I have the following questions:
Where should I define my signal handlers. Should I define them in the parent (the daemon) and assume that they will be inherited in the children?
If I run exec('handle_event.pl') will the handlers get inherited across the exec (I know that they are inherited across the fork)?
If I re-define a new signal handler in handle_event.pl will this definition override the one defined in the parent?
What are best practices in a situation like this?
Thank you
When you fork, the child process has the same signal handlers as the parent. When you exec, any ignored signals remain ignored; any handled signals are reset back to the default handler.
The exec replaces the whole process code with the code that will be executed. As signal handlers are code in the process image, they cannot be inherited across an exec, so exec will reset the signal handling dispositions of handled signals to their default states (ignored signals will remain ignored). You will therefore need to install any signal handling in the execed process when it starts up.