intertask_interface.c 16.9 KB
Newer Older
Cedric Roux's avatar
 
Cedric Roux committed
1
2
/*******************************************************************************

3
4
 Eurecom OpenAirInterface
 Copyright(c) 1999 - 2012 Eurecom
Cedric Roux's avatar
 
Cedric Roux committed
5

6
7
8
 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.
Cedric Roux's avatar
 
Cedric Roux committed
9

10
11
12
13
 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.
Cedric Roux's avatar
 
Cedric Roux committed
14

15
16
17
 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.
Cedric Roux's avatar
 
Cedric Roux committed
18

19
20
 The full GNU General Public License is included in this distribution in
 the file called "COPYING".
Cedric Roux's avatar
 
Cedric Roux committed
21

22
23
24
25
26
27
 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
Cedric Roux's avatar
 
Cedric Roux committed
28

29
 *******************************************************************************/
Cedric Roux's avatar
 
Cedric Roux committed
30
31
32
33
34
35
36

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
37
#include <signal.h>
Cedric Roux's avatar
 
Cedric Roux committed
38
39
40
41
42
43
44
45
46
47
48

#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

49
#include "signals.h"
Cedric Roux's avatar
 
Cedric Roux committed
50
51
52
53
54
55
56
57
58
59
60
61
62
#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 {
63
    TASK_STATE_NOT_CONFIGURED, TASK_STATE_STARTING, TASK_STATE_READY, TASK_STATE_ENDED, TASK_STATE_MAX,
Cedric Roux's avatar
 
Cedric Roux committed
64
65
66
67
68
69
} 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;

70
    MessageDef *msg; ///< Pointer to the message
Cedric Roux's avatar
 
Cedric Roux committed
71

72
73
    message_number_t message_number; ///< Unique message number
    uint32_t message_priority; ///< Message priority
Cedric Roux's avatar
 
Cedric Roux committed
74
75
76
77
};

typedef struct task_desc_s {
    /* Queue of messages belonging to the task */
78
79
    STAILQ_HEAD(message_queue_head, message_list_s)
    message_queue;
Cedric Roux's avatar
 
Cedric Roux committed
80
81

    /* Number of messages in the queue */
82
    volatile uint32_t message_in_queue;
Cedric Roux's avatar
 
Cedric Roux committed
83
    /* Mutex for the message queue */
84
    pthread_mutex_t message_queue_mutex;
Cedric Roux's avatar
 
Cedric Roux committed
85
    /* Conditional var for message queue and task synchro */
86
87
    pthread_cond_t message_queue_cond_var;
    pthread_t task_thread;
Cedric Roux's avatar
 
Cedric Roux committed
88
89
90
91
92
93
    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 */
94
    message_number_t message_number __attribute__((aligned(8)));
Cedric Roux's avatar
 
Cedric Roux committed
95
96
97
98

    thread_id_t thread_max;
    MessagesIds messages_id_max;

99
100
    pthread_t thread_handling_signals;

Cedric Roux's avatar
 
Cedric Roux committed
101
102
103
104
105
106
    const char * const *threads_name;
    const message_info_t *messages_info;
};

static struct itti_desc_s itti_desc;

107
static inline message_number_t itti_increment_message_number(void) {
Cedric Roux's avatar
 
Cedric Roux committed
108
109
110
111
    /* Atomic operation supported by GCC: returns the current message number
     * and then increment it by 1.
     * This can be done without mutex.
     */
112
    return __sync_fetch_and_add (&itti_desc.message_number, 1);
Cedric Roux's avatar
 
Cedric Roux committed
113
114
}

115
static inline uint32_t itti_get_message_priority(MessagesIds message_id) {
Cedric Roux's avatar
 
Cedric Roux committed
116
117
118
119
120
    DevCheck(message_id < itti_desc.messages_id_max, message_id, itti_desc.messages_id_max, 0);

    return (itti_desc.messages_info[message_id].priority);
}

121
char *itti_get_message_name(MessagesIds message_id) {
Cedric Roux's avatar
 
Cedric Roux committed
122
123
124
125
126
    DevCheck(message_id < itti_desc.messages_id_max, message_id, itti_desc.messages_id_max, 0);

    return (itti_desc.messages_info[message_id].name);
}

