I'm trying to write a signal handler which needs to know the pid of the process that sends the signal. I'm having no luck with getting anything useful from the siginfo_t
passed into my handler on macOS 10.14 with Xcode 10.
I've reduced my code to the below minimal sample to demonstrate the issue. In this sample I spawn a child process to send the signal I want to test which is defaulted to SIGTERM
, but no other signal I've tried works any better.
Assuming you want to build and test this on a mac, you probably want to tell lldb to not stop when receiving a signal. You can use this lldb command: pro hand -p true -s false SIGTERM
.
I'm also compiling with C++, but I believe I have excised all of that and the sample code should be pure C now.
Note that it doesn't matter if the signal originates from a child, terminal, or another process the result is always that si_pid
is always 0 (along with everything other than the si_signo
and si_addr
). It doesnt matter how many times I send the signal, so it seems to not be simply a race condition.
How can I get the pid of the process sending the signal on macOS 10.14? I don't recall having this issue on 10.12 which is what I was using before.
This is just a sample to demostrate the problem, so please ignore anything that isn't actually causing a problem.
If the code seems like it should work as I expect, then I would be interested in seeing comments about systems that it works on too.
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
volatile sig_atomic_t histogram[3] = {0,0,0};
volatile sig_atomic_t signaled = 0;
const int testsig = SIGTERM;
void sigaction_handler(int sig, siginfo_t* info, void* context)
{
switch (info->si_pid) {
case 0:
case 1:
histogram[info->si_pid]++;
break;
default:
histogram[2]++;
break;
}
signaled = 1;
}
int main(int argc, const char * argv[]) {
pid_t mainpid = getpid();
pid_t pid = fork();
if (pid == 0) {
while (kill(mainpid, 0) == 0) {
sleep(1);
kill(mainpid, testsig);
}
_exit(0);
}
struct sigaction sigAction;
memset( &sigAction, 0, sizeof( sigAction ) );
sigAction.sa_sigaction = sigaction_handler;
sigemptyset (&sigAction.sa_mask);
sigAction.sa_flags = SA_SIGINFO;
sigaction(testsig, &sigAction, NULL);
while (1) {
if (signaled) {
printf("pid 0: %d, pid 1: %d, others: %d\n", histogram[0], histogram[1], histogram[2]);
signaled = 0;
}
sleep(1);
}
}
I'm currently using macOS Mojave 10.14.1.
The following code meets your wish simply. If you send
SIGTERM
, you can see pid of sender process.For your code,
I'd prefer initialize signal utilities prior forking what if the parent process doesn't have a chance to register signal action? Moreover, I don't understand why you handle
0
and1
cases inswitch
. Intrinsically the cases aren't hit, so always omitted.In addition, you didn't use
break
in yourif
condition withinmain()
. It doesn't go inif
after a while yet the following circumstance which is not anticipated and desirable is that the program stays forever inwhile()
loop. I'd prefer to putsignaled
into condition ofwhile()
loop.At last but not least, due to
sleep()
call in child process untilsignaled
is turned out0
,SIGTERM
is caught several times successfully. When signaled is0
, the loop stops.It turns out that debugging via
XcodeLLDB is the culprit. If I build and run the program normally it works fine. If I find out why I will update this answer.I already have the "PASS" set for SIGTERM in lldb as noted in the question, so it seems like somehow there is a bug in the version of lldb shipped with Xcode 10.0 and it is "passing" the signal by creating a new struct and setting the signal number rather then the structure that would have normally been received. As I stated before this did used to work fine in whatever version of lldb shipped with macos 10.12
If somebody has a better explaination, please post an answer and I will accept and award bounty.