2 //Author: Tomas 'Harvie' Mudrunka 2021
3 //Build: CFLAGS=-lpthread make pause; ./pause
4 //Test: valgrind --tool=helgrind ./pause
6 //I've wrote this code as excercise to solve following stack overflow question:
7 // https://stackoverflow.com/questions/9397068/how-to-pause-a-pthread-any-time-i-want/68119116#68119116
11 //#include <pthread_extra.h>
17 #include <sys/resource.h>
19 #define PTHREAD_XSIG_STOP (SIGRTMIN+0)
20 #define PTHREAD_XSIG_CONT (SIGRTMIN+1)
21 #define PTHREAD_XSIGRTMIN (SIGRTMIN+2) //First unused RT signal
23 void pthread_pause_handler(int signal
) {
24 //Do nothing when there are more signals pending (to cleanup the queue)
27 if(sigismember(&pending
, PTHREAD_XSIG_STOP
)) return;
28 if(sigismember(&pending
, PTHREAD_XSIG_CONT
)) return;
30 if(signal
== PTHREAD_XSIG_STOP
) {
33 sigdelset(&sigset
, PTHREAD_XSIG_STOP
);
34 sigdelset(&sigset
, PTHREAD_XSIG_CONT
);
35 sigsuspend(&sigset
); //Wait for next signal
39 void pthread_pause_enable() {
40 //Having signal queue too deep might not be necessary
41 //It can be limited using RLIMIT_SIGPENDING
42 //You can get runtime SigQ stats using following command:
43 //grep -i sig /proc/$(pgrep binary)/status
44 struct rlimit sigq
= {.rlim_cur
= 32, .rlim_max
=32};
45 setrlimit(RLIMIT_SIGPENDING
, &sigq
);
47 //Register signal handlers
48 signal(PTHREAD_XSIG_STOP
, pthread_pause_handler
);
49 signal(PTHREAD_XSIG_CONT
, pthread_pause_handler
);
54 sigaddset(&sigset
, PTHREAD_XSIG_STOP
);
55 sigaddset(&sigset
, PTHREAD_XSIG_CONT
);
56 pthread_sigmask(SIG_UNBLOCK
, &sigset
, NULL
);
59 void pthread_pause_disable() {
60 //This is important for when you want to do some signal unsafe stuff
61 //Eg.: locking mutex, calling printf() which has internal mutex, etc...
62 //After unlocking mutex, you can enable pause again.
67 sigaddset(&sigset
, PTHREAD_XSIG_STOP
);
68 sigaddset(&sigset
, PTHREAD_XSIG_CONT
);
69 pthread_sigmask(SIG_BLOCK
, &sigset
, NULL
);
73 int pthread_pause(pthread_t thread
) {
74 //If signal queue is full, we keep retrying
75 while(pthread_kill(thread
, PTHREAD_XSIG_STOP
) == EAGAIN
) usleep(1000);
79 int pthread_unpause(pthread_t thread
) {
80 //If signal queue is full, we keep retrying
81 while(pthread_kill(thread
, PTHREAD_XSIG_CONT
) == EAGAIN
) usleep(1000);
86 //Whole process dies if you kill thread immediately before it is pausable
87 //pthread_pause_enable();
90 //Printf() is not async signal safe (because it holds internal mutex),
91 //you should call it only with pause disabled!
92 //Will throw helgrind warnings anyway, not sure why...
93 //See: man 7 signal-safety
94 pthread_pause_disable();
96 pthread_pause_enable();
102 pthread_pause_enable(); //Will get inherited by all threads from now on
103 //you need to call pthread_pause_enable (or disable) before creating threads,
104 //otherwise first signal will kill whole process
105 pthread_create(&t
, NULL
, thread_test
, NULL
);
112 printf("UNPAUSED\n");
117 pthread_join(t
, NULL
);
This page took 0.342984 seconds and 4 git commands to generate.