Why is Linux signal always handled by main thread? - linux

I use pthread_create to get 2 threads and register the signal handler in both created thread.
In main thread, the signal handler is not set.
#include <signal.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
void sig_hand(int no) //signal handler
{
printf("handler executing...\n");
printf("%d\n", pthread_self());
pthread_exit(NULL);
}
void* thread1(void *arg1) //thread1
{
signal(SIGINT, sig_hand);
printf("%d\n", pthread_self());
}
void * thread2(void * arg2) //thread2
{
signal(SIGINT , sig_hand);
printf("%d\n", pthread_self());
}
int main()
{
pthread_t t1;
pthread_t t2;
sigset_t newmask;
sigaddset(&newmask, SIGINT);
// set sigproc, SIGINT can be received;
// sigproc not set, SIGINT can't be received
if(sigprocmask(SIG_BLOCK, &newmask, NULL) < 0){
perror("sigprocmask error");
}
printf("main thread %d\n", pthread_self());
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
while(1);
}
If I don't set sigprocmask in main thread, SIGINT can be received, but it is handled by the main thread while main thread doesn't register handler function.
main thread -1335200000
-1343535360
-1351928064
^Cpthread -1335200000 handler executing...
However if sigprocmask is set in the main thread, SIGINT can't be received while two child threads have registerd handler function.
main thread 2061661952
2053326592
2044933888
^C^C
This is very confusing.

Related

Pause thread execution without using condition variable or other various synchronization pritmives

Problem
I wish to be able to pause the execution of a thread from a different thread. Note the thread paused should not have to cooperate. The pausing of the target thread does not have to occur as soon as the pauser thread wants to pause. Delaying the pausing is allowed.
I cannot seem to find any information on this, as all searches yielded me results that use condition variables...
Ideas
use the scheduler and kernel syscalls to stop the thread from being scheduled again
use debugger syscalls to stop the target thread
OS-agnostic is preferable, but not a requirement. This likely will be very OS-dependent, as messing with scheduling and threads is a pretty low-level operation.
On a Unix-like OS, there's pthread_kill() which delivers a signal to a specified thread. You can arrange for that signal to have a handler which waits until told in some manner to resume.
Here's a simple example, where the "pause" just sleeps for a fixed time before resuming. Try on godbolt.
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
void safe_print(const char *s) {
int saved_errno = errno;
if (write(1, s, strlen(s)) < 0) {
exit(1);
}
errno = saved_errno;
}
void sleep_msec(int msec) {
struct timespec t = {
.tv_sec = msec / 1000,
.tv_nsec = (msec % 1000) * 1000 * 1000
};
nanosleep(&t, NULL);
}
void *work(void *unused) {
(void) unused;
for (;;) {
safe_print("I am running!\n");
sleep_msec(100);
}
return NULL;
}
void handler(int sig) {
(void) sig;
safe_print("I am stopped.\n");
sleep_msec(500);
}
int main(void) {
pthread_t thr;
pthread_create(&thr, NULL, work, NULL);
sigset_t empty;
sigemptyset(&empty);
struct sigaction sa = {
.sa_handler = handler,
.sa_flags = 0,
};
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
for (int i = 0; i < 5; i++) {
sleep_msec(1000);
pthread_kill(thr, SIGUSR1);
}
pthread_cancel(thr);
pthread_join(thr, NULL);
return 0;
}

Sigaction doesnt work

I am learning about signals and wrote a simple programs that plays with them.
So i am inputting a number then using fork i create a process.The parent process is supposed to send the number as a signal to the child process,then the child_signal handler is supposed to send back the number squared as a signal.
This is the code.
#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
using namespace std;
void child_handler(int sig_num){
cout<<"Child recieved a signal"<<endl;
pid_t ppid = getppid();
if(kill(ppid,sig_num*sig_num) == -1){
cout<<"Childs signal handler failed to send a signal "<<endl;
}
cout<<"Sent a sgnal to the parent"<<endl;
return;
}
void parent_handler(int sig_num){
cout<<"Parent recieved a signal "<<endl;
cout<<sig_num<<endl;
return;
}
int main(){
int n;
cin>>n;
pid_t pid = fork();
if(pid != 0){
struct sigaction sa2;
memset(&sa2,0,sizeof(sa2));
sa2.sa_handler = parent_handler;
if(sigaction(n,&sa2,NULL) == -1){
cout<<"Parents sigaction failed "<<endl;
}
if(kill(pid,n) == -1){
cout<<"Kill failed "<<endl;
}
cout<<"Sent a signal to the child"<<endl;
waitpid(pid,0,0);
}
else{
struct sigaction sa1;
memset(&sa1,0,sizeof(sa1));
sa1.sa_handler = child_handler;
if(sigaction(n,&sa1,NULL) == -1){
cout<<"Childs sigaction failed eerno:"<<errno<<endl;
}
sleep(20);
return 0;
}
return 0;
}
The output is this.
Sent a signal to the child.
And it doesn't say anything about sigaction.
In your code a child process can receive a signal before setting a handler.

