mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Moved ITTI into common/utils.
git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4236 818b1a75-f10b-46b9-bf7c-635c3b92a50f
This commit is contained in:
20
common/utils/itti/Makefile.am
Normal file
20
common/utils/itti/Makefile.am
Normal file
@@ -0,0 +1,20 @@
|
||||
AM_CFLAGS = @ADD_CFLAGS@ \
|
||||
-I$(top_srcdir)/UTILS \
|
||||
-I$(top_srcdir)/COMMON
|
||||
|
||||
noinst_LTLIBRARIES = libitti.la
|
||||
|
||||
libitti_la_LDFLAGS = -all-static
|
||||
libitti_la_SOURCES = \
|
||||
gtpv1_u_messages_def.h gtpv1_u_messages_types.h \
|
||||
nas_messages_def.h nas_messages_types.h \
|
||||
timer_messages_def.h timer_messages_types.h \
|
||||
s11_messages_def.h s11_messages_types.h \
|
||||
s1ap_messages_def.h s1ap_messages_types.h \
|
||||
s6a_messages_def.h s6a_messages_types.h \
|
||||
sgw_lite_def.h sgw_lite_messages_types.h \
|
||||
sctp_messages_def.h sctp_messages_types.h \
|
||||
udp_message_def.h udp_messages_types.h \
|
||||
intertask_interface.c intertask_interface.h \
|
||||
intertask_interface_dump.c intertask_interface_dump.h \
|
||||
timer.c timer.h
|
||||
459
common/utils/itti/intertask_interface.c
Normal file
459
common/utils/itti/intertask_interface.c
Normal file
@@ -0,0 +1,459 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Eurecom OpenAirInterface
|
||||
Copyright(c) 1999 - 2012 Eurecom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information
|
||||
Openair Admin: openair_admin@eurecom.fr
|
||||
Openair Tech : openair_tech@eurecom.fr
|
||||
Forums : http://forums.eurecom.fr/openairinterface
|
||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
||||
06410 Biot FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "queue.h"
|
||||
#include "assertions.h"
|
||||
|
||||
#include "intertask_interface.h"
|
||||
#include "intertask_interface_dump.h"
|
||||
/* Includes "intertask_interface_init.h" to check prototype coherence, but disable threads and messages information generation */
|
||||
#define CHECK_PROTOTYPE_ONLY
|
||||
#include "intertask_interface_init.h"
|
||||
#undef CHECK_PROTOTYPE_ONLY
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
int itti_debug = 1;
|
||||
|
||||
#define ITTI_DEBUG(x, args...) do { if (itti_debug) fprintf(stdout, "[ITTI][D]"x, ##args); } \
|
||||
while(0)
|
||||
#define ITTI_ERROR(x, args...) do { fprintf(stdout, "[ITTI][E]"x, ##args); } \
|
||||
while(0)
|
||||
|
||||
/* Global message size */
|
||||
#define MESSAGE_SIZE(mESSAGEiD) (sizeof(MessageHeader) + itti_desc.messages_info[mESSAGEiD].size)
|
||||
|
||||
typedef enum task_state_s {
|
||||
TASK_STATE_NOT_CONFIGURED,
|
||||
TASK_STATE_STARTING,
|
||||
TASK_STATE_READY,
|
||||
TASK_STATE_MAX,
|
||||
} task_state_t;
|
||||
|
||||
/* This list acts as a FIFO of messages received by tasks (RRC, NAS, ...) */
|
||||
struct message_list_s {
|
||||
STAILQ_ENTRY(message_list_s) next_element;
|
||||
|
||||
MessageDef *msg; ///< Pointer to the message
|
||||
|
||||
message_number_t message_number; ///< Unique message number
|
||||
uint32_t message_priority; ///< Message priority
|
||||
};
|
||||
|
||||
typedef struct task_desc_s {
|
||||
/* Queue of messages belonging to the task */
|
||||
STAILQ_HEAD(message_queue_head, message_list_s) message_queue;
|
||||
|
||||
/* Number of messages in the queue */
|
||||
volatile uint32_t message_in_queue;
|
||||
/* Mutex for the message queue */
|
||||
pthread_mutex_t message_queue_mutex;
|
||||
/* Conditional var for message queue and task synchro */
|
||||
pthread_cond_t message_queue_cond_var;
|
||||
pthread_t task_thread;
|
||||
volatile task_state_t task_state;
|
||||
} task_desc_t;
|
||||
|
||||
struct itti_desc_s {
|
||||
task_desc_t *tasks;
|
||||
/* Current message number. Incremented every call to send_msg_to_task */
|
||||
message_number_t message_number __attribute__((aligned(8)));
|
||||
|
||||
thread_id_t thread_max;
|
||||
MessagesIds messages_id_max;
|
||||
|
||||
const char * const *threads_name;
|
||||
const message_info_t *messages_info;
|
||||
};
|
||||
|
||||
static struct itti_desc_s itti_desc;
|
||||
|
||||
static inline
|
||||
message_number_t increment_message_number(void)
|
||||
{
|
||||
/* Atomic operation supported by GCC: returns the current message number
|
||||
* and then increment it by 1.
|
||||
* This can be done without mutex.
|
||||
*/
|
||||
return __sync_fetch_and_add(&itti_desc.message_number, 1);
|
||||
}
|
||||
|
||||
static inline uint32_t get_message_priority(MessagesIds message_id)
|
||||
{
|
||||
DevCheck(message_id < itti_desc.messages_id_max, message_id, itti_desc.messages_id_max, 0);
|
||||
|
||||
return (itti_desc.messages_info[message_id].priority);
|
||||
}
|
||||
|
||||
char *get_message_name(MessagesIds message_id)
|
||||
{
|
||||
DevCheck(message_id < itti_desc.messages_id_max, message_id, itti_desc.messages_id_max, 0);
|
||||
|
||||
return (itti_desc.messages_info[message_id].name);
|
||||
}
|
||||
|
||||
int send_broadcast_message(MessageDef *message_p)
|
||||
{
|
||||
uint32_t i;
|
||||
int ret = 0;
|
||||
int temp;
|
||||
|
||||
for (i = THREAD_FIRST; i < itti_desc.thread_max; i++)
|
||||
{
|
||||
MessageDef *new_message_p;
|
||||
|
||||
/* Skip tasks which are not running */
|
||||
if (itti_desc.tasks[i].task_state != TASK_STATE_READY)
|
||||
continue;
|
||||
|
||||
new_message_p = malloc(sizeof(MessageDef));
|
||||
|
||||
if (new_message_p == NULL) {
|
||||
ITTI_ERROR("Failed to allocate memory (%s:%d)\n",
|
||||
__FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
memcpy(new_message_p, message_p, sizeof(MessageDef));
|
||||
temp = send_msg_to_task(i, INSTANCE_DEFAULT, new_message_p);
|
||||
if (temp < 0) {
|
||||
ITTI_ERROR("Failed to send broadcast message (%s) to queue (%u:%s)\n",
|
||||
itti_desc.messages_info[message_p->header.messageId].name, i, itti_desc.threads_name[i]);
|
||||
ret = temp;
|
||||
free(new_message_p);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline MessageDef *alloc_new_message(
|
||||
task_id_t origin_task_id,
|
||||
MessagesIds message_id)
|
||||
{
|
||||
MessageDef *temp = NULL;
|
||||
|
||||
if ((TASK_GET_THREAD_ID(origin_task_id) >= itti_desc.thread_max) ||
|
||||
(message_id >= itti_desc.messages_id_max))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
temp = calloc(1, MESSAGE_SIZE(message_id));
|
||||
|
||||
if (temp == NULL) {
|
||||
ITTI_ERROR("Cannot allocate memory for new message (%s:%d)\n",
|
||||
__FILE__, __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
temp->header.messageId = message_id;
|
||||
temp->header.originTaskId = origin_task_id;
|
||||
temp->header.size = itti_desc.messages_info[message_id].size;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
int send_msg_to_task(task_id_t task_id, instance_t instance, MessageDef *message)
|
||||
{
|
||||
thread_id_t thread_id = TASK_GET_THREAD_ID(task_id);
|
||||
struct message_list_s *new;
|
||||
uint32_t priority;
|
||||
message_number_t message_number;
|
||||
uint32_t message_id;
|
||||
|
||||
if (thread_id >= itti_desc.thread_max)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
message->header.destinationTaskId = task_id;
|
||||
message->header.instance = instance;
|
||||
message_id = message->header.messageId;
|
||||
|
||||
DevAssert(message != NULL);
|
||||
DevCheck(thread_id < itti_desc.thread_max, thread_id, 0, 0);
|
||||
DevCheck(message_id < itti_desc.messages_id_max, itti_desc.messages_id_max, message_id, 0);
|
||||
|
||||
priority = get_message_priority(message_id);
|
||||
|
||||
/* Lock the mutex to get exclusive access to the list */
|
||||
pthread_mutex_lock(&itti_desc.tasks[thread_id].message_queue_mutex);
|
||||
|
||||
/* We cannot send a message if the task is not running */
|
||||
DevCheck(itti_desc.tasks[thread_id].task_state == TASK_STATE_READY,
|
||||
itti_desc.tasks[thread_id].task_state, TASK_STATE_READY, thread_id);
|
||||
|
||||
/* Check the number of messages in the queue */
|
||||
DevCheck((itti_desc.tasks[thread_id].message_in_queue * sizeof(MessageDef))
|
||||
< ITTI_QUEUE_SIZE_PER_TASK,
|
||||
(itti_desc.tasks[thread_id].message_in_queue * sizeof(MessageDef)),
|
||||
ITTI_QUEUE_SIZE_PER_TASK,
|
||||
itti_desc.tasks[thread_id].message_in_queue);
|
||||
|
||||
/* Allocate new list element */
|
||||
if ((new = (struct message_list_s *)malloc(sizeof(struct message_list_s))) == NULL)
|
||||
{
|
||||
ITTI_ERROR("Cannot allocate memory for new message (%s:%d)\n",
|
||||
__FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Increment the global message number */
|
||||
message_number = increment_message_number();
|
||||
|
||||
/* Fill in members */
|
||||
new->msg = message;
|
||||
new->message_number = message_number;
|
||||
new->message_priority = priority;
|
||||
|
||||
itti_dump_queue_message(message_number, message, itti_desc.messages_info[message_id].name, MESSAGE_SIZE(message_id));
|
||||
|
||||
if (STAILQ_EMPTY(&itti_desc.tasks[thread_id].message_queue)) {
|
||||
STAILQ_INSERT_HEAD(&itti_desc.tasks[thread_id].message_queue, new, next_element);
|
||||
} else {
|
||||
// struct message_list_s *insert_after = NULL;
|
||||
// struct message_list_s *temp;
|
||||
//
|
||||
// /* This method is inefficient... */
|
||||
// STAILQ_FOREACH(temp, &itti_desc.tasks[thread_id].message_queue, next_element) {
|
||||
// struct message_list_s *next;
|
||||
// next = STAILQ_NEXT(temp, next_element);
|
||||
// /* Increment message priority to create a sort of
|
||||
// * priority based scheduler */
|
||||
// // if (temp->message_priority < TASK_PRIORITY_MAX) {
|
||||
// // temp->message_priority++;
|
||||
// // }
|
||||
// if (next && next->message_priority < priority) {
|
||||
// insert_after = temp;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (insert_after == NULL) {
|
||||
STAILQ_INSERT_TAIL(&itti_desc.tasks[thread_id].message_queue, new, next_element);
|
||||
// } else {
|
||||
// STAILQ_INSERT_AFTER(&itti_desc.tasks[thread_id].message_queue, insert_after, new,
|
||||
// next_element);
|
||||
// }
|
||||
}
|
||||
|
||||
/* Update the number of messages in the queue */
|
||||
itti_desc.tasks[thread_id].message_in_queue++;
|
||||
if (itti_desc.tasks[thread_id].message_in_queue == 1) {
|
||||
/* Emit a signal to wake up target task thread */
|
||||
pthread_cond_signal(&itti_desc.tasks[thread_id].message_queue_cond_var);
|
||||
}
|
||||
/* Release the mutex */
|
||||
pthread_mutex_unlock(&itti_desc.tasks[thread_id].message_queue_mutex);
|
||||
ITTI_DEBUG("Message %s, number %lu with priority %d successfully sent to queue (%u:%s)\n",
|
||||
itti_desc.messages_info[message_id].name, message_number,
|
||||
priority, thread_id, itti_desc.threads_name[thread_id]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void receive_msg(task_id_t task_id, MessageDef **received_msg)
|
||||
{
|
||||
thread_id_t thread_id = TASK_GET_THREAD_ID(task_id);
|
||||
|
||||
DevCheck(thread_id < itti_desc.thread_max, thread_id, 0, 0);
|
||||
DevAssert(received_msg != NULL);
|
||||
|
||||
// Lock the mutex to get exclusive access to the list
|
||||
pthread_mutex_lock(&itti_desc.tasks[thread_id].message_queue_mutex);
|
||||
|
||||
if (itti_desc.tasks[thread_id].message_in_queue == 0) {
|
||||
ITTI_DEBUG("Message in queue[(%u:%s)] == 0, waiting\n",
|
||||
thread_id, itti_desc.threads_name[thread_id]);
|
||||
// Wait while list == 0
|
||||
pthread_cond_wait(&itti_desc.tasks[thread_id].message_queue_cond_var,
|
||||
&itti_desc.tasks[thread_id].message_queue_mutex);
|
||||
ITTI_DEBUG("Receiver queue[(%u:%s)] got new message notification for task %x\n",
|
||||
thread_id, itti_desc.threads_name[thread_id], task_id);
|
||||
}
|
||||
|
||||
if (!STAILQ_EMPTY(&itti_desc.tasks[thread_id].message_queue)) {
|
||||
struct message_list_s *temp = STAILQ_FIRST(
|
||||
&itti_desc.tasks[thread_id].message_queue);
|
||||
|
||||
/* Update received_msg reference */
|
||||
*received_msg = temp->msg;
|
||||
|
||||
/* Remove message from queue */
|
||||
STAILQ_REMOVE_HEAD(&itti_desc.tasks[thread_id].message_queue, next_element);
|
||||
free(temp);
|
||||
itti_desc.tasks[thread_id].message_in_queue--;
|
||||
}
|
||||
// Release the mutex
|
||||
pthread_mutex_unlock(&itti_desc.tasks[thread_id].message_queue_mutex);
|
||||
}
|
||||
|
||||
void poll_msg(task_id_t task_id, instance_t instance, MessageDef **received_msg)
|
||||
{
|
||||
thread_id_t thread_id = TASK_GET_THREAD_ID(task_id);
|
||||
|
||||
DevCheck (thread_id < itti_desc.thread_max, thread_id, 0, 0);
|
||||
DevAssert (received_msg != NULL);
|
||||
|
||||
*received_msg = NULL;
|
||||
|
||||
if (itti_desc.tasks[thread_id].message_in_queue != 0)
|
||||
{
|
||||
struct message_list_s *temp;
|
||||
|
||||
// Lock the mutex to get exclusive access to the list
|
||||
pthread_mutex_lock (&itti_desc.tasks[thread_id].message_queue_mutex);
|
||||
|
||||
STAILQ_FOREACH(temp, &itti_desc.tasks[thread_id].message_queue, next_element)
|
||||
{
|
||||
if ((temp->msg->header.destinationTaskId == task_id)
|
||||
&& ((instance == INSTANCE_ALL) || (temp->msg->header.instance == instance)))
|
||||
{
|
||||
/* Update received_msg reference */
|
||||
*received_msg = temp->msg;
|
||||
|
||||
/* Remove message from queue */
|
||||
STAILQ_REMOVE(&itti_desc.tasks[thread_id].message_queue, temp, message_list_s, next_element);
|
||||
free (temp);
|
||||
itti_desc.tasks[thread_id].message_in_queue--;
|
||||
|
||||
ITTI_DEBUG("Receiver queue[(%u:%s)] got new message %s, number %lu for task %x\n",
|
||||
thread_id, itti_desc.threads_name[thread_id], itti_desc.messages_info[temp->msg->header.messageId].name,
|
||||
temp->message_number, task_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Release the mutex
|
||||
pthread_mutex_unlock (&itti_desc.tasks[thread_id].message_queue_mutex);
|
||||
}
|
||||
|
||||
if (*received_msg == NULL)
|
||||
{
|
||||
ITTI_DEBUG("No message in queue[(%u:%s)] for task %x\n", thread_id, itti_desc.threads_name[thread_id], task_id);
|
||||
}
|
||||
}
|
||||
|
||||
int intertask_interface_create_task(task_id_t task_id,
|
||||
void *(*start_routine) (void *),
|
||||
void *args_p)
|
||||
{
|
||||
thread_id_t thread_id = TASK_GET_THREAD_ID(task_id);
|
||||
|
||||
DevAssert(start_routine != NULL);
|
||||
DevCheck(thread_id < itti_desc.thread_max, thread_id, 0, 0);
|
||||
|
||||
if (itti_desc.tasks[thread_id].task_state != TASK_STATE_NOT_CONFIGURED) {
|
||||
ITTI_ERROR("You are attempting to start an already configured thread"
|
||||
" for %s thread\n", itti_desc.threads_name[thread_id]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
itti_desc.tasks[thread_id].task_state = TASK_STATE_STARTING;
|
||||
|
||||
if (pthread_create(&itti_desc.tasks[thread_id].task_thread, NULL, start_routine,
|
||||
args_p) < 0) {
|
||||
ITTI_ERROR("Failed to initialize %s thread: %s:%d\n", itti_desc.threads_name[thread_id],
|
||||
strerror(errno),
|
||||
errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Wait till the thread is completely ready */
|
||||
while (itti_desc.tasks[thread_id].task_state != TASK_STATE_READY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intertask_interface_mark_task_ready(task_id_t task_id)
|
||||
{
|
||||
thread_id_t thread_id = TASK_GET_THREAD_ID(task_id);
|
||||
|
||||
DevCheck(thread_id < itti_desc.thread_max, thread_id, 0, 0);
|
||||
// Lock the mutex to get exclusive access to the list
|
||||
pthread_mutex_lock(&itti_desc.tasks[thread_id].message_queue_mutex);
|
||||
itti_desc.tasks[thread_id].task_state = TASK_STATE_READY;
|
||||
// Release the mutex
|
||||
pthread_mutex_unlock(&itti_desc.tasks[thread_id].message_queue_mutex);
|
||||
}
|
||||
|
||||
int intertask_interface_init(thread_id_t thread_max, MessagesIds messages_id_max,
|
||||
const char * const *threads_name,
|
||||
const message_info_t *messages_info,
|
||||
const char * const messages_definition_xml)
|
||||
{
|
||||
int i;
|
||||
itti_desc.message_number = 0;
|
||||
|
||||
/* Saves threads and messages max values */
|
||||
itti_desc.thread_max = thread_max;
|
||||
itti_desc.messages_id_max = messages_id_max;
|
||||
itti_desc.threads_name = threads_name;
|
||||
itti_desc.messages_info = messages_info;
|
||||
|
||||
/* Allocates memory for tasks info */
|
||||
itti_desc.tasks = calloc(itti_desc.thread_max, sizeof(task_desc_t));
|
||||
|
||||
/* Initializing each queue and related stuff */
|
||||
for (i = THREAD_FIRST; i < itti_desc.thread_max; i++) {
|
||||
STAILQ_INIT(&itti_desc.tasks[i].message_queue);
|
||||
itti_desc.tasks[i].message_in_queue = 0;
|
||||
// Initialize mutexes
|
||||
pthread_mutex_init(&itti_desc.tasks[i].message_queue_mutex, NULL);
|
||||
// Initialize Cond vars
|
||||
pthread_cond_init(&itti_desc.tasks[i].message_queue_cond_var, NULL);
|
||||
itti_desc.tasks[i].task_state = TASK_STATE_NOT_CONFIGURED;
|
||||
}
|
||||
itti_dump_init(messages_definition_xml);
|
||||
|
||||
timer_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intertask_interface_send_quit_signal(void)
|
||||
{
|
||||
int i;
|
||||
MessageDef *terminate_message_p;
|
||||
|
||||
terminate_message_p = alloc_new_message(TASK_UNKNOWN, TERMINATE_MESSAGE);
|
||||
|
||||
send_broadcast_message(terminate_message_p);
|
||||
|
||||
for (i = THREAD_FIRST; i < itti_desc.thread_max; i++) {
|
||||
/* Skip tasks which are not running */
|
||||
if (itti_desc.tasks[i].task_state != TASK_STATE_READY)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
142
common/utils/itti/intertask_interface.h
Normal file
142
common/utils/itti/intertask_interface.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Eurecom OpenAirInterface
|
||||
Copyright(c) 1999 - 2012 Eurecom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information
|
||||
Openair Admin: openair_admin@eurecom.fr
|
||||
Openair Tech : openair_tech@eurecom.fr
|
||||
Forums : http://forums.eurecom.fr/openairinterface
|
||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
||||
06410 Biot FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/** @defgroup _intertask_interface_impl_ Intertask Interface Mechanisms
|
||||
* Implementation
|
||||
* @ingroup _ref_implementation_
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef INTERTASK_INTERFACE_H_
|
||||
#define INTERTASK_INTERFACE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mme_config.h"
|
||||
#include "common_types.h"
|
||||
|
||||
#include "intertask_interface_types.h"
|
||||
|
||||
/* Make the message number platform specific */
|
||||
typedef unsigned long message_number_t;
|
||||
#define MESSAGE_NUMBER_SIZE (sizeof(unsigned long))
|
||||
|
||||
enum message_priorities {
|
||||
MESSAGE_PRIORITY_MAX = 100,
|
||||
MESSAGE_PRIORITY_MAX_LEAST = 85,
|
||||
MESSAGE_PRIORITY_MED_PLUS = 70,
|
||||
MESSAGE_PRIORITY_MED = 55,
|
||||
MESSAGE_PRIORITY_MED_LEAST = 40,
|
||||
MESSAGE_PRIORITY_MIN_PLUS = 25,
|
||||
MESSAGE_PRIORITY_MIN = 10,
|
||||
};
|
||||
|
||||
typedef struct message_info_s {
|
||||
task_id_t id;
|
||||
uint32_t priority;
|
||||
/* Message payload size */
|
||||
MessageHeaderSize size;
|
||||
/* Printable name */
|
||||
char *name;
|
||||
} message_info_t;
|
||||
|
||||
enum task_priorities {
|
||||
TASK_PRIORITY_MAX = 100,
|
||||
TASK_PRIORITY_MAX_LEAST = 85,
|
||||
TASK_PRIORITY_MED_PLUS = 70,
|
||||
TASK_PRIORITY_MED = 55,
|
||||
TASK_PRIORITY_MED_LEAST = 40,
|
||||
TASK_PRIORITY_MIN_PLUS = 25,
|
||||
TASK_PRIORITY_MIN = 10,
|
||||
};
|
||||
|
||||
/** \brief Send a broadcast message to every task
|
||||
\param message_p Pointer to the message to send
|
||||
@returns < 0 on failure, 0 otherwise
|
||||
**/
|
||||
int send_broadcast_message(MessageDef *message_p);
|
||||
|
||||
/** \brief Send a message to a task (could be itself)
|
||||
\param task_id Task ID
|
||||
\param instance Instance of the task used for virtualization
|
||||
\param message Pointer to the message to send
|
||||
@returns -1 on failure, 0 otherwise
|
||||
**/
|
||||
int send_msg_to_task(task_id_t task_id, instance_t instance, MessageDef *message);
|
||||
|
||||
/** \brief Retrieves a message in the queue associated to task_id.
|
||||
* If the queue is empty, the thread is blocked till a new message arrives.
|
||||
\param task_id Task ID of the receiving task
|
||||
\param received_msg Pointer to the allocated message
|
||||
**/
|
||||
void receive_msg(task_id_t task_id, MessageDef **received_msg);
|
||||
|
||||
/** \brief Try to retrieves a message in the queue associated to task_id and matching requested instance.
|
||||
\param task_id Task ID of the receiving task
|
||||
\param instance Instance of the task used for virtualization
|
||||
\param received_msg Pointer to the allocated message
|
||||
**/
|
||||
void poll_msg(task_id_t task_id, instance_t instance, MessageDef **received_msg);
|
||||
|
||||
/** \brief Start thread associated to the task
|
||||
* \param task_id task to start
|
||||
* \param start_routine entry point for the task
|
||||
* \param args_p Optional argument to pass to the start routine
|
||||
* @returns -1 on failure, 0 otherwise
|
||||
**/
|
||||
int intertask_interface_create_task(task_id_t task_id,
|
||||
void *(*start_routine) (void *),
|
||||
void *args_p);
|
||||
|
||||
/** \brief Mark the task as in ready state
|
||||
* \param task_id task to mark as ready
|
||||
**/
|
||||
void intertask_interface_mark_task_ready(task_id_t task_id);
|
||||
|
||||
/** \brief Return the printable string associated with the message
|
||||
* \param message_id Id of the message
|
||||
**/
|
||||
char *get_message_name(MessagesIds message_id);
|
||||
|
||||
/** \brief Alloc and memset(0) a new itti message.
|
||||
\param origin_task_id Task ID of the sending task
|
||||
\param message_id Message ID
|
||||
@returns NULL in case of failure or newly allocated mesage ref
|
||||
**/
|
||||
inline MessageDef *alloc_new_message(
|
||||
task_id_t origin_task_id,
|
||||
MessagesIds message_id);
|
||||
|
||||
void intertask_interface_send_quit_signal(void);
|
||||
|
||||
#endif /* INTERTASK_INTERFACE_H_ */
|
||||
/* @} */
|
||||
503
common/utils/itti/intertask_interface_dump.c
Normal file
503
common/utils/itti/intertask_interface_dump.c
Normal file
@@ -0,0 +1,503 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Eurecom OpenAirInterface
|
||||
Copyright(c) 1999 - 2013 Eurecom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information
|
||||
Openair Admin: openair_admin@eurecom.fr
|
||||
Openair Tech : openair_tech@eurecom.fr
|
||||
Forums : http://forums.eurecom.fr/openairinterface
|
||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
||||
06410 Biot FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/** @brief Intertask Interface Signal Dumper
|
||||
* Allows users to connect their itti_debugger to this process and dump
|
||||
* signals exchanged between tasks.
|
||||
* @author Sebastien Roux <sebastien.roux@eurecom.fr>
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "assertions.h"
|
||||
#include "queue.h"
|
||||
|
||||
#include "mme_default_values.h"
|
||||
|
||||
#include "intertask_interface.h"
|
||||
#include "intertask_interface_dump.h"
|
||||
|
||||
#define SIGNAL_NAME_LENGTH 50
|
||||
|
||||
/* Declared in intertask_interface.c */
|
||||
extern int itti_debug;
|
||||
|
||||
#define ITTI_DEBUG(x, args...) do { fprintf(stdout, "[ITTI][D]"x, ##args); } \
|
||||
while(0)
|
||||
#define ITTI_ERROR(x, args...) do { fprintf(stdout, "[ITTI][E]"x, ##args); } \
|
||||
while(0)
|
||||
|
||||
typedef struct itti_queue_item_s {
|
||||
STAILQ_ENTRY(itti_queue_item_s) entry;
|
||||
void *data;
|
||||
uint32_t data_size;
|
||||
uint32_t message_number;
|
||||
char message_name[SIGNAL_NAME_LENGTH];
|
||||
} itti_queue_item_t;
|
||||
|
||||
typedef struct {
|
||||
int sd;
|
||||
uint32_t last_message_number;
|
||||
} itti_client_desc_t;
|
||||
|
||||
typedef struct itti_desc_s {
|
||||
/* The acceptor thread */
|
||||
pthread_t itti_acceptor_thread;
|
||||
pthread_t itti_write_thread;
|
||||
|
||||
/* Protect the circular queue */
|
||||
pthread_mutex_t queue_mutex;
|
||||
|
||||
/* List of messages to dump.
|
||||
* NOTE: we limit the size of this queue to retain only the last exchanged
|
||||
* messages. The size can be increased by setting up the ITTI_QUEUE_SIZE_MAX
|
||||
* in mme_default_values.h or by putting a custom in the configuration file.
|
||||
*/
|
||||
STAILQ_HEAD(itti_queue_s, itti_queue_item_s) itti_message_queue;
|
||||
struct itti_queue_item_s *itti_queue_last;
|
||||
uint32_t queue_size;
|
||||
|
||||
int nb_connected;
|
||||
|
||||
itti_client_desc_t itti_clients[ITTI_DUMP_MAX_CON];
|
||||
} itti_desc_t;
|
||||
|
||||
static itti_desc_t itti_queue;
|
||||
|
||||
/* Message sent is an intertask dump type */
|
||||
#define ITTI_DUMP_MESSAGE_TYPE 0x1
|
||||
#define ITTI_STATISTIC_MESSAGE_TYPE 0x2
|
||||
#define ITTI_DUMP_XML_DEFINITION 0x3
|
||||
|
||||
typedef struct {
|
||||
/* The size of this structure */
|
||||
uint32_t message_size;
|
||||
uint32_t message_type;
|
||||
} itti_socket_header_t;
|
||||
|
||||
typedef struct {
|
||||
itti_socket_header_t header;
|
||||
|
||||
uint32_t message_number;
|
||||
char signal_name[SIGNAL_NAME_LENGTH];
|
||||
|
||||
/* Message payload is added here, this struct is used as an header */
|
||||
} itti_dump_message_t;
|
||||
|
||||
typedef struct {
|
||||
itti_socket_header_t header;
|
||||
|
||||
} itti_statistic_message_t;
|
||||
|
||||
static int itti_dump_send_message(int sd, itti_queue_item_t *message);
|
||||
static int itti_dump_handle_new_connection(int sd, const char *xml_definition,
|
||||
uint32_t xml_definition_length);
|
||||
static int itti_dump_send_xml_definition(const int sd, const char *message_definition_xml,
|
||||
const uint32_t message_definition_xml_length);
|
||||
|
||||
static
|
||||
int itti_dump_send_message(int sd, itti_queue_item_t *message)
|
||||
{
|
||||
int result = 0;
|
||||
itti_dump_message_t *new_message;
|
||||
|
||||
/* Allocate memory for message header and payload */
|
||||
uint32_t size = sizeof(itti_dump_message_t) + message->data_size;
|
||||
|
||||
DevCheck(sd > 0, sd, 0, 0);
|
||||
DevAssert(message != NULL);
|
||||
|
||||
new_message = calloc(1, size);
|
||||
DevAssert(new_message != NULL);
|
||||
|
||||
/* Preparing the header */
|
||||
new_message->header.message_size = size;
|
||||
new_message->header.message_type = ITTI_DUMP_MESSAGE_TYPE;
|
||||
|
||||
new_message->message_number = message->message_number;
|
||||
/* Copy the name, but leaves last byte set to 0 in case name is too long */
|
||||
memcpy(new_message->signal_name, message->message_name, SIGNAL_NAME_LENGTH - 1);
|
||||
/* Appends message payload */
|
||||
memcpy(&new_message[1], message->data, message->data_size);
|
||||
|
||||
if (write(sd, new_message, size) == -1) {
|
||||
ITTI_ERROR("[%d] Failed to write message of size %u to socket (%d:%s)\n",
|
||||
sd, size, errno, strerror(errno));
|
||||
result = -1;
|
||||
}
|
||||
|
||||
free(new_message);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int itti_dump_send_xml_definition(const int sd, const char *message_definition_xml,
|
||||
const uint32_t message_definition_xml_length)
|
||||
{
|
||||
itti_socket_header_t xml_definition_header;
|
||||
|
||||
DevCheck(sd > 0, sd, 0, 0);
|
||||
DevAssert(message_definition_xml != NULL);
|
||||
|
||||
ITTI_DEBUG("[%d] Sending XML definition of size %u to observer peer\n",
|
||||
sd, message_definition_xml_length);
|
||||
|
||||
xml_definition_header.message_size = sizeof(xml_definition_header)
|
||||
+ message_definition_xml_length;
|
||||
xml_definition_header.message_type = ITTI_DUMP_XML_DEFINITION;
|
||||
|
||||
if (write(sd, &xml_definition_header, sizeof(xml_definition_header)) < 0) {
|
||||
ITTI_ERROR("[%d] Failed to write header of size %zu to socket (%d:%s)\n",
|
||||
sd, sizeof(xml_definition_header), errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (write(sd, message_definition_xml, message_definition_xml_length) < 0) {
|
||||
ITTI_ERROR("[%d] Failed to write XML definition of size %u to socket (%d:%s)\n",
|
||||
sd, message_definition_xml_length, errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int itti_dump_queue_message(message_number_t message_number,
|
||||
MessageDef *message_p,
|
||||
const char *message_name,
|
||||
const uint32_t message_size)
|
||||
{
|
||||
itti_queue_item_t *new;
|
||||
itti_queue_item_t *head = NULL;
|
||||
size_t message_name_length;
|
||||
int i;
|
||||
|
||||
DevAssert(message_name != NULL);
|
||||
DevAssert(message_p != NULL);
|
||||
|
||||
new = calloc(1, sizeof(itti_queue_item_t));
|
||||
|
||||
if (new == NULL) {
|
||||
ITTI_ERROR("Failed to allocate memory (%s:%d)\n",
|
||||
__FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
new->data = malloc(message_size);
|
||||
|
||||
if (new->data == NULL) {
|
||||
ITTI_ERROR("Failed to allocate memory (%s:%d)\n",
|
||||
__FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
memcpy(new->data, message_p, message_size);
|
||||
new->data_size = message_size;
|
||||
new->message_number = message_number;
|
||||
|
||||
message_name_length = strlen(message_name) + 1;
|
||||
DevCheck(message_name_length <= SIGNAL_NAME_LENGTH, message_name_length,
|
||||
SIGNAL_NAME_LENGTH, 0);
|
||||
memcpy(new->message_name, message_name, message_name_length);
|
||||
|
||||
/* Lock the queue mutex for writing to insert the new element */
|
||||
pthread_mutex_lock(&itti_queue.queue_mutex);
|
||||
|
||||
/* We reached the maximum size for the queue of messages -> remove the head */
|
||||
if (itti_queue.queue_size + message_size > ITTI_QUEUE_SIZE_MAX) {
|
||||
head = STAILQ_FIRST(&itti_queue.itti_message_queue);
|
||||
/* Remove the head */
|
||||
STAILQ_REMOVE_HEAD(&itti_queue.itti_message_queue, entry);
|
||||
} else {
|
||||
itti_queue.queue_size += message_size;
|
||||
}
|
||||
/* Insert the packet at tail */
|
||||
STAILQ_INSERT_TAIL(&itti_queue.itti_message_queue, new, entry);
|
||||
itti_queue.itti_queue_last = new;
|
||||
|
||||
/* Release the mutex */
|
||||
pthread_mutex_unlock(&itti_queue.queue_mutex);
|
||||
|
||||
for (i = 0; i < ITTI_DUMP_MAX_CON; i++) {
|
||||
if (itti_queue.itti_clients[i].sd == -1)
|
||||
continue;
|
||||
itti_dump_send_message(itti_queue.itti_clients[i].sd, new);
|
||||
}
|
||||
|
||||
/* No need to have the mutex locked to free data as at this point the message
|
||||
* is no more in the list.
|
||||
*/
|
||||
if (head) {
|
||||
free(head->data);
|
||||
free(head);
|
||||
head = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *itti_dump_socket(void *arg_p)
|
||||
{
|
||||
uint32_t message_definition_xml_length;
|
||||
char *message_definition_xml;
|
||||
int rc;
|
||||
int itti_listen_socket, max_sd;
|
||||
int on = 1;
|
||||
fd_set master_set, working_set;
|
||||
struct sockaddr_in servaddr; /* socket address structure */
|
||||
|
||||
ITTI_DEBUG("Creating TCP dump socket on port %u\n", ITTI_PORT);
|
||||
|
||||
message_definition_xml = (char *)arg_p;
|
||||
DevAssert(message_definition_xml != NULL);
|
||||
|
||||
message_definition_xml_length = strlen(message_definition_xml) + 1;
|
||||
|
||||
if ((itti_listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
||||
ITTI_ERROR("Socket creation failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
/* Allow socket reuse */
|
||||
rc = setsockopt(itti_listen_socket, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *)&on, sizeof(on));
|
||||
if (rc < 0) {
|
||||
ITTI_ERROR("setsockopt SO_REUSEADDR failed (%d:%s)\n", errno, strerror(errno));
|
||||
close(itti_listen_socket);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
/* Set socket to be non-blocking.
|
||||
* NOTE: sockets accepted will inherit this option.
|
||||
*/
|
||||
rc = ioctl(itti_listen_socket, FIONBIO, (char *)&on);
|
||||
if (rc < 0) {
|
||||
ITTI_ERROR("ioctl FIONBIO (non-blocking) failed (%d:%s)\n", errno, strerror(errno));
|
||||
close(itti_listen_socket);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
servaddr.sin_port = htons(ITTI_PORT);
|
||||
|
||||
if (bind(itti_listen_socket, (struct sockaddr *) &servaddr,
|
||||
sizeof(servaddr)) < 0 ) {
|
||||
ITTI_ERROR("Bind failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
if (listen(itti_listen_socket, 5) < 0 ) {
|
||||
ITTI_ERROR("Listen failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
FD_ZERO(&master_set);
|
||||
max_sd = itti_listen_socket;
|
||||
FD_SET(itti_listen_socket, &master_set);
|
||||
|
||||
/* Loop waiting for incoming connects or for incoming data
|
||||
* on any of the connected sockets.
|
||||
*/
|
||||
while (1) {
|
||||
int desc_ready;
|
||||
int client_socket = -1;
|
||||
int i;
|
||||
|
||||
memcpy(&working_set, &master_set, sizeof(master_set));
|
||||
|
||||
ITTI_DEBUG("Stuck on select\n");
|
||||
|
||||
/* No timeout: select blocks till a new event has to be handled
|
||||
* on sd's.
|
||||
*/
|
||||
rc = select(max_sd + 1, &working_set, NULL, NULL, NULL);
|
||||
|
||||
if (rc < 0) {
|
||||
ITTI_ERROR("select failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
desc_ready = rc;
|
||||
for (i = 0; i <= max_sd && desc_ready > 0; i++) {
|
||||
if (FD_ISSET(i, &working_set)) {
|
||||
ITTI_DEBUG("Handling socket %d\n", i);
|
||||
desc_ready -= 1;
|
||||
/* Check if the socket where data available is the listening
|
||||
* socket.
|
||||
*/
|
||||
if (i == itti_listen_socket) {
|
||||
do {
|
||||
client_socket = accept(itti_listen_socket, NULL, NULL);
|
||||
if (client_socket < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
/* No more new connection */
|
||||
ITTI_DEBUG("No more new connection\n");
|
||||
continue;
|
||||
} else {
|
||||
ITTI_ERROR("accept failed (%d:%s)\n", errno, strerror(errno));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
}
|
||||
if (itti_dump_handle_new_connection(client_socket, message_definition_xml,
|
||||
message_definition_xml_length) == 0) {
|
||||
/* The socket has been accepted.
|
||||
* We have to update the set to include this new sd.
|
||||
*/
|
||||
FD_SET(client_socket, &master_set);
|
||||
if (client_socket > max_sd)
|
||||
max_sd = client_socket;
|
||||
}
|
||||
} while(client_socket != -1);
|
||||
} else {
|
||||
/* For now the MME itti dumper should not receive data
|
||||
* other than connection oriented (CLOSE).
|
||||
*/
|
||||
uint8_t j;
|
||||
|
||||
ITTI_DEBUG("Socket %d disconnected\n", i);
|
||||
|
||||
/* Close the socket and update info related to this connection */
|
||||
close(i);
|
||||
|
||||
for (j = 0; j < ITTI_DUMP_MAX_CON; j++) {
|
||||
if (itti_queue.itti_clients[j].sd == i)
|
||||
break;
|
||||
}
|
||||
|
||||
/* In case we don't find the matching sd in list of known
|
||||
* connections -> assert.
|
||||
*/
|
||||
DevCheck(j < ITTI_DUMP_MAX_CON, j, ITTI_DUMP_MAX_CON, i);
|
||||
|
||||
/* Re-initialize the socket to -1 so we can accept new
|
||||
* incoming connections.
|
||||
*/
|
||||
itti_queue.itti_clients[j].sd = -1;
|
||||
itti_queue.itti_clients[j].last_message_number = 0;
|
||||
itti_queue.nb_connected--;
|
||||
|
||||
/* Remove the socket from the FD set and update the max sd */
|
||||
FD_CLR(i, &master_set);
|
||||
if (i == max_sd)
|
||||
{
|
||||
if (itti_queue.nb_connected == 0) {
|
||||
/* No more new connection max_sd = itti_listen_socket */
|
||||
max_sd = itti_listen_socket;
|
||||
} else {
|
||||
while (FD_ISSET(max_sd, &master_set) == FALSE) {
|
||||
max_sd -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int itti_dump_handle_new_connection(int sd, const char *xml_definition, uint32_t xml_definition_length)
|
||||
{
|
||||
if (itti_queue.nb_connected < ITTI_DUMP_MAX_CON) {
|
||||
itti_queue_item_t *item;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < ITTI_DUMP_MAX_CON; i++) {
|
||||
/* Let's find a place to store the new client */
|
||||
if (itti_queue.itti_clients[i].sd == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ITTI_DEBUG("Found place to store new connection: %d\n", i);
|
||||
|
||||
DevCheck(i < ITTI_DUMP_MAX_CON, i, ITTI_DUMP_MAX_CON, sd);
|
||||
itti_queue.itti_clients[i].sd = sd;
|
||||
itti_queue.nb_connected++;
|
||||
|
||||
ITTI_DEBUG("Socket %d accepted\n", sd);
|
||||
|
||||
/* Send the XML message definition */
|
||||
if (itti_dump_send_xml_definition(sd, xml_definition, xml_definition_length) < 0) {
|
||||
ITTI_ERROR("Failed to send XML definition\n");
|
||||
close (sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we have to dump the complete list */
|
||||
pthread_mutex_lock(&itti_queue.queue_mutex);
|
||||
STAILQ_FOREACH(item, &itti_queue.itti_message_queue, entry) {
|
||||
itti_dump_send_message(sd, item);
|
||||
}
|
||||
pthread_mutex_unlock(&itti_queue.queue_mutex);
|
||||
} else {
|
||||
ITTI_DEBUG("Socket %d rejected\n", sd);
|
||||
/* We have reached max number of users connected...
|
||||
* Reject the connection.
|
||||
*/
|
||||
close (sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int itti_dump_init(const char * const messages_definition_xml)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(&itti_queue, 0, sizeof(itti_desc_t));
|
||||
|
||||
pthread_mutex_init(&itti_queue.queue_mutex, NULL);
|
||||
STAILQ_INIT(&itti_queue.itti_message_queue);
|
||||
itti_queue.queue_size = 0;
|
||||
itti_queue.nb_connected = 0;
|
||||
|
||||
for(i = 0; i < ITTI_DUMP_MAX_CON; i++) {
|
||||
itti_queue.itti_clients[i].sd = -1;
|
||||
itti_queue.itti_clients[i].last_message_number = 0;
|
||||
}
|
||||
if (pthread_create(&itti_queue.itti_acceptor_thread, NULL, &itti_dump_socket,
|
||||
(void *)messages_definition_xml) < 0) {
|
||||
ITTI_ERROR("pthread_create failed (%d:%s)\n", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
41
common/utils/itti/intertask_interface_dump.h
Normal file
41
common/utils/itti/intertask_interface_dump.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Eurecom OpenAirInterface
|
||||
Copyright(c) 1999 - 2013 Eurecom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information
|
||||
Openair Admin: openair_admin@eurecom.fr
|
||||
Openair Tech : openair_tech@eurecom.fr
|
||||
Forums : http://forums.eurecom.fr/openairinterface
|
||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
||||
06410 Biot FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INTERTASK_INTERFACE_DUMP_H_
|
||||
#define INTERTASK_INTERFACE_DUMP_H_
|
||||
|
||||
int itti_dump_queue_message(message_number_t message_number,
|
||||
MessageDef *message_p,
|
||||
const char *message_name,
|
||||
const uint32_t message_size);
|
||||
|
||||
int itti_dump_init(const char * const messages_definition_xml);
|
||||
|
||||
#endif /* INTERTASK_INTERFACE_DUMP_H_ */
|
||||
87
common/utils/itti/intertask_interface_init.h
Normal file
87
common/utils/itti/intertask_interface_init.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Eurecom OpenAirInterface
|
||||
Copyright(c) 1999 - 2012 Eurecom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information
|
||||
Openair Admin: openair_admin@eurecom.fr
|
||||
Openair Tech : openair_tech@eurecom.fr
|
||||
Forums : http://forums.eurecom.fr/openairinterface
|
||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
||||
06410 Biot FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/** @defgroup _intertask_interface_impl_ Intertask Interface Mechanisms
|
||||
* Implementation
|
||||
* @ingroup _ref_implementation_
|
||||
* @{
|
||||
*/
|
||||
|
||||
/********************************************************************************
|
||||
*
|
||||
* !!! This header should only be included by the file that initialize
|
||||
* the intertask interface module for the process !!!
|
||||
*
|
||||
* Other files should include "intertask_interface.h"
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INTERTASK_INTERFACE_INIT_H_
|
||||
#define INTERTASK_INTERFACE_INIT_H_
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#ifndef CHECK_PROTOTYPE_ONLY
|
||||
|
||||
const char * const messages_definition_xml = {
|
||||
#include "../messages_xml.h"
|
||||
};
|
||||
|
||||
/* Map thread id to printable name. */
|
||||
const char * const threads_name[] = {
|
||||
"unused",
|
||||
#define TASK_DEF(tHREADiD, pRIO) #tHREADiD,
|
||||
#define SUB_TASK_DEF(tHREADiD, sUBtASKiD)
|
||||
#include <tasks_def.h>
|
||||
#undef SUB_TASK_DEF
|
||||
#undef TASK_DEF
|
||||
};
|
||||
|
||||
/* Map message id to message information */
|
||||
const message_info_t messages_info[] = {
|
||||
#define MESSAGE_DEF(iD, pRIO, sTRUCT, fIELDnAME) { iD, pRIO, sizeof(sTRUCT), #iD },
|
||||
#include <messages_def.h>
|
||||
#undef MESSAGE_DEF
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/** \brief Init function for the intertask interface. Init queues, Mutexes and Cond vars.
|
||||
* \param thread_max Maximum number of threads
|
||||
* \param messages_id_max Maximum message id
|
||||
* \param threads_name Pointer on the threads name information as created by this include file
|
||||
* \param messages_info Pointer on messages information as created by this include file
|
||||
**/
|
||||
int intertask_interface_init(thread_id_t thread_max, MessagesIds messages_id_max,
|
||||
const char * const *threads_name, const message_info_t *messages_info,
|
||||
const char * const messages_definition_xml);
|
||||
|
||||
#endif /* INTERTASK_INTERFACE_INIT_H_ */
|
||||
/* @} */
|
||||
145
common/utils/itti/intertask_interface_types.h
Normal file
145
common/utils/itti/intertask_interface_types.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Eurecom OpenAirInterface
|
||||
Copyright(c) 1999 - 2012 Eurecom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information
|
||||
Openair Admin: openair_admin@eurecom.fr
|
||||
Openair Tech : openair_tech@eurecom.fr
|
||||
Forums : http://forums.eurecom.fr/openairinterface
|
||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
||||
06410 Biot FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/** @defgroup _intertask_interface_impl_ Intertask Interface Mechanisms
|
||||
* Implementation
|
||||
* @ingroup _ref_implementation_
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef INTERTASK_INTERFACE_TYPES_H_
|
||||
#define INTERTASK_INTERFACE_TYPES_H_
|
||||
|
||||
/* Defines to handle bit fields on unsigned long values */
|
||||
#define UL_BIT_MASK(lENGTH) ((1UL << (lENGTH)) - 1UL)
|
||||
#define UL_BIT_SHIFT(vALUE, oFFSET) ((vALUE) << (oFFSET))
|
||||
#define UL_BIT_UNSHIFT(vALUE, oFFSET) ((vALUE) >> (oFFSET))
|
||||
|
||||
#define UL_FIELD_MASK(oFFSET, lENGTH) UL_BIT_SHIFT(UL_BIT_MASK(lENGTH), (oFFSET))
|
||||
#define UL_FIELD_INSERT(vALUE, fIELD, oFFSET, lENGTH) (((vALUE) & (~UL_FIELD_MASK(oFFSET, lENGTH))) | UL_BIT_SHIFT(((fIELD) & UL_BIT_MASK(lENGTH)), oFFSET))
|
||||
#define UL_FIELD_EXTRACT(vALUE, oFFSET, lENGTH) (UL_BIT_UNSHIFT((vALUE), (oFFSET)) & UL_BIT_MASK(lENGTH))
|
||||
|
||||
/* Definitions of task ID fields */
|
||||
#define TASK_THREAD_ID_OFFSET 8
|
||||
#define TASK_THREAD_ID_LENGTH 8
|
||||
|
||||
#define TASK_SUB_TASK_ID_OFFSET 0
|
||||
#define TASK_SUB_TASK_ID_LENGTH 8
|
||||
|
||||
/* Defines to extract task ID fields */
|
||||
#define TASK_GET_THREAD_ID(tASKiD) UL_FIELD_EXTRACT(tASKiD, TASK_THREAD_ID_OFFSET, TASK_THREAD_ID_LENGTH)
|
||||
#define TASK_GET_SUB_TASK_ID(tASKiD) UL_FIELD_EXTRACT(tASKiD, TASK_SUB_TASK_ID_OFFSET, TASK_SUB_TASK_ID_LENGTH)
|
||||
|
||||
#include <messages_types.h>
|
||||
|
||||
/* This enum defines messages ids. Each one is unique. */
|
||||
typedef enum
|
||||
{
|
||||
#define MESSAGE_DEF(iD, pRIO, sTRUCT, fIELDnAME) iD,
|
||||
#include <messages_def.h>
|
||||
#undef MESSAGE_DEF
|
||||
|
||||
MESSAGES_ID_MAX, MESSAGES_ID_END = MESSAGES_ID_MAX
|
||||
} MessagesIds;
|
||||
|
||||
//! Thread id of each task
|
||||
typedef enum
|
||||
{
|
||||
THREAD_FIRST = 1, THREAD_NULL = 0,
|
||||
|
||||
#define TASK_DEF(tHREADiD, pRIO) THREAD_##tHREADiD,
|
||||
#define SUB_TASK_DEF(tHREADiD, sUBtASKiD)
|
||||
#include <tasks_def.h>
|
||||
#undef SUB_TASK_DEF
|
||||
#undef TASK_DEF
|
||||
|
||||
THREAD_MAX, THREAD_END = THREAD_MAX,
|
||||
} thread_id_t;
|
||||
|
||||
//! Sub-tasks id, to defined offset form thread id
|
||||
typedef enum
|
||||
{
|
||||
#define TASK_DEF(tHREADiD, pRIO) SUB_TASK_INIT_##tHREADiD = 0,
|
||||
#define SUB_TASK_DEF(tHREADiD, sUBtASKiD) SUB_TASK_OFFSET_##sUBtASKiD,
|
||||
#include <tasks_def.h>
|
||||
#undef SUB_TASK_DEF
|
||||
#undef TASK_DEF
|
||||
} sub_task_id_t;
|
||||
|
||||
//! Tasks id of each task
|
||||
typedef enum
|
||||
{
|
||||
#define TASK_DEF(tHREADiD, pRIO) tHREADiD = UL_BIT_SHIFT(THREAD_##tHREADiD, TASK_THREAD_ID_OFFSET),
|
||||
#define SUB_TASK_DEF(tHREADiD, sUBtASKiD) sUBtASKiD = (UL_BIT_SHIFT(THREAD_##tHREADiD, TASK_THREAD_ID_OFFSET) | UL_BIT_SHIFT(SUB_TASK_OFFSET_##sUBtASKiD, TASK_SUB_TASK_ID_OFFSET)),
|
||||
#include <tasks_def.h>
|
||||
#undef SUB_TASK_DEF
|
||||
#undef TASK_DEF
|
||||
|
||||
TASK_UNKNOWN = 0xFFFF,
|
||||
} task_id_t;
|
||||
|
||||
typedef union msg_s
|
||||
{
|
||||
#define MESSAGE_DEF(iD, pRIO, sTRUCT, fIELDnAME) sTRUCT fIELDnAME;
|
||||
#include <messages_def.h>
|
||||
#undef MESSAGE_DEF
|
||||
} msg_t;
|
||||
|
||||
#define INSTANCE_DEFAULT 0
|
||||
#define INSTANCE_ALL -1
|
||||
|
||||
typedef int16_t instance_t;
|
||||
typedef uint16_t MessageHeaderSize;
|
||||
|
||||
/** @struct MessageHeader
|
||||
* @brief Message Header structure for inter-task communication.
|
||||
*/
|
||||
typedef struct MessageHeader_s
|
||||
{
|
||||
MessagesIds messageId; /**< Unique message id as referenced in enum MessagesIds */
|
||||
|
||||
task_id_t originTaskId; /**< ID of the sender task */
|
||||
task_id_t destinationTaskId; /**< ID of the destination task */
|
||||
instance_t instance; /* Task instance for virtualization */
|
||||
|
||||
MessageHeaderSize size; /**< Message size (not including header size) */
|
||||
} MessageHeader;
|
||||
|
||||
/** @struct MessageDef
|
||||
* @brief Message structure for inter-task communication.
|
||||
*/
|
||||
typedef struct MessageDef_s
|
||||
{
|
||||
MessageHeader header; /**< Message header */
|
||||
msg_t msg; /**< Union of payloads as defined in x_messages_def.h headers */
|
||||
} MessageDef;
|
||||
|
||||
#endif /* INTERTASK_INTERFACE_TYPES_H_ */
|
||||
/* @} */
|
||||
5
common/utils/itti/intertask_messages_def.h
Normal file
5
common/utils/itti/intertask_messages_def.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/* This message asks for task termination */
|
||||
MESSAGE_DEF(TERMINATE_MESSAGE, MESSAGE_PRIORITY_MAX, struct {}, terminate_message)
|
||||
/* Test message used for debug */
|
||||
MESSAGE_DEF(MESSAGE_TEST, MESSAGE_PRIORITY_MAX, struct {}, message_test)
|
||||
|
||||
5
common/utils/itti/messages_def.h
Normal file
5
common/utils/itti/messages_def.h
Normal file
@@ -0,0 +1,5 @@
|
||||
// These messages files are mandatory and must always be placed in first position
|
||||
#include "intertask_messages_def.h"
|
||||
#include "timer_messages_def.h"
|
||||
|
||||
// Dummy file for the generic intertask interface definition. Actual definition should be in top level build directory.
|
||||
15
common/utils/itti/messages_types.h
Normal file
15
common/utils/itti/messages_types.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* messages_types.h
|
||||
*
|
||||
* Created on: Oct 14, 2013
|
||||
* Author: winckel
|
||||
*/
|
||||
|
||||
#ifndef MESSAGES_TYPES_H_
|
||||
#define MESSAGES_TYPES_H_
|
||||
|
||||
#include "timer_messages_types.h"
|
||||
|
||||
// Dummy file for the generic intertask interface definition. Actual definition should be in top level build directory.
|
||||
|
||||
#endif /* MESSAGES_TYPES_H_ */
|
||||
4
common/utils/itti/tasks_def.h
Normal file
4
common/utils/itti/tasks_def.h
Normal file
@@ -0,0 +1,4 @@
|
||||
// This task is mandatory and must always be placed in first position
|
||||
TASK_DEF(TASK_TIMER, TASK_PRIORITY_MED)
|
||||
|
||||
// Dummy file for the generic intertask interface definition. Actual definition should be in top level build directory.
|
||||
251
common/utils/itti/timer.c
Normal file
251
common/utils/itti/timer.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Eurecom OpenAirInterface
|
||||
Copyright(c) 1999 - 2012 Eurecom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information
|
||||
Openair Admin: openair_admin@eurecom.fr
|
||||
Openair Tech : openair_tech@eurecom.fr
|
||||
Forums : http://forums.eurecom.fr/openairinterface
|
||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
||||
06410 Biot FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "assertions.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "timer.h"
|
||||
|
||||
#include "queue.h"
|
||||
|
||||
#ifndef TMR_DEBUG
|
||||
# define TMR_DEBUG(x, args...) do { fprintf(stdout, "[TMR] [D]"x, ##args); } while(0)
|
||||
#endif
|
||||
#ifndef TMR_ERROR
|
||||
# define TMR_ERROR(x, args...) do { fprintf(stdout, "[TMR] [E]"x, ##args); } while(0)
|
||||
#endif
|
||||
|
||||
int timer_handle_signal(siginfo_t *info);
|
||||
|
||||
struct timer_elm_s {
|
||||
task_id_t task_id; ///< Task ID which has requested the timer
|
||||
int32_t instance; ///< Instance of the task which has requested the timer
|
||||
timer_t timer; ///< Unique timer id
|
||||
timer_type_t type; ///< Timer type
|
||||
void *timer_arg; ///< Optional argument that will be passed when timer expires
|
||||
STAILQ_ENTRY(timer_elm_s) entries; ///< Pointer to next element
|
||||
};
|
||||
|
||||
typedef struct timer_desc_s {
|
||||
STAILQ_HEAD(timer_list_head, timer_elm_s) timer_queue;
|
||||
pthread_mutex_t timer_list_mutex;
|
||||
struct timespec timeout;
|
||||
} timer_desc_t;
|
||||
|
||||
static timer_desc_t timer_desc;
|
||||
|
||||
#define TIMER_SEARCH(vAR, tIMERfIELD, tIMERvALUE, tIMERqUEUE) \
|
||||
do { \
|
||||
STAILQ_FOREACH(vAR, tIMERqUEUE, entries) { \
|
||||
if (((vAR)->tIMERfIELD == tIMERvALUE)) \
|
||||
break; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
int timer_handle_signal(siginfo_t *info)
|
||||
{
|
||||
struct timer_elm_s *timer_p;
|
||||
MessageDef *message_p;
|
||||
timer_has_expired_t *timer_expired_p;
|
||||
task_id_t task_id;
|
||||
int32_t instance;
|
||||
|
||||
/* Get back pointer to timer list element */
|
||||
timer_p = (struct timer_elm_s *)info->si_ptr;
|
||||
|
||||
TMR_DEBUG("Timer with id 0x%lx has expired\n", (long)timer_p->timer);
|
||||
|
||||
task_id = timer_p->task_id;
|
||||
instance = timer_p->instance;
|
||||
message_p = alloc_new_message(TASK_TIMER, TIMER_HAS_EXPIRED);
|
||||
|
||||
timer_expired_p = &message_p->msg.timer_has_expired;
|
||||
|
||||
timer_expired_p->timer_id = (long)timer_p->timer;
|
||||
timer_expired_p->arg = timer_p->timer_arg;
|
||||
|
||||
/* Timer is a one shot timer, remove it */
|
||||
if (timer_p->type == TIMER_ONE_SHOT) {
|
||||
// if (timer_delete(timer_p->timer) < 0) {
|
||||
// TMR_DEBUG("Failed to delete timer 0x%lx\n", (long)timer_p->timer);
|
||||
// }
|
||||
// TMR_DEBUG("Removed timer 0x%lx\n", (long)timer_p->timer);
|
||||
// pthread_mutex_lock(&timer_desc.timer_list_mutex);
|
||||
// STAILQ_REMOVE(&timer_desc.timer_queue, timer_p, timer_elm_s, entries);
|
||||
// pthread_mutex_unlock(&timer_desc.timer_list_mutex);
|
||||
// free(timer_p);
|
||||
// timer_p = NULL;
|
||||
if (timer_remove((long)timer_p->timer) != 0) {
|
||||
TMR_DEBUG("Failed to delete timer 0x%lx\n", (long)timer_p->timer);
|
||||
}
|
||||
}
|
||||
/* Notify task of timer expiry */
|
||||
if (send_msg_to_task(task_id, instance, message_p) < 0) {
|
||||
TMR_DEBUG("Failed to send msg TIMER_HAS_EXPIRED to task %u\n", task_id);
|
||||
free(message_p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_setup(
|
||||
uint32_t interval_sec,
|
||||
uint32_t interval_us,
|
||||
task_id_t task_id,
|
||||
int32_t instance,
|
||||
timer_type_t type,
|
||||
void *timer_arg,
|
||||
long *timer_id)
|
||||
{
|
||||
struct sigevent se;
|
||||
struct itimerspec its;
|
||||
struct timer_elm_s *timer_p;
|
||||
timer_t timer;
|
||||
|
||||
if (timer_id == NULL) {
|
||||
return -1;
|
||||
}
|
||||
DevAssert(type < TIMER_TYPE_MAX);
|
||||
|
||||
/* Allocate new timer list element */
|
||||
timer_p = malloc(sizeof(struct timer_elm_s));
|
||||
if (timer_p == NULL) {
|
||||
TMR_ERROR("Failed to create new timer element\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&timer, 0, sizeof(timer_t));
|
||||
memset(&se, 0, sizeof(struct sigevent));
|
||||
|
||||
timer_p->task_id = task_id;
|
||||
timer_p->instance = instance;
|
||||
timer_p->type = type;
|
||||
timer_p->timer_arg = timer_arg;
|
||||
|
||||
/* Setting up alarm */
|
||||
/* Set and enable alarm */
|
||||
se.sigev_notify = SIGEV_SIGNAL;
|
||||
se.sigev_signo = SIGTIMER;
|
||||
se.sigev_value.sival_ptr = timer_p;
|
||||
/* At the timer creation, the timer structure will be filled in with timer_id,
|
||||
* which is unique for this process. This id is allocated by kernel and the
|
||||
* value might be used to distinguish timers.
|
||||
*/
|
||||
if (timer_create(CLOCK_REALTIME, &se, &timer) < 0) {
|
||||
TMR_ERROR("Failed to create timer: (%s:%d)\n", strerror(errno), errno);
|
||||
free(timer_p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill in the first expiration value. */
|
||||
its.it_value.tv_sec = interval_sec;
|
||||
its.it_value.tv_nsec = interval_us * 1000;
|
||||
|
||||
if (type == TIMER_PERIODIC) {
|
||||
/* Asked for periodic timer. We set the interval time */
|
||||
its.it_interval.tv_sec = interval_sec;
|
||||
its.it_interval.tv_nsec = interval_us * 1000;
|
||||
} else {
|
||||
/* Asked for one-shot timer. Do not set the interval field */
|
||||
its.it_interval.tv_sec = 0;
|
||||
its.it_interval.tv_nsec = 0;
|
||||
}
|
||||
timer_settime(timer, 0, &its, NULL);
|
||||
/* Simply set the timer_id argument. so it can be used by caller */
|
||||
*timer_id = (long)timer;
|
||||
TMR_DEBUG("Requesting new %s timer with id 0x%lx that expires within "
|
||||
"%d sec and %d usec\n",
|
||||
type == TIMER_PERIODIC ? "periodic" : "single shot",
|
||||
*timer_id, interval_sec, interval_us);
|
||||
|
||||
timer_p->timer = timer;
|
||||
|
||||
/* Lock the queue and insert the timer at the tail */
|
||||
pthread_mutex_lock(&timer_desc.timer_list_mutex);
|
||||
STAILQ_INSERT_TAIL(&timer_desc.timer_queue, timer_p, entries);
|
||||
pthread_mutex_unlock(&timer_desc.timer_list_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_remove(long timer_id)
|
||||
{
|
||||
struct timer_elm_s *timer_p;
|
||||
int rc = 0;
|
||||
|
||||
TMR_DEBUG("Removing timer 0x%lx\n", timer_id);
|
||||
|
||||
pthread_mutex_lock(&timer_desc.timer_list_mutex);
|
||||
TIMER_SEARCH(timer_p, timer, ((timer_t)timer_id), &timer_desc.timer_queue);
|
||||
|
||||
/* We didn't find the timer in list */
|
||||
if (timer_p == NULL) {
|
||||
pthread_mutex_unlock(&timer_desc.timer_list_mutex);
|
||||
TMR_ERROR("Didn't find timer 0x%lx in list\n", (long)timer_p->timer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
STAILQ_REMOVE(&timer_desc.timer_queue, timer_p, timer_elm_s, entries);
|
||||
pthread_mutex_unlock(&timer_desc.timer_list_mutex);
|
||||
|
||||
if (timer_delete(timer_p->timer) < 0) {
|
||||
TMR_ERROR("Failed to delete timer 0x%lx\n", (long)timer_p->timer);
|
||||
rc = -1;
|
||||
}
|
||||
free(timer_p);
|
||||
timer_p = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int timer_init(void)
|
||||
{
|
||||
TMR_DEBUG("Initializing TIMER task interface\n");
|
||||
|
||||
memset(&timer_desc, 0, sizeof(timer_desc_t));
|
||||
|
||||
STAILQ_INIT(&timer_desc.timer_queue);
|
||||
pthread_mutex_init(&timer_desc.timer_list_mutex, NULL);
|
||||
|
||||
timer_desc.timeout.tv_sec = MME_TIMER_TIMEOUT_S;
|
||||
timer_desc.timeout.tv_nsec = MME_TIMER_TIMEOUT_NS;
|
||||
|
||||
TMR_DEBUG("Initializing TIMER task interface: DONE\n");
|
||||
return 0;
|
||||
}
|
||||
76
common/utils/itti/timer.h
Normal file
76
common/utils/itti/timer.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Eurecom OpenAirInterface
|
||||
Copyright(c) 1999 - 2012 Eurecom
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information
|
||||
Openair Admin: openair_admin@eurecom.fr
|
||||
Openair Tech : openair_tech@eurecom.fr
|
||||
Forums : http://forums.eurecom.fr/openairinterface
|
||||
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
||||
06410 Biot FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include "mme_config.h"
|
||||
|
||||
#ifndef TIMER_H_
|
||||
#define TIMER_H_
|
||||
|
||||
#define SIGTIMER SIGRTMIN
|
||||
|
||||
typedef enum timer_type_s {
|
||||
TIMER_PERIODIC,
|
||||
TIMER_ONE_SHOT,
|
||||
TIMER_TYPE_MAX,
|
||||
} timer_type_t;
|
||||
|
||||
/** \brief Request a new timer
|
||||
* \param interval_sec timer interval in seconds
|
||||
* \param interval_us timer interval in micro seconds
|
||||
* \param task_id task id of the task requesting the timer
|
||||
* \param instance instance of the task requesting the timer
|
||||
* \param type timer type
|
||||
* \param timer_id unique timer identifier
|
||||
* @returns -1 on failure, 0 otherwise
|
||||
**/
|
||||
int timer_setup(
|
||||
uint32_t interval_sec,
|
||||
uint32_t interval_us,
|
||||
task_id_t task_id,
|
||||
int32_t instance,
|
||||
timer_type_t type,
|
||||
void *timer_arg,
|
||||
long *timer_id);
|
||||
|
||||
/** \brief Remove the timer from list
|
||||
* \param timer_id unique timer id
|
||||
* @returns -1 on failure, 0 otherwise
|
||||
**/
|
||||
|
||||
int timer_remove(long timer_id);
|
||||
#define timer_stop timer_remove
|
||||
|
||||
/** \brief Initialize timer task and its API
|
||||
* \param mme_config MME common configuration
|
||||
* @returns -1 on failure, 0 otherwise
|
||||
**/
|
||||
int timer_init();
|
||||
|
||||
#endif
|
||||
1
common/utils/itti/timer_messages_def.h
Normal file
1
common/utils/itti/timer_messages_def.h
Normal file
@@ -0,0 +1 @@
|
||||
MESSAGE_DEF(TIMER_HAS_EXPIRED, MESSAGE_PRIORITY_MED_PLUS, timer_has_expired_t, timer_has_expired)
|
||||
9
common/utils/itti/timer_messages_types.h
Normal file
9
common/utils/itti/timer_messages_types.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef TIMER_MESSAGES_TYPES_H_
|
||||
#define TIMER_MESSAGES_TYPES_H_
|
||||
|
||||
typedef struct {
|
||||
void *arg;
|
||||
long timer_id;
|
||||
} timer_has_expired_t;
|
||||
|
||||
#endif /* TIMER_MESSAGES_TYPES_H_ */
|
||||
Reference in New Issue
Block a user