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)
Antonia Francis's avatar
Antonia Francis 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