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 | |
22 | #define CANCEL_DISABLED 0 |
23 | #define CANCEL_DEFERRED 1 |
24 | #define CANCEL_ASYNC 2 |
25 | |
26 | //------------------------------------------------------------------------------ |
27 | // Cleanup handlers |
28 | //------------------------------------------------------------------------------ |
29 | void cleanup1(void *arg) |
30 | { |
31 | tbprint("[thread 0x%llx] Cleanup handler 1\n" , arg); |
32 | } |
33 | |
34 | void cleanup2(void *arg) |
35 | { |
36 | tbprint("[thread 0x%llx] Cleanup handler 2\n" , arg); |
37 | } |
38 | |
39 | void cleanup3(void *arg) |
40 | { |
41 | tbprint("[thread 0x%llx] Cleanup handler 3\n" , arg); |
42 | } |
43 | |
44 | //------------------------------------------------------------------------------ |
45 | // Thread function |
46 | //------------------------------------------------------------------------------ |
47 | void *thread_func(void *arg) |
48 | { |
49 | tbthread_t self = tbthread_self(); |
50 | int mode = *(int *)arg; |
51 | tbthread_setcancelstate(TBTHREAD_CANCEL_DISABLE, 0); |
52 | tbprint("[thread 0x%llx] Started\n" , self); |
53 | |
54 | tbthread_cleanup_push(cleanup1, self); |
55 | tbthread_cleanup_push(cleanup2, self); |
56 | tbthread_cleanup_push(cleanup3, self); |
57 | |
58 | if(mode == CANCEL_ASYNC) |
59 | tbthread_setcanceltype(TBTHREAD_CANCEL_ASYNCHRONOUS, 0); |
60 | |
61 | if(mode != CANCEL_DISABLED) |
62 | tbthread_setcancelstate(TBTHREAD_CANCEL_ENABLE, 0); |
63 | |
64 | for(int i = 0; i < 5; ++i) { |
65 | if(mode != CANCEL_ASYNC) |
66 | tbprint("[thread 0x%llx] Ping\n" , self); |
67 | tbsleep(1); |
68 | if(mode != CANCEL_ASYNC) |
69 | tbthread_testcancel(); |
70 | } |
71 | tbprint("[thread 0x%llx] Not canceled\n" , self); |
72 | tbthread_cleanup_pop(0); |
73 | tbthread_cleanup_pop(1); |
74 | tbthread_cleanup_pop(0); |
75 | |
76 | return 0; |
77 | } |
78 | |
79 | //------------------------------------------------------------------------------ |
80 | // Run threads in a given mode |
81 | //------------------------------------------------------------------------------ |
82 | int run(int mode, const char *msg) |
83 | { |
84 | tbthread_t thread[5]; |
85 | tbthread_attr_t attr; |
86 | int st = 0; |
87 | |
88 | //---------------------------------------------------------------------------- |
89 | // Spawn the threads |
90 | //---------------------------------------------------------------------------- |
91 | tbprint("[thread main] %s\n" , msg); |
92 | tbthread_attr_init(&attr); |
93 | for(int i = 0; i < 5; ++i) { |
94 | st = tbthread_create(&thread[i], &attr, thread_func, &mode); |
95 | if(st != 0) { |
96 | tbprint("Failed to spawn thread %d: %s\n" , i, tbstrerror(-st)); |
97 | return st; |
98 | } |
99 | } |
100 | |
101 | tbprint("[thread main] Threads spawned successfully\n" ); |
102 | tbsleep(1); |
103 | |
104 | for(int i = 0; i < 5; ++i) { |
105 | tbprint("[thread main] Canceling thread #%d\n" , i); |
106 | tbthread_cancel(thread[i]); |
107 | } |
108 | |
109 | void *ret; |
110 | for(int i = 0; i < 5; ++i) { |
111 | st = tbthread_join(thread[i], &ret); |
112 | if(st != 0) { |
113 | tbprint("Failed to join thread %d: %s\n" , i, tbstrerror(-st)); |
114 | return st; |
115 | } |
116 | |
117 | if(mode != CANCEL_DISABLED && ret != TBTHREAD_CANCELED) { |
118 | tbprint("Thread #%d was not canceled\n" , i); |
119 | return -EFAULT; |
120 | } |
121 | } |
122 | |
123 | tbprint("[thread main] Threads joined\n" ); |
124 | tbprint("---\n" ); |
125 | return 0; |
126 | } |
127 | |
128 | //------------------------------------------------------------------------------ |
129 | // Start the show |
130 | //------------------------------------------------------------------------------ |
131 | int main(int argc, char **argv) |
132 | { |
133 | tbthread_init(); |
134 | int st = 0; |
135 | |
136 | if((st = run(CANCEL_DISABLED, "Test CANCEL_DISABLED" ))) |
137 | goto exit; |
138 | |
139 | if((st = run(CANCEL_DEFERRED, "Test CANCEL_DEFERRED" ))) |
140 | goto exit; |
141 | |
142 | if((st = run(CANCEL_ASYNC, "Test CANCEL_ASYNC" ))) |
143 | goto exit; |
144 | |
145 | exit: |
146 | tbthread_finit(); |
147 | return st; |
148 | }; |
149 | |