po_hi_task.c 21.5 KB
Newer Older
1
2
3
4
5
/*
 * This is a part of PolyORB-HI-C distribution, a minimal
 * middleware written for generated code from AADL models.
 * You should use it with the Ocarina toolsuite.
 *
yoogx's avatar
yoogx committed
6
 * For more informations, please visit http://taste.tuxfamily.org/wiki
7
 *
8
 * Copyright (C) 2007-2009 Telecom ParisTech, 2010-2016 ESA & ISAE.
9
10
 */

11
12
13
14
15
16
17
18
#ifdef POSIX

#ifdef __linux__
/*  We need GNU extensions to support thread affinify.
    These are Linux specific
 */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
yoogx's avatar
yoogx committed
19
#endif /* _GNU_SOURCE */
20
#include <sched.h>
yoogx's avatar
yoogx committed
21
22
#endif /* __linux__ */
#endif /* POSIX */
23

24
25
26
27
28
#if defined (SIMULATOR)
#include <um_threads.h>
#undef POSIX
#endif

29
#if defined (RTEMS_POSIX) || defined (RTEMS_PURE)
30
#ifdef RTEMS412
31
32
#include <sys/cpuset.h>
#endif
33
#endif
34

35
#if defined (RTEMS_POSIX) || defined (POSIX) || defined (XENO_POSIX)
36
#if defined (__CYGWIN__) || defined (__MINGW32__) || defined (RTEMS_POSIX) || defined (RTEMS_PURE)
yoogx's avatar
yoogx committed
37
#else
38
#include <xlocale.h>
yoogx's avatar
yoogx committed
39
40
#endif

41
42
#include <pthread.h>
#include <sched.h>
43
44
#endif

jdelange's avatar
jdelange committed
45
46
47
48
49
#if defined (_WIN32)
#include <tchar.h>
#include <windows.h>
#endif

50
51
52
53
54
55
56
57
#include <errno.h>
/* Headers from the executive */

#include <po_hi_config.h>
#include <po_hi_time.h>
#include <po_hi_task.h>
#include <po_hi_debug.h>
#include <po_hi_returns.h>
58
#include <po_hi_types.h>
59
#include <po_hi_utils.h>
60
61
/* Header files in PolyORB-HI */

62
63
64
65
66
#if defined (MONITORING)
#include <trace_manager.hh>
#endif
/* Headers from run-time verification */

67
#include <deployment.h>
68
/* Header files from generated code */
69

70
71
72
typedef enum __po_hi_task_category_t { TASK_PERIODIC, TASK_SPORADIC, TASK_BACKGROUND }
    __po_hi_task_category;

73
74
75
76
77
78

int nb_tasks; /* number of created tasks */

typedef struct
{
  __po_hi_task_id     id;       /* Identifier of the task in the system */
79
  __po_hi_task_category task_category;
80
  __po_hi_time_t      period;
yoogx's avatar
yoogx committed
81
82
  __po_hi_time_t      offset;

julien.delange's avatar
julien.delange committed
83
#if defined (RTEMS_POSIX) || defined (POSIX) || defined (XENO_POSIX)
84
  __po_hi_time_t      timer;
yoogx's avatar
yoogx committed
85
86
87
#if defined (_WIN32)
  DWORD tid;
#else
88
89
  pthread_t           tid;              /* The pthread_t type used by the
                                           POSIX library */
yoogx's avatar
yoogx committed
90
#endif
91
92
  pthread_mutex_t     mutex;
  pthread_cond_t      cond;
jdelange's avatar
jdelange committed
93
94
95
#elif defined (_WIN32)
  __po_hi_time_t      timer;
  DWORD               tid;
julien.delange's avatar
julien.delange committed
96
#elif defined (RTEMS_PURE)
97
  rtems_id            ratemon_period;
98
  rtems_id            rtems_id;
99
100
#elif defined(XENO_NATIVE)
  RT_TASK             xeno_id;
101
102
#elif defined(SIMULATOR)
  um_thread_id        um_id;
103
#endif
104
} __po_hi_task_t;
105
106
107
108
109
110
111
/*
 * Structure of a task, contains platform-dependent members
 */

__po_hi_task_t tasks[__PO_HI_NB_TASKS];
/* Array which contains all tasks informations */

jdelange's avatar
jdelange committed
112
113
114
115
#if defined (_WIN32)
HANDLE  __po_hi_tasks_array[__PO_HI_NB_TASKS];
#endif

116
117
118
119
__po_hi_task_id __po_hi_get_task_id (void) {

#if defined (RTEMS_POSIX) || defined (POSIX) || defined (XENO_POSIX)
  pthread_t pthread_id = pthread_self();
120
  int i;
121

122
  for (i = 0; i < __PO_HI_NB_TASKS; i++) {
123
124
125
126
127
128
129
130
131
    if (pthread_id == tasks[i].tid) {
      return tasks[i].id;
    }
  }
#endif

  return (__PO_HI_ERROR_UNKNOWN);

}
132

133
134
void __po_hi_wait_for_tasks ()
{
julien.delange's avatar
julien.delange committed
135
#if defined (RTEMS_POSIX) || defined (POSIX) || defined (XENO_POSIX)
136
137
  int i;

138
139
140
141
  for (i = 0; i < __PO_HI_NB_TASKS; i++)
    {
      pthread_join( tasks[i].tid , NULL );
    }
142

143
#elif defined (RTEMS_PURE)
144
  rtems_task_suspend(RTEMS_SELF);
145

jdelange's avatar
jdelange committed
146
147
#elif defined (_WIN32)
  WaitForMultipleObjects (__PO_HI_NB_TASKS, __po_hi_tasks_array, TRUE, INFINITE);
148

149
150
151
152
#elif defined (XENO_NATIVE)
  int ret;
  while (1)
  {
153
154
155
156
157
    ret = rt_task_join (&(tasks[0].xeno_id));
    if (ret != 0)
      {
        __PO_HI_DEBUG_DEBUG ("Error while calling rt_task_suspend in __po_hi_wait_for_tasks (ret=%d)\n", ret);
      }
158
  }
159
160
161
162
#elif defined (SIMULATOR)
  start_scheduler();
  return (__PO_HI_SUCCESS);

163
#endif
jdelange's avatar
jdelange committed
164
165
166
167
168
169
170

#ifdef __PO_HI_DEBUG
   while (1)
   {
      __DEBUGMSG ("Should NEVER be called !!!\n");
   }
#endif
171
172
173
174
175
}

/*
 * compute next period for a task
 * The argument is the task-id
176
 * The task must be a cyclic task (periodic or sporadic)
177
178
179
 */
int __po_hi_compute_next_period (__po_hi_task_id task)
{
jdelange's avatar
jdelange committed
180
#if defined (RTEMS_POSIX) || defined (POSIX) || defined (XENO_POSIX) || defined (_WIN32)
181

182
    /* If we call this function for the first time, we need to configure
yoogx's avatar
yoogx committed
183
       the initial timer to epoch */
184
185
  if (tasks[task].timer.sec == 0 && tasks[task].timer.nsec == 0) {
    tasks[task].timer = get_epoch();
yoogx's avatar
yoogx committed
186
    __po_hi_add_times(&(tasks[task].timer), &(tasks[task].timer), &tasks[task].offset);
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
    return (__PO_HI_SUCCESS);
  }

  /* Otherwise, we increment either using an absoulte timeline
     (periodic), or relative to the latest dispatch time (sporadic task) */

  switch (tasks[task].task_category) {
  case TASK_PERIODIC:
    __po_hi_add_times(&(tasks[task].timer), &(tasks[task].timer), &tasks[task].period );
    break;

  case TASK_SPORADIC: {
      __po_hi_time_t mytime;

      if (__po_hi_get_time (&mytime) != __PO_HI_SUCCESS) {
        return (__PO_HI_ERROR_CLOCK);
      }

      __po_hi_add_times(&(tasks[task].timer), &mytime, &tasks[task].period );
      break;
   }
  }
209

210
  return (__PO_HI_SUCCESS);
211

212
#elif defined (RTEMS_PURE)
213
214
   rtems_status_code ret;
   rtems_name name;
215

216
217
   if (tasks[task].ratemon_period == RTEMS_INVALID_ID)
   {
218
      name = rtems_build_name ('P', 'R', 'D' + (char)task, ' ');
219

220
221
222
223
224
225
      __DEBUGMSG ("Create monotonic server for task %d\n", task);
      ret = rtems_rate_monotonic_create (name, &(tasks[task].ratemon_period));
      if (ret != RTEMS_SUCCESSFUL)
      {
         __DEBUGMSG ("Error while creating the monotonic server, task=%d, status=%d\n", task, ret);
      }
226
227
   }
  return (__PO_HI_SUCCESS);
228
229
230
231
232
233
234
235
#elif defined (XENO_NATIVE)

  /*
   * In XENO_NATIVE target, we don't need to recompute the next period
   * since the API provides functionnalities to do it automatically.
   */

  return (__PO_HI_SUCCESS);
236
237
238
#else
   return (__PO_HI_UNAVAILABLE);
#endif
239
240
}

241

242
243
int __po_hi_wait_for_next_period (__po_hi_task_id task)
{
244
245
246
247
248

/*!
 * Entry ports monitoring at dispatch if MONITORING is defined
 */
#if defined (MONITORING)
yoogx's avatar
yoogx committed
249
  update_periodic_dispatch(task); // XXX ?
250
251
#endif

yoogx's avatar
yoogx committed
252
253
254
255
256
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
  int ret;
   __PO_HI_INSTRUMENTATION_VCD_WRITE("0t%d\n", task);
  __po_hi_task_delay_until (&(tasks[task].timer), task);

257
258
259
260
261
  if ( (ret = __po_hi_compute_next_period (task)) != 1)
    {
      return (__PO_HI_ERROR_CLOCK);
    }

262
   __PO_HI_INSTRUMENTATION_VCD_WRITE("1t%d\n", task);
263

jdelange's avatar
jdelange committed
264
  return (__PO_HI_SUCCESS);
265

jdelange's avatar
jdelange committed
266
267
268
269
270
271
272
273
#elif defined (_WIN32)
  int ret;
  __po_hi_task_delay_until (&(tasks[task].timer), task);
  if ( (ret = __po_hi_compute_next_period (task)) != 1)
    {
      return (__PO_HI_ERROR_CLOCK);
    }

274
  return (__PO_HI_SUCCESS);
275

276
#elif defined (RTEMS_PURE)
277
   rtems_status_code ret;
278
   ret = rtems_rate_monotonic_period (tasks[task].ratemon_period, (rtems_interval)__PO_HI_TIME_TO_US(tasks[task].period) / rtems_configuration_get_microseconds_per_tick());
jdelange's avatar
jdelange committed
279
   /*
280
   ret = rtems_rate_monotonic_period (tasks[task].ratemon_period, tasks[task].period / _TOD_Microseconds_per_tick);
jdelange's avatar
jdelange committed
281
   */
282

283
284
285
286
287
288
   switch (ret)
   {
      case RTEMS_SUCCESSFUL:
         return (__PO_HI_SUCCESS);
         break;
      case RTEMS_TIMEOUT:
289
         __DEBUGMSG ("Error in rtems_rate_monotonic_period (TIMEOUT, task = %d)\n", task);
290
291
292
         return (__PO_HI_ERROR_TASK_PERIOD);
         break;
      default:
293
         __DEBUGMSG ("Error in rtems_rate_monotonic_period (unknown, error code=%d, task=%d)\n", ret, task);
294
         return (__PO_HI_ERROR_UNKNOWN);
295
296
         break;
   }
297

298
   return (__PO_HI_UNAVAILABLE);
299

300
#elif defined (XENO_NATIVE)
301
302
303
304
   unsigned long overrun;
   int ret;
   ret = rt_task_wait_period (&overrun);
   if ( ret != 0)
305
   {
306
         __DEBUGMSG ("Error in rt_task_period (task=%d;ret=%d,overrun=%lu)\n", task, ret, overrun);
307
308
309
         return (__PO_HI_ERROR_TASK_PERIOD);
   }

310
311
312
313
   if (overrun != 0)
   {
      return (__PO_HI_ERROR_TASK_PERIOD);
   }
yoogx's avatar
yoogx committed
314

315
   return (__PO_HI_SUCCESS);
316
317
318
#else
  return (__PO_HI_UNAVAILABLE);
#endif
319
320
321
322
323
324
325
326
}

int __po_hi_initialize_tasking( )
{
  int i;

  for (i = 0; i < __PO_HI_NB_TASKS; i++)
  {
327
     __po_hi_seconds (&(tasks[i].period), 0);
328
     tasks[i].id     = invalid_task_id;
329
330
331
#ifdef RTEMS_PURE
      tasks[i].ratemon_period = RTEMS_INVALID_ID;
#endif
332
333
334
335
336
337
338
339
340
341
342
343
344
  }

  nb_tasks = 0;

  return (__PO_HI_SUCCESS);
}

/*
 * For each kind of system, we declare a generic function that
 * create a thread. For POSIX-compliant systems, the function
 * is called __po_hi_posix_create_thread
 */

345
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
346
pthread_t __po_hi_posix_create_thread (__po_hi_priority_t priority,
347
                                       __po_hi_stack_t    stack_size,
348
349
                                       const __po_hi_int8_t       core_id,
                                       void*              (*start_routine)(void),
jdelange's avatar
jdelange committed
350
                                       void*              arg)
351
352
353
354
{
  int                policy;
  pthread_t          tid;
  pthread_attr_t     attr;
355
  struct sched_param param;
356
  int err;
357

358
359
  /* Create attributes to store all configuration parameters */

360
361
362
363
364
  if (pthread_attr_init (&attr) != 0)
    {
      return ((pthread_t)__PO_HI_ERROR_PTHREAD_ATTR);
    }

365
#if ( (defined (POSIX) && defined (__linux__)) || (defined (RTEMS_POSIX) && defined (RTEMS412)))
366
367

#ifndef __COMPCERT__
368
369
370
371
372
373
374
375
376
377
378
  /* Thread affinity */
  cpu_set_t cpuset;

  CPU_ZERO(&cpuset);
  CPU_SET(core_id, &cpuset);

  if (pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset) != 0)
    {
      __DEBUGMSG("CANNOT SET AFFINTY\n");
      return ((pthread_t)__PO_HI_ERROR_PTHREAD_ATTR);
    }
379
380
381
#else
#warning pthread_affinity managmeent disabled for Compcert
#endif
382
383
#endif

julien.delange's avatar
julien.delange committed
384
#if defined (POSIX) || defined (XENO_POSIX)
385
386
387
388
  if (pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM) != 0)
    {
      return ((pthread_t)__PO_HI_ERROR_PTHREAD_ATTR);
    }
389
390
391
392
393
394
395
#elif defined (RTEMS_POSIX)
  if (pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS) != 0)
  {
    return ((pthread_t)__PO_HI_ERROR_PTHREAD_ATTR);
  }
#endif

396
397
398
399
400
  if (stack_size != 0)
    {
      if (pthread_attr_setstacksize (&attr, stack_size) != 0)
	{
	  return ((pthread_t)__PO_HI_ERROR_PTHREAD_ATTR);
401
        }
402
403
    }

404
405
    err = pthread_create (&tid, &attr, (void* (*)(void*))start_routine, arg);
    if (err != 0)