127
128
int itti_send_broadcast_message(MessageDef *message_p) {
    thread_id_t origin_thread_id;
Cedric Roux's avatar
 
Cedric Roux committed
129
130
    uint32_t i;
    int ret = 0;
131
    int result;
Cedric Roux's avatar
 
Cedric Roux committed
132

133
134
135
136
    if (message_p == NULL) {
        ITTI_ERROR("Message to broadcast is NULL (%s:%d)\n", __FILE__, __LINE__);
        return -1;
    }
Cedric Roux's avatar
 
Cedric Roux committed
137

138
    origin_thread_id = TASK_GET_THREAD_ID(message_p->header.originTaskId);
Cedric Roux's avatar
 
Cedric Roux committed
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    for (i = THREAD_FIRST; i < itti_desc.thread_max; i++) {
        MessageDef *new_message_p;

        /* Skip task that broadcast the message */
        if (i != origin_thread_id) {
            /* Skip tasks which are not running */
            if (itti_desc.tasks[i].task_state == TASK_STATE_READY) {
                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));
                result = itti_send_msg_to_task (TASK_SHIFT_THREAD_ID(i), INSTANCE_DEFAULT, new_message_p);
                if (result < 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 = result;
                    free (new_message_p);
                }
161
            }
Cedric Roux's avatar
 
Cedric Roux committed
162
163
        }
    }
164
    free (message_p);
Cedric Roux's avatar
 
Cedric Roux committed
165
166
167
168

    return ret;
}

169
inline MessageDef *itti_alloc_new_message(task_id_t origin_task_id, MessagesIds message_id) {
Cedric Roux's avatar
 
Cedric Roux committed
170
171
    MessageDef *temp = NULL;

172
173
    if (message_id >= itti_desc.messages_id_max) {
        ITTI_ERROR("Invalid message id %d (%s:%d)\n", message_id, __FILE__, __LINE__);
Cedric Roux's avatar
 
Cedric Roux committed
174
175
176
        return NULL;
    }

177
    temp = calloc (1, MESSAGE_SIZE(message_id));
Cedric Roux's avatar
 
Cedric Roux committed
178
179

    if (temp == NULL) {
180
        ITTI_ERROR("Cannot allocate memory for new message (%s:%d)\n", __FILE__, __LINE__);
Cedric Roux's avatar
 
Cedric Roux committed
181
182
183
184
185
186
187
188
189
190
        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;
}

191
192
193
194
195
196
int itti_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;
Cedric Roux's avatar
 
Cedric Roux committed
197

198
    if (thread_id >= itti_desc.thread_max) {
Cedric Roux's avatar
 
Cedric Roux committed
199
200
201
202
203
204
205
206
207
208
209
        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);

210
    priority = itti_get_message_priority (message_id);
Cedric Roux's avatar
 
Cedric Roux committed
211
212

    /* Lock the mutex to get exclusive access to the list */
213
    pthread_mutex_lock (&itti_desc.tasks[thread_id].message_queue_mutex);
Cedric Roux's avatar
 
Cedric Roux committed
214
215

    /* We cannot send a message if the task is not running */
216
217
    DevCheck(itti_desc.tasks[thread_id].task_state == TASK_STATE_READY, itti_desc.tasks[thread_id].task_state,
             TASK_STATE_READY, thread_id);
Cedric Roux's avatar
 
Cedric Roux committed
218
219

    /* Check the number of messages in the queue */
220
221
    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,
Cedric Roux's avatar
 
Cedric Roux committed
222
223
224
             itti_desc.tasks[thread_id].message_in_queue);

    /* Allocate new list element */
225
226
    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__);
Cedric Roux's avatar
 
Cedric Roux committed
227
228
229
230
        return -1;
    }

    /* Increment the global message number */
231
    message_number = itti_increment_message_number ();
Cedric Roux's avatar
 
Cedric Roux committed
232
233

    /* Fill in members */
234
235
    new->msg = message;
    new->message_number = message_number;
Cedric Roux's avatar
 
Cedric Roux committed
236
237
    new->message_priority = priority;

238
239
    itti_dump_queue_message (message_number, message, itti_desc.messages_info[message_id].name,
                             MESSAGE_SIZE(message_id));
Cedric Roux's avatar
 
Cedric Roux committed
240

241
242
243
244
    if (STAILQ_EMPTY (&itti_desc.tasks[thread_id].message_queue)) {
        STAILQ_INSERT_HEAD (&itti_desc.tasks[thread_id].message_queue, new, next_element);
    }
    else {
Cedric Roux's avatar
 
Cedric Roux committed
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
//         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) {
263
        STAILQ_INSERT_TAIL (&itti_desc.tasks[thread_id].message_queue, new, next_element);
Cedric Roux's avatar
 
Cedric Roux committed
264
265
266
267
268
269
270
271
272
273
//         } 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 */
274
        pthread_cond_signal (&itti_desc.tasks[thread_id].message_queue_cond_var);
Cedric Roux's avatar
 
Cedric Roux committed
275
276
    }
    /* Release the mutex */
