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//------------------------------------------------------------------------------
29void cleanup1(void *arg)
30{
31 tbprint("[thread 0x%llx] Cleanup handler 1\n", arg);
32}
33
34void cleanup2(void *arg)
35{
36 tbprint("[thread 0x%llx] Cleanup handler 2\n", arg);
37}
38
39void cleanup3(void *arg)
40{
41 tbprint("[thread 0x%llx] Cleanup handler 3\n", arg);
42}
43
44//------------------------------------------------------------------------------
45// Thread function
46//------------------------------------------------------------------------------
47void *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//------------------------------------------------------------------------------
82int 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//------------------------------------------------------------------------------
131int 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
145exit:
146 tbthread_finit();
147 return st;
148};
149