ru.po from igor, intl tweaks, picon fixes for last chkin, snap motion event on btns
[goodguy/history.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->cancelled ) TheList::dbg_del(thread->tid);
69                 if( thread->autodelete ) delete thread;
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         pthread_create(&tid, &attr, Thread::entrypoint, this);
110
111         TheList::dbg_add(tid, owner, typeid(*this).name());
112 }
113
114 int Thread::cancel()
115 {
116         if( exists() && !cancelled ) {
117                 LOCK_LOCKS("Thread::cancel");
118                 pthread_cancel(tid);
119                 cancelled = true;
120                 if( !synchronous ) TheList::dbg_del(tid);
121                 UNLOCK_LOCKS;
122         }
123         return 0;
124 }
125
126 int Thread::join()   // join this thread
127 {
128         if( !exists() ) return 0;
129         if( synchronous ) {
130 // NOTE: this fails if the thread is not synchronous or
131 //  or another thread is already waiting to join.
132                 int ret = pthread_join(tid, 0);
133                 if( ret ) {
134                         fflush(stdout);
135                         fprintf(stderr, "Thread %p: %s\n", (void*)tid, strerror(ret));
136                         fflush(stderr);
137                 }
138                 CLEAR_LOCKS_TID(tid);
139                 TheList::dbg_del(tid);
140                 tid = ((pthread_t)-1);
141 // Don't execute anything after this.
142                 if( autodelete ) delete this;
143         }
144         else {
145 // kludge
146                 while( running() && !cancelled ) {
147                         int ret = pthread_kill(tid, 0);
148                         if( ret ) break;
149                         usleep(200000);
150                 }
151                 tid = ((pthread_t)-1);
152         }
153         return 0;
154 }
155
156 int Thread::enable_cancel()
157 {
158         if( !cancel_enabled ) {
159                 cancel_enabled = true;
160                 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
161         }
162         return 0;
163 }
164
165 int Thread::disable_cancel()
166 {
167         if( cancel_enabled ) {
168                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
169                 cancel_enabled = false;
170         }
171         return 0;
172 }
173
174 int Thread::get_cancel_enabled()
175 {
176         return cancel_enabled;
177 }
178
179 void Thread::exit_thread()
180 {
181         finished = true;
182         pthread_exit(0);
183 }
184
185
186 int Thread::suspend_thread()
187 {
188         if( exists() )
189                 pthread_kill(tid, SIGSTOP);
190         return 0;
191 }
192
193 int Thread::continue_thread()
194 {
195         if( exists() )
196                 pthread_kill(tid, SIGCONT);
197         return 0;
198 }
199
200 int Thread::set_synchronous(int value)
201 {
202         this->synchronous = value != 0;
203         return 0;
204 }
205
206 int Thread::set_realtime(int value)
207 {
208         this->realtime = value != 0;
209         return 0;
210 }
211
212 int Thread::set_autodelete(int value)
213 {
214         this->autodelete = value != 0;
215         return 0;
216 }
217
218 int Thread::get_autodelete()
219 {
220         return autodelete ? 1 : 0;
221 }
222
223 int Thread::get_synchronous()
224 {
225         return synchronous ? 1 : 0;
226 }
227
228 bool Thread::calculate_realtime()
229 {
230 //printf("Thread::calculate_realtime %d %d\n", getpid(), sched_getscheduler(0));
231         return (sched_getscheduler(0) == SCHED_RR ||
232                 sched_getscheduler(0) == SCHED_FIFO);
233 }
234
235 int Thread::get_realtime()
236 {
237         return realtime ? 1 : 0;
238 }
239
240 unsigned long Thread::get_tid()
241 {
242         return tid;
243 }
244