| /* Creates several daemon threads and non-daemon threads. |
| Tests that the process can exit even if the daemon threads are still running, |
| as per thr_create(3C). */ |
| |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <thread.h> |
| #include <unistd.h> |
| |
| #define DAEMON_THREADS 5 |
| #define NON_DAEMON_THREADS 6 |
| #define SLEEP_100_MS usleep(100 * 1000) |
| |
| static pthread_barrier_t barrier; |
| |
| void *daemon_thread_func(void *arg) { |
| size_t index = (size_t) arg; |
| printf("DAEMON thread #%zu running\n", index); fflush(stdout); |
| pthread_barrier_wait(&barrier); |
| |
| /* Give the non-daemon threads enough time to exit. */ |
| sleep(10); |
| printf("DAEMON thread #%zu still running?!\n", index); fflush(stdout); |
| return NULL; |
| } |
| |
| void *normal_thread_func(void *arg) { |
| size_t index = (size_t) arg; |
| printf("non-daemon thread #%zu running\n", index); fflush(stdout); |
| pthread_barrier_wait(&barrier); |
| |
| sleep(2); |
| return NULL; |
| } |
| |
| int main(void) { |
| size_t i; |
| int ret = pthread_barrier_init(&barrier, NULL, |
| DAEMON_THREADS + NON_DAEMON_THREADS + 1); |
| if (ret != 0) { |
| fprintf(stderr, "pthread_barrier_init failed: %s\n", strerror(ret)); |
| return 1; |
| } |
| |
| for (i = 0; i < DAEMON_THREADS; i++) { |
| ret = thr_create(NULL, 0, daemon_thread_func, (void *) i, |
| THR_DAEMON, NULL); |
| if (ret != 0) { |
| fprintf(stderr, "thr_create failed: %s\n", strerror(ret)); |
| return 1; |
| } |
| SLEEP_100_MS; |
| } |
| |
| for (i = 0; i < NON_DAEMON_THREADS; i++) { |
| ret = thr_create(NULL, 0, normal_thread_func, (void *) i, 0, NULL); |
| if (ret != 0) { |
| fprintf(stderr, "thr_create failed: %s\n", strerror(ret)); |
| return 1; |
| } |
| SLEEP_100_MS; |
| } |
| |
| pthread_barrier_wait(&barrier); |
| |
| printf("MAIN thread exiting\n"); |
| /* Exit only the main thread, not whole process. |
| That is, do not exit(0) or return(0). */ |
| thr_exit(NULL); |
| } |