How does the systemd stop command actually work? - systemd

I am using a systemd service which calls a process when it's been "started" (e.g. systemctl start test.service). As per the design, the process stays in a loop forever, we are able to see process existence using the ps command. We have also seen that the process is getting killed (as intended) for systemctl stop command.
However, our requirement is that we want to do some safe shutdown operations from within the process before it gets killed. But I am not sure how to detect a systemd stop operation from within the process.
Does a systemctl stop test.service command send SIGKILL or SIGTERM signal to kill the process? How can I detect a systemctl stop operation from within a process?

By default, a SIGTERM is sent, followed by 90 seconds of waiting followed by a SIGKILL.
Killing processes with systemd is very customizable and well-documented.
I recommend reading all of man systemd.kill as well as reading about ExecStop= in man systemd.service.
To respond to those signals, refer to the signal handling documentation for the language you are using.

Does a systemctl stop test.service command send SIGKILL or SIGTERM signal to kill the
process? How can i detect a systemctl stop operation from within a process?
Systemd sends SIGTERM signal to process. In process you have to register signals, which are "caught".
In process, eg. SIGTERM signal can be registered like this:
void signal_callback()
{
printf("Process is going down\n");
}
signal(SIGTERM, signal_callback)
When SIGTERM is sent to the process, the signal_callback() function is executed.

Related

Killing script with hardware control

I have a script that controls an array of 12v relays depending on certain paramters. For an example: I am monitoring temperatures and pressures. If a temperature exceeds a certain value a relay will be pulled in to open vents and start fans. If the temperature drops to a certain value the relays are released and the vents will close and the fans will stop. Same with the pressures, which will open a solenoid valve and close it again depending on the pressure values.
All works fine and I am happy. The script (bash) is started at boot-up. However, sometimes the script dies mysteriously which leaves the relays in an "active" state.
Is there a way to ensure to reset the relays to "not-active" or "unenergized" when the script dies?
Continuing from my comment, you can trap any of the signals your script can receive (except SIGKILL and SIGSTOP) that are shutting it down and use trap to intercept the signal received and run the required commands to reset the relays to "not-active" or "unenergized" state before the process dies.
Using trap is quite easy. You simply set a trap at the top of your script listing the commands to be executed when a signal is caught. For simply commands you can do
trap 'command1; command2` SIGTERM SIGINT EXIT
to run command1 and command2 on receipt of any of the three listed signals. If you have a series of commands you need to execute, declare a function and then have trap execute the function on signal receipt, e.g.
cleanup () {
# any number of commands to run
}
trap cleanup SIGTERM SIGINT EXIT
See man 7 signals for addition information on standard signals. Consult man bash (or search on "using trap in bash") for additional information on trap.

Background process getting killed when its parent is terminated?

I have code that looks something like this
function doTheThing{
# a potentially infinite while loop...
}
# other stuff...
doTheThing &
trap "kill $!" SIGINT SIGTERM
Strangely, when I ctrl-C out of the parent process before the loop is done, I get a message that the process doesn't exist. Furthermore, if I get rid of the trap, I can't find the process with a ps -aF. It looks like the background process is getting killed when its parent is terminated, but my understanding was that wasn't supposed to happen. I just want to make sure that I can safely leave out the trap and not leave zombie processes everywhere.
The POSIX specification says that when you type the interrupt character (normally Control-C) the SIGINT is sent to the foreground process group. So as long as the background process is running in the same process group as the script that invoked it, it will receive the signal at the same time as the script process.
Shells generally use process groups to implement job control, and by default this is only enabled in interactive shells, not shells running scripts. There's no standard way to run a function in its own process group, but you could use setsid to run it in a new session, which is an even higher level of grouping than process groups. Then it wouldn't receive the interrupt.
You might still want to write a trap command that kills the function on EXIT, though.
doTheThing&
trap "kill $!" EXIT
since exiting the script doesn't automatically kill the rest of the process group.

Send Ctrl-C to app in LLDB

I have an CLI app that is seg faulting during termination (After sending a Ctrl-C)
Pressing Ctrl-C in lldb naturally pauses execution.
Then I try:
(lldb)process signal SIGINT
(lldb)process continue
But that doesn't actually seem to do anything to terminate the app.
Also tried:
(lldb)process signal 2
The debugger uses ^C for interrupting the target, so it assumes that you don't actually want the ^C propagated to the target. You can change this behavior by using the "process handle" command:
(lldb) process handle SIGINT -p true
telling lldb to "pass" SIGINT to the process.
If you had stopped the process in lldb by issuing a ^C, then when you change the process handle as shown here and continue, that SIGINT will be forwarded to the process.
If you stopped for some other reason, after specifying SIGINT to be passed to the process, you can generate a SIGINT by getting the PID of the debugee using the process status and send a SIGINT directly to said process using platform shell:
(lldb) process status
(lldb) platform shell kill -INT {{PID from previous step}}
(lldb) continue
The easiest way I found was just to send the process a SIGINT directly. Take the pid of the debuggee process (which process status will show you) and run
kill -INT <pid>
from another terminal.

bash & linux symbols, Jboss

I'm writing a script to start Jboss, load an application, send requests to the application, shutdown jboss and repeat. However I dont know how to shut Jboss down from the script. At the moment I'm using
pkill -9 java
But I dont think this is right, because it kills the process, not shut it down. Is there a way to shut it down similar to pressing CTRL-C?
You want a simple
pkill java
From the man page:
pkill will send the specified signal (by default SIGTERM) to each
process
SIGTERM will send a termination signal to the process. If the process is well-written, it will catch this signal and perform an orderly shutdown. If that fails, that's when you can use SIGKILL (-9) which is a forceable termination with no chance for the process to catch and perform cleanup.
Never use kill -9 <PID> by default. It breaks things up, like file descriptors and such.
Start to run kill <PID> alone, default is -15 signal.
See
man 7 signal
And In what order should I send signals to gracefully shutdown processes?
NOTE
kill or pkill doesn't change things so much, same signals are trigered
What you actually want is:
pkill -f jboss
using pkill java could kill any other processes using java on the box.

why background process group die when terminal closed

According to this faq (and by many other books):
ftp://rtfm.mit.edu/pub/faqs/unix-faq/programmer/faq
1.15 Why doesn't my process get SIGHUP when its parent dies?
SIGHUP won't be sent to background processes when none of them is " stopped ".
but we all know that if SIGHUP isn't captured in background processes, they will die when you close the terminal(or connection like ssh).
i.e. CTRL+Z - bg isn't enough for a process to survive when terminal is closed.
But why?
Any wisdom is appreciated!
There is an easy solution for it. Use nohup before running the command.
After googling a bit.
I assume the HUP signal which result in exiting of background processes is from shell.
Here are the steps:
Terminal is closed, bash receives SIGHUP from kernel(driver)
Bash exits by default upon receipt of a SIGHUP. Before exiting, it resends the SIGHUP to all jobs, running or stopped
All jobs, including background processes, exit if they don't capture SIGHUP

Resources