Last active
June 21, 2022 14:12
-
-
Save ysbaddaden/9a484ef55ed451673176a7614207a1c1 to your computer and use it in GitHub Desktop.
Stop the World in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <errno.h> | |
#include <pthread.h> | |
#include <signal.h> | |
#include <stdatomic.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <ucontext.h> | |
#define SIG_SUSPEND SIGUSR1 | |
#define SIG_RESUME SIGUSR2 | |
int running = 1; | |
atomic_int started_threads; | |
atomic_int stopped_threads; | |
void *thread_main(__attribute__((__unused__)) void *data) { | |
printf("starting thread (%lu)\n", pthread_self()); | |
++started_threads; | |
int count; | |
do { | |
++count; | |
} while(running); | |
printf("exiting thread: count=%d (%lu)\n", count, pthread_self()); | |
--started_threads; | |
return NULL; | |
} | |
pthread_t thread_start() { | |
pthread_t tid; | |
int err = pthread_create(&tid, NULL, thread_main, NULL); | |
if (err != 0) { | |
fprintf(stderr, "pthread_create: %s (%d)\n", strerror(err), err); | |
abort(); | |
} | |
return tid; | |
} | |
void thread_suspend(__attribute__((__unused__)) int signal, __attribute__((__unused__)) siginfo_t *info, __attribute__((__unused__)) void *ucontext) { | |
fprintf(stderr, "stopping thread (waiting for RESUME signal) (%lu)\n", pthread_self()); | |
++stopped_threads; | |
sigset_t mask; | |
sigfillset(&mask); | |
sigdelset(&mask, SIG_RESUME); | |
sigsuspend(&mask); | |
fprintf(stderr, "resuming suspended signal handler (%lu)\n", pthread_self()); | |
--stopped_threads; | |
} | |
void thread_resume(__attribute__((__unused__)) int signal, __attribute__((__unused__)) siginfo_t *info, __attribute__((__unused__)) void *ucontext) { | |
fprintf(stderr, "waking up thread (%lu)\n", pthread_self()); | |
} | |
int main() { | |
struct sigaction action; | |
action.sa_handler = NULL; | |
sigemptyset(&action.sa_mask); | |
action.sa_restorer = NULL; | |
action.sa_flags = SA_SIGINFO; | |
action.sa_sigaction = thread_suspend; | |
if (sigaction(SIG_SUSPEND, &action, NULL) < 0) { | |
fprintf(stderr, "sigaction: %s (%d)\n", strerror(errno), errno); | |
abort(); | |
} | |
action.sa_flags = 0; | |
action.sa_sigaction = thread_resume; | |
if (sigaction(SIG_RESUME, &action, NULL) < 0) { | |
fprintf(stderr, "sigaction: %s (%d)\n", strerror(errno), errno); | |
abort(); | |
} | |
fprintf(stderr, "starting threads...\n"); | |
pthread_t t1 = thread_start(); | |
pthread_t t2 = thread_start(); | |
pthread_t t3 = thread_start(); | |
pthread_t t4 = thread_start(); | |
do { | |
usleep(1); | |
} while (started_threads < 4); | |
fprintf(stderr, "started_threads=%d stopped_threads=%d\n", started_threads, stopped_threads); | |
fprintf(stderr, "\nWORLD IS RUNNING!\n"); | |
fprintf(stderr, "\nsuspending threads...\n"); | |
pthread_kill(t1, SIG_SUSPEND); | |
pthread_kill(t2, SIG_SUSPEND); | |
pthread_kill(t3, SIG_SUSPEND); | |
pthread_kill(t4, SIG_SUSPEND); | |
do { | |
usleep(1); | |
} while (stopped_threads < 4); | |
fprintf(stderr, "started_threads=%d stopped_threads=%d\n", started_threads, stopped_threads); | |
fprintf(stderr, "\nWORLD IS STOPPED!\n"); | |
fprintf(stderr, "\nresuming threads...\n"); | |
pthread_kill(t1, SIG_RESUME); | |
pthread_kill(t2, SIG_RESUME); | |
pthread_kill(t3, SIG_RESUME); | |
pthread_kill(t4, SIG_RESUME); | |
do { | |
usleep(1); | |
} while (stopped_threads > 0); | |
fprintf(stderr, "started_threads=%d stopped_threads=%d\n", started_threads, stopped_threads); | |
fprintf(stderr, "\nWORLD IS RUNNING AGAIN!\n"); | |
fprintf(stderr, "\nstopping threads...\n"); | |
running = 0; | |
void *retval; | |
pthread_join(t1, &retval); | |
pthread_join(t2, &retval); | |
pthread_join(t3, &retval); | |
pthread_join(t4, &retval); | |
fprintf(stderr, "started_threads=%d stopped_threads=%d\n", started_threads, stopped_threads); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment