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.