Ptrace prevents signal from interrupting pselect() in traced process

I'm trying to monitor syscalls for a binary using ptrace. The binary sleeps in pselect() and without ptrace, a SIGQUIT makes it return from pselect. The mask of blocked signals passed to pselect includes SIGQUIT.
When executed with ptrace, it exits from sys_pselect6 but not all the way out of glibc's pselect. What am I doing that prevents sys_pselect6 from exiting out to user code ?
Tracer:
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <err.h>
#include <wait.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int pid = fork(), sys_in = 1, status;
if (pid == 0) {
if (ptrace(PTRACE_TRACEME, getppid(), NULL, NULL) < 0)
err(1, "TRACEME()");
execl("./child", "./child", NULL);
err(1, "execl()");
}
if (waitpid(pid, &status, 0) != pid) err(1, "wait()");
for (;; sys_in ^= 1) {
if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) < 0) err(1, "SYSCALL");
if (waitpid(pid, &status, 0) != pid) err(1, "wait()");
if (sys_in) {
long long sys_no = ptrace(PTRACE_PEEKUSER, pid, 8 * ORIG_RAX, NULL);
printf("syscall entry %lld\n", sys_no);
}
else printf("syscall exit\n");
}
return 0;
}
Child:
#include <stdio.h>
#include <sys/select.h>
#include <signal.h>
#include <err.h>
void handle_sigquit(int sig, siginfo_t* info, void *ctx)
{
}
int main()
{
sigset_t mask;
sigset_t orig_mask;
struct sigaction sa = {};
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handle_sigquit;
sigaction(SIGQUIT, &sa, NULL);
sigemptyset(&mask);
sigaddset(&mask, SIGQUIT);
if (sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0) err(1, "sigprocmask()");
pselect(0, NULL, NULL, NULL, NULL, &orig_mask);
warn("pselect()");
return 0;
}
ptrace(PTRACE_SYSCALL, pid, NULL, NULL)
Whenever your debugger gets a notification, you just assume that that notification is about a system call, and handle it accordingly. That is not the case.
Some of the notifications you receive using wait are for signals that your debugee has received. When those happen, the last NULL in your PTRACE_SYSCALL call eliminates, effectively masks, the signal from arriving at the debugee process.
When processing ptrace results, you need to check the signal that caused your debugger to wake up. At the very least, check if it's a SIGTRAP or something else. If it is something else, the best bet is to pass it on to the debugee process.
Check out this small program to see a simple way of doing it.

sending signal to a blocked thread with a timer

