1 | //------------------------------------------------------------------------------ |
2 | // Copyright (c) 2016 by Lukasz Janyst <lukasz@jany.st> |
3 | //------------------------------------------------------------------------------ |
4 | // This file is part of thread-bites. |
5 | // |
6 | // thread-bites is free software: you can redistribute it and/or modify |
7 | // it under the terms of the GNU General Public License as published by |
8 | // the Free Software Foundation, either version 3 of the License, or |
9 | // (at your option) any later version. |
10 | // |
11 | // thread-bites is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | // |
16 | // You should have received a copy of the GNU General Public License |
17 | // along with thread-bites. If not, see <http://www.gnu.org/licenses/>. |
18 | //------------------------------------------------------------------------------ |
19 | |
20 | #include <tb.h> |
21 | #include <string.h> |
22 | |
23 | //------------------------------------------------------------------------------ |
24 | // TLS keys |
25 | //------------------------------------------------------------------------------ |
26 | tbthread_key_t key1; |
27 | tbthread_key_t key2; |
28 | tbthread_key_t key3; |
29 | |
30 | //------------------------------------------------------------------------------ |
31 | // TLS destructors |
32 | //------------------------------------------------------------------------------ |
33 | void dest1(void *data) |
34 | { |
35 | tbprint("[thread 0x%llx] Error: calling dest1\n" , tbthread_self()); |
36 | } |
37 | |
38 | void dest2(void *data) |
39 | { |
40 | tbprint("[thread 0x%llx] Error: calling dest2\n" , tbthread_self()); |
41 | } |
42 | |
43 | void dest3(void *data) |
44 | { |
45 | tbprint("[thread 0x%llx] Calling dest3\n" , tbthread_self()); |
46 | free(data); |
47 | } |
48 | |
49 | //------------------------------------------------------------------------------ |
50 | // Thread function |
51 | //------------------------------------------------------------------------------ |
52 | void *thread_func(void *arg) |
53 | { |
54 | int num = *(int*)arg; |
55 | int i; |
56 | tbthread_t self = tbthread_self(); |
57 | tbprint("[thread 0x%llx] Hello from thread #%d\n" , self, num); |
58 | tbprint("[thread 0x%llx] Allocating the TLS data\n" , self); |
59 | void *data1 = malloc(20); |
60 | void *data2 = malloc(20); |
61 | void *data3 = malloc(20); |
62 | tbthread_setspecific(key1, data1); |
63 | tbthread_setspecific(key2, data2); |
64 | tbthread_setspecific(key3, data3); |
65 | |
66 | tbprint("[thread 0x%llx] Sleeping 3 seconds\n" , self); |
67 | tbsleep(3); |
68 | void *data1r = tbthread_getspecific(key1); |
69 | void *data2r = tbthread_getspecific(key2); |
70 | void *data3r = tbthread_getspecific(key3); |
71 | if(data1r != data1) |
72 | tbprint("[thread 0x%llx] Error: datar != data\n" , self); |
73 | if(data2r != 0) |
74 | tbprint("[thread 0x%llx] Error: data2r != 0\n" , self); |
75 | if(data3r != data3) |
76 | tbprint("[thread 0x%llx] Error: data3r != data3\n" , self); |
77 | free(data2); |
78 | free(data1); |
79 | tbthread_setspecific(key1, 0); |
80 | tbprint("[thread 0x%llx] Sleeping 1 second\n" , self); |
81 | tbsleep(1); |
82 | return 0; |
83 | } |
84 | |
85 | //------------------------------------------------------------------------------ |
86 | // Start the show |
87 | //------------------------------------------------------------------------------ |
88 | int main(int argc, char **argv) |
89 | { |
90 | tbthread_init(); |
91 | |
92 | tbthread_t thread[5]; |
93 | int targ[5]; |
94 | tbthread_attr_t attr; |
95 | void *ret; |
96 | int st = 0; |
97 | |
98 | //---------------------------------------------------------------------------- |
99 | // Allocate the keys |
100 | //---------------------------------------------------------------------------- |
101 | tbthread_key_create(&key1, dest1); |
102 | tbthread_key_create(&key2, dest2); |
103 | tbthread_key_create(&key3, dest3); |
104 | tbthread_key_delete(key1); |
105 | tbthread_key_delete(key3); |
106 | tbthread_key_create(&key3, dest3); |
107 | tbthread_key_create(&key1, dest1); |
108 | tbprint("[thread main] TLS keys: %u, %u, %u\n" , key1, key2, key3); |
109 | |
110 | //---------------------------------------------------------------------------- |
111 | // Spawn the threads |
112 | //---------------------------------------------------------------------------- |
113 | tbthread_attr_init(&attr); |
114 | for(int i = 0; i < 5; ++i) { |
115 | targ[i] = i; |
116 | st = tbthread_create(&thread[i], &attr, thread_func, &targ[i]); |
117 | if(st != 0) { |
118 | tbprint("Failed to spawn thread %d: %s\n" , i, strerror(-st)); |
119 | goto exit; |
120 | } |
121 | tbthread_detach(thread[i]); |
122 | } |
123 | |
124 | tbprint("[thread main] Threads spawned successfully\n" ); |
125 | tbprint("[thread main] Sleeping 1 second\n" ); |
126 | tbsleep(1); |
127 | tbprint("[thread main] Destroying key2\n" ); |
128 | tbthread_key_delete(key2); |
129 | tbprint("[thread main] Sleeping 10 seconds\n" ); |
130 | tbsleep(10); |
131 | |
132 | exit: |
133 | tbthread_finit(); |
134 | return st; |
135 | }; |
136 | |