threadkey.c raw
1
2 #ifdef HAVE_CONFIG_H
3 # include "config.h"
4 #endif
5
6 #ifndef GC_THREADS
7 # define GC_THREADS
8 #endif
9
10 #define GC_NO_THREAD_REDIRECTS 1
11
12 #include "gc.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16
17 #if (!defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
18 || defined(__native_client__)) \
19 && !defined(SKIP_THREADKEY_TEST)
20 /*
21 * FIXME: Skip this test on Solaris for now. The test may fail on other
22 * targets as well. Currently, tested only on Linux, Cygwin and Darwin.
23 */
24 # define SKIP_THREADKEY_TEST
25 #endif
26
27 #ifdef SKIP_THREADKEY_TEST
28
29 int
30 main(void)
31 {
32 printf("test skipped\n");
33 return 0;
34 }
35
36 #else
37
38 # include <errno.h> /*< for `EAGAIN` */
39 # include <pthread.h>
40
41 pthread_key_t key;
42
43 /* TODO: Use `pthread_once_t` on Solaris. */
44 pthread_once_t key_once = PTHREAD_ONCE_INIT;
45
46 static void *
47 entry(void *arg)
48 {
49 pthread_setspecific(key,
50 (void *)GC_HIDE_NZ_POINTER(GC_STRDUP("hello, world")));
51 return arg;
52 }
53
54 static void *GC_CALLBACK
55 on_thread_exit_inner(struct GC_stack_base *sb, void *arg)
56 {
57 int res = GC_register_my_thread(sb);
58 pthread_t t;
59 int creation_res; /*< to suppress a warning about unchecked result */
60 pthread_attr_t attr;
61
62 if (pthread_attr_init(&attr) != 0
63 || pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) {
64 fprintf(stderr, "Thread attribute init or setdetachstate failed\n");
65 exit(2);
66 }
67 creation_res = GC_pthread_create(&t, &attr, entry, NULL);
68 (void)pthread_attr_destroy(&attr);
69 if (res == GC_SUCCESS)
70 GC_unregister_my_thread();
71
72 # if defined(CPPCHECK)
73 GC_noop1_ptr(sb);
74 GC_noop1_ptr(arg);
75 # endif
76 return arg ? (void *)(GC_uintptr_t)creation_res : 0;
77 }
78
79 static void
80 on_thread_exit(void *v)
81 {
82 (void)GC_call_with_stack_base(on_thread_exit_inner, v);
83 }
84
85 static void
86 make_key(void)
87 {
88 pthread_key_create(&key, on_thread_exit);
89 }
90
91 # ifndef NTHREADS
92 # define NTHREADS 5
93 # endif
94
95 /* Number of threads to create. */
96 # define NTHREADS_INNER (NTHREADS * 6)
97
98 int
99 main(void)
100 {
101 int i;
102
103 GC_INIT();
104 if (GC_get_find_leak())
105 printf("This test program is not designed for leak detection mode\n");
106 /* TODO: Call `make_key()` instead on Solaris. */
107 pthread_once(&key_once, make_key);
108
109 for (i = 0; i < NTHREADS_INNER; i++) {
110 pthread_t t;
111 void *res;
112 int err = GC_pthread_create(&t, NULL, entry, NULL);
113
114 if (err != 0) {
115 fprintf(stderr, "Thread #%d creation failed, errno= %d\n", i, err);
116 if (i > 0 && EAGAIN == err)
117 break;
118 exit(2);
119 }
120
121 if ((i & 1) != 0) {
122 err = GC_pthread_join(t, &res);
123 if (err != 0) {
124 fprintf(stderr, "Thread #%d join failed, errno= %d\n", i, err);
125 exit(2);
126 }
127 } else {
128 err = GC_pthread_detach(t);
129 if (err != 0) {
130 fprintf(stderr, "Thread #%d detach failed, errno= %d\n", i, err);
131 exit(2);
132 }
133 }
134 }
135 printf("SUCCEEDED\n");
136 return 0;
137 }
138
139 #endif /* !SKIP_THREADKEY_TEST */
140