I am running two processes (Process A and B) on the same core. Process B is multithreaded in which one thread is sending Signal to the next thread to wake it and start its work. At a time, only one thread of process B can run on the common core.
**//Process A**
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
int main(int argc, char const *argv[])
{
struct timeval tval_result;
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(2, &my_set);
sched_setaffinity(0, sizeof(cpu_set_t), &my_set);
long int loopNum;
while(1)
{
gettimeofday(&tval_result, NULL);
printf("Dummy Time elapsed: %ld.%06ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec);
//for(loopNum = 1; loopNum <= 100000; loopNum++);
//printf("Dummy!!! # \n");
}
return 0;
}
Following is the code of Process B.
//Import
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#define NUM_THREADS 100
//global variables
pthread_cond_t condA[NUM_THREADS+1] = PTHREAD_COND_INITIALIZER;
pthread_cond_t condB = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_t tid[NUM_THREADS];
int state = 0;
void *threadA(void *data_)
{
int i = 0, rValue;
long int loopNum;
int turn = (intptr_t)data_;
struct timeval tval_result;
while(1)
{
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(2, &my_set);
sched_setaffinity(0, sizeof(cpu_set_t), &my_set);
/* Wait for state A */
pthread_mutex_lock(&mutex);
// while (state != STATE_A)
if(state != turn)
{
pthread_cond_wait(&condA[turn], &mutex);
}
pthread_mutex_unlock(&mutex);
//do stuff
gettimeofday(&tval_result, NULL);
printf("Time elapsed: %ld.%06ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec);
//for(loopNum = 1; loopNum <= 10000000000; loopNum++);
//printf("Hello Thread # %d\n", turn);
/* Set state TRUE for next thread */
pthread_mutex_lock(&mutex);
state = (state +1)%NUM_THREADS;
pthread_cond_signal(&condA[state]);
pthread_mutex_unlock(&mutex);
}
}
int main(int argc, char *argv[])
{
int data = 0;
int err;
while(data < NUM_THREADS)
{
//create our threads
err = pthread_create(&tid[data], NULL, threadA, (void *)(intptr_t)data);
if(err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
else
printf("\n Thread created successfully\n");
data++;
}
pthread_exit(NULL);
}
I want to interleave the execution of process B in between threads of Process A for a very short duration (less than 1 microseconds). So, when thread i of process B finishes its work it'll send the signal to the next thread i+1 and in between, I want process A to come. This should be repeated for the rest of the course of execution.
When I am running above programs, process A is not able to come in between threads of the Process B. Is there any mechanism by which I can send signal with some timer so that signal does not reach the next thread immediately (and hence Process A comes for some time between two consecutive threads.)
There's no way you can force the Linux scheduler at that level.
You'll have to "signal" process A and then let it "signal" the other B thread.
But to "signal" may be a user space mechanism like spinning on a variable in shared memory.
I'd suggest you first try it with normal signals (going through the kernel) and see is the latency good enough. Only if it's too long, go play with spinning in user space.
Don't expect all that to work always under 1us. You'll probably get lots of jitter will have to move processes away from that core to reduce it, regardless of spinning or using kernel signalling.
For kernel signalling you may also use sockets, pipes, futexes,...
Now my question is, if you're running all that on one core, as you said, why not run it as a single thread - Just have one thread call B1, then A, then B2?

How to read the valgrind return value from child processes?

i am running valgrind in a bash script to use it for automated testing. I already added the option to return an exit code on error and to trace children.
/usr/bin/valgrind --error-exitcode=1 --trace-children=yes ./test_prog
My programm forks other processes and I can see the output of valgrind running the different processes in the terminal. The problem is, that the exit code option only seems to work when there is an error in the parent process. Because even though there is an error (SIGSEGV) in one of the child processes the exit code of valgrind is still 0, which means it is useless for the automated testing of several processes.
So is there any option, that would make the parent valgrind catch the error in the child and return it? I already looked into the man page. Maybe there would be another solution to this problem, like grepping the output of the children to the terminal for any error messages?
Thanks in advance.
it's important to implement a proper error handling in the code. Compare following two pieces of code.
A:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#define BUFSIZE 1024
int incr=0;
int loop=1;
void runTicks(const char *n) {
time_t t;
char buf[BUFSIZE+1];
pid_t pid;
int counter;
pid=getpid();
counter=0;
while(loop) {
sleep(1);
t=time(NULL);
strftime(buf,BUFSIZE,"%Y.%m.%d %H:%M:%S",localtime(&t));
printf("%s[%d] %s\n",n,pid,buf);
counter+=incr;
if(counter>5) memcpy((void *)1,buf,1); /* this line is for causing SEGV */
}
}
void handler(int s) {
if(s==SIGCHLD) {
printf("Received SIGCHLD\n");
loop=0;
}
}
void setHandler() {
struct sigaction sa;
sa.sa_handler=handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags=SA_NOCLDSTOP;
if(sigaction(SIGCHLD,&sa,NULL)!=0) {
printf("Cannot set signal handler, there is no purpose in running the test\n");
exit(0);
}
}
int main() {
pid_t pid;
printf("start\n");
pid=fork();
if(pid==-1) {
printf("fork failed\n");
exit(10);
}
if(pid==0) {
printf("child\n");
incr=1;
usleep(500000);
runTicks("C");
exit(1);
} else {
printf("parent spawned child pid=%d\n",pid);
setHandler();
runTicks("P");
exit(0);
}
}
B:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#define BUFSIZE 1024
int incr=0;
int loop=1;
void runTicks(const char *n) {
time_t t;
char buf[BUFSIZE+1];
pid_t pid;
int counter;
pid=getpid();
counter=0;
while(loop) {
sleep(1);
t=time(NULL);
strftime(buf,BUFSIZE,"%Y.%m.%d %H:%M:%S",localtime(&t));
printf("%s[%d] %s\n",n,pid,buf);
counter+=incr;
if(counter>5) memcpy((void *)1,buf,1); /* this line is for causing SEGV */
}
}
void handler(int s) {
if(s==SIGCHLD) {
int status;
printf("Received SIGCHLD\n");
wait(&status);
printf("Exit code from child: %d\n",status);
if(status!=0) exit(status);
loop=0;
}
}
void setHandler() {
struct sigaction sa;
sa.sa_handler=handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags=SA_NOCLDSTOP;
if(sigaction(SIGCHLD,&sa,NULL)!=0) {
printf("Cannot set signal handler, there is no purpose in running the test\n");
exit(0);
}
}
int main() {
pid_t pid;
printf("start\n");
pid=fork();
if(pid==-1) {
printf("fork failed\n");
exit(10);
}
if(pid==0) {
printf("child\n");
incr=1;
usleep(500000);
runTicks("C");
exit(1);
} else {
printf("parent spawned child pid=%d\n",pid);
setHandler();
runTicks("P");
exit(0);
}
}
Run those first without valgrind and compare the exit code of both programs. Then run them under valgrind and enjoy.
Using such construction you even don't need to run it under valgrind, to catch segfaults from child processes.

Resources