po_hi_main.c 12.4 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) 2010-2016 ESA & ISAE.
9
10
 */

11

12
13
#include <deployment.h>
/* included files from the generated code */
14
#include <po_hi_time.h>
15
#include <po_hi_config.h>
jdelange's avatar
jdelange committed
16
#include <po_hi_common.h>
17
#include <po_hi_returns.h>
jdelange's avatar
jdelange committed
18
#include <po_hi_monitor.h>
19
#include <po_hi_task.h>
20
#include <po_hi_debug.h>
21
#include <po_hi_protected.h>
22
#include <po_hi_utils.h>
23
/* included files from PolyORB-HI-C */
24

25
#if defined (MONITORING)
yoogx's avatar
yoogx committed
26
#include <trace_manager.h>
27
28
29
#endif
/* Headers from run-time verification */

30
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
31
32
33
#include <pthread.h>
/* POSIX files */

34
35
pthread_cond_t cond_init;
pthread_mutex_t mutex_init;
36
#endif
37

38
#if defined (RTEMS_POSIX) || defined (__PO_HI_RTEMS_CLASSIC_API)
jdelange's avatar
jdelange committed
39
40
41
42
#include <rtems.h>
#include <rtems/rtems/clock.h>
#endif

43
#ifdef __PO_HI_RTEMS_CLASSIC_API
44
45
46
rtems_id __po_hi_main_initialization_barrier;
#endif

jdelange's avatar
jdelange committed
47
48
49
50
51
#ifdef _WIN32
CRITICAL_SECTION __po_hi_main_initialization_critical_section;
HANDLE           __po_hi_main_initialization_event;
#endif

52
53
54
55
56
#if defined (XENO_NATIVE)
#include <native/cond.h>
#include <native/mutex.h>
RT_COND   cond_init;
RT_MUTEX  mutex_init;
57
58
59
60
61
62
63
64
65
66

RT_TASK*  main_task_id;
/*
 * If we use the XENO_NATIVE skin, then, the main task
 * is considered as non real-time and cannot lock
 * mutexes that are used by real-time threads.
 * Then, we need to differenciate operations
 * between the main task and the other tasks.
 *
 * For that reason, the main task does not wait for
67
 * the initialization of the other tasks. The
68
69
70
71
72
73
74
75
76
77
78
 * __po_hi_wait_initialization just passes when it is
 * called from the main task. To do that, we need
 * to differentiate the main task from the other,
 * we do that by getting the main task descriptor
 * address in the main_task_id variable.
 *
 * Moreover, when using the XENO_NATIVE API, we
 * remove one task to initialize (the main task).
 * Only generated/created tasks wait for their mutual
 * initialization.
 */
79
80
#endif

81
int __po_hi_initialized_tasks = 0;
julien.delange's avatar
julien.delange committed
82
/* The barrier is initialized with __PO_HI_NB_TASKS +1
83
84
85
86
87
 * members, because the main function must pass the barrier.
 *
 * Be careful: for the XENO_NATIVE API, we decrement
 * the __po_hi_nb_tasks_to_init variable since the main task
 * does not wait for the other tasks to be initialized.
julien.delange's avatar
julien.delange committed
88
 */
89
int __po_hi_nb_tasks_to_init = __PO_HI_NB_TASKS + 1;
90

91
92
void __po_hi_initialize_add_task ()
{
93
      __DEBUGMSG ("[MAIN] Add a task to initialize\n");
94
      __po_hi_nb_tasks_to_init++;
95
96
}

97

98
int __po_hi_initialize_early ()
99
{
100

101
102
#if defined (XENO_POSIX) || defined (XENO_NATIVE)
   /*
103
    * Once initialization has been done, we avoid ALL
104
105
106
107
108
    * potential paging operations that can introduce
    * some indeterministic timing behavior.
    */

   #include <sys/mman.h>
109
   mlockall (MCL_CURRENT|MCL_FUTURE);
110
111
#endif

112
113
#if defined (XENO_NATIVE)
   main_task_id = rt_task_self ();
114

115
116
117
118
119
120
121
122
123
124
   __po_hi_nb_tasks_to_init--;
   /*
    * If we are using the XENO_NATIVE skin, we need
    * to differentiate the main task (that is non real-time)
    * from the others since the main task cannot use
    * the services and operates on resources of real-time tasks.
    * In addition, we decrement the amount of tasks to
    * initialize since the main task does not wait
    * for the initialization of the other tasks.
    */
125
#endif
126
127

#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
128
129
130
131
132
133
   pthread_mutexattr_t mutex_attr;
   if (pthread_mutexattr_init (&mutex_attr) != 0)
   {
      __DEBUGMSG ("[MAIN] Unable to init mutex attributes\n");
   }

julien.delange's avatar
julien.delange committed
134
#ifdef RTEMS_POSIX
135
136
137
138
   if (pthread_mutexattr_setprioceiling (&mutex_attr, 50) != 0)
   {
      __DEBUGMSG ("[MAIN] Unable to set priority ceiling on mutex\n");
   }
julien.delange's avatar
julien.delange committed
139
#endif
140
141

   if (pthread_mutex_init (&mutex_init, &mutex_attr) != 0 )
142
    {
143
      __DEBUGMSG ("[MAIN] Unable to init pthread_mutex\n");
144
145
146
      return (__PO_HI_ERROR_PTHREAD_MUTEX);
    }

147
  __DEBUGMSG ("[MAIN] Have %d tasks to init\n", __po_hi_nb_tasks_to_init);
148
149
150
151
152

  if (pthread_cond_init (&cond_init, NULL) != 0)
  {
     return (__PO_HI_ERROR_PTHREAD_COND);
  }
153
154
#endif

155
156
157
158
159
160
161
162
163
164
165
166
167
168
#if defined (XENO_NATIVE)
   if (rt_cond_create (&cond_init, NULL))
   {
      __DEBUGMSG ("[MAIN] Unable to init the initialization condition variable \n");
      return (__PO_HI_ERROR_PTHREAD_MUTEX);
   }

  if (rt_mutex_create (&mutex_init, NULL) != 0)
  {
      __DEBUGMSG ("[MAIN] Unable to init the initialization mutex variable \n");
     return (__PO_HI_ERROR_PTHREAD_COND);
  }
#endif

169

170
#if defined (RTEMS_POSIX) || defined (__PO_HI_RTEMS_CLASSIC_API)
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  rtems_status_code ret;
  rtems_time_of_day time;

  time.year   = 1988;
  time.month  = 12;
  time.day    = 31;
  time.hour   = 9;
  time.minute = 1;
  time.second = 10;
  time.ticks  = 0;

  ret = rtems_clock_set( &time );
  if (ret != RTEMS_SUCCESSFUL)
  {
     __DEBUGMSG ("[MAIN] Cannot set the clock\n");
     return __PO_HI_ERROR_CLOCK;
  }
188
189
#endif

190
#ifdef __PO_HI_RTEMS_CLASSIC_API
191
  __DEBUGMSG ("[MAIN] Create a barrier that wait for %d tasks\n", __po_hi_nb_tasks_to_init);
192

193
  ret = rtems_barrier_create (rtems_build_name ('B', 'A', 'R', 'M'), RTEMS_BARRIER_AUTOMATIC_RELEASE, __po_hi_nb_tasks_to_init, &__po_hi_main_initialization_barrier);
194
195
196
197
  if (ret != RTEMS_SUCCESSFUL)
  {
     __DEBUGMSG ("[MAIN] Cannot create the main barrier, return code=%d\n", ret);
  }
198
#endif
199

jdelange's avatar
jdelange committed
200
201
202
203
204
#ifdef _WIN32
   __po_hi_main_initialization_event = CreateEvent (NULL, FALSE, FALSE, NULL);
   InitializeCriticalSection (&__po_hi_main_initialization_critical_section);
#endif

205
206
207
208
209
210
211
  __po_hi_initialize_tasking ();

  /* Initialize protected objects */
#if __PO_HI_NB_PROTECTED > 0
  __po_hi_protected_init();
#endif

jdelange's avatar
jdelange committed
212
213
214
215
#if __PO_HI_MONITOR_ENABLED == 1
  __po_hi_monitor_init ();
#endif

216
217
218
219
220
221
222
223
224
225
   return (__PO_HI_SUCCESS);
}

/*
 * The __po_hi_initialize function is only called
 * by the main thread (the one that executes the traditional
 * main() function.
 */
