#include #include #include #include #include #include #include #include #include enum events{ EVENT_VICTIM_THREAD_READY, EVENT_PRINT_BUFFER_UPDATED, EVENTS_NR }; enum threads_roles { ROLE_VICTIM, ROLE_KILLER, ROLE_PRINTER, ROLES_NR }; #define ERR_PTR(ret) ((void*)(long)ret) #define PRINTER_TIMEOUT_SECS 2 #define PRINT_BUFF_SIZE 256 static sem_t sems[EVENTS_NR]; static pthread_t threads[ROLES_NR]; static char print_buffer[PRINT_BUFF_SIZE]; static volatile bool run = true; void sig_handler(int signal) { snprintf(print_buffer, PRINT_BUFF_SIZE, "signal %d recieved", signal); pthread_exit(ERR_PTR(sem_post(&sems[EVENT_PRINT_BUFFER_UPDATED]))); } void *killer_thread(void* _) { sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGUSR1); if (pthread_sigmask(SIG_BLOCK, &ss, NULL)) pthread_exit(ERR_PTR(-EFAULT)); int ret = sem_wait(&sems[EVENT_VICTIM_THREAD_READY]); if (ret) pthread_exit(ERR_PTR(ret)); pthread_exit(ERR_PTR(pthread_kill(threads[ROLE_VICTIM], SIGUSR1))); } void *victim_thread(void* _) { int ret = sem_post(&sems[EVENT_VICTIM_THREAD_READY]); if (ret) pthread_exit(ERR_PTR(ret)); volatile int x = 0; // for compiler not to optimize infinite loop while (run) { x++; } pthread_exit(NULL); } void *printer_thread(void* _) { sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGUSR1); if (pthread_sigmask(SIG_BLOCK, &ss, NULL)) pthread_exit(ERR_PTR(-EFAULT)); while (run) { struct timespec ts = {0}; int ret = timespec_get(&ts, TIME_UTC); if (ret != TIME_UTC) pthread_exit(ERR_PTR(-EFAULT)); ts.tv_sec += PRINTER_TIMEOUT_SECS; if (sem_timedwait(&sems[EVENT_PRINT_BUFFER_UPDATED], &ts)) pthread_exit(ERR_PTR(-EFAULT)); puts(print_buffer); memset(print_buffer, 0, PRINT_BUFF_SIZE); } pthread_exit(NULL); } #define DO_OR_FAIL(cond) if (cond) return EXIT_FAILURE int main() { struct sigaction sa = { .sa_handler = sig_handler, }; DO_OR_FAIL(sigaction(SIGUSR1, &sa, NULL)); DO_OR_FAIL(sem_init(&sems[EVENT_VICTIM_THREAD_READY], 0, 0)); DO_OR_FAIL(sem_init(&sems[EVENT_PRINT_BUFFER_UPDATED], 0, 0)); DO_OR_FAIL(pthread_create(&threads[ROLE_KILLER], NULL, killer_thread, NULL)); DO_OR_FAIL(pthread_create(&threads[ROLE_PRINTER], NULL, printer_thread, NULL)); DO_OR_FAIL(pthread_create(&threads[ROLE_VICTIM], NULL, victim_thread, NULL)); for (size_t i = 0; i < ROLES_NR; i++) { DO_OR_FAIL(pthread_join(threads[i], NULL)); } return EXIT_SUCCESS; }