/[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 57 - (hide annotations) (download)
Sun May 2 17:45:43 2004 UTC (20 years, 1 month 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 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 53 * *
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 schoenebeck 57 pthread_cond_init(&__thread_start_condition, NULL);
33 schoenebeck 53 pthread_cond_init(&__thread_exit_condition, NULL);
34     }
35    
36     Thread::~Thread() {
37 schoenebeck 57 StopThread();
38     pthread_cond_destroy(&__thread_start_condition);
39 schoenebeck 53 pthread_cond_destroy(&__thread_exit_condition);
40     pthread_mutex_destroy(&__thread_state_mutex);
41     }
42    
43     /**
44 schoenebeck 57 * 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 schoenebeck 53 */
49     int Thread::StartThread() {
50 schoenebeck 57 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 schoenebeck 53 // 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 schoenebeck 57 *
111     * @see StopThread()
112 schoenebeck 53 */
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 schoenebeck 57 if (!isRealTime) return 0;
129    
130 schoenebeck 53 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 schoenebeck 57 pthread_cond_broadcast(&__thread_start_condition);
166 schoenebeck 53 }
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 schoenebeck 57 t->SetSchedulingPriority();
184 schoenebeck 53 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