int __po_hi_initialize ()
{
jdelange's avatar
jdelange committed
226
#if (defined (XM3_RTEMS_MODE) && (__PO_HI_NB_PORTS > 0))
227
228
   #include <deployment.h>
   #include <po_hi_types.h>
229
   #include <po_hi_transport.h>
230
231
   #include <xm.h>

232
   __po_hi_port_kind_t        pkind;
233
234
235
236
   __po_hi_port_t             tmp;
   __po_hi_node_t             tmpnode;
   __po_hi_node_t             mynode;
   int                        portno;
237

238
   mynode = __po_hi_transport_get_mynode ();
239
240
241

   for (tmp = 0 ; tmp < __PO_HI_NB_PORTS ; tmp++)
   {
242
243
244
245
246
247
248
      pkind = __po_hi_transport_get_port_kind (tmp);
      tmpnode = __po_hi_transport_get_node_from_entity (__po_hi_get_entity_from_global_port (tmp));
      if ((tmpnode == mynode) &&
          ( (pkind ==  __PO_HI_IN_DATA_INTER_PROCESS)          ||
            (pkind ==  __PO_HI_OUT_DATA_INTER_PROCESS)         ||
            (pkind ==  __PO_HI_IN_EVENT_DATA_INTER_PROCESS)    ||
            (pkind ==  __PO_HI_OUT_EVENT_DATA_INTER_PROCESS)
249
250
251
          ))
      {
         __DEBUGMSG ("[MAIN] Should init port %d\n", tmp);
252
253
         portno = -1;
         switch (pkind)
254
255
         {
            case __PO_HI_IN_DATA_INTER_PROCESS:
256
               portno = XM_create_sampling_port (__po_hi_transport_get_model_name (tmp), __po_hi_transport_get_queue_size (tmp), XM_DESTINATION_PORT);
257
258
259
               break;

            case __PO_HI_OUT_DATA_INTER_PROCESS:
260
               portno = XM_create_sampling_port (__po_hi_transport_get_model_name (tmp), __po_hi_transport_get_queue_size (tmp), XM_SOURCE_PORT);
261
262
263
               break;

            case __PO_HI_IN_EVENT_DATA_INTER_PROCESS:
264
               portno = XM_create_queuing_port (__po_hi_transport_get_model_name (tmp), __po_hi_transport_get_queue_size (tmp), __po_hi_transport_get_data_size (tmp), XM_DESTINATION_PORT);
265
266
267
               break;

            case __PO_HI_OUT_EVENT_DATA_INTER_PROCESS:
268
               portno = XM_create_queuing_port (__po_hi_transport_get_model_name (tmp), __po_hi_transport_get_queue_size (tmp), __po_hi_transport_get_data_size (tmp), XM_SOURCE_PORT);
269
270
271
272
273
274
275
               break;

            default:
               __DEBUGMSG ("[MAIN] Port kind not handled at this time for port %d\n", tmp);
               break;
         }

276
277
278
279
280
281
282
283
284
285
         if (portno < 0)
         {
               __DEBUGMSG ("[MAIN] Cannot open port %d, name=%s, return=%d\n", tmp, __po_hi_transport_get_model_name (tmp), portno);
         }
         else
         {
               __po_hi_transport_xtratum_port_init (tmp, portno);
               __DEBUGMSG ("[MAIN] Port %d (name=%s) created, identifier = %d\n", tmp, __po_hi_transport_get_model_name (tmp), portno);
         }

286
287
288
      }
   }
#endif
289

290
291
292
   /*!
    * Initialize the monitoring trace if needed
    */
293
#if defined (MONITORING)
294
   trace_initialize ();
295
296
#endif

297
   return (__PO_HI_SUCCESS);
298
299
}

300
int __po_hi_wait_initialization (void)
301
{
302

303
#if defined (POSIX) || defined (RTEMS_POSIX) || defined (XENO_POSIX)
304
305
306
307
308
309
310
311
312
313
314
   int cstate;
   if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &cstate) != 0)
   {
      __DEBUGMSG ("[MAIN] Cannot modify the cancel state\n");
   }

   if (pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &cstate) != 0)
   {
      __DEBUGMSG ("[MAIN] Cannot modify the cancel type\n");
   }

315
  if (pthread_mutex_lock (&mutex_init) != 0)
316
  {
317
    __DEBUGMSG ("[MAIN] Unable to lock the mutex\n");
318
    return (__PO_HI_ERROR_PTHREAD_MUTEX);
319
  }
320

321
  __po_hi_initialized_tasks++;
322

323
  __DEBUGMSG ("[MAIN] %d task(s) initialized (total to init =%d)\n", __po_hi_initialized_tasks, __po_hi_nb_tasks_to_init);
324

325
326
  if (__po_hi_initialized_tasks < __po_hi_nb_tasks_to_init) {
    while (__po_hi_initialized_tasks < __po_hi_nb_tasks_to_init) {
327
      pthread_cond_wait (&cond_init, &mutex_init);
328
    }
329
  }
330
331
332
333
334
  else {
    pthread_cond_broadcast (&cond_init);
    set_epoch();
  }

335
  pthread_mutex_unlock (&mutex_init);
