How to trap the signals sent to the sub-processes?

Posted by George Potemkin on 01-Aug-2017 08:07

I'd like to trap a signal sent to a process launched by my shell (namely to a Progress session but let's start just with another shell):

TrapLog=trap.log
TrapAction()
{
 echo "`date '+%Y/%m/%d %H:%M:%S'` PID: $$" >>$TrapLog
 ps -fp $$ >>$TrapLog
 ps -ef | awk '$3 == "'$$'" {print}' >>$TrapLog
}
 
test -f $TrapLog && rm -f $TrapLog
trap TrapAction 15
echo Shell PID1=$$
trap

sh
echo Shell PID2=$$
trap

Sub-process (PID2) obviously ignores the trap command used in the parent shell (PID1). Moreover the parent shell postpones the reaction specified in the trap until I'll kill the sub-process:

date; kill -15 <PID1>
sleep 5
date; kill -9 <PID2>
cat trap.log

Time in trap.log created by PID1 matches the time of kill PID2 command.

If I'll comment out the start of the sub-process (sh) then the trap works as expected.

What I'm doing wrong?

All Replies

Posted by Old Jeremiah Johnson on 01-Aug-2017 10:04

I would say that if parent is waiting for the child to finish (like your case), the trap will not be handled until the child is done.

Once the child is done, the trap sent to the parent will be handled.

Posted by George Potemkin on 01-Aug-2017 10:09

del

Posted by George Potemkin on 01-Aug-2017 10:11

Does it mean that I can't catch the signals sent to a Progress session? I can set the trap only in a shell that launches Progress.

Posted by Old Jeremiah Johnson on 02-Aug-2017 03:21

I never tried to do that, but I would say it's not possible, at least the way you are doing it. You can add more complexity to your code and make the parent to fork the child and not wait for him. In such a way, the parent will handle the signals.

If you just need to monitor the signals sent to a process and if you have red hat, you can use the system tap (stap) tool.

I used it in the past and it's very useful, but I don't know if it exists for other linux distributions.

Posted by George Potemkin on 02-Aug-2017 04:30

Really I'm trying to find out an explanation of the mystery on the client's side where the protrace files are created after hangups:

community.progress.com/.../34409

I'm suspecting that the customer uses a monitor that infinitely and without pauses reads the _Connect VST and sends SIGUSR1 to the processes with the non-zero _Connect-Disconnect flag. Unfortunaly until 11.7 Progress does not reports to db log when a process gets the SIGUSR1.

Since V11.7 we will get: (-----) Protrace location: /path/to/protrace.<PID>

There is the undocumented PROSIGTRACE option that reports the actions of Progress process to the all possible signals. Unfortunately it does not force Progress to report about the signals it really received. Or maybe I just did not find such option.

Posted by Old Jeremiah Johnson on 02-Aug-2017 05:41

That's interesting!.

The way OS handles the signal is different from the way it's done via trap command. In your example if you remove the trap command, the SIGINT signal is transferred to the child, as expected.

You can give systemtap a try if your customer is using Linux. I just saw it's also available in Debian and Ubuntu.

Posted by ske on 08-Aug-2017 08:08

> Really I'm trying to find out an explanation of the mystery ...

> I'm suspecting ... sends SIGUSR1 to the processes ...

Usually in Unix you can use trap to set a signal to be ignored, and then it will continue to be ignored also by the child process (e.g Progress) started from this process. A specific trap procedure will not be inherited by a child process after the child execs a new program, since the procedure needs to live inside the new process, and that is wiped when the new program is loaded. But the status of being ignored is usually kept, in addition to a few other states that do not require a trap procedure. (See man exec & man fork.)

So maybe you can set SIGUSR1 to be ignored before starting Progress, and then see if that stops the actions that you suspect are caused by SIGUSR1. (Unless Progress interferes with this some other way.)

On the other hand, if the problem is that you do not see any action caused by SIGUSR1 and are wondering if they are really being received, then I would say like previous respondents that it can not be done by using trap in the parent process. You would have to do something inside the Progress process to set that up.

However, if the signal is not reaching the process, one possible cause to look for is whether there is already some startup procedure that is setting this signal up to be ignored, before starting Progress. Also, maybe you could fool the sender of the signal, to send the signal to a wrapper process of your own, where you can trap it, in stead of to the real Progress process. E.g replace the Progress command with a script of your own.

Posted by George Potemkin on 08-Aug-2017 08:57

> Usually in Unix you can use trap to set a signal to be ignored, and then it will continue to be ignored also by the child process (e.g Progress) started from this process.

Example in the starting post shows that it's not true at least on Linux. I started Progress session instead of the second shell (sub-shell). Then I escaped from Progress to Unix and run the trap. It returned nothing while the trap's output in the parent shell (right before launching the Progress session) was not empty.

Posted by ske on 08-Aug-2017 13:59

1. What is not true? Your example doesn't set any signal up to be ignored. To ignore it, you need to set the action to an empty string. Other actions, like the one in the example, will not be inherited by the child.

2. Specifically SIGUSR1 doesn't seem to do much in the shell when not trapped or ignored, when I test it. So when the sub-shell doesn't react to it, that result is consistent with the signal just having been reset to its original state when the sub-shell was started. (That's all the shell can do when starting another program, since the trap procedure can not be inherited.)

Other signals have other defaults or original states.

(E.g SIGHUP will kill the sub-shell, even when trapped in the parent, when I try it.)

If the sub-shell had stopped reacting to a signal that ordinarily would have killed the shell, then one conclusion might have been that perhaps Progress had changed to signal to be ignored.

Or if you try to set a trap procedure in the sub-shell, and that doesn't work (doesn't react to signals sent directly to the sub-shell), then that may be caused by the parent (or earlier) process having set the signal to be ignored before starting the sub-shell.

3. When you start another shell from Progress, that is a another child process, which has no reason to react to any signal sent to the Progress process. So sending signals to Progress, and checking what happens to the sub-shell doesn't say anything about what signal handling Progress is using for itself. I thought you tried to find out how Progress was reacting to the signal? Which process did you send the signal to?

4. When the parent process, e.g sh or Progress, starts a sub-shell, usually they change some of their signal settings for themselves to ignore or wait until the sub-shell returns, in order to protect themselves. This way, for instance, when you press the interrupt or quit key on the keyboard, only the active sub-shell will react to it, not the parent too. (The signal from the keyboard may be sent to all processes running on that terminal.)

So even testing how the parent process reacts while waiting for a sub-shell, is not representative of how they react when actually running alone, either.

5. I don't know what Progress sets all the signals to for the sub-shell when starting one. It could set them any way it likes. But Progress can not make the sub-shell inherit any signal handler that Progress is using internally. That wouldn't make sense, either. So how the subshell reacts to them doesn't say much about how the parent Progress reacts. Probably Progress should be restoring the original state of SIGUSR1 from when Progress was started, like the shell.

6. As an interesting variation of your example, you could also have tested a sub-shell started in the background with "&". In that case, the parent shell will not wait until the sub-shell finishes, before it reacts to signals. (The parent will also set the background shell to ignore SIGINT and SIGQUIT, if job control i not used. This is different than for a foreground sub-shell. The rest of the signals should be the same as when the parent shell started, except ignored signals.) This further illustrates that how the parent process reacts while waiting for a foreground sub-shell is not representative of what it might do in other situations, including when running alone with no sub-shells.

7. (An interactive shell shell also by default ignores SIGTERM, SIGQUIT, and catches SIGINT while running. So testing these signals doesn't say anything about how they were set in the parent, and will not reflect how other signals are handled.)

Is there anything in this that doesn't seem to fit your results?

Maybe I misunderstood your test somehow?

To see what signals actually reach Progress, I would still suggest replacing Progress, with a script of your own. Or use some system tool to track signals, like others suggested. I don't see any other way to check what signals are being sent to Progress (except possibly finding out that they are ignored).

Posted by George Potemkin on 08-Aug-2017 14:16

I'd like to force Progress session to ignore SIGUSR1  (only for the test purposes):

trap "" SIGUSR1
echo Shell PID1=$$
trap
$DLC/bin/_progres -zp

but Progress session is still generating a protrace file after getting the SIGUSR1. Did I miss something?

Posted by ske on 09-Aug-2017 04:20

Forcing a sub-process to ignore a signal like that, even if it was a signal that the sub-process would usually set up its own trap for, would work if the sub-process was sh (or a sh script), because sh doesn't allow setting a trap procedure for a signal that was already ignored when sh was started.

It would also work if the child process never changed the signal for its own purposes. Then it would just remain ignored from the parent.

But not allowing a trap procedure to be set if it was ignored when the process started, is just a rule that sh (most shells) applies for itself (and its scripts). Other commands, like Progress, can change the handling even for a signal that was originally ignored, if they want to. The child process could choose to not change it if it is already ignored, just like sh. But I guess Progress does not choose to do so, and always explicitly sets up a signal handler to produce a protrace file.

I haven't seen any way to tell Progress to ignore (or not handle) any signals. But I don't know all about all versions of Progress in all environments. (But I guess, if there was some way, then someone would have said that by now.)

I noticed that KB article knowledgebase.progress.com/.../P112486 seems to be under the impression that SIGUSR1 actually could be blocked by being trapped in the script that started Progress. (It is mentioned as a precaution, not something they suggest doing.) I think that is an error. I didn't see that in any other KB article, and you already tried it and it didn't work, and I have tried it too and it didn't work.

There are some other KB articles about how Progress reacts to signals, but they don't mention any way to change them:

knowledgebase.progress.com/.../P133912

knowledgebase.progress.com/.../P67938

Posted by George Potemkin on 10-Aug-2017 11:14

> I haven't seen any way to tell Progress to ignore (or not handle) any signals.

I think (based on my tests) that the same is applied for any sub-processes launched by shell. The 'trap' command changes the default actions only for shell itself. It does not change the rules for the shell's sub-processes. If sub-process is a new shell then it can use its own 'trap' command to change the default actions. If sub-process is, for example, a Progress process then it will keep its own actions for any signals - no matter what was set by 'trap' command in the parent shell.

Also it does not matter which trap procedure was specified - to ignore a signal or not.

Posted by ske on 10-Aug-2017 12:57

Agreed.

Except some nit-picks:

> It does not change the rules for the shell's sub-processes.

The command set by "trap" is not inherited, that is right.

If "trap" is used to ignore the signal (trap "" <sig>), though, then that setting IS in general (initially) inherited by the sub-process, and especially by sub-shells. It will still be ignored by the sub-shell. But in general the sub-process can change that, and choose to set their own trap anyway, like you say.

> If sub-process is a new shell then it can use its own 'trap' command to change the default actions.

A special case with the shell (at least all the ones on my system), is that if I ignore (only ignore) a signal in the parent shell, then a sub-shell does NOT allow me to set some other trap for that signal. But that is only a special rule applied by the shell, not other commands like Progress, so it is still of no use to you.

For a demonstration, see the following:

$ trap "" 1

$ echo $$

27770

$ kill -1 27770

$ echo $$

27770

# [Without the trap, it would have died. But now it was ignored.]

$ sh

$ echo $$

27773

$ kill -1 27773

$ echo $$

27773

# [The sub-shell didn't die either, as it would usually have done.]

$ trap "echo SIG 1" 1

$ kill -1 27773

# [No "SIG 1" was printed. The trap didn't have any effect, because it was already ignored.]

Posted by George Potemkin on 11-Aug-2017 05:42

In my tests the "trap" setting is NOT inherited by a sub-process even if "trap" is used to ignore the signal.

# cat /proc/version
Linux version 2.6.32-131.0.15.el6.x86_64

Test:

/bin/sh
trap "" 1
echo Shell PID1=$$
ps -fp $$
trap
 
/bin/sh
echo Shell PID2=$$
ps -fp $$
trap

But if a sub-process is started with the brackets () then the "trap" setting IS fully inherited:

trap "" 1
echo Shell PID1=$$
ps -fp $$
trap
 
(echo Shell PID2=$$
 ps -fp $$
 trap
 sleep 3600
)

BTW, the trap of SIGHUP also traps SIGTERM. It looks like the default action for SIGTERM in the shell is to send SIGHUP to itself.



Posted by ske on 11-Aug-2017 06:50

Interesting.

Which shell is /bin/sh on your Linux system? Different default shells may be linked to /bin/sh on different systems. bash, ksh, bourne shell, others.

I don't think you can always trust "trap" without parameters to list all inherited ignored signals. Different shells list them differently. (E.g my default shell does not list ignored signals in the sub-shell, even though it doesn't die from them.) You may have to actually try to kill it, to see the effect.

