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