336
337
338

   __PO_HI_INSTRUMENTATION_VCD_INIT

339
  return (__PO_HI_SUCCESS);
yoogx's avatar
yoogx committed
340

jdelange's avatar
jdelange committed
341
342
343
344
345
346
#elif defined (_WIN32)
   EnterCriticalSection (&__po_hi_main_initialization_critical_section);

  __po_hi_initialized_tasks++;

  __DEBUGMSG ("[MAIN] %d task(s) initialized (total to init =%d)\n", __po_hi_initialized_tasks, __po_hi_nb_tasks_to_init);
347

jdelange's avatar
jdelange committed
348
349
350
  while (__po_hi_initialized_tasks < __po_hi_nb_tasks_to_init)
  {
      LeaveCriticalSection (&__po_hi_main_initialization_critical_section);
351
      WaitForSingleObject (__po_hi_main_initialization_event, INFINITE);
jdelange's avatar
jdelange committed
352
353
354
355
356
357
358
      EnterCriticalSection (&__po_hi_main_initialization_critical_section);
  }

  SetEvent (__po_hi_main_initialization_event);
  LeaveCriticalSection (&__po_hi_main_initialization_critical_section);
  return (__PO_HI_SUCCESS);

359
#elif defined (__PO_HI_RTEMS_CLASSIC_API)
360
361
362
363
364
365
366
367
368
369
370
  rtems_status_code ret;

  __DEBUGMSG ("[MAIN] Task wait for the barrier\n");
  ret = rtems_barrier_wait (__po_hi_main_initialization_barrier, RTEMS_WAIT);
  if (ret != RTEMS_SUCCESSFUL)
  {
     __DEBUGMSG ("[MAIN] Error while waiting for the barrier, return code=%d\n", ret);
     return (__PO_HI_ERROR_UNKNOWN);
  }
  __DEBUGMSG ("[MAIN] Task release the barrier\n");
  return (__PO_HI_SUCCESS);
371
372
#elif defined (XENO_NATIVE)
  int ret;
373
374
375
376
377
378
379
380
381
382
383
384

  if (main_task_id == rt_task_self ())
  {
     /*
      * Here, this function is called by the main thread (the one that executes
      * the main() function) so that we don't wait for the initialization of the
      * other tasks, we automatically pass through the function and immeditaly
      * return.
      */
     return (__PO_HI_SUCCESS);
  }

385
386
387
388
389
390
391
  ret = rt_mutex_acquire (&mutex_init, TM_INFINITE);
  if (ret != 0)
  {
   __DEBUGMSG ("[MAIN] Cannot acquire mutex (return code = %d)\n", ret);
    return (__PO_HI_ERROR_PTHREAD_MUTEX);
  }

392
  __po_hi_initialized_tasks++;
393

394
  __DEBUGMSG ("[MAIN] %d task(s) initialized (total to init =%d)\n", __po_hi_initialized_tasks, __po_hi_nb_tasks_to_init);
395

396
  while (__po_hi_initialized_tasks < __po_hi_nb_tasks_to_init)
397
398
399
400
401
402
403
  {
      rt_cond_wait (&cond_init, &mutex_init, TM_INFINITE);
  }
  rt_cond_broadcast (&cond_init);
  rt_mutex_release (&mutex_init);
  return (__PO_HI_SUCCESS);

404
405
406
#else
  return (__PO_HI_UNAVAILABLE);
#endif
407
}
408
409
410
411

#ifdef __PO_HI_USE_GPROF
void __po_hi_wait_end_of_instrumentation ()
{
412
#ifdef __PO_HI_RTEMS_CLASSIC_API
413
   rtems_task_wake_after (10000000 / _TOD_Microseconds_per_tick);
414
#else
415
   #include <po_hi_time.h>
416
   #include <unistd.h>
417

418
   __po_hi_time_t now;
jdelange's avatar
jdelange committed
419
420
   __po_hi_time_t ten_secs;
   __po_hi_time_t time_to_wait;
421
   __po_hi_get_time (&now);
jdelange's avatar
jdelange committed
422
423
424
   __po_hi_seconds (&ten_secs, 10);
   __po_hi_add_times (&time_to_wait, &ten_secs, &now);
   __po_hi_delay_until (&time_to_wait);
425
#endif
426
  __DEBUGMSG ("Call exit()\n");
427
  __po_hi_tasks_killall ();
428
429
430
   exit (1);

  __DEBUGMSG ("exit() called\n");
431
#ifdef __PO_HI_RTEMS_CLASSIC_API
432
433
  rtems_task_delete (rtems_self ());
#endif
434
435
}
#endif