/[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 1424 - (show annotations) (download)
Sun Oct 14 22:00:17 2007 UTC (16 years, 7 months ago) by schoenebeck
File size: 9587 byte(s)
* code cleanup:
- global.h now only covers global definitions that are needed for the C++
  API header files, all implementation internal global definitions are now
  in global_private.h
- atomic.h is not exposed to the C++ API anymore (replaced the references
  in SynchronizedConfig.h for this with local definitions)
- no need to include config.h anymore for using LS's API header files
- DB instruments classes are not exposed to the C++ API
- POSIX callback functions of Thread.h are hidden
- the (optional) gig Engine benchmark compiles again
- updated Doxyfile.in
- fixed warnings in API doc generation
* preparations for release 0.5.0

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2007 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #include "Thread.h"
25
26 // this is the minimum stack size a thread will be spawned with
27 // if this value is too small, the OS will allocate memory on demand and
28 // thus might lead to dropouts in realtime threads
29 // TODO: should be up for testing to get a reasonable good value
30 #define MIN_STACK_SIZE 524288
31
32 namespace LinuxSampler {
33
34 // Callback functions for the POSIX thread API
35 static void* __pthread_launcher(void* thread);
36 static void __pthread_destructor(void* thread);
37
38 Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {
39 this->bLockedMemory = LockMemory;
40 this->isRealTime = RealTime;
41 this->PriorityDelta = PriorityDelta;
42 this->PriorityMax = PriorityMax;
43 __thread_destructor_key = 0;
44 pthread_attr_init(&__thread_attr);
45 }
46
47 Thread::~Thread() {
48 StopThread();
49 pthread_attr_destroy(&__thread_attr);
50 }
51
52 /**
53 * Starts the thread. This method will wait until the thread actually
54 * started it's execution before it will return. The abstract method
55 * Main() is the entry point for the new thread. You have to implement the
56 * Main() method in your subclass.
57 */
58 int Thread::StartThread() {
59 RunningCondition.Lock();
60 if (!RunningCondition.GetUnsafe()) {
61 SignalStartThread();
62 // wait until thread started execution
63 RunningCondition.WaitIf(false);
64 }
65 RunningCondition.Unlock();
66 return 0;
67 }
68
69 /**
70 * Starts the thread. This method will signal to start the thread and
71 * return immediately. Note that the thread might not yet run when this
72 * method returns! The abstract method Main() is the entry point for the
73 * new thread. You have to implement the Main() method in your subclass.
74 *
75 * @see StartThread()
76 */
77 int Thread::SignalStartThread() {
78 // prepare the thread properties
79 int res = pthread_attr_setinheritsched(&__thread_attr, PTHREAD_EXPLICIT_SCHED);
80 if (res) {
81 std::cerr << "Thread creation failed: Could not inherit thread properties."
82 << std::endl << std::flush;
83 RunningCondition.Set(false);
84 return res;
85 }
86 res = pthread_attr_setdetachstate(&__thread_attr, PTHREAD_CREATE_JOINABLE);
87 if (res) {
88 std::cerr << "Thread creation failed: Could not request a joinable thread."
89 << std::endl << std::flush;
90 RunningCondition.Set(false);
91 return res;
92 }
93 res = pthread_attr_setscope(&__thread_attr, PTHREAD_SCOPE_SYSTEM);
94 if (res) {
95 std::cerr << "Thread creation failed: Could not request system scope for thread scheduling."
96 << std::endl << std::flush;
97 RunningCondition.Set(false);
98 return res;
99 }
100 res = pthread_attr_setstacksize(&__thread_attr, MIN_STACK_SIZE);
101 if (res) {
102 std::cerr << "Thread creation failed: Could not set minimum stack size."
103 << std::endl << std::flush;
104 RunningCondition.Set(false);
105 return res;
106 }
107 // Create and run the thread
108 res = pthread_create(&this->__thread_id, &__thread_attr, __pthread_launcher, this);
109 switch (res) {
110 case 0: // Success
111 break;
112 case EAGAIN:
113 std::cerr << "Thread creation failed: System doesn't allow to create another thread."
114 << std::endl << std::flush;
115 RunningCondition.Set(false);
116 break;
117 case EPERM:
118 std::cerr << "Thread creation failed: You're lacking permisssions to set required scheduling policy and parameters."
119 << std::endl << std::flush;
120 RunningCondition.Set(false);
121 break;
122 default:
123 std::cerr << "Thread creation failed: Unknown cause."
124 << std::endl << std::flush;
125 RunningCondition.Set(false);
126 break;
127 }
128 return res;
129 }
130
131 /**
132 * Stops the thread. This method will wait until the thread actually stopped
133 * it's execution before it will return.
134 */
135 int Thread::StopThread() {
136 RunningCondition.Lock();
137 if (RunningCondition.GetUnsafe()) {
138 SignalStopThread();
139 // wait until thread stopped execution
140 RunningCondition.WaitIf(true);
141 pthread_detach(__thread_id);
142 }
143 RunningCondition.Unlock();
144 return 0;
145 }
146
147 /**
148 * Stops the thread. This method will signal to stop the thread and return
149 * immediately. Note that the thread might still run when this method
150 * returns!
151 *
152 * @see StopThread()
153 */
154 int Thread::SignalStopThread() {
155 //FIXME: segfaults when thread is not yet running
156 pthread_cancel(__thread_id);
157 return 0;
158 }
159
160 /**
161 * Returns @c true in case the thread is currently running.
162 */
163 bool Thread::IsRunning() {
164 return RunningCondition.GetUnsafe();
165 }
166
167 /**
168 * Sets the process SCHED_FIFO policy, if max=1 then set at max priority,
169 * else use min priority. delta is added to the priority so that we can
170 * for example set 3 SCHED_FIFO tasks to different priorities by specifying
171 * delta 0 , -1 , -2 ( 0 = highest priority because -1 is subtracted to the
172 * current priority).
173 */
174 int Thread::SetSchedulingPriority() {
175 #if !defined(__APPLE__)
176 int policy;
177 const char* policyDescription = NULL;
178 if (isRealTime) { // becomes a RT thread
179 policy = SCHED_FIFO;
180 policyDescription = "realtime";
181 } else { // 'normal', non-RT thread
182 policy = SCHED_OTHER;
183 policyDescription = "normal (non-RT)";
184 }
185 // set selected scheduling policy and priority
186 struct sched_param schp;
187 memset(&schp, 0, sizeof(schp));
188 if (isRealTime) { // it is not possible to change priority for the SCHED_OTHER policy
189 if (this->PriorityMax == 1) {
190 schp.sched_priority = sched_get_priority_max(policy) + this->PriorityDelta;
191 }
192 if (this->PriorityMax == -1) {
193 schp.sched_priority = sched_get_priority_min(policy) + this->PriorityDelta;
194 }
195 }
196 if (pthread_setschedparam(__thread_id, policy, &schp) != 0) {
197 std::cerr << "Thread: WARNING, can't assign "
198 << policyDescription
199 << " scheduling to thread!"
200 << std::endl << std::flush;
201 return -1;
202 }
203 #endif
204 return 0;
205 }
206
207 /**
208 * Locks the memory so it will not be swapped out by the operating system.
209 */
210 int Thread::LockMemory() {
211 #if !defined(__APPLE__)
212 if (!bLockedMemory) return 0;
213 if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
214 std::cerr << "Thread: WARNING, can't mlockall() memory!\n"
215 << std::flush;
216 return -1;
217 }
218 #endif
219 return 0;
220 }
221
222 /**
223 * Registers thread destructor callback function which will be executed when
224 * the thread stops it's execution and sets the 'Running' flag to true. This
225 * method will be called by the __pthread_launcher callback function, DO NOT
226 * CALL THIS METHOD YOURSELF!
227 */
228 void Thread::EnableDestructor() {
229 RunningCondition.Lock();
230 pthread_key_create(&__thread_destructor_key, __pthread_destructor);
231 pthread_setspecific(__thread_destructor_key, this);
232 RunningCondition.Set(true);
233 RunningCondition.Unlock();
234 }
235
236 /**
237 * Will be called by the kernel when the thread stops it's execution.
238 */
239 int Thread::Destructor() {
240 pthread_key_delete(__thread_destructor_key);
241 RunningCondition.Set(false);
242 return 0;
243 }
244
245 /// Callback function for the POSIX thread API
246 static void* __pthread_launcher(void* thread) {
247 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // let the thread be killable under any circumstances
248 Thread* t;
249 t = (Thread*) thread;
250 t->SetSchedulingPriority();
251 t->LockMemory();
252 t->EnableDestructor();
253 t->Main();
254 return NULL;
255 }
256
257 /// Callback function for the POSIX thread API
258 static void __pthread_destructor(void* thread) {
259 Thread* t;
260 t = (Thread*) thread;
261 t->Destructor();
262 }
263
264 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC