/[svn]/linuxsampler/trunk/src/common/Thread.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/common/Thread.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 57 - (show annotations) (download)
Sun May 2 17:45:43 2004 UTC (19 years, 11 months ago) by schoenebeck
File size: 7035 byte(s)
* src/common/Thread.cpp: method StartThread() now blocks until thread
  actually runs, mlockall() will only be applied for realtime threads
* libtoolized liblinuxsampler
* initiated automatic unit tests against the LinuxSampler codebase
  (see src/testcases): already added a couple of tests for the Thread and
  Mutex classes, you have to explicitly compile the unit tests by running
  'make testcases' (you need to have cppunit installed though) and then you
  can run the console version of the test runner by calling
  'src/testcases/linuxsamplertest'
* src/Sampler.h: added API documentation

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "Thread.h"
24
25 Thread::Thread(bool RealTime, int PriorityMax, int PriorityDelta) {
26 this->isRealTime = RealTime;
27 this->Running = false;
28 this->PriorityDelta = PriorityDelta;
29 this->PriorityMax = PriorityMax;
30 __thread_destructor_key = 0;
31 pthread_mutex_init(&__thread_state_mutex, NULL);
32 pthread_cond_init(&__thread_start_condition, NULL);
33 pthread_cond_init(&__thread_exit_condition, NULL);
34 }
35
36 Thread::~Thread() {
37 StopThread();
38 pthread_cond_destroy(&__thread_start_condition);
39 pthread_cond_destroy(&__thread_exit_condition);
40 pthread_mutex_destroy(&__thread_state_mutex);
41 }
42
43 /**
44 * Starts the thread. This method will wait until the thread actually
45 * started it's execution before it will return. The abstract method
46 * Main() is the entry point for the new thread. You have to implement the
47 * Main() method in your subclass.
48 */
49 int Thread::StartThread() {
50 pthread_mutex_lock(&__thread_state_mutex);
51 if (!Running) {
52 SignalStartThread();
53 pthread_cond_wait(&__thread_start_condition, &__thread_state_mutex);
54 }
55 pthread_mutex_unlock(&__thread_state_mutex);
56 return 0;
57 }
58
59 /**
60 * Starts the thread. This method will signal to start the thread and
61 * return immediately. Note that the thread might not yet run when this
62 * method returns! The abstract method Main() is the entry point for the
63 * new thread. You have to implement the Main() method in your subclass.
64 *
65 * @see StartThread()
66 */
67 int Thread::SignalStartThread() {
68 // Create and run the thread
69 int res = pthread_create(&this->__thread_id, NULL, __pthread_launcher, this);
70 switch (res) {
71 case 0: // Success
72 break;
73 case EAGAIN:
74 std::cerr << "Thread creation failed: System doesn't allow to create another thread."
75 << std::endl << std::flush;
76 this->Running = false;
77 break;
78 case EPERM:
79 std::cerr << "Thread creation failed: You're lacking permisssions to set required scheduling policy and parameters."
80 << std::endl << std::flush;
81 this->Running = false;
82 break;
83 default:
84 std::cerr << "Thread creation failed: Unknown cause."
85 << std::endl << std::flush;
86 this->Running = false;
87 break;
88 }
89 return res;
90 }
91
92 /**
93 * Stops the thread. This method will wait until the thread actually stopped
94 * it's execution before it will return.
95 */
96 int Thread::StopThread() {
97 pthread_mutex_lock(&__thread_state_mutex);
98 if (Running) {
99 SignalStopThread();
100 pthread_cond_wait(&__thread_exit_condition, &__thread_state_mutex);
101 }
102 pthread_mutex_unlock(&__thread_state_mutex);
103 return 0;
104 }
105
106 /**
107 * Stops the thread. This method will signal to stop the thread and return
108 * immediately. Note that the thread might still run when this method
109 * returns!
110 *
111 * @see StopThread()
112 */
113 int Thread::SignalStopThread() {
114 pthread_cancel(__thread_id);
115 return 0;
116 }
117
118 /**
119 * Sets the process SCHED_FIFO policy, if max=1 then set at max priority,
120 * else use min priority. delta is added to the priority so that we can
121 * for example set 3 SCHED_FIFO tasks to different priorities by specifying
122 * delta 0 , -1 , -2 ( 0 = highest priority because -1 is subtracted to the
123 * current priority).
124 */
125 int Thread::SetSchedulingPriority() {
126 struct sched_param schp;
127
128 if (!isRealTime) return 0;
129
130 if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
131 perror("WARNING, can't mlockall() memory!");
132 }
133
134 /*
135 * set the process to realtime privs
136 */
137 memset(&schp, 0, sizeof(schp));
138 if (this->PriorityMax == 1) {
139 schp.sched_priority = sched_get_priority_max(SCHED_FIFO) + this->PriorityDelta;
140 }
141 if (this->PriorityMax == -1) {
142 schp.sched_priority = sched_get_priority_min(SCHED_FIFO) + this->PriorityDelta;
143 }
144
145 if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {
146 perror("sched_setscheduler");
147 return -1;
148 }
149
150 return 0;
151 }
152
153 /**
154 * Registers thread destructor callback function which will be executed when
155 * the thread stops it's execution and sets the 'Running' flag to true. This
156 * method will be called by the __pthread_launcher callback function, DO NOT
157 * CALL THIS METHOD YOURSELF!
158 */
159 void Thread::EnableDestructor() {
160 pthread_mutex_lock(&__thread_state_mutex);
161 pthread_key_create(&__thread_destructor_key, __pthread_destructor);
162 pthread_setspecific(__thread_destructor_key, this);
163 Running = true;
164 pthread_mutex_unlock(&__thread_state_mutex);
165 pthread_cond_broadcast(&__thread_start_condition);
166 }
167
168 /**
169 * Will be called by the kernel when the thread stops it's execution.
170 */
171 int Thread::Destructor() {
172 pthread_key_delete(__thread_destructor_key);
173 pthread_mutex_lock(&__thread_state_mutex);
174 Running = false;
175 pthread_mutex_unlock(&__thread_state_mutex);
176 pthread_cond_broadcast(&__thread_exit_condition);
177 }
178
179 /// Callback function for the POSIX thread API
180 void* __pthread_launcher(void* thread) {
181 Thread* t;
182 t = (Thread*) thread;
183 t->SetSchedulingPriority();
184 t->EnableDestructor();
185 t->Main();
186 }
187
188 /// Callback function for the POSIX thread API
189 void __pthread_destructor(void* thread) {
190 Thread* t;
191 t = (Thread*) thread;
192 t->Destructor();
193 }

  ViewVC Help
Powered by ViewVC