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

Last change on this file since 205 was 202, checked in by Sanahuja Guillaume, 7 years ago

modifs usleep

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