277
278
279
280
    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]);
Cedric Roux's avatar
 
Cedric Roux committed
281
282
283
    return 0;
}

284
void itti_receive_msg(task_id_t task_id, MessageDef **received_msg) {
Cedric Roux's avatar
 
Cedric Roux committed
285
286
287
288
289
290
    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
291
    pthread_mutex_lock (&itti_desc.tasks[thread_id].message_queue_mutex);
Cedric Roux's avatar
 
Cedric Roux committed
292
293

    if (itti_desc.tasks[thread_id].message_in_queue == 0) {
294
        ITTI_DEBUG("Message in queue[(%u:%s)] == 0, waiting\n", thread_id, itti_desc.threads_name[thread_id]);
Cedric Roux's avatar
 
Cedric Roux committed
295
        // Wait while list == 0
296
297
        pthread_cond_wait (&itti_desc.tasks[thread_id].message_queue_cond_var,
                           &itti_desc.tasks[thread_id].message_queue_mutex);
Cedric Roux's avatar
 
Cedric Roux committed
298
299
300
301
        ITTI_DEBUG("Receiver queue[(%u:%s)] got new message notification for task %x\n",
                   thread_id, itti_desc.threads_name[thread_id], task_id);
    }

302
303
    if (!STAILQ_EMPTY (&itti_desc.tasks[thread_id].message_queue)) {
        struct message_list_s *temp = STAILQ_FIRST (&itti_desc.tasks[thread_id].message_queue);
Cedric Roux's avatar
 
Cedric Roux committed
304
305
306
307
308

        /* Update received_msg reference */
        *received_msg = temp->msg;

        /* Remove message from queue */
309
310
        STAILQ_REMOVE_HEAD (&itti_desc.tasks[thread_id].message_queue, next_element);
        free (temp);
Cedric Roux's avatar
 
Cedric Roux committed
311
312
313
        itti_desc.tasks[thread_id].message_in_queue--;
    }
    // Release the mutex
314
    pthread_mutex_unlock (&itti_desc.tasks[thread_id].message_queue_mutex);
Cedric Roux's avatar
 
Cedric Roux committed
315
316
}

317
void itti_poll_msg(task_id_t task_id, instance_t instance, MessageDef **received_msg) {
Cedric Roux's avatar
 
Cedric Roux committed
318
319
    thread_id_t thread_id = TASK_GET_THREAD_ID(task_id);

320
321
    DevCheck(thread_id < itti_desc.thread_max, thread_id, 0, 0);
    DevAssert(received_msg != NULL);
Cedric Roux's avatar
 
Cedric Roux committed
322
323
324

    *received_msg = NULL;

325
    if (itti_desc.tasks[thread_id].message_in_queue != 0) {
Cedric Roux's avatar
 
Cedric Roux committed
326
327
328
329
330
        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);

331
        STAILQ_FOREACH (temp, &itti_desc.tasks[thread_id].message_queue, next_element)
Cedric Roux's avatar
 
Cedric Roux committed
332
333
        {
            if ((temp->msg->header.destinationTaskId == task_id)
334
                    && ((instance == INSTANCE_ALL) || (temp->msg->header.instance == instance))) {
Cedric Roux's avatar
 
Cedric Roux committed
335
336
337
338
                /* Update received_msg reference */
                *received_msg = temp->msg;

                /* Remove message from queue */
339
                STAILQ_REMOVE (&itti_desc.tasks[thread_id].message_queue, temp, message_list_s, next_element);
Cedric Roux's avatar
 
Cedric Roux committed
340
341
342
                free (temp);
                itti_desc.tasks[thread_id].message_in_queue--;

343
344
345
                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);
Cedric Roux's avatar
 
Cedric Roux committed
346
347
348
349
350
351
352
353
                break;
            }
        }

        // Release the mutex
        pthread_mutex_unlock (&itti_desc.tasks[thread_id].message_queue_mutex);
    }

354
    if (*received_msg == NULL) {
Cedric Roux's avatar
 
Cedric Roux committed
355
356
357
358
        ITTI_DEBUG("No message in queue[(%u:%s)] for task %x\n", thread_id, itti_desc.threads_name[thread_id], task_id);
    }
}

359
int itti_create_task(task_id_t task_id, void *(*start_routine)(void *), void *args_p) {
Cedric Roux's avatar
 
Cedric Roux committed
360
361
362
363
364
365
366
    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"
367
368
        " for %s thread\n",
                   itti_desc.threads_name[thread_id]);
