timer.c 8.35 KB
Newer Older
Cedric Roux's avatar
 
Cedric Roux committed
1
/*******************************************************************************
ghaddab's avatar
ghaddab committed
2
3
    OpenAirInterface 
    Copyright(c) 1999 - 2014 Eurecom
Cedric Roux's avatar
 
Cedric Roux committed
4

ghaddab's avatar
ghaddab committed
5
6
7
8
    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
Cedric Roux's avatar
 
Cedric Roux committed
9
10


ghaddab's avatar
ghaddab committed
11
12
13
14
    OpenAirInterface is distributed in the hope that 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
15

ghaddab's avatar
ghaddab committed
16
17
18
19
    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is 
   included in this distribution in the file called "COPYING". If not, 
   see <http://www.gnu.org/licenses/>.
Cedric Roux's avatar
 
Cedric Roux committed
20
21

  Contact Information
ghaddab's avatar
ghaddab committed
22
23
24
25
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
  OpenAirInterface Dev  : openair4g-devel@eurecom.fr
  
ghaddab's avatar
ghaddab committed
26
  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
Cedric Roux's avatar
 
Cedric Roux committed
27

ghaddab's avatar
ghaddab committed
28
 *******************************************************************************/
Cedric Roux's avatar
 
Cedric Roux committed
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#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"
43
#include "log.h"
Cedric Roux's avatar
 
Cedric Roux committed
44
45
#include "queue.h"

46
47
48
49
50
#if defined (LOG_D) && defined (LOG_E)
# define TMR_DEBUG(x, args...)  LOG_D(TMR, x, ##args)
# define TMR_ERROR(x, args...)  LOG_E(TMR, x, ##args)
#endif

Cedric Roux's avatar
 
Cedric Roux committed
51
#ifndef TMR_DEBUG
52
# define TMR_DEBUG(x, args...)  do { fprintf(stdout, "[TMR][D]"x, ##args); } while(0)
Cedric Roux's avatar
 
Cedric Roux committed
53
54
#endif
#ifndef TMR_ERROR
55
# define TMR_ERROR(x, args...)  do { fprintf(stdout, "[TMR][E]"x, ##args); } while(0)
Cedric Roux's avatar
 
Cedric Roux committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#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;
100
    message_p = itti_alloc_new_message(TASK_TIMER, TIMER_HAS_EXPIRED);
Cedric Roux's avatar
 
Cedric Roux committed
101

102
    timer_expired_p = &message_p->ittiMsg.timer_has_expired;
Cedric Roux's avatar
 
Cedric Roux committed
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

    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 */
123
    if (itti_send_msg_to_task(task_id, instance, message_p) < 0) {
Cedric Roux's avatar
 
Cedric Roux committed
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
        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;
    }
149
    AssertFatal (type < TIMER_TYPE_MAX, "Invalid timer type (%d/%d)!\n", type, TIMER_TYPE_MAX);
Cedric Roux's avatar
 
Cedric Roux committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214

    /* 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)
{
    int rc = 0;
215
    struct timer_elm_s *timer_p;
Cedric Roux's avatar
 
Cedric Roux committed
216
217
218
219
220
221
222
223
224

    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);
225
        TMR_ERROR("Didn't find timer 0x%lx in list\n", timer_id);
Cedric Roux's avatar
 
Cedric Roux committed
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
        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);

    TMR_DEBUG("Initializing TIMER task interface: DONE\n");
    return 0;
}