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

Last change on this file since 124 was 118, checked in by Sanahuja Guillaume, 5 years ago

aded semaphore
resolved bug for rt_printf before thread is started

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