Cedric Roux's avatar
 
Cedric Roux committed
369
370
371
372
373
        return -1;
    }

    itti_desc.tasks[thread_id].task_state = TASK_STATE_STARTING;

374
375
376
    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);
Cedric Roux's avatar
 
Cedric Roux committed
377
378
379
380
        return -1;
    }

    /* Wait till the thread is completely ready */
381
382
    while (itti_desc.tasks[thread_id].task_state != TASK_STATE_READY)
        ;
Cedric Roux's avatar
 
Cedric Roux committed
383
384
385
    return 0;
}

386
void itti_mark_task_ready(task_id_t task_id) {
Cedric Roux's avatar
 
Cedric Roux committed
387
388
389
390
    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
391
    pthread_mutex_lock (&itti_desc.tasks[thread_id].message_queue_mutex);
Cedric Roux's avatar
 
Cedric Roux committed
392
393
    itti_desc.tasks[thread_id].task_state = TASK_STATE_READY;
    // Release the mutex
394
395
396
397
398
399
400
401
402
403
404
405
    pthread_mutex_unlock (&itti_desc.tasks[thread_id].message_queue_mutex);
}

void itti_terminate_tasks(task_id_t task_id) {
    // Sends Terminate signals to all tasks.
    itti_send_terminate_message (task_id);

    if (itti_desc.thread_handling_signals >= 0) {
        pthread_kill (itti_desc.thread_handling_signals, SIGUSR1);
    }

    pthread_exit (NULL);
Cedric Roux's avatar
 
Cedric Roux committed
406
407
}

408
409
int itti_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) {
Cedric Roux's avatar
 
Cedric Roux committed
410
411
412
    int i;
    itti_desc.message_number = 0;

413
414
    CHECK_INIT_RETURN(signal_init());

Cedric Roux's avatar
 
Cedric Roux committed
415
416
417
    /* Saves threads and messages max values */
    itti_desc.thread_max = thread_max;
    itti_desc.messages_id_max = messages_id_max;
418
    itti_desc.thread_handling_signals = -1;
Cedric Roux's avatar
 
Cedric Roux committed
419
420
421
422
    itti_desc.threads_name = threads_name;
    itti_desc.messages_info = messages_info;

    /* Allocates memory for tasks info */
423
    itti_desc.tasks = calloc (itti_desc.thread_max, sizeof(task_desc_t));
Cedric Roux's avatar
 
Cedric Roux committed
424
425
426

    /* Initializing each queue and related stuff */
    for (i = THREAD_FIRST; i < itti_desc.thread_max; i++) {
427
        STAILQ_INIT (&itti_desc.tasks[i].message_queue);
Cedric Roux's avatar
 
Cedric Roux committed
428
429
        itti_desc.tasks[i].message_in_queue = 0;
        // Initialize mutexes
430
        pthread_mutex_init (&itti_desc.tasks[i].message_queue_mutex, NULL);
Cedric Roux's avatar
 
Cedric Roux committed
431
        // Initialize Cond vars
432
        pthread_cond_init (&itti_desc.tasks[i].message_queue_cond_var, NULL);
Cedric Roux's avatar
 
Cedric Roux committed
433
434
        itti_desc.tasks[i].task_state = TASK_STATE_NOT_CONFIGURED;
    }
435
    itti_dump_init (messages_definition_xml);
Cedric Roux's avatar
 
Cedric Roux committed
436

437
    CHECK_INIT_RETURN(timer_init ());
Cedric Roux's avatar
 
Cedric Roux committed
438
439
440
441

    return 0;
}

442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
void itti_wait_tasks_end(void) {
    int end = 0;
    int i;

    itti_desc.thread_handling_signals = pthread_self ();

    /* Handle signals here */
    while (end == 0) {
        signal_handle (&end);
    }

    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) {
            ITTI_DEBUG("Waiting end of thread %s\n", itti_desc.threads_name[i]);

            pthread_join (itti_desc.tasks[i].task_thread, NULL);
            itti_desc.tasks[i].task_state = TASK_STATE_ENDED;
        }
    }
}

void itti_send_terminate_message(task_id_t task_id) {
Cedric Roux's avatar
 
Cedric Roux committed
465
466
    MessageDef *terminate_message_p;

467
    terminate_message_p = itti_alloc_new_message (task_id, TERMINATE_MESSAGE);
Cedric Roux's avatar
 
Cedric Roux committed
468

469
    itti_send_broadcast_message (terminate_message_p);
Cedric Roux's avatar
 
Cedric Roux committed
470
}