The last codeblock of three lines in your post just displays as empty, when i see the post..

Posted by George Potemkin on 11-Aug-2017 07:29

> Which shell is /bin/sh on your Linux system?

/bin/sh -version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

> The last codeblock of three lines in your post just displays as empty, when i see the post..

I did not delete it because the editing of the posts has its own glitches. E.g. one of my posts was hided for moderation after editing.

Posted by ske on 11-Aug-2017 12:53

I can confirm that bash behaves differently (than what I said) for me too.

This was a bit unexpected, because "man bash" clearly states the following things about changing and inheriting ignored signals:

(Far down under the command "trap")
| ... Signals ignored upon entry to the shell cannot be trapped or reset. ...

(Second half of the section COMMAND EXECUTION ENVIRONMENT)
| When a simple command other than a builtin or shell function is to be
| executed, it is invoked in a separate execution environment that consists
| of the following. Unless otherwise noted, the values are inherited from the
| shell.
...
| o      traps caught by the shell are reset to the values inherited from
|         the shell's parent, and traps ignored by the shell are ignored

It seems to me that either bash or its man page are broken/incorrect.
(And have been so for a very long time, many versions back.)

Anyway, it is correct that there is some variation between different shells how they handle inheritance of ignored signals.

I guess some just want to do their own things with many or most of the signals, like Progress, and/or didn't care to follow previous patterns for this from the earliest Unix shells (like Bourne and Korn shell). And I guess original Bourne
is not available in Linux. Availability of Korn shell appears to vary in different Linuxes.

csh & tcsh inherit ignored signals from their parent, but don't have the trap command, for changing them.

You can try some other shells for yourself too, and see what you find in Linux.
Check out /bin/*sh or /usr/bin/*sh.

I see that when POSIX standardized Unix, they did not require their version of the shell to always inherit ignored signals, or prevent a new trap to be set for an inherited ignored signal. Apparently they only require that for non-interactive shells (scripts). But for those, both of these ARE requirements for POSIX-compliant shells. An interactive shell "may" allow changes to ignored signals. (But doesn't have to.) See e.g http://www.unix.com/man-page/POSIX/1posix/trap/ (Of course, all shells don't need to be POSIX compliant.)

So it might be interesting to redo our tests with scripts in stead of interactive shells, to see if they behave differently. When I tried that with a script in bash, it DID ignore my attempt to set a new trap for a signal ignored by the parent shell. When run from an interactive sub-shell of this parent (e.g the same script through the command "source"), it did execute my new trap when signaled.

But I don't think this will be of any help with Progress, still.

This thread is closed