root/trunk/libffado/src/libutil/PosixThread.cpp

Revision 1498, 7.9 kB (checked in by ppalmers, 15 years ago)

Merge all changes from 2.0 branch into trunk (since r1361). This _should_ contain all forward merges done in the mean time. At this moment in time both branches should be in sync.

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 /*
25  * Copied from the jackd/jackdmp sources
26  * function names changed in order to avoid naming problems when using this in
27  * a jackd backend.
28  */
29
30 /* Original license:
31  * Copyright (C) 2001 Paul Davis
32  * Copyright (C) 2004-2006 Grame
33  *
34  * this program is free software; you can redistribute it and/or modify
35  * it under the terms of the GNU General Public License as published by
36  * the Free Software Foundation; either version 2 of the License, or
37  * (at your option) version 3 of the License.
38  *
39  * This program is distributed in the hope that it will be useful,
40  * but WITHOUT ANY WARRANTY; without even the implied warranty of
41  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42  * GNU General Public License for more details.
43  *
44  * You should have received a copy of the GNU General Public License
45  * along with this program; if not, write to the Free Software
46  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
47  *
48  */
49
50 #include "PosixThread.h"
51 #include <string.h> // for memset
52 #include <errno.h>
53 #include <assert.h>
54
55 namespace Util
56 {
57
58 IMPL_DEBUG_MODULE( Thread, Thread, DEBUG_LEVEL_NORMAL );
59
60 void* PosixThread::ThreadHandler(void* arg)
61 {
62     PosixThread* obj = (PosixThread*)arg;
63     RunnableInterface* runnable = obj->fRunnable;
64     int err;
65
66     if ((err = pthread_setcanceltype(obj->fCancellation, NULL)) != 0) {
67         debugError("pthread_setcanceltype err = %s\n", strerror(err));
68     }
69
70     // Call Init method
71     if (!runnable->Init()) {
72         debugError("Thread init fails: thread quits\n");
73         return 0;
74     }
75
76     debugOutput( DEBUG_LEVEL_VERBOSE, "(%s) ThreadHandler: start %p\n", obj->m_id.c_str(), obj);
77
78     // If Init succeed start the thread loop
79     bool res = true;
80     while (obj->fRunning && res) {
81         debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, "(%s) ThreadHandler: run %p\n", obj->m_id.c_str(), obj);
82         res = runnable->Execute();
83         pthread_testcancel();
84     }
85
86     debugOutput( DEBUG_LEVEL_VERBOSE, "(%s) ThreadHandler: exit %p\n", obj->m_id.c_str(), obj);
87     return 0;
88 }
89
90 int PosixThread::Start()
91 {
92     int res;
93     fRunning = true;
94
95     if (fRealTime) {
96
97         debugOutput( DEBUG_LEVEL_VERBOSE, "(%s) Create RT thread %p with priority %d\n", m_id.c_str(), this, fPriority);
98
99         /* Get the client thread to run as an RT-FIFO
100            scheduled thread of appropriate priority.
101         */
102         pthread_attr_t attributes;
103         struct sched_param rt_param;
104         pthread_attr_init(&attributes);
105
106         if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) {
107             debugError("Cannot request explicit scheduling for RT thread  %d %s\n", res, strerror(res));
108             return -1;
109         }
110         if ((res = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE))) {
111             debugError("Cannot request joinable thread creation for RT thread  %d %s\n", res, strerror(res));
112             return -1;
113         }
114         if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) {
115             debugError("Cannot set scheduling scope for RT thread %d %s\n", res, strerror(res));
116             return -1;
117         }
118
119         if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_FIFO))) {
120
121         //if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_RR))) {
122             debugError("Cannot set FIFO scheduling class for RT thread  %d %s\n", res, strerror(res));
123             return -1;
124         }
125
126         memset(&rt_param, 0, sizeof(rt_param));
127         if(fPriority <= 0) {
128             debugWarning("Clipping to minimum priority (%d -> 1)\n", fPriority);
129             rt_param.sched_priority = 1;
130         } else if(fPriority >= 99) {
131             debugWarning("Clipping to maximum priority (%d -> 98)\n", fPriority);
132             rt_param.sched_priority = 98;
133         } else {
134             rt_param.sched_priority = fPriority;
135         }
136
137         if ((res = pthread_attr_setschedparam(&attributes, &rt_param))) {
138             debugError("Cannot set scheduling priority for RT thread %d %s\n", res, strerror(res));
139             return -1;
140         }
141
142         if ((res = pthread_create(&fThread, &attributes, ThreadHandler, this))) {
143             debugError("Cannot create realtime thread (%d: %s)\n", res, strerror(res));
144             debugError(" priority: %d %s\n", fPriority);
145             return -1;
146         }
147
148         return 0;
149     } else {
150         debugOutput( DEBUG_LEVEL_VERBOSE, "(%s) Create non RT thread %p\n", m_id.c_str(), this);
151
152         if ((res = pthread_create(&fThread, 0, ThreadHandler, this))) {
153             debugError("Cannot create thread %d %s\n", res, strerror(res));
154             return -1;
155         }
156
157         return 0;
158     }
159 }
160
161 int PosixThread::Kill()
162 {
163     if (fThread) { // If thread has been started
164         debugOutput( DEBUG_LEVEL_VERBOSE, "(%s) Kill %p (thread: %p)\n", m_id.c_str(), this, fThread);
165         void* status;
166         pthread_cancel(fThread);
167         pthread_join(fThread, &status);
168         debugOutput( DEBUG_LEVEL_VERBOSE, "(%s) Killed %p (thread: %p)\n", m_id.c_str(), this, fThread);
169         return 0;
170     } else {
171         return -1;
172     }
173 }
174
175 int PosixThread::Stop()
176 {
177     if (fThread) { // If thread has been started
178         debugOutput( DEBUG_LEVEL_VERBOSE, "(%s) Stop %p (thread: %p)\n", m_id.c_str(), this, fThread);
179         void* status;
180         fRunning = false; // Request for the thread to stop
181         pthread_join(fThread, &status);
182         debugOutput( DEBUG_LEVEL_VERBOSE, "(%s) Stopped %p (thread: %p)\n", m_id.c_str(), this, fThread);
183         return 0;
184     } else {
185         return -1;
186     }
187 }
188
189 int PosixThread::AcquireRealTime()
190 {
191     struct sched_param rtparam;
192     int res;
193     debugOutput( DEBUG_LEVEL_VERBOSE, "(%s, %p) Aquire realtime, prio %d\n", m_id.c_str(), this, fPriority);
194
195     if (!fThread)
196         return -1;
197
198     memset(&rtparam, 0, sizeof(rtparam));
199     if(fPriority <= 0) {
200         debugWarning("Clipping to minimum priority (%d -> 1)\n", fPriority);
201         rtparam.sched_priority = 1;
202     } else if(fPriority >= 99) {
203         debugWarning("Clipping to maximum priority (%d -> 98)\n", fPriority);
204         rtparam.sched_priority = 98;
205     } else {
206         rtparam.sched_priority = fPriority;
207     }
208
209     //if ((res = pthread_setschedparam(fThread, SCHED_FIFO, &rtparam)) != 0) {
210
211     if ((res = pthread_setschedparam(fThread, SCHED_FIFO, &rtparam)) != 0) {
212         debugError("Cannot use real-time scheduling (FIFO/%d) "
213                    "(%d: %s)", rtparam.sched_priority, res,
214                    strerror(res));
215         return -1;
216     }
217     return 0;
218 }
219
220 int PosixThread::AcquireRealTime(int priority)
221 {
222     fPriority = priority;
223     return AcquireRealTime();
224 }
225
226 int PosixThread::DropRealTime()
227 {
228     struct sched_param rtparam;
229     int res;
230     debugOutput( DEBUG_LEVEL_VERBOSE, "(%s, %p) Drop realtime\n", m_id.c_str(), this);
231
232     if (!fThread)
233         return -1;
234
235     memset(&rtparam, 0, sizeof(rtparam));
236     rtparam.sched_priority = 0;
237
238     if ((res = pthread_setschedparam(fThread, SCHED_OTHER, &rtparam)) != 0) {
239         debugError("Cannot switch to normal scheduling priority(%s)\n", strerror(errno));
240         return -1;
241     }
242     return 0;
243 }
244
245 pthread_t PosixThread::GetThreadID()
246 {
247     return fThread;
248 }
249
250 } // end of namespace
251
Note: See TracBrowser for help on using the browser.