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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1212 - (hide annotations) (download)
Tue May 29 23:59:36 2007 UTC (17 years ago) by schoenebeck
File size: 7839 byte(s)
* added highly experimental support for on-the-fly instrument editing
  within the sampler's process (by using instrument editor plugins),
  you'll notice the new "Registered instrument editors:" message on
  startup, the plugin path can be overridden at compile time with
  ./configure --enable-plugin-dir=/some/dir
* added a new LSCP command "EDIT INSTRUMENT <sampler-channel>" to spawn
  a matching instrument editor for the instrument on the given sampler
  channel (LSCP command syntax might be subject to change soon)
* config.h is not going to be installed along with liblinuxsampler's
  API header files anymore (not necessary anymore)
* take care of $(DESTDIR) when creating the instruments DB on 'make
  install' rule (needed for packaging and cross compilation)
* bumped version to 0.4.0.5cvs

1 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 1212 * Copyright (C) 2005 - 2007 Christian Schoenebeck *
7 schoenebeck 53 * *
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 schoenebeck 1212 namespace LinuxSampler {
27    
28 schoenebeck 392 Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {
29     this->bLockedMemory = LockMemory;
30 schoenebeck 53 this->isRealTime = RealTime;
31     this->Running = false;
32     this->PriorityDelta = PriorityDelta;
33     this->PriorityMax = PriorityMax;
34     __thread_destructor_key = 0;
35     pthread_mutex_init(&__thread_state_mutex, NULL);
36 schoenebeck 57 pthread_cond_init(&__thread_start_condition, NULL);
37 schoenebeck 53 pthread_cond_init(&__thread_exit_condition, NULL);
38     }
39    
40     Thread::~Thread() {
41 schoenebeck 57 StopThread();
42     pthread_cond_destroy(&__thread_start_condition);
43 schoenebeck 53 pthread_cond_destroy(&__thread_exit_condition);
44     pthread_mutex_destroy(&__thread_state_mutex);
45     }
46    
47     /**
48 schoenebeck 57 * Starts the thread. This method will wait until the thread actually
49     * started it's execution before it will return. The abstract method
50     * Main() is the entry point for the new thread. You have to implement the
51     * Main() method in your subclass.
52 schoenebeck 53 */
53     int Thread::StartThread() {
54 schoenebeck 57 pthread_mutex_lock(&__thread_state_mutex);
55     if (!Running) {
56     SignalStartThread();
57     pthread_cond_wait(&__thread_start_condition, &__thread_state_mutex);
58     }
59     pthread_mutex_unlock(&__thread_state_mutex);
60     return 0;
61     }
62    
63     /**
64     * Starts the thread. This method will signal to start the thread and
65     * return immediately. Note that the thread might not yet run when this
66     * method returns! The abstract method Main() is the entry point for the
67     * new thread. You have to implement the Main() method in your subclass.
68     *
69     * @see StartThread()
70     */
71     int Thread::SignalStartThread() {
72 schoenebeck 53 // Create and run the thread
73     int res = pthread_create(&this->__thread_id, NULL, __pthread_launcher, this);
74     switch (res) {
75     case 0: // Success
76     break;
77     case EAGAIN:
78     std::cerr << "Thread creation failed: System doesn't allow to create another thread."
79     << std::endl << std::flush;
80     this->Running = false;
81     break;
82     case EPERM:
83     std::cerr << "Thread creation failed: You're lacking permisssions to set required scheduling policy and parameters."
84     << std::endl << std::flush;
85     this->Running = false;
86     break;
87     default:
88     std::cerr << "Thread creation failed: Unknown cause."
89     << std::endl << std::flush;
90     this->Running = false;
91     break;
92     }
93     return res;
94     }
95    
96     /**
97     * Stops the thread. This method will wait until the thread actually stopped
98     * it's execution before it will return.
99     */
100     int Thread::StopThread() {
101     pthread_mutex_lock(&__thread_state_mutex);
102     if (Running) {
103     SignalStopThread();
104     pthread_cond_wait(&__thread_exit_condition, &__thread_state_mutex);
105 schoenebeck 351 pthread_detach(__thread_id);
106 schoenebeck 53 }
107     pthread_mutex_unlock(&__thread_state_mutex);
108     return 0;
109     }
110    
111     /**
112     * Stops the thread. This method will signal to stop the thread and return
113     * immediately. Note that the thread might still run when this method
114     * returns!
115 schoenebeck 57 *
116     * @see StopThread()
117 schoenebeck 53 */
118     int Thread::SignalStopThread() {
119     pthread_cancel(__thread_id);
120     return 0;
121     }
122    
123     /**
124 schoenebeck 1212 * Returns @c true in case the thread is currently running.
125     */
126     bool Thread::IsRunning() {
127     return Running;
128     }
129    
130     /**
131 schoenebeck 53 * Sets the process SCHED_FIFO policy, if max=1 then set at max priority,
132     * else use min priority. delta is added to the priority so that we can
133     * for example set 3 SCHED_FIFO tasks to different priorities by specifying
134     * delta 0 , -1 , -2 ( 0 = highest priority because -1 is subtracted to the
135     * current priority).
136     */
137     int Thread::SetSchedulingPriority() {
138 schoenebeck 361 #if !defined(__APPLE__)
139 schoenebeck 53 struct sched_param schp;
140    
141 schoenebeck 57 if (!isRealTime) return 0;
142    
143 schoenebeck 53 /*
144     * set the process to realtime privs
145     */
146     memset(&schp, 0, sizeof(schp));
147     if (this->PriorityMax == 1) {
148     schp.sched_priority = sched_get_priority_max(SCHED_FIFO) + this->PriorityDelta;
149     }
150     if (this->PriorityMax == -1) {
151     schp.sched_priority = sched_get_priority_min(SCHED_FIFO) + this->PriorityDelta;
152     }
153    
154     if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {
155 schoenebeck 392 perror("Thread: WARNING, can't assign realtime scheduling to thread!");
156 schoenebeck 53 return -1;
157     }
158 schoenebeck 361 #endif
159 schoenebeck 53 return 0;
160     }
161    
162     /**
163 schoenebeck 392 * Locks the memory so it will not be swapped out by the operating system.
164     */
165     int Thread::LockMemory() {
166 letz 399 #if !defined(__APPLE__)
167 schoenebeck 392 if (!bLockedMemory) return 0;
168     if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
169     perror("Thread: WARNING, can't mlockall() memory!");
170     return -1;
171     }
172 letz 399 #endif
173 schoenebeck 392 return 0;
174     }
175    
176     /**
177 schoenebeck 53 * Registers thread destructor callback function which will be executed when
178     * the thread stops it's execution and sets the 'Running' flag to true. This
179     * method will be called by the __pthread_launcher callback function, DO NOT
180     * CALL THIS METHOD YOURSELF!
181     */
182     void Thread::EnableDestructor() {
183     pthread_mutex_lock(&__thread_state_mutex);
184     pthread_key_create(&__thread_destructor_key, __pthread_destructor);
185     pthread_setspecific(__thread_destructor_key, this);
186     Running = true;
187     pthread_mutex_unlock(&__thread_state_mutex);
188 schoenebeck 57 pthread_cond_broadcast(&__thread_start_condition);
189 schoenebeck 53 }
190    
191     /**
192     * Will be called by the kernel when the thread stops it's execution.
193     */
194     int Thread::Destructor() {
195     pthread_key_delete(__thread_destructor_key);
196     pthread_mutex_lock(&__thread_state_mutex);
197     Running = false;
198     pthread_mutex_unlock(&__thread_state_mutex);
199     pthread_cond_broadcast(&__thread_exit_condition);
200 persson 497 return 0;
201 schoenebeck 53 }
202    
203     /// Callback function for the POSIX thread API
204     void* __pthread_launcher(void* thread) {
205 schoenebeck 63 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // let the thread be killable under any circumstances
206 schoenebeck 53 Thread* t;
207     t = (Thread*) thread;
208 schoenebeck 57 t->SetSchedulingPriority();
209 schoenebeck 392 t->LockMemory();
210 schoenebeck 53 t->EnableDestructor();
211     t->Main();
212 persson 497 return NULL;
213 schoenebeck 53 }
214    
215     /// Callback function for the POSIX thread API
216     void __pthread_destructor(void* thread) {
217     Thread* t;
218     t = (Thread*) thread;
219     t->Destructor();
220     }
221 schoenebeck 1212
222     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC