remove whitespace at eol
[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 does not do anything if the thread is not synchronous
131                 int ret = pthread_join(tid, 0);
132                 if( ret ) strerror(ret);
133                 CLEAR_LOCKS_TID(tid);
134                 TheList::dbg_del(tid);
135                 tid = ((pthread_t)-1);
136 // Don't execute anything after this.
137                 if( autodelete ) delete this;
138         }
139         else {
140 // kludge
141                 while( running() && !cancelled ) {
142                         int ret = pthread_kill(tid, 0);
143                         if( ret ) break;
144                         usleep(200000);
145                 }
146                 tid = ((pthread_t)-1);
147         }
148         return 0;
149 }
150
151 int Thread::enable_cancel()
152 {
153         if( !cancel_enabled ) {
154                 cancel_enabled = true;
155                 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
156         }
157         return 0;
158 }
159
160 int Thread::disable_cancel()
161 {
162         if( cancel_enabled ) {
163                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
164                 cancel_enabled = false;
165         }
166         return 0;
167 }
168
169 int Thread::get_cancel_enabled()
170 {
171         return cancel_enabled;
172 }
173
174 void Thread::exit_thread()
175 {
176         finished = true;
177         pthread_exit(0);
178 }
179
180
181 int Thread::suspend_thread()
182 {
183         if( exists() )
184                 pthread_kill(tid, SIGSTOP);
185         return 0;
186 }
187
188 int Thread::continue_thread()
189 {
190         if( exists() )
191                 pthread_kill(tid, SIGCONT);
192         return 0;
193 }
194
195 int Thread::set_synchronous(int value)
196 {
197         this->synchronous = value != 0;
198         return 0;
199 }
200
201 int Thread::set_realtime(int value)
202 {
203         this->realtime = value != 0;
204         return 0;
205 }
206
207 int Thread::set_autodelete(int value)
208 {
209         this->autodelete = value != 0;
210         return 0;
211 }
212
213 int Thread::get_autodelete()
214 {
215         return autodelete ? 1 : 0;
216 }
217
218 int Thread::get_synchronous()
219 {
220         return synchronous ? 1 : 0;
221 }
222
223 bool Thread::calculate_realtime()
224 {
225 //printf("Thread::calculate_realtime %d %d\n", getpid(), sched_getscheduler(0));
226         return (sched_getscheduler(0) == SCHED_RR ||
227                 sched_getscheduler(0) == SCHED_FIFO);
228 }
229
230 int Thread::get_realtime()
231 {
232         return realtime ? 1 : 0;
233 }
234
235 unsigned long Thread::get_tid()
236 {
237         return tid;
238 }
239