source: flair-src/trunk/lib/FlairCore/src/Thread_impl.cpp@ 2

Last change on this file since 2 was 2, checked in by Sanahuja Guillaume, 6 years ago

flaircore

File size: 9.3 KB
Line 
1// %flair:license{
2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
4// %flair:license}
5// created: 2012/10/04
6// filename: Thread_impl.cpp
7//
8// author: Guillaume Sanahuja
9// Copyright Heudiasyc UMR UTC/CNRS 7253
10//
11// version: $Id: $
12//
13// purpose: classe implementant un thread rt ou non
14//
15//
16/*********************************************************************/
17
18#include "Thread_impl.h"
19#include "Thread.h"
20#include "IODevice.h"
21#include "IODevice_impl.h"
22#include "ConditionVariable.h"
23#include "config.h"
24#include "FrameworkManager.h"
25#include <string.h>
26#ifdef __XENO__
27#include <rtdk.h>
28#else
29#include <sys/resource.h>
30#endif
31
32using std::string;
33using namespace flair::core;
34
35Thread_impl::Thread_impl(Thread* self,uint8_t priority)
36{
37 isRunning=false;
38 tobestopped=false;
39 is_suspended=false;
40 period_set=false;
41
42 this->self=self;
43 cond=new ConditionVariable(self,self->ObjectName());
44
45 if(priority<MIN_THREAD_PRIORITY)
46 {
47 priority=MIN_THREAD_PRIORITY;
48// printf("Thread::Thread, %s: priority set to %i\n",self->ObjectName().c_str(), priority);
49 }
50 if(priority>MAX_THREAD_PRIORITY)
51 {
52 priority=MAX_THREAD_PRIORITY;
53 self->Warn("priority set to %i\n",MAX_THREAD_PRIORITY);
54 }
55
56 this->priority=priority;
57 period=100*1000*1000;//100ms par defaut
58 min_jitter=1000*1000*1000;
59 max_jitter=0;
60 mean_jitter=0;
61 last=0;
62 cpt=0;
63}
64
65Thread_impl::~Thread_impl()
66{
67 SafeStop();
68 Join();
69}
70
71void Thread_impl::Start(void)
72{
73 int status;
74
75 isRunning=true;
76
77#ifdef __XENO__
78 string th_name=getFrameworkManager()->ObjectName()+ "-" + self->ObjectName();
79
80#ifdef RT_STACK_SIZE
81 status=rt_task_create(&task_rt, th_name.c_str(), RT_STACK_SIZE, (int)priority, T_JOINABLE);
82#else
83 status=rt_task_create(&task_rt, th_name.c_str(), 0,(int)priority, T_JOINABLE);
84#endif //RT_STACK_SIZE
85 if(status!=0)
86 {
87 self->Err("rt_task_create error (%s)\n",strerror(-status));
88 }
89 else
90 {
91 //_printf("rt_task_create ok %s\n",th_name);
92 }
93
94 status=rt_task_start(&task_rt, &main_rt, (void*)this);
95 if(status!=0)
96 {
97 self->Err("rt_task_start error (%s)\n",strerror(-status));
98 }
99 else
100 {
101 //_printf("rt_task_start ok %s\n",th_name);
102 }
103
104 // Initialise the rt_print buffer for this task explicitly
105 rt_print_init(512, th_name.c_str());
106
107#else //__XENO__
108
109 // Initialize thread creation attributes
110 pthread_attr_t attr;
111 if(pthread_attr_init(&attr) != 0)
112 {
113 self->Err("Error pthread_attr_init\n");
114 }
115
116#ifdef NRT_STACK_SIZE
117 if(pthread_attr_setstacksize(&attr, NRT_STACK_SIZE) != 0)
118 {
119 self->Err("Error pthread_attr_setstacksize\n");
120 }
121#endif //NRT_STACK_SIZE
122
123 if(pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED)!=0)
124 {
125 self->Err("Error pthread_attr_setinheritsched\n");
126 }
127
128 if(pthread_attr_setschedpolicy(&attr, SCHED_FIFO)!=0)
129 {
130 self->Err("Error pthread_attr_setschedpolicy\n");
131 }
132
133 struct sched_param parm;
134 parm.sched_priority = priority;
135 if(pthread_attr_setschedparam(&attr,&parm)!=0)
136 {
137 self->Err("Error pthread_attr_setschedparam\n");
138 }
139
140 next_time=GetTime()+period;
141
142 if(pthread_create(&task_nrt, &attr, main_nrt, (void*)this) != 0)
143 {
144 self->Err("pthread_create error\n");
145 }
146
147 if(pthread_attr_destroy(&attr) != 0)
148 {
149 self->Err("Error pthread_attr_destroy\n");
150 }
151
152#endif //__XENO__
153}
154
155#ifdef __XENO__
156void Thread_impl::main_rt(void * arg)
157{
158 Thread_impl *caller = (Thread_impl*)arg;
159
160 // Perform auto-init of rt_print buffers if the task doesn't do so
161 rt_print_auto_init(1);
162
163 caller->self->Run();
164
165 caller->PrintStats();
166}
167#else
168void* Thread_impl::main_nrt(void * arg)
169{
170 Thread_impl *caller = (Thread_impl*)arg;
171
172 caller->self->Run();
173
174 caller->PrintStats();
175
176 pthread_exit(0);
177}
178#endif //__XENO__
179
180void Thread_impl::SetPeriodUS(uint32_t period) {
181 if(period==0) {
182 self->Err("Period must be>0\n");
183 return;
184 }
185
186#ifdef __XENO__
187 int status=rt_task_set_periodic(&task_rt, TM_NOW, period*1000);
188 if(status!=0) self->Err("Error rt_task_set_periodic %s\n",strerror(-status));
189#else
190 next_time-=period;
191 next_time+=period*1000;
192#endif
193 this->period=period*1000;
194 period_set=true;
195}
196
197uint32_t Thread_impl::GetPeriodUS() const {
198 return this->period/1000;
199}
200
201void Thread_impl::SetPeriodMS(uint32_t period) {
202 if(period==0) {
203 self->Err("Period must be>0\n");
204 return;
205 }
206
207#ifdef __XENO__
208 int status=rt_task_set_periodic(&task_rt, TM_NOW, period*1000*1000);
209 if(status!=0) self->Err("Error rt_task_set_periodic %s\n",strerror(-status));
210#else
211 next_time-=period;
212 next_time+=period*1000*1000;
213#endif
214 this->period=period*1000*1000;
215 period_set=true;
216}
217
218uint32_t Thread_impl::GetPeriodMS() const {
219 return this->period/1000/1000;
220}
221
222void Thread_impl::WaitPeriod(void)
223{
224 if(period_set==false)
225 {
226 self->Err("Period must be set befaore calling this method\n");
227 return;
228 }
229#ifdef __XENO__
230 unsigned long overruns_r;
231 int status=rt_task_wait_period(&overruns_r);
232 if(status!=0) self->Err("Error rt_task_wait_period %s\n",strerror(-status));
233 if(status==-ETIMEDOUT) self->Err("overrun: %lld\n",overruns_r);
234#else
235 self->SleepUntil(next_time);
236 next_time+=period;
237#endif
238 ComputeJitter(GetTime());
239}
240
241
242void Thread_impl::Suspend(void) {
243 if(isRunning==false) {
244 self->Err("thread is not started\n");
245 return;
246 }
247
248 cond->GetMutex(),
249 is_suspended=true;
250 cond->CondWait();
251 is_suspended=false;
252 cond->ReleaseMutex();
253}
254
255bool Thread_impl::SuspendUntil(Time date) {
256 if(isRunning==false) {
257 self->Err("thread is not started\n");
258 return false;
259 }
260
261 cond->GetMutex(),
262 is_suspended=true;
263 bool success=cond->CondWaitUntil(date);
264 is_suspended=false;
265 cond->ReleaseMutex();
266 return success;
267}
268
269bool Thread_impl::IsSuspended(void)
270{
271 bool result;
272
273 cond->GetMutex();
274 result=is_suspended;
275 cond->ReleaseMutex();
276
277 return result;
278}
279
280void Thread_impl::Resume(void)
281{
282 if(isRunning==false)
283 {
284 self->Err("thread is not started\n");
285 return;
286 }
287
288 cond->GetMutex();
289 if(is_suspended==true)
290 {
291 cond->CondSignal();
292 }
293 else
294 {
295 self->Err("thread is not suspended\n");
296 }
297 cond->ReleaseMutex();
298}
299
300int Thread_impl::WaitUpdate(const IODevice* device)
301{
302 int status=0;
303
304 if(IsSuspended()==true)
305 {
306 self->Err("thread is already supended\n");
307 status=-1;
308 }
309 else
310 {
311 cond->GetMutex();
312
313 if(device->pimpl_->SetToWake(self)==0)
314 {
315 is_suspended=true;
316 cond->CondWait();
317 is_suspended=false;
318 }
319 else
320 {
321 self->Err("%s is already waiting an update\n",device->ObjectName().c_str());
322 status=-1;
323 }
324
325 cond->ReleaseMutex();
326 }
327
328 return status;
329}
330
331void Thread_impl::PrintStats(void)
332{
333#ifdef __XENO__
334 RT_TASK_INFO info;
335
336 int status=rt_task_inquire(NULL, &info);
337 if(status!=0)
338 {
339 self->Err("Error rt_task_inquire %s\n",strerror(-status));
340 }
341 else
342#endif
343 {
344#ifndef __XENO__
345 //if(last!=0)
346#endif
347 {
348 Printf("Thread::%s :\n",self->ObjectName().c_str());
349 }
350#ifdef __XENO__
351 Printf(" number of context switches: %i\n",info.ctxswitches);
352 Printf(" number of primary->secondary mode switch: %i\n",info.modeswitches);
353 //printf("number of page faults: %i\n",info.pagefaults);
354 Printf(" execution time (ms) in primary mode: %lld\n",info.exectime/1000000);
355#else
356/*
357 struct rusage r_usage;
358 getrusage(RUSAGE_THREAD,&r_usage);
359 printf(" memory usage = %ld\n",r_usage.ru_maxrss);
360 printf("RUSAGE :ru_utime => %lld [sec] : %lld [usec], :ru_stime => %lld [sec] : %lld [usec] \n",
361 (int64_t)r_usage.ru_utime.tv_sec, (int64_t)r_usage.ru_utime.tv_usec,
362 (int64_t)r_usage.ru_stime.tv_sec, (int64_t)r_usage.ru_stime.tv_usec);*/
363#endif
364 if(last!=0)
365 {
366 Printf(" min jitter (ns): %lld\n",min_jitter);
367 Printf(" max jitter (ns): %lld\n",max_jitter);
368 Printf(" jitter moy (ns): %lld\n",mean_jitter/cpt);
369 Printf(" itertions: %lld\n",cpt);
370 }
371 }
372}
373
374void Thread_impl::Join(void)
375{
376 if(isRunning==true)
377 {
378 int status;
379
380#ifdef __XENO__
381 status=rt_task_join(&task_rt);
382#else
383 status=pthread_join(task_nrt,NULL);
384#endif
385 if(status!=0) self->Err("error %s\n",strerror(-status));
386 isRunning=false;
387 }
388}
389
390void Thread_impl::ComputeJitter(Time time)
391{
392 Time diff,delta;
393 diff=time-last;
394
395 if(diff>=period)
396 {
397 delta=diff-period;
398 }
399 else
400 {
401 delta=period-diff;
402 }
403 //if(delta==0) rt_printf("%lld %lld\n",time,last);
404 last=time;
405 if(diff==time) return;
406
407 if(delta>max_jitter) max_jitter=delta;
408 if(delta<min_jitter) min_jitter=delta;
409 mean_jitter+=delta;
410 cpt++;
411
412 //Printf("Thread::%s jitter moy (ns): %lld\n",self->ObjectName().c_str(),mean_jitter/cpt);
413
414}
415
416void Thread_impl::SafeStop(void)
417{
418 tobestopped=true;
419 if(IsSuspended()) Resume();
420}
421
422bool Thread_impl::ToBeStopped(void)
423{
424 return tobestopped;
425}
Note: See TracBrowser for help on using the repository browser.