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

Last change on this file since 16 was 15, checked in by Bayard Gildas, 6 years ago

sources reformatted with flair-format-dir script

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