no longer need ffmpeg patch0 which was for Termux
[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 // not on bsd
62 #if defined (__linux__) || defined (__TERMUX__)
63 // Set realtime here since it doesn't work in start
64         if( thread->realtime && getuid() == 0 ) {
65                 struct sched_param param = { sched_priority : 1 };
66                 if(pthread_setschedparam(thread->tid, SCHED_RR, &param) < 0)
67                         perror("Thread::entrypoint pthread_attr_setschedpolicy");
68         }
69 #endif
70         thread->run();
71         thread->finished = true;
72         if( !thread->synchronous ) {
73                 if( thread->autodelete ) delete thread;
74                 else if( !thread->cancelled ) TheList::dbg_del(thread->tid);
75                 else thread->tid = ((pthread_t)-1);
76         }
77         return NULL;
78 }
79
80 void Thread::start()
81 {
82         pthread_attr_t  attr;
83         struct sched_param param;
84
85         pthread_attr_init(&attr);
86
87 // previously run, and did not join, join to clean up zombie
88         if( synchronous && exists() )
89                 join();
90
91         finished = false;
92         cancelled = false;
93         owner = get_self();
94
95 // Inherit realtime from current thread the easy way.
96         if( !realtime )
97                 realtime = calculate_realtime();
98
99         if( !synchronous )
100                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
101
102         if( realtime && getuid() == 0 ) {
103                 if(pthread_attr_setschedpolicy(&attr, SCHED_RR) < 0)
104                         perror("Thread::start pthread_attr_setschedpolicy");
105                 param.sched_priority = 50;
106                 if(pthread_attr_setschedparam(&attr, &param) < 0)
107                         perror("Thread::start pthread_attr_setschedparam");
108         }
109         else {
110 #if !defined(__TERMUX__)
111                 if(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED) < 0)
112                         perror("Thread::start pthread_attr_setinheritsched");
113 #endif
114         }
115
116 // autodelete may delete this immediately after create
117         int autodelete = this->autodelete;
118
119         pthread_create(&tid, &attr, Thread::entrypoint, this);
120
121         if( !autodelete )
122                 TheList::dbg_add(tid, owner, typeid(*this).name());
123 }
124
125 int Thread::cancel()
126 {
127         if( exists() && !cancelled ) {
128                 LOCK_LOCKS("Thread::cancel");
129                 pthread_cancel(tid);
130                 cancelled = true;
131                 if( !synchronous ) TheList::dbg_del(tid);
132                 UNLOCK_LOCKS;
133         }
134         return 0;
135 }
136
137 int Thread::join()   // join this thread
138 {
139         if( !exists() ) return 0;
140         if( synchronous ) {
141 // NOTE: this fails if the thread is not synchronous or
142 //  or another thread is already waiting to join.
143                 int ret = pthread_join(tid, 0);
144                 if( ret ) {
145                         fflush(stdout);
146                         fprintf(stderr, "Thread %p: %s\n", (void*)tid, strerror(ret));
147                         fflush(stderr);
148                 }
149                 CLEAR_LOCKS_TID(tid);
150                 TheList::dbg_del(tid);
151                 tid = ((pthread_t)-1);
152 // Don't execute anything after this.
153                 if( autodelete ) delete this;
154         }
155         else {
156 // kludge
157                 while( running() && !cancelled ) {
158                         int ret = pthread_kill(tid, 0);
159                         if( ret ) break;
160                         usleep(10000);
161                 }
162                 tid = ((pthread_t)-1);
163         }
164         return 0;
165 }
166
167 int Thread::enable_cancel()
168 {
169         if( !cancel_enabled ) {
170                 cancel_enabled = true;
171                 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
172         }
173         return 0;
174 }
175
176 int Thread::disable_cancel()
177 {
178         if( cancel_enabled ) {
179                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
180                 cancel_enabled = false;
181         }
182         return 0;
183 }
184
185 int Thread::get_cancel_enabled()
186 {
187         return cancel_enabled;
188 }
189
190 void Thread::exit_thread()
191 {
192         finished = true;
193         pthread_exit(0);
194 }
195
196
197 int Thread::suspend_thread()
198 {
199         if( exists() )
200                 pthread_kill(tid, SIGSTOP);
201         return 0;
202 }
203
204 int Thread::continue_thread()
205 {
206         if( exists() )
207                 pthread_kill(tid, SIGCONT);
208         return 0;
209 }
210
211 int Thread::set_synchronous(int value)
212 {
213         this->synchronous = value != 0;
214         return 0;
215 }
216
217 int Thread::set_realtime(int value)
218 {
219         this->realtime = value != 0;
220         return 0;
221 }
222
223 int Thread::set_autodelete(int value)
224 {
225         this->autodelete = value != 0;
226         return 0;
227 }
228
229 int Thread::get_autodelete()
230 {
231         return autodelete ? 1 : 0;
232 }
233
234 int Thread::get_synchronous()
235 {
236         return synchronous ? 1 : 0;
237 }
238
239 bool Thread::calculate_realtime()
240 {
241 //printf("Thread::calculate_realtime %d %d\n", getpid(), sched_getscheduler(0));
242         return (sched_getscheduler(0) == SCHED_RR ||
243                 sched_getscheduler(0) == SCHED_FIFO);
244 }
245
246 int Thread::get_realtime()
247 {
248         return realtime ? 1 : 0;
249 }
250
251 unsigned long Thread::get_tid()
252 {
253         return (unsigned long)tid;
254 }
255