additional Andrew provided Termux mods +
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / thread.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program 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 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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 this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcsignals.h"
23 #include <sys/wait.h>
24 #include <sched.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <typeinfo>
30 #include "thread.h"
31 #if defined(__TERMUX__)
32 #include "bthread.h"
33 #endif
34
35
36 Thread::Thread(int synchronous, int realtime, int autodelete)
37 {
38         this->synchronous = synchronous != 0;
39         this->realtime = realtime != 0;
40         this->autodelete = autodelete != 0;
41         tid = (pthread_t)-1;
42         finished = false;
43         cancelled = false;
44         cancel_enabled = false;
45 }
46
47 Thread::~Thread()
48 {
49 }
50
51 void* Thread::entrypoint(void *parameters)
52 {
53         Thread *thread = (Thread*)parameters;
54
55 // allow thread to be cancelled at any point during a region where it is enabled.
56         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
57 // Disable cancellation by default.
58         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
59         thread->cancel_enabled = false;
60
61 // Set realtime here since it doesn't work in start
62         if( thread->realtime && getuid() == 0 ) {
63                 struct sched_param param = { sched_priority : 1 };
64                 if(pthread_setschedparam(thread->tid, SCHED_RR, &param) < 0)
65                         perror("Thread::entrypoint pthread_attr_setschedpolicy");
66         }
67
68         thread->run();
69         thread->finished = true;
70         if( !thread->synchronous ) {
71                 if( thread->autodelete ) delete thread;
72                 else if( !thread->cancelled ) TheList::dbg_del(thread->tid);
73                 else thread->tid = ((pthread_t)-1);
74         }
75         return NULL;
76 }
77
78 void Thread::start()
79 {
80         pthread_attr_t  attr;
81         struct sched_param param;
82
83         pthread_attr_init(&attr);
84
85 // previously run, and did not join, join to clean up zombie
86         if( synchronous && exists() )
87                 join();
88
89         finished = false;
90         cancelled = false;
91         owner = get_self();
92
93 // Inherit realtime from current thread the easy way.
94         if( !realtime )
95                 realtime = calculate_realtime();
96
97         if( !synchronous )
98                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
99
100         if( realtime && getuid() == 0 ) {
101                 if(pthread_attr_setschedpolicy(&attr, SCHED_RR) < 0)
102                         perror("Thread::start pthread_attr_setschedpolicy");
103                 param.sched_priority = 50;
104                 if(pthread_attr_setschedparam(&attr, &param) < 0)
105                         perror("Thread::start pthread_attr_setschedparam");
106         }
107         else {
108 #if !defined(__TERMUX__)
109                 if(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED) < 0)
110                         perror("Thread::start pthread_attr_setinheritsched");
111 #endif
112         }
113
114 // autodelete may delete this immediately after create
115         int autodelete = this->autodelete;
116
117         pthread_create(&tid, &attr, Thread::entrypoint, this);
118
119         if( !autodelete )
120                 TheList::dbg_add(tid, owner, typeid(*this).name());
121 }
122
123 int Thread::cancel()
124 {
125         if( exists() && !cancelled ) {
126                 LOCK_LOCKS("Thread::cancel");
127                 pthread_cancel(tid);
128                 cancelled = true;
129                 if( !synchronous ) TheList::dbg_del(tid);
130                 UNLOCK_LOCKS;
131         }
132         return 0;
133 }
134
135 int Thread::join()   // join this thread
136 {
137         if( !exists() ) return 0;
138         if( synchronous ) {
139 // NOTE: this fails if the thread is not synchronous or
140 //  or another thread is already waiting to join.
141                 int ret = pthread_join(tid, 0);
142                 if( ret ) {
143                         fflush(stdout);
144                         fprintf(stderr, "Thread %p: %s\n", (void*)tid, strerror(ret));
145                         fflush(stderr);
146                 }
147                 CLEAR_LOCKS_TID(tid);
148                 TheList::dbg_del(tid);
149                 tid = ((pthread_t)-1);
150 // Don't execute anything after this.
151                 if( autodelete ) delete this;
152         }
153         else {
154 // kludge
155                 while( running() && !cancelled ) {
156                         int ret = pthread_kill(tid, 0);
157                         if( ret ) break;
158                         usleep(10000);
159                 }
160                 tid = ((pthread_t)-1);
161         }
162         return 0;
163 }
164
165 int Thread::enable_cancel()
166 {
167         if( !cancel_enabled ) {
168                 cancel_enabled = true;
169                 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
170         }
171         return 0;
172 }
173
174 int Thread::disable_cancel()
175 {
176         if( cancel_enabled ) {
177                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
178                 cancel_enabled = false;
179         }
180         return 0;
181 }
182
183 int Thread::get_cancel_enabled()
184 {
185         return cancel_enabled;
186 }
187
188 void Thread::exit_thread()
189 {
190         finished = true;
191         pthread_exit(0);
192 }
193
194
195 int Thread::suspend_thread()
196 {
197         if( exists() )
198                 pthread_kill(tid, SIGSTOP);
199         return 0;
200 }
201
202 int Thread::continue_thread()
203 {
204         if( exists() )
205                 pthread_kill(tid, SIGCONT);
206         return 0;
207 }
208
209 int Thread::set_synchronous(int value)
210 {
211         this->synchronous = value != 0;
212         return 0;
213 }
214
215 int Thread::set_realtime(int value)
216 {
217         this->realtime = value != 0;
218         return 0;
219 }
220
221 int Thread::set_autodelete(int value)
222 {
223         this->autodelete = value != 0;
224         return 0;
225 }
226
227 int Thread::get_autodelete()
228 {
229         return autodelete ? 1 : 0;
230 }
231
232 int Thread::get_synchronous()
233 {
234         return synchronous ? 1 : 0;
235 }
236
237 bool Thread::calculate_realtime()
238 {
239 //printf("Thread::calculate_realtime %d %d\n", getpid(), sched_getscheduler(0));
240         return (sched_getscheduler(0) == SCHED_RR ||
241                 sched_getscheduler(0) == SCHED_FIFO);
242 }
243
244 int Thread::get_realtime()
245 {
246         return realtime ? 1 : 0;
247 }
248
249 unsigned long Thread::get_tid()
250 {
251         return (unsigned long)tid;
252 }
253