406
    {
407
      __PO_HI_DEBUG_CRITICAL("Thread creation failed - pthread_create returned %d\n", err);
408
409
410
      return ((pthread_t)__PO_HI_ERROR_PTHREAD_CREATE);
    }

411
  policy = SCHED_FIFO;
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
  param.sched_priority = priority;

#ifdef __PO_HI_DEBUG
  if (priority < sched_get_priority_min (policy))
  {
      __DEBUGMSG("PRIORITY IS TOO LOW\n");
  }

  if (priority > sched_get_priority_max (policy))
  {
      __DEBUGMSG("PRIORITY IS TOO HIGH\n");
  }
#endif

  /*
   * We print a message that the user has to be root on
   * its computer. In fact, most of the time, the
   * function pthread_setschedparam fails because
   * the user is not root. On many systems, only root
   * can change the priority of the threads.
   */
433
  __DEBUGMSG("ABOUT TO SET PRIORITY FOR TASK %d\n" , nb_tasks );
434
435
436
437
438
439
440
441
442
443
  if (pthread_setschedparam (tid, policy, &param)!=0)
    {
      __DEBUGMSG("CANNOT SET PRIORITY FOR TASK %d\n" , nb_tasks );
      __DEBUGMSG("IF YOU ARE USING POSIX IMPLEMENTATION\n");
      __DEBUGMSG("BE SURE TO BE LOGGED AS ROOT\n");
    }

  return tid;
}

444

445
446
int __po_hi_posix_initialize_task (__po_hi_task_t* task)
{
447
448
449
450
  if (pthread_mutex_init (&(task->mutex), NULL) != 0)
    {
      return (__PO_HI_ERROR_PTHREAD_MUTEX);
    }
451

452
453
454
455
456
457
  if (pthread_cond_init (&(task->cond), NULL) != 0)
    {
      return (__PO_HI_ERROR_PTHREAD_COND);
    }

  return (__PO_HI_SUCCESS);
458
}
459
460
461

#endif /* POSIX || RTEMS_POSIX */

jdelange's avatar
jdelange committed
462
463
#if defined (_WIN32)
DWORD __po_hi_win32_create_thread (__po_hi_task_id    id,
464
                                   __po_hi_priority_t priority,
jdelange's avatar
jdelange committed
465
466
467
468
469
470
                                   __po_hi_stack_t    stack_size,
                                   void*              (*start_routine)(void),
                                   void*              arg)
{
   DWORD tid;
   HANDLE h;
yoogx's avatar
yoogx committed
471
   h = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) start_routine, NULL, 0, &tid);
jdelange's avatar
jdelange committed
472
473
474
475
476
   __po_hi_tasks_array[id] = h;
   return tid;
}
#endif

477
#ifdef RTEMS_PURE
478
rtems_id __po_hi_rtems_create_thread (__po_hi_priority_t priority,
479
                                      __po_hi_stack_t    stack_size,
480
                                      __po_hi_int8_t       core_id,
jdelange's avatar
jdelange committed
481
482
                                      void*              (*start_routine)(void),
                                      void*              arg)
483
{
484
  rtems_id rid;
485
486
487
488
489
490
491
  if (rtems_task_create (rtems_build_name( 'T', 'A', nb_tasks, ' ' ),
                         1,
                         RTEMS_MINIMUM_STACK_SIZE,
                         RTEMS_DEFAULT_MODES,
                         RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &rid)
      != RTEMS_SUCCESSFUL)
    {
492
      __DEBUGMSG ("ERROR when creating the task\n");
493
      return __PO_HI_ERROR_CREATE_TASK;
494
495
    }

496
#ifdef RTEMS412
497
  /* Thread affinity API for SMP systems appeared in RTEMS 4.11,
498
499
     section 25 of RTEMS Applications C User's Guide .
  */
500
501
502
503

  cpu_set_t         cpuset;

  CPU_ZERO(&cpuset);
504
  CPU_SET(core_id, &cpuset);
505

506
  if (rtems_task_set_affinity(rid, sizeof(cpuset), &cpuset) != RTEMS_SUCCESSFUL)
507
508
509
510
511
    {
      __DEBUGMSG ("ERROR setting thread affinity\n");
      return __PO_HI_ERROR_CREATE_TASK;
    }
#endif
512

513
  if (rtems_task_start (rid, (rtems_task_entry)start_routine, 0 ) != RTEMS_SUCCESSFUL)
514
    {
515
      __DEBUGMSG ("ERROR when starting the task\n");
516
      return __PO_HI_ERROR_CREATE_TASK;
517
    }
518

519
   return rid;
520
521
522
}
#endif

523
#ifdef XENO_NATIVE
524
RT_TASK __po_hi_xenomai_create_thread (__po_hi_priority_t priority,
jdelange's avatar
jdelange committed
525
526
527
                                       __po_hi_stack_t    stack_size,
                                       void*              (*start_routine)(void),
                                       void*              arg)
528
529
530
{
   RT_TASK newtask;

531
532
533
534
535
536
   /*
    * Uses T_JOINABLE at this time, should avoid that later and put 0 instead
    * to be able to use kernel-based threads.
    */

   if (rt_task_create (&newtask, NULL, stack_size, priority, T_JOINABLE))
537
538
539
540
541
542
543
   {
      __DEBUGMSG ("ERROR when creating the task\n");
   }
   return newtask;
}
#endif

544
545
546
int __po_hi_create_generic_task (const __po_hi_task_id      id,
                                 const __po_hi_time_t*      period,
                                 const __po_hi_priority_t   priority,
547
                                 const __po_hi_stack_t      stack_size,
548
                                 const __po_hi_int8_t       core_id,
jdelange's avatar
jdelange committed
549
550
                                 void*                      (*start_routine)(void),
                                 void*                      arg)
551
552
{
  __po_hi_task_t* my_task;
553
  if (id == -1)
554
    {
555
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
556
      __po_hi_posix_create_thread (priority, stack_size, core_id, start_routine, arg);
557
      return (__PO_HI_SUCCESS);
jdelange's avatar
jdelange committed
558
559
560
#elif defined (_WIN32)
      __po_hi_win32_create_thread (id, priority, stack_size, start_routine, arg);
      return (__PO_HI_SUCCESS);
561
#elif defined (XENO_NATIVE)
562
      RT_TASK t;
jdelange's avatar
jdelange committed
563
      (void) arg;
jdelange's avatar
jdelange committed
564
      t = __po_hi_xenomai_create_thread (priority, stack_size, start_routine, arg);
565
566
567
568
      if (rt_task_start (&(t), (void*)start_routine, NULL))
      {
         __DEBUGMSG ("ERROR when starting the task\n");
      }
569
      return (__PO_HI_SUCCESS);
570
#elif defined (RTEMS_PURE)
jdelange's avatar
jdelange committed
571
      (void) arg;
572
      __po_hi_rtems_create_thread (priority, stack_size, core_id, start_routine, arg);
573
574
575
576
      return (__PO_HI_SUCCESS);
#else
      return (__PO_HI_UNAVAILABLE);
#endif
577
    }
578
579
580
  else
    {
      my_task         = &(tasks[id]);
581
      __po_hi_time_copy (&(my_task->period), period);
582
      my_task->id     = id;
583

584
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
585
586
      my_task->tid    = __po_hi_posix_create_thread
        (priority, stack_size, core_id, start_routine, arg);
587
      my_task->timer = ORIGIN_OF_TIME;
588
      __po_hi_posix_initialize_task (my_task);
589
#elif defined (RTEMS_PURE)
590
591
      my_task->rtems_id = __po_hi_rtems_create_thread
        (priority, stack_size, core_id, start_routine, arg);
jdelange's avatar
jdelange committed
592
#elif defined (_WIN32)
593
594
      my_task->tid = __po_hi_win32_create_thread
        (id, priority, stack_size, start_routine, arg);
595
#elif defined (XENO_NATIVE)
596
597
598
599
      my_task->xeno_id = __po_hi_xenomai_create_thread
        (priority, stack_size, start_routine, arg);
#elif defined (SIMULATOR)
      my_task->um_id = um_thread_create (start_routine, stack_size, priority);
600
601
602
#else
      return (__PO_HI_UNAVAILABLE);
#endif
603
604
605
606
607
608
      nb_tasks++;
    }

  return (__PO_HI_SUCCESS);
}

609

610
611
612
int __po_hi_create_periodic_task (const __po_hi_task_id     id,
                                  const __po_hi_time_t*     period,
                                  const __po_hi_priority_t  priority,
613
                                  const __po_hi_stack_t     stack_size,
614
                                  const __po_hi_int8_t      core_id,
615
                                  void*                     (*start_routine)(void))
616
{
617
618
619
620
621
622
623
624
  /*
   * Send Task type to trace manager, if there is monitoring.
   */

#if defined (MONITORING)
   periodic_task_creation(id);
#endif

625
  if (__po_hi_create_generic_task( id, period , priority , stack_size, core_id, start_routine, NULL) != 1)
626
627
   {
      __DEBUGMSG ("ERROR when creating generic task (task id=%d)\n", id);
628
      return (__PO_HI_ERROR_CREATE_TASK);
629
   }
630
631

  /*
632
   * Compute the next period of the task, using the
633
634
   *__po_hi_time* functions.
   */
635
#if defined (RTEMS_POSIX) || defined (POSIX) || defined (XENO_POSIX)
636
637
638
639
640
641

  // XXX The following is (a priori) not necessary, it should be
  // reviewed for all runtimes: the body of a periodic task already
  // call __po_hi_compute_next_period() as part of its skeleton

  /*if (__po_hi_compute_next_period (id) != __PO_HI_SUCCESS)
642
643
644
    {
      return (__PO_HI_ERROR_CLOCK);
    }
645
  */
646

647
#elif defined (XENO_NATIVE)
648
649
   int ret;

650
   ret = rt_task_set_periodic (&(tasks[id].xeno_id), TM_NOW,  (tasks[id].period.sec * 1000000000) + tasks[id].period.nsec);
651
   if (ret != 0)
652
   {
jdelange's avatar
jdelange committed
653
      __DEBUGMSG ("ERROR when calling rt_task_set_periodic on task %d, ret=%d\n", id, ret);
654
655
      return (__PO_HI_ERROR_CLOCK);
   }
656
657
658
659
660

   if (rt_task_start (&(tasks[id].xeno_id), (void*)start_routine, NULL))
   {
      __DEBUGMSG ("ERROR when starting the task\n");
   }
661
#endif
662
663
   tasks[id].task_category = TASK_PERIODIC;
   return (__PO_HI_SUCCESS);
664
665
}

jdelange's avatar
jdelange committed
666
667
void __po_hi_task_wait_offset (const __po_hi_time_t* time)
{
668

yoogx's avatar
yoogx committed
669
670
  if (time->sec == 0 && time->nsec == 0)
    return; // No need to wait, exit immediately
671

yoogx's avatar
yoogx committed
672
  tasks[__po_hi_get_task_id()].offset = *time;
jdelange's avatar
jdelange committed
673
674
}

675
int __po_hi_create_sporadic_task (const __po_hi_task_id     id,
676
677
                                  const __po_hi_time_t*     period,
                                  const __po_hi_priority_t  priority,
678
                                  const __po_hi_stack_t     stack_size,
679
                                  const __po_hi_int8_t      core_id,
680
                                  void*                     (*start_routine)(void) )
