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:
winckel
2013-10-21 09:08:27 +00:00
parent b58c8c4b6e
commit 04fa42dd01
15 changed files with 0 additions and 0 deletions

View 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

View 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;
}
}

View 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_ */
/* @} */

View 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;
}

View 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_ */

View 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_ */
/* @} */

View 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_ */
/* @} */

View 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)

View 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.

View 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_ */

View 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
View 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
View 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

View File

@@ -0,0 +1 @@
MESSAGE_DEF(TIMER_HAS_EXPIRED, MESSAGE_PRIORITY_MED_PLUS, timer_has_expired_t, timer_has_expired)

View 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_ */