timer.c 8.76 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
 * Copyright (c) 2015, EURECOM (www.eurecom.fr)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those
 * of the authors and should not be interpreted as representing official policies,
 * either expressed or implied, of the FreeBSD Project.
 */
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
#endif

int timer_handle_signal(siginfo_t *info);

struct timer_elm_s {
61
62
63
64
65
66
  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
Cedric Roux's avatar
   
Cedric Roux committed
67
68
69
};

typedef struct timer_desc_s {
70
71
72
  STAILQ_HEAD(timer_list_head, timer_elm_s) timer_queue;
  pthread_mutex_t timer_list_mutex;
  struct timespec timeout;
Cedric Roux's avatar
   
Cedric Roux committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
} 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)
{
87
88
89
90
91
92
93
94
95
  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;

96
  // LG: To many traces for msc timer:
97
98
  TMR_DEBUG("Timer with id 0x%lx has expired\n", (long)timer_p->timer);
  printf("Timer with id 0x%lx has expired\n", (long)timer_p->timer);
nikaeinn's avatar
nikaeinn committed
99

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  task_id = timer_p->task_id;
  instance = timer_p->instance;
  message_p = itti_alloc_new_message(TASK_TIMER, TIMER_HAS_EXPIRED);

  timer_expired_p = &message_p->ittiMsg.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);
Cedric Roux's avatar
   
Cedric Roux committed
122
    }
123
  }
124

125
126
127
128
129
130
  /* Notify task of timer expiry */
  if (itti_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;
  }
131
132
133

#if defined(ENB_AGENT_SB_IF)

nikaeinn's avatar
nikaeinn committed
134
#endif 
Cedric Roux's avatar
   
Cedric Roux committed
135

136
  return 0;
Cedric Roux's avatar
   
Cedric Roux committed
137
138
139
}

int timer_setup(
140
141
142
143
144
145
146
  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)
Cedric Roux's avatar
   
Cedric Roux committed
147
{
148
149
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
  struct sigevent     se;
  struct itimerspec   its;
  struct timer_elm_s *timer_p;
  timer_t             timer;

  if (timer_id == NULL) {
    return -1;
  }

  AssertFatal (type < TIMER_TYPE_MAX, "Invalid timer type (%d/%d)!\n", 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);

213
214
215
216
217
  printf("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);

218
219
220
221
222
223
224
225
  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;
Cedric Roux's avatar
   
Cedric Roux committed
226
227
228
229
}

int timer_remove(long timer_id)
{
230
231
  int rc = 0;
  struct timer_elm_s *timer_p;
Cedric Roux's avatar
   
Cedric Roux committed
232

233
  TMR_DEBUG("Removing timer 0x%lx\n", timer_id);
Cedric Roux's avatar
   
Cedric Roux committed
234

235
236
  pthread_mutex_lock(&timer_desc.timer_list_mutex);
  TIMER_SEARCH(timer_p, timer, ((timer_t)timer_id), &timer_desc.timer_queue);
Cedric Roux's avatar
   
Cedric Roux committed
237

238
239
  /* We didn't find the timer in list */
  if (timer_p == NULL) {
Cedric Roux's avatar
   
Cedric Roux committed
240
    pthread_mutex_unlock(&timer_desc.timer_list_mutex);
241
242
243
    TMR_ERROR("Didn't find timer 0x%lx in list\n", timer_id);
    return -1;
  }
Cedric Roux's avatar
   
Cedric Roux committed
244

245
246
247
248
249
250
251
252
253
254
255
  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;
Cedric Roux's avatar
   
Cedric Roux committed
256
257
258
259
}

int timer_init(void)
{
260
  TMR_DEBUG("Initializing TIMER task interface\n");
Cedric Roux's avatar
   
Cedric Roux committed
261

262
  memset(&timer_desc, 0, sizeof(timer_desc_t));
Cedric Roux's avatar
   
Cedric Roux committed
263

264
265
  STAILQ_INIT(&timer_desc.timer_queue);
  pthread_mutex_init(&timer_desc.timer_list_mutex, NULL);
Cedric Roux's avatar
   
Cedric Roux committed
266

267
268
  TMR_DEBUG("Initializing TIMER task interface: DONE\n");
  return 0;
Cedric Roux's avatar
   
Cedric Roux committed
269
}