4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
23 #include "bcsignals.h"
33 // track unjoined threads at termination
35 #include "arraylist.h"
40 static Mutex the_lock;
42 MLocker() { the_lock.lock(); }
43 ~MLocker() { the_lock.unlock(); }
45 Mutex MLocker::the_lock;
49 pthread_t tid, owner; const char *name;
50 the_dbg(pthread_t t, pthread_t o, const char *nm) { tid = t; owner = o; name = nm; }
55 static class the_list : public ArrayList<the_dbg*> {
57 static void dump_threads(FILE *fp);
65 static void dbg_add(pthread_t tid, pthread_t owner, const char *nm)
68 int i = thread_list.size();
69 while( --i >= 0 && thread_list[i]->tid != tid );
71 printf("dbg_add, dup %016lx %s %s\n",
72 (unsigned long)tid, nm, thread_list[i]->name);
75 thread_list.append(new the_dbg(tid, owner, nm));
78 static void dbg_del(pthread_t tid)
81 int i = thread_list.size();
82 while( --i >= 0 && thread_list[i]->tid != tid );
84 printf("dbg_del, mis %016lx\n",(unsigned long)tid);
87 thread_list.remove_object_number(i);
90 static class the_chkr {
94 int i = thread_list.size();
96 printf("unjoined tids / owner %d\n", i);
97 while( --i >= 0 ) printf(" %016lx / %016lx %s\n",
98 (unsigned long)thread_list[i]->tid,
99 (unsigned long)thread_list[i]->owner,
100 thread_list[i]->name);
104 #define dbg_add(t, nm) do {} while(0)
105 #define dbg_del(t) do {} while(0)
108 Thread::Thread(int synchronous, int realtime, int autodelete)
110 this->synchronous = synchronous != 0;
111 this->realtime = realtime != 0;
112 this->autodelete = autodelete != 0;
116 cancel_enabled = false;
123 void* Thread::entrypoint(void *parameters)
125 Thread *thread = (Thread*)parameters;
127 // allow thread to be cancelled at any point during a region where it is enabled.
128 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
129 // Disable cancellation by default.
130 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
131 thread->cancel_enabled = false;
133 // Set realtime here seince it doesn't work in start
134 if( thread->realtime && getuid() == 0 ) {
135 struct sched_param param = { sched_priority : 1 };
136 if(pthread_setschedparam(thread->tid, SCHED_RR, ¶m) < 0)
137 perror("Thread::entrypoint pthread_attr_setschedpolicy");
141 thread->finished = true;
142 if( !thread->synchronous ) {
143 if( !thread->cancelled ) dbg_del(thread->tid);
144 if( thread->autodelete ) delete thread;
145 else thread->tid = ((pthread_t)-1);
153 struct sched_param param;
155 pthread_attr_init(&attr);
157 // previously run, and did not join, join to clean up zombie
158 if( synchronous && exists() )
165 // Inherit realtime from current thread the easy way.
167 realtime = calculate_realtime();
170 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
172 if( realtime && getuid() == 0 ) {
173 if(pthread_attr_setschedpolicy(&attr, SCHED_RR) < 0)
174 perror("Thread::start pthread_attr_setschedpolicy");
175 param.sched_priority = 50;
176 if(pthread_attr_setschedparam(&attr, ¶m) < 0)
177 perror("Thread::start pthread_attr_setschedparam");
180 if(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED) < 0)
181 perror("Thread::start pthread_attr_setinheritsched");
184 pthread_create(&tid, &attr, Thread::entrypoint, this);
186 dbg_add(tid, owner, typeid(*this).name());
191 if( exists() && !cancelled ) {
192 LOCK_LOCKS("Thread::cancel");
195 if( !synchronous ) dbg_del(tid);
201 int Thread::join() // join this thread
203 if( !exists() ) return 0;
205 // NOTE: this does not do anything if the thread is not synchronous
206 int ret = pthread_join(tid, 0);
207 if( ret ) strerror(ret);
208 CLEAR_LOCKS_TID(tid);
210 tid = ((pthread_t)-1);
211 // Don't execute anything after this.
212 if( autodelete ) delete this;
216 while( running() && !cancelled ) {
217 int ret = pthread_kill(tid, 0);
221 tid = ((pthread_t)-1);
226 int Thread::enable_cancel()
228 if( !cancel_enabled ) {
229 cancel_enabled = true;
230 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
235 int Thread::disable_cancel()
237 if( cancel_enabled ) {
238 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
239 cancel_enabled = false;
244 int Thread::get_cancel_enabled()
246 return cancel_enabled;
249 void Thread::exit_thread()
256 int Thread::suspend_thread()
259 pthread_kill(tid, SIGSTOP);
263 int Thread::continue_thread()
266 pthread_kill(tid, SIGCONT);
270 int Thread::set_synchronous(int value)
272 this->synchronous = value != 0;
276 int Thread::set_realtime(int value)
278 this->realtime = value != 0;
282 int Thread::set_autodelete(int value)
284 this->autodelete = value != 0;
288 int Thread::get_autodelete()
290 return autodelete ? 1 : 0;
293 int Thread::get_synchronous()
295 return synchronous ? 1 : 0;
298 bool Thread::calculate_realtime()
300 //printf("Thread::calculate_realtime %d %d\n", getpid(), sched_getscheduler(0));
301 return (sched_getscheduler(0) == SCHED_RR ||
302 sched_getscheduler(0) == SCHED_FIFO);
305 int Thread::get_realtime()
307 return realtime ? 1 : 0;
310 unsigned long Thread::get_tid()
315 void Thread::dump_threads(FILE *fp)
317 int i = thread_list.size();
319 fprintf(fp, "thread 0x%012lx, owner 0x%012lx, %s\n",
320 (unsigned long)thread_list[i]->tid, (unsigned long)thread_list[i]->owner,
321 thread_list[i]->name);