intertask_interface.cpp 19.4 KB
Newer Older
laurent's avatar
laurent committed
1
/*
laurent's avatar
laurent committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1  (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.openairinterface.org/?page_id=698
*
* Author and copyright: Laurent Thomas, open-cells.com
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
*      contact@openairinterface.org
laurent's avatar
laurent committed
22
*/
laurent's avatar
laurent committed
23

laurent's avatar
laurent committed
24 25 26
#include <vector>
#include <map>
#include <sys/eventfd.h>
27
#include <semaphore.h>
laurent's avatar
laurent committed
28 29


laurent's avatar
laurent committed
30
extern "C" {
laurent's avatar
laurent committed
31
#include <intertask_interface.h>
laurent's avatar
laurent committed
32
#include <common/utils/system.h>
33
#include "executables/softmodem-common.h"
laurent's avatar
laurent committed
34

35 36 37 38 39 40 41
typedef struct timer_elm_s {
  timer_type_t type; ///< Timer type
  long instance;
  long duration;
  uint64_t timeout;
  void *timer_arg; ///< Optional argument that will be passed when timer expires
} timer_elm_t;
42 43 44

  typedef struct task_list_s {
    task_info_t admin;
45
    ittiTask_parms_t task_parms;
46 47 48 49 50 51 52 53
    pthread_t thread;
    pthread_mutex_t queue_cond_lock;
    std::vector<MessageDef *> message_queue;
    std::map<long,timer_elm_t> timer_map;
    uint64_t next_timer=UINT64_MAX;
    int nb_fd_epoll=0;
    int epoll_fd=-1;
    int sem_fd=-1;
54
    size_t last_log_size = 0;
55 56 57
  } task_list_t;

  int timer_expired(int fd);
Laurent's avatar
Laurent committed
58
  static task_list_t **tasks=NULL;
59 60
  static int nb_queues=0;
  static pthread_mutex_t lock_nb_queues;
laurent's avatar
laurent committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

  void *pool_buffer_init (void) {
    return 0;
  }

  void *pool_buffer_clean (void *arg) {
    //-----------------------------------------------------------------------------
    return 0;
  }

  void free_mem_block (mem_block_t *leP, const char *caller) {
    AssertFatal(leP!=NULL,"");
    free(leP);
  }

  mem_block_t *get_free_mem_block (uint32_t sizeP, const char *caller) {
    mem_block_t *ptr=(mem_block_t *)malloc(sizeP+sizeof(mem_block_t));
78 79
    ptr->next = NULL;
    ptr->previous = NULL;
laurent's avatar
laurent committed
80 81 82 83 84 85 86
    ptr->data=((unsigned char *)ptr)+sizeof(mem_block_t);
    ptr->size=sizeP;
    return ptr;
  }

  void *itti_malloc(task_id_t origin_task_id, task_id_t destination_task_id, ssize_t size) {
    void *ptr = NULL;
Laurent's avatar
Laurent committed
87
    AssertFatal ((ptr=calloc (size, 1)) != NULL, "Memory allocation of %zu bytes failed (%d -> %d)!\n",
laurent's avatar
laurent committed
88 89 90 91 92 93 94 95 96 97
                 size, origin_task_id, destination_task_id);
    return ptr;
  }

  int itti_free(task_id_t task_id, void *ptr) {
    AssertFatal (ptr != NULL, "Trying to free a NULL pointer (%d)!\n", task_id);
    free (ptr);
    return (EXIT_SUCCESS);
  }

98 99 100 101 102 103 104 105
  // in the two following functions, the +32 in malloc is there to deal with gcc memory alignment
  // because a struct size can be larger than sum(sizeof(struct components))
  // We should remove the itti principle of a huge union for all types of messages in paramter "msg_t ittiMsg"
  // to use a more C classical pointer casting "void * ittiMsg", later casted in the right struct
  // but we would have to change all legacy macros, as per this example
  // #define S1AP_REGISTER_ENB_REQ(mSGpTR)           (mSGpTR)->ittiMsg.s1ap_register_enb_req
  // would become
  // #define S1AP_REGISTER_ENB_REQ(mSGpTR)           (s1ap_register_enb_req) mSGpTR)->ittiMsg
106
  MessageDef *itti_alloc_new_message_sized(task_id_t origin_task_id, instance_t originInstance, MessagesIds message_id, MessageHeaderSize size) {
107
    MessageDef *temp = (MessageDef *)itti_malloc (origin_task_id, TASK_UNKNOWN, sizeof(MessageHeader) +32 + size);
laurent's avatar
laurent committed
108 109 110 111 112 113
    temp->ittiMsgHeader.messageId = message_id;
    temp->ittiMsgHeader.originTaskId = origin_task_id;
    temp->ittiMsgHeader.ittiMsgSize = size;
    return temp;
  }

114
  MessageDef *itti_alloc_new_message(task_id_t origin_task_id, instance_t originInstance, MessagesIds message_id) {
115
    int size=sizeof(MessageHeader) + 32 + messages_info[message_id].size;
laurent's avatar
laurent committed
116 117 118 119
    MessageDef *temp = (MessageDef *)itti_malloc (origin_task_id, TASK_UNKNOWN, size);
    temp->ittiMsgHeader.messageId = message_id;
    temp->ittiMsgHeader.originTaskId = origin_task_id;
    temp->ittiMsgHeader.ittiMsgSize = size;
laurent's avatar
laurent committed
120
    temp->ittiMsgHeader.destinationTaskId=TASK_UNKNOWN;
121 122 123
    temp->ittiMsgHeader.originInstance=originInstance;
    temp->ittiMsgHeader.destinationInstance=0;
    temp->ittiMsgHeader.lte_time= {0};
laurent's avatar
laurent committed
124 125 126 127
    return temp;
    //return itti_alloc_new_message_sized(origin_task_id, message_id, messages_info[message_id].size);
  }

128
  static inline int itti_send_msg_to_task_locked(task_id_t destination_task_id, instance_t destinationInstance, MessageDef *message) {
Laurent's avatar
Laurent committed
129
    task_list_t *t=tasks[destination_task_id];
laurent's avatar
laurent committed
130
    message->ittiMsgHeader.destinationTaskId = destination_task_id;
131
    message->ittiMsgHeader.destinationInstance = destinationInstance;
laurent's avatar
laurent committed
132 133 134 135 136
    message->ittiMsgHeader.lte_time.frame = 0;
    message->ittiMsgHeader.lte_time.slot = 0;
    int message_id = message->ittiMsgHeader.messageId;
    size_t s=t->message_queue.size();

137
    // to reduce the number of logs, we give a message each increase of 25%
138 139 140 141 142 143 144 145 146 147
    if ((s > t->last_log_size * 1.25) && (s > t->admin.queue_size / 10)) {
      if (s > t->admin.queue_size) {
        LOG_E(TMR, "Queue for %s task contains %ld messages\n", itti_get_task_name(destination_task_id), s);
      } else {
        LOG_I(ITTI,
              "Queue for %s task size: %ld (last message %s)\n",
              itti_get_task_name(destination_task_id),
              s + 1,
              ITTI_MSG_NAME(message));
      }
Laurent THOMAS's avatar
Laurent THOMAS committed
148
      t->last_log_size = s;
149
    } else if (t->last_log_size && s < t->admin.queue_size / 10) {
150 151 152 153
      // Inform when the queue decreases
      LOG_I(ITTI, "Queue for %s task size is back under 10%% of max size\n", itti_get_task_name(destination_task_id));
      t->last_log_size = 0;
    }
laurent's avatar
laurent committed
154 155 156 157

    t->message_queue.insert(t->message_queue.begin(), message);
    eventfd_t sem_counter = 1;
    AssertFatal ( sizeof(sem_counter) == write(t->sem_fd, &sem_counter, sizeof(sem_counter)), "");
laurent's avatar
laurent committed
158
    LOG_D(ITTI, "sent messages id=%s messages_info to %s\n", messages_info[message_id].name, t->admin.name);
laurent's avatar
laurent committed
159 160 161
    return 0;
  }

162
  int itti_send_msg_to_task(task_id_t destination_task_id, instance_t destinationInstance, MessageDef *message) {
Laurent's avatar
Laurent committed
163
    task_list_t *t=tasks[destination_task_id];
laurent's avatar
laurent committed
164
    pthread_mutex_lock (&t->queue_cond_lock);
165
    int ret=itti_send_msg_to_task_locked(destination_task_id, destinationInstance, message);
laurent's avatar
laurent committed
166

167
    while (t->message_queue.size() > 0 && t->task_parms.shortcut_func != NULL) {
laurent's avatar
laurent committed
168
      if (t->message_queue.size()>1)
169
        LOG_W(ITTI,"queue in no thread mode is %ld\n", t->message_queue.size());
170

laurent's avatar
laurent committed
171
      pthread_mutex_unlock (&t->queue_cond_lock);
172
      t->task_parms.shortcut_func(NULL);
173
      pthread_mutex_lock (&t->queue_cond_lock);
174
    }
175

176
    pthread_mutex_unlock (&t->queue_cond_lock);
laurent's avatar
laurent committed
177 178 179 180 181
    return ret;
  }

  void itti_subscribe_event_fd(task_id_t task_id, int fd) {
    struct epoll_event event;
Laurent's avatar
Laurent committed
182
    task_list_t *t=tasks[task_id];
laurent's avatar
laurent committed
183 184 185 186 187 188 189
    t->nb_fd_epoll++;
    event.events  = EPOLLIN | EPOLLERR;
    event.data.u64 = 0;
    event.data.fd  = fd;
    AssertFatal(epoll_ctl(t->epoll_fd, EPOLL_CTL_ADD, fd, &event) == 0,
                "epoll_ctl (EPOLL_CTL_ADD) failed for task %s, fd %d: %s!\n",
                itti_get_task_name(task_id), fd, strerror(errno));
190 191
    eventfd_t sem_counter = 1;
    AssertFatal ( sizeof(sem_counter) == write(t->sem_fd, &sem_counter, sizeof(sem_counter)), "");
laurent's avatar
laurent committed
192 193 194
  }

  void itti_unsubscribe_event_fd(task_id_t task_id, int fd) {
Laurent's avatar
Laurent committed
195
    task_list_t *t=tasks[task_id];
laurent's avatar
laurent committed
196 197 198 199 200 201
    AssertFatal (epoll_ctl(t->epoll_fd, EPOLL_CTL_DEL, fd, NULL) == 0,
                 "epoll_ctl (EPOLL_CTL_DEL) failed for task %s, fd %d: %s!\n",
                 itti_get_task_name(task_id), fd, strerror(errno));
    t->nb_fd_epoll--;
  }

202
  static inline int itti_get_events_locked(task_id_t task_id, struct epoll_event *events, int max_events) {
Laurent's avatar
Laurent committed
203
    task_list_t *t=tasks[task_id];
laurent's avatar
laurent committed
204
    uint64_t current_time=0;
205
    int nb_events;
laurent's avatar
laurent committed
206 207 208 209 210 211 212 213 214 215
    do {
      if ( t->next_timer != UINT64_MAX ) {
        struct timespec tp;
        clock_gettime(CLOCK_MONOTONIC, &tp);
        current_time=(uint64_t)tp.tv_sec*1000+tp.tv_nsec/(1000*1000);

        if ( t->next_timer < current_time) {
          t->next_timer=UINT64_MAX;

          // Proceed expired timer
216
          for ( auto it=t->timer_map.begin(), next_it = it; it != t->timer_map.end() ; it = next_it ) {
Laurent's avatar
Laurent committed
217
            ++next_it;
218

laurent's avatar
laurent committed
219
            if ( it->second.timeout < current_time ) {
220
              MessageDef *message = itti_alloc_new_message(TASK_TIMER, it->second.instance,TIMER_HAS_EXPIRED);
laurent's avatar
laurent committed
221 222 223 224
              message->ittiMsg.timer_has_expired.timer_id=it->first;
              message->ittiMsg.timer_has_expired.arg=it->second.timer_arg;

              if (itti_send_msg_to_task_locked(task_id, it->second.instance, message) < 0) {
225
                LOG_W(ITTI,"Failed to send msg TIMER_HAS_EXPIRED to task %u\n", task_id);
laurent's avatar
laurent committed
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
                free(message);
                t->timer_map.erase(it);
                return -1;
              }

              if ( it->second.type==TIMER_PERIODIC ) {
                it->second.timeout+=it->second.duration;

                if (it->second.timeout < t->next_timer)
                  t->next_timer=it->second.timeout;
              } else
                t->timer_map.erase(it);
            } else if (it->second.timeout < t->next_timer)
              t->next_timer=it->second.timeout;
          }
        }
      }

      int epoll_timeout = -1;

      if ( t->next_timer != UINT64_MAX )
        epoll_timeout = t->next_timer-current_time;

      pthread_mutex_unlock(&t->queue_cond_lock);
250
      LOG_D(ITTI,"enter blocking wait for %s, timeout: %d ms\n", itti_get_task_name(task_id),  epoll_timeout);
251
      nb_events = epoll_wait(t->epoll_fd, events, max_events, epoll_timeout);
252

laurent's avatar
laurent committed
253
      if ( nb_events  < 0 && (errno == EINTR || errno == EAGAIN ) )
254
        pthread_mutex_lock(&t->queue_cond_lock);
laurent's avatar
laurent committed
255
    } while (nb_events  < 0 && (errno == EINTR || errno == EAGAIN ) );
laurent's avatar
laurent committed
256

laurent's avatar
laurent committed
257
    AssertFatal (nb_events >=0,
laurent's avatar
laurent committed
258
                 "epoll_wait failed for task %s, nb fds %d, timeout %lu: %s!\n",
259 260 261
                 itti_get_task_name(task_id), t->nb_fd_epoll, 
                 t->next_timer != UINT64_MAX ? t->next_timer-current_time : -1, 
                 strerror(errno));
laurent's avatar
laurent committed
262
    LOG_D(ITTI,"receive on %d descriptors for %s\n", nb_events, itti_get_task_name(task_id));
laurent's avatar
laurent committed
263

laurent's avatar
laurent committed
264
    if (nb_events == 0)
laurent's avatar
laurent committed
265 266 267
      /* No data to read -> return */
      return 0;

laurent's avatar
laurent committed
268
    for (int i = 0; i < nb_events; i++) {
laurent's avatar
laurent committed
269
      /* Check if there is an event for ITTI for the event fd */
laurent's avatar
laurent committed
270 271
      if ((events[i].events & EPOLLIN) &&
          (events[i].data.fd == t->sem_fd)) {
laurent's avatar
laurent committed
272 273 274 275
        eventfd_t   sem_counter;
        /* Read will always return 1 */
        AssertFatal( sizeof(sem_counter) == read (t->sem_fd, &sem_counter, sizeof(sem_counter)), "");
        /* Mark that the event has been processed */
laurent's avatar
laurent committed
276
        events[i].events &= ~EPOLLIN;
laurent's avatar
laurent committed
277 278 279
      }
    }

laurent's avatar
laurent committed
280
    return nb_events;
laurent's avatar
laurent committed
281 282
  }

laurent's avatar
laurent committed
283
  int itti_get_events(task_id_t task_id, struct epoll_event *events, int nb_evts) {
Laurent's avatar
Laurent committed
284
    pthread_mutex_lock(&tasks[task_id]->queue_cond_lock);
laurent's avatar
laurent committed
285
    return itti_get_events_locked(task_id, events, nb_evts);
laurent's avatar
laurent committed
286 287 288 289
  }

  void itti_receive_msg(task_id_t task_id, MessageDef **received_msg) {
    // Reception of one message, blocking caller
Laurent's avatar
Laurent committed
290
    task_list_t *t=tasks[task_id];
laurent's avatar
laurent committed
291 292
    pthread_mutex_lock(&t->queue_cond_lock);

laurent's avatar
laurent committed
293
    struct epoll_event events[t->nb_fd_epoll];
laurent's avatar
laurent committed
294
    // Weird condition to deal with crap legacy itti interface
295 296
    if (t->message_queue.empty()) {
      do {
laurent's avatar
laurent committed
297
        itti_get_events_locked(task_id, events, t->nb_fd_epoll);
laurent's avatar
laurent committed
298 299
        pthread_mutex_lock(&t->queue_cond_lock);
      }
300
      while (t->message_queue.empty() && t->nb_fd_epoll == 1);
laurent's avatar
laurent committed
301 302 303 304 305 306
    }

    // Legacy design: we return even if we have no message
    // in this case, *received_msg is NULL
    if (t->message_queue.empty()) {
      *received_msg=NULL;
307
      LOG_D(ITTI,"task %s received even from other fd (total fds: %d), returning msg NULL\n",t->admin.name, t->nb_fd_epoll);
laurent's avatar
laurent committed
308 309 310
    } else {
      *received_msg=t->message_queue.back();
      t->message_queue.pop_back();
311
      LOG_D(ITTI,"task %s received a message\n",t->admin.name);
laurent's avatar
laurent committed
312 313 314 315 316
    }

    pthread_mutex_unlock (&t->queue_cond_lock);
  }

317
  void itti_poll_msg(task_id_t task_id, MessageDef **received_msg) {
laurent's avatar
laurent committed
318
    //reception of one message, non-blocking
Laurent's avatar
Laurent committed
319
    task_list_t *t=tasks[task_id];
laurent's avatar
laurent committed
320 321 322
    pthread_mutex_lock(&t->queue_cond_lock);

    if (!t->message_queue.empty()) {
323
      LOG_D(ITTI,"task %s received a message in polling mode\n",t->admin.name);
laurent's avatar
laurent committed
324 325 326 327 328 329 330 331
      *received_msg=t->message_queue.back();
      t->message_queue.pop_back();
    } else
      *received_msg=NULL;

    pthread_mutex_unlock (&t->queue_cond_lock);
  }

332 333
  int itti_create_task(const task_id_t task_id, void *(*start_routine)(void *), const ittiTask_parms_t *parms)
  {
Laurent's avatar
Laurent committed
334
    task_list_t *t=tasks[task_id];
335 336 337 338 339 340 341 342 343 344 345
    if (get_softmodem_params()->no_itti && task_id < sizeofArray(tasks_info) && parms && parms->shortcut_func) {
      LOG_W(ITTI, "not starting the thread for %s, the msg processing will be done in place\n", tasks_info[task_id].name);
      t->task_parms.shortcut_func = parms->shortcut_func;
      return 0;
    }
    threadCreate(&t->thread,
                 start_routine,
                 parms ? parms->args_to_start_routine : NULL,
                 (char *)itti_get_task_name(task_id),
                 -1,
                 OAI_PRIORITY_RT);
346
    LOG_I(ITTI,"Created Posix thread %s\n",  itti_get_task_name(task_id) );
laurent's avatar
laurent committed
347 348 349 350 351 352 353
    return 0;
  }

  void itti_exit_task(void) {
    pthread_exit (NULL);
  }

354
  void itti_terminate_tasks(task_id_t task_id) {
laurent's avatar
laurent committed
355 356
    // Sends Terminate signals to all tasks.
    itti_send_terminate_message (task_id);
357
    usleep(100*1000); // Allow the tasks to receive the message before going returning to main thread
laurent's avatar
laurent committed
358 359
  }

Laurent Thomas's avatar
Laurent Thomas committed
360
  int itti_create_queue(const task_info_t *taskInfo) {
361
    pthread_mutex_lock (&lock_nb_queues);
Laurent's avatar
Laurent committed
362
    int newQueue=nb_queues++;
363 364 365
    task_list_t **new_tasks = (task_list_t **)realloc(tasks, nb_queues * sizeof(*tasks));
    AssertFatal(new_tasks != NULL, "could not realloc() tasks list");
    tasks = new_tasks;
Laurent's avatar
Laurent committed
366
    tasks[newQueue]= new task_list_t;
367
    tasks[newQueue]->task_parms = {0};
368
    pthread_mutex_unlock (&lock_nb_queues);
369
    LOG_I(ITTI,"Starting itti queue: %s as task %d\n", taskInfo->name, newQueue);
Laurent's avatar
Laurent committed
370
    pthread_mutex_init(&tasks[newQueue]->queue_cond_lock, NULL);
Laurent Thomas's avatar
Laurent Thomas committed
371
    memcpy(&tasks[newQueue]->admin, taskInfo, sizeof(task_info_t));
Laurent's avatar
Laurent committed
372 373 374 375
    AssertFatal( ( tasks[newQueue]->epoll_fd = epoll_create1(0) ) >=0, "");
    AssertFatal( ( tasks[newQueue]->sem_fd = eventfd(0, EFD_SEMAPHORE) ) >=0, "");
    itti_subscribe_event_fd((task_id_t)newQueue, tasks[newQueue]->sem_fd);

376
    return newQueue;
377 378
  }

379
  int itti_init(task_id_t task_max,
Laurent Thomas's avatar
Laurent Thomas committed
380 381
                const task_info_t *tasks
               ) {
382 383
    pthread_mutex_init(&lock_nb_queues, NULL);
    nb_queues=0;
laurent's avatar
laurent committed
384 385

    for(int i=0; i<task_max; ++i) {
Laurent Thomas's avatar
Laurent Thomas committed
386
      itti_create_queue(&tasks[i]);
laurent's avatar
laurent committed
387 388 389 390 391 392 393 394 395
    }

    return 0;
  }

  int timer_setup(
    uint32_t      interval_sec,
    uint32_t      interval_us,
    task_id_t     task_id,
396
    instance_t       instance,
laurent's avatar
laurent committed
397 398
    timer_type_t  type,
    void         *timer_arg,
399
    long         *timer_id) {
Laurent's avatar
Laurent committed
400
    task_list_t *t=tasks[task_id];
laurent's avatar
laurent committed
401 402 403 404 405 406 407 408 409 410 411 412 413

    do {
      // set the taskid in the timer id to keep compatible with the legacy API
      // timer_remove() takes only the timer id as parameter
      *timer_id=(random()%UINT16_MAX) << 16 | task_id ;
    } while ( t->timer_map.find(*timer_id) != t->timer_map.end());

    /* Allocate new timer list element */
    timer_elm_t timer;
    struct timespec tp;
    clock_gettime(CLOCK_MONOTONIC, &tp);

    if (interval_us%1000 != 0)
414
      LOG_W(ITTI, "Can't set timer precision below 1ms, rounding it\n");
laurent's avatar
laurent committed
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432

    timer.duration  = interval_sec*1000+interval_us/1000;
    timer.timeout= ((uint64_t)tp.tv_sec*1000+tp.tv_nsec/(1000*1000)+timer.duration);
    timer.instance  = instance;
    timer.type      = type;
    timer.timer_arg = timer_arg;
    pthread_mutex_lock (&t->queue_cond_lock);
    t->timer_map[*timer_id]= timer;

    if (timer.timeout < t->next_timer)
      t->next_timer=timer.timeout;

    eventfd_t sem_counter = 1;
    AssertFatal ( sizeof(sem_counter) == write(t->sem_fd, &sem_counter, sizeof(sem_counter)), "");
    pthread_mutex_unlock (&t->queue_cond_lock);
    return 0;
  }

433
  int timer_remove(long timer_id) {
laurent's avatar
laurent committed
434 435
    task_id_t task_id=(task_id_t)(timer_id&0xffff);
    int ret;
Laurent's avatar
Laurent committed
436 437 438
    pthread_mutex_lock (&tasks[task_id]->queue_cond_lock);
    ret=tasks[task_id]->timer_map.erase(timer_id);
    pthread_mutex_unlock (&tasks[task_id]->queue_cond_lock);
laurent's avatar
laurent committed
439 440 441 442

    if (ret==1)
      return 0;
    else {
443
      LOG_W(ITTI, "tried to remove a non existing timer\n");
laurent's avatar
laurent committed
444 445 446 447 448 449 450 451 452
      return 1;
    }
  }

  const char *itti_get_message_name(MessagesIds message_id) {
    return messages_info[message_id].name;
  }

  const char *itti_get_task_name(task_id_t task_id) {
Laurent's avatar
Laurent committed
453
    return tasks[task_id]->admin.name;
laurent's avatar
laurent committed
454 455 456 457 458 459
  }

  // void for compatibility
  void itti_send_terminate_message(task_id_t task_id) {
  }

460 461 462 463 464 465
  sem_t itti_sem_block;
  void itti_wait_tasks_unblock()
  {
    int rc = sem_post(&itti_sem_block);
    AssertFatal(rc == 0, "error in sem_post(): %d %s\n", errno, strerror(errno));
  }
466 467 468 469 470

  static void catch_sigterm(int) {
    static const char msg[] = "\n** Caught SIGTERM, shutting down\n";
    __attribute__((unused))
    int unused = write(STDOUT_FILENO, msg, sizeof(msg) - 1);
471
    itti_wait_tasks_unblock();
472 473
  }

474 475 476 477
  void itti_wait_tasks_end(void (*handler)(int))
  {
    int rc = sem_init(&itti_sem_block, 0, 0);
    AssertFatal(rc == 0, "error in sem_init(): %d %s\n", errno, strerror(errno));
478

479 480 481 482
    if (handler == NULL) /* no handler given: install default */
      handler = catch_sigterm;
    signal(SIGTERM, handler);
    signal(SIGINT, handler);
483

484 485
    rc = sem_wait(&itti_sem_block);
    AssertFatal(rc == 0, "error in sem_wait(): %d %s\n", errno, strerror(errno));
laurent's avatar
laurent committed
486 487 488 489 490 491 492 493 494 495 496
  }

  void itti_update_lte_time(uint32_t frame, uint8_t slot) {}
  void itti_set_task_real_time(task_id_t task_id) {}
  void itti_mark_task_ready(task_id_t task_id) {
    // Function meaning is clear, but legacy implementation is wrong
    // keep it void is fine: today implementation accepts messages in the queue before task is ready
  }
  void itti_wait_ready(int wait_tasks) {
    // Stupid function, kept for compatibility (the parameter is meaningless!!!)
  }
497 498 499
  int signal_mask(void) {
    return 0;
  }
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535

void log_scheduler(const char* label)
{
    int policy = sched_getscheduler(0);
    struct sched_param param;
    if (sched_getparam(0, &param) == -1)
    {
        LOG_E(HW, "sched_getparam: %s\n", strerror(errno));
        abort();
    }

    cpu_set_t cpu_set;
    if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) == -1)
    {
        LOG_E(HW, "sched_getaffinity: %s\n", strerror(errno));
        abort();
    }
    int num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
    if (num_cpus < 1)
    {
        LOG_E(HW, "sysconf(_SC_NPROCESSORS_ONLN): %s\n", strerror(errno));
        abort();
    }
    char buffer[num_cpus];
    for (int i = 0; i < num_cpus; i++)
    {
        buffer[i] = CPU_ISSET(i, &cpu_set) ? 'Y' : '-';
    }

    LOG_A(HW, "Scheduler policy=%d priority=%d affinity=[%d]%.*s label=%s\n",
          policy,
          param.sched_priority,
          num_cpus,
          num_cpus,
          buffer,
          label);
laurent's avatar
laurent committed
536
}
537
} // extern "C"
538