681
{
682
683
684
685
686
687
688
  /*
   * Send Task type to trace manager, if there is monitoring.
   */
#if defined (MONITORING)
   sporadic_task_creation(id);
#endif

689
690
691
692
693
  /*
   * Create generic task which will execute the routine given in the
   * last parameter. Typically, a sporadic thread will wait on a
   * mutex.
   */
694
  if (__po_hi_create_generic_task( id, period , priority , stack_size, core_id, start_routine, NULL) != 1)
695
696
697
    {
      return (__PO_HI_ERROR_CREATE_TASK);
    }
698

699
700
701
#if defined (XENO_NATIVE)
   int ret;

702
   ret = rt_task_set_periodic (&(tasks[id].xeno_id), TM_NOW,  tasks[id].period.sec * 1000000000 + tasks[id].period.nsec);
703
704
   if (ret != 0)
   {
jdelange's avatar
jdelange committed
705
      __DEBUGMSG ("ERROR when calling rt_task_set_periodic on task %d, ret=%d\n", id, ret);
706
707
708
709
710
711
712
713
      return (__PO_HI_ERROR_CLOCK);
   }

   if (rt_task_start (&(tasks[id].xeno_id), (void*)start_routine, NULL))
   {
      __DEBUGMSG ("ERROR when starting the task\n");
   }
#endif
714
715
   tasks[id].task_category = TASK_SPORADIC;
   return (__PO_HI_SUCCESS);
716
717
}

718
int __po_hi_task_delay_until (__po_hi_time_t* time, __po_hi_task_id task)
719
{
720
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
721
722
723
  struct timespec timer;
  int ret;

724
  timer.tv_sec = time->sec;
725

726
  timer.tv_nsec = time->nsec;
727
728

  pthread_mutex_lock (&tasks[task].mutex);
729

730
731
732
733
734
735
736
737
738
739
740
741
742
743
  ret = pthread_cond_timedwait (&tasks[task].cond, &tasks[task].mutex, &timer);

  if ( (ret != 0) && (ret != ETIMEDOUT))
    {
      ret = __PO_HI_ERROR_PTHREAD_COND;
    }
  else
    {
      ret = __PO_HI_SUCCESS;
    }

  pthread_mutex_unlock (&tasks[task].mutex);

  return (ret);
jdelange's avatar
jdelange committed
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
#elif defined (_WIN32)
   HANDLE hTimer = NULL;
   LARGE_INTEGER ularge;

   hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
   ularge = __po_hi_unix_seconds_to_windows_tick (time->sec, time->nsec);

    if (!SetWaitableTimer(hTimer, &ularge, 0, NULL, NULL, 0))
    {
        __PO_HI_DEBUG_DEBUG("[DELAY UNTIL] SetWaitableTimer failed (%d)\n", GetLastError());
        return 2;
    }

    if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0)
    {
        __PO_HI_DEBUG_DEBUG("[DELAY UNTIL] WaitForSingleObject failed (%d)\n", GetLastError());
    }

    if (CloseHandle(hTimer) != TRUE)
    {
        __PO_HI_DEBUG_DEBUG("[DELAY UNTIL] CloseHandle failed (%d)\n", GetLastError());
    }


  return __PO_HI_SUCCESS;
769
770
#elif defined (XENO_NATIVE)
  int ret;
771
  ret =  rt_task_sleep_until (time->sec * 1000000000 + time->nsec);
772
773
774
775
776
777
  if (ret)
  {
      __DEBUGMSG ("[TASK] Error in rt_task_sleep_until, ret=%d\n", ret);
      return (__PO_HI_ERROR_PTHREAD_COND);
  }
  return (__PO_HI_SUCCESS);
778
779
#endif
  return (__PO_HI_UNAVAILABLE);
780
}
781
782
783
784
785
786
787
788
789

void __po_hi_tasks_killall ()
{
   int i;
   for (i = 0; i < __PO_HI_NB_TASKS; i++)
    {
       __DEBUGMSG ("Kill task %d\n", i);
#ifdef RTEMS_PURE
      rtems_task_delete (tasks[i].rtems_id);
790
#elif defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
791
      pthread_cancel (tasks[i].tid);
792
      __DEBUGMSG ("[TASKS] Cancel thread %p\n", tasks[i].tid);
793
794
795
#endif
    }
}