Wed Jan 8 2020 09:50:19

Asterisk developer's documentation


res_timing_timerfd.c File Reference

timerfd timing interface More...

#include "asterisk.h"
#include <sys/timerfd.h>
#include "asterisk/module.h"
#include "asterisk/astobj2.h"
#include "asterisk/timing.h"
#include "asterisk/logger.h"
#include "asterisk/utils.h"
#include "asterisk/time.h"

Go to the source code of this file.

Data Structures

struct  timerfd_timer
 

Macros

#define TIMERFD_MAX_RATE   1000
 
#define TIMERFD_TIMER_BUCKETS   563
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int load_module (void)
 
static void timer_destroy (void *obj)
 
static int timerfd_timer_ack (int handle, unsigned int quantity)
 
static void timerfd_timer_close (int handle)
 
static int timerfd_timer_cmp (void *obj, void *args, int flags)
 
static int timerfd_timer_disable_continuous (int handle)
 
static int timerfd_timer_enable_continuous (int handle)
 
static enum ast_timer_event timerfd_timer_get_event (int handle)
 
static unsigned int timerfd_timer_get_max_rate (int handle)
 
static int timerfd_timer_hash (const void *obj, const int flags)
 
static int timerfd_timer_open (void)
 
static int timerfd_timer_set_rate (int handle, unsigned int rate)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Timerfd Timing Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_TIMING, }
 
static struct ast_module_infoast_module_info = &__mod_info
 
static struct ao2_containertimerfd_timers
 
static struct ast_timing_interface timerfd_timing
 
static void * timing_funcs_handle
 

Detailed Description

timerfd timing interface

Author
Mark Michelson mmich.nosp@m.elso.nosp@m.n@dig.nosp@m.ium..nosp@m.com

Definition in file res_timing_timerfd.c.

Macro Definition Documentation

#define TIMERFD_MAX_RATE   1000

Definition at line 69 of file res_timing_timerfd.c.

Referenced by timerfd_timer_get_max_rate().

#define TIMERFD_TIMER_BUCKETS   563

Definition at line 68 of file res_timing_timerfd.c.

Referenced by load_module().

Function Documentation

static void __reg_module ( void  )
static

Definition at line 376 of file res_timing_timerfd.c.

static void __unreg_module ( void  )
static

Definition at line 376 of file res_timing_timerfd.c.

static int load_module ( void  )
static

Definition at line 336 of file res_timing_timerfd.c.

References ao2_container_alloc, ao2_ref, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_timing_interface, LOG_ERROR, TIMERFD_TIMER_BUCKETS, timerfd_timer_cmp(), timerfd_timer_hash(), and timing_funcs_handle.

337 {
338  int fd;
339 
340  /* Make sure we support the necessary clock type */
341  if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
342  ast_log(LOG_ERROR, "timerfd_create() not supported by the kernel. Not loading.\n");
344  }
345 
346  close(fd);
347 
350  }
351 
353  ao2_ref(timerfd_timers, -1);
355  }
356 
358 }
static int timerfd_timer_hash(const void *obj, const int flags)
static void * timing_funcs_handle
static struct ast_timing_interface timerfd_timing
static struct ao2_container * timerfd_timers
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int timerfd_timer_cmp(void *obj, void *args, int flags)
#define TIMERFD_TIMER_BUCKETS
#define ao2_container_alloc(arg1, arg2, arg3)
Definition: astobj2.h:734
#define ast_register_timing_interface(i)
Register a set of timing functions.
Definition: timing.h:94
static void timer_destroy ( void *  obj)
static

Definition at line 90 of file res_timing_timerfd.c.

References timerfd_timer::handle, and timer.

Referenced by timerfd_timer_open().

91 {
92  struct timerfd_timer *timer = obj;
93  close(timer->handle);
94  timer->handle = -1;
95 }
static struct ast_timer * timer
Definition: chan_iax2.c:313
static int timerfd_timer_ack ( int  handle,
unsigned int  quantity 
)
static

Definition at line 172 of file res_timing_timerfd.c.

References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_debug, ast_log(), errno, timerfd_timer::handle, LOG_ERROR, and OBJ_POINTER.

173 {
174  uint64_t expirations;
175  int read_result = 0;
176  int res = 0;
177  struct timerfd_timer *our_timer, find_helper = {
178  .handle = handle,
179  };
180 
181  if (handle == -1) {
182  ast_log(LOG_ERROR, "Attempting to ack timerfd handle -1");
183  return -1;
184  }
185 
186  if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
187  ast_log(LOG_ERROR, "Couldn't find a timer with handle %d\n", handle);
188  return -1;
189  }
190 
191  ao2_lock(our_timer);
192 
193  do {
194  struct itimerspec timer_status;
195 
196  if (timerfd_gettime(handle, &timer_status)) {
197  ast_log(LOG_ERROR, "Call to timerfd_gettime() using handle %d error: %s\n", handle, strerror(errno));
198  expirations = 0;
199  res = -1;
200  break;
201  }
202 
203  if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) {
204  ast_debug(1, "Avoiding read on disarmed timerfd %d\n", handle);
205  expirations = 0;
206  break;
207  }
208 
209  read_result = read(handle, &expirations, sizeof(expirations));
210  if (read_result == -1) {
211  if (errno == EINTR || errno == EAGAIN) {
212  continue;
213  } else {
214  ast_log(LOG_ERROR, "Read error: %s\n", strerror(errno));
215  res = -1;
216  break;
217  }
218  }
219  } while (read_result != sizeof(expirations));
220 
221  ao2_unlock(our_timer);
222  ao2_ref(our_timer, -1);
223 
224  if (expirations != quantity) {
225  ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations);
226  }
227  return res;
228 }
#define ao2_unlock(a)
Definition: astobj2.h:497
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static struct ao2_container * timerfd_timers
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define ao2_lock(a)
Definition: astobj2.h:488
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
int errno
static void timerfd_timer_close ( int  handle)
static

Definition at line 119 of file res_timing_timerfd.c.

References ao2_find, ao2_ref, ao2_unlink, ast_log(), timerfd_timer::handle, LOG_ERROR, and OBJ_POINTER.

120 {
121  struct timerfd_timer *our_timer, find_helper = {
122  .handle = handle,
123  };
124 
125  if (handle == -1) {
126  ast_log(LOG_ERROR, "Attempting to close timerfd handle -1");
127  return;
128  }
129 
130  if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
131  ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
132  return;
133  }
134 
135  ao2_unlink(timerfd_timers, our_timer);
136  ao2_ref(our_timer, -1);
137 }
static struct ao2_container * timerfd_timers
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
#define ao2_unlink(arg1, arg2)
Definition: astobj2.h:817
static int timerfd_timer_cmp ( void *  obj,
void *  args,
int  flags 
)
static

Definition at line 84 of file res_timing_timerfd.c.

References args, CMP_MATCH, CMP_STOP, and timerfd_timer::handle.

Referenced by load_module().

85 {
86  struct timerfd_timer *timer1 = obj, *timer2 = args;
87  return timer1->handle == timer2->handle ? CMP_MATCH | CMP_STOP : 0;
88 }
static struct @350 args
static int timerfd_timer_disable_continuous ( int  handle)
static

Definition at line 267 of file res_timing_timerfd.c.

References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), timerfd_timer::handle, timerfd_timer::is_continuous, LOG_ERROR, OBJ_POINTER, and timerfd_timer::saved_timer.

268 {
269  int res;
270  struct timerfd_timer *our_timer, find_helper = {
271  .handle = handle,
272  };
273 
274  if (handle == -1) {
275  ast_log(LOG_ERROR, "Attempting to disable timerfd handle -1");
276  return -1;
277  }
278 
279  if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
280  ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
281  return -1;
282  }
283  ao2_lock(our_timer);
284 
285  if (!our_timer->is_continuous) {
286  /* No reason to do anything if we're not
287  * in continuous mode
288  */
289  ao2_unlock(our_timer);
290  ao2_ref(our_timer, -1);
291  return 0;
292  }
293 
294  res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL);
295  our_timer->is_continuous = 0;
296  memset(&our_timer->saved_timer, 0, sizeof(our_timer->saved_timer));
297  ao2_unlock(our_timer);
298  ao2_ref(our_timer, -1);
299  return res;
300 }
#define ao2_unlock(a)
Definition: astobj2.h:497
static struct ao2_container * timerfd_timers
unsigned int is_continuous
struct itimerspec saved_timer
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define ao2_lock(a)
Definition: astobj2.h:488
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
static int timerfd_timer_enable_continuous ( int  handle)
static

Definition at line 230 of file res_timing_timerfd.c.

References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), timerfd_timer::handle, timerfd_timer::is_continuous, LOG_ERROR, OBJ_POINTER, and timerfd_timer::saved_timer.

231 {
232  int res;
233  struct itimerspec continuous_timer = {
234  .it_value.tv_nsec = 1L,
235  };
236  struct timerfd_timer *our_timer, find_helper = {
237  .handle = handle,
238  };
239 
240  if (handle == -1) {
241  ast_log(LOG_ERROR, "Attempting to enable timerfd handle -1");
242  return -1;
243  }
244 
245  if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
246  ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
247  return -1;
248  }
249  ao2_lock(our_timer);
250 
251  if (our_timer->is_continuous) {
252  /*It's already in continous mode, no need to do
253  * anything further
254  */
255  ao2_unlock(our_timer);
256  ao2_ref(our_timer, -1);
257  return 0;
258  }
259 
260  res = timerfd_settime(handle, 0, &continuous_timer, &our_timer->saved_timer);
261  our_timer->is_continuous = 1;
262  ao2_unlock(our_timer);
263  ao2_ref(our_timer, -1);
264  return res;
265 }
#define ao2_unlock(a)
Definition: astobj2.h:497
static struct ao2_container * timerfd_timers
unsigned int is_continuous
struct itimerspec saved_timer
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define ao2_lock(a)
Definition: astobj2.h:488
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
static enum ast_timer_event timerfd_timer_get_event ( int  handle)
static

Definition at line 302 of file res_timing_timerfd.c.

References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), AST_TIMING_EVENT_CONTINUOUS, AST_TIMING_EVENT_EXPIRED, timerfd_timer::handle, timerfd_timer::is_continuous, LOG_ERROR, and OBJ_POINTER.

303 {
304  enum ast_timer_event res;
305  struct timerfd_timer *our_timer, find_helper = {
306  .handle = handle,
307  };
308 
309  if (handle == -1) {
310  ast_log(LOG_ERROR, "Attempting to get event from timerfd handle -1");
311  return -1;
312  }
313 
314  if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
315  ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
316  return -1;
317  }
318  ao2_lock(our_timer);
319 
320  if (our_timer->is_continuous) {
322  } else {
324  }
325 
326  ao2_unlock(our_timer);
327  ao2_ref(our_timer, -1);
328  return res;
329 }
ast_timer_event
Definition: timing.h:57
#define ao2_unlock(a)
Definition: astobj2.h:497
static struct ao2_container * timerfd_timers
unsigned int is_continuous
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define ao2_lock(a)
Definition: astobj2.h:488
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
static unsigned int timerfd_timer_get_max_rate ( int  handle)
static

Definition at line 331 of file res_timing_timerfd.c.

References TIMERFD_MAX_RATE.

332 {
333  return TIMERFD_MAX_RATE;
334 }
#define TIMERFD_MAX_RATE
static int timerfd_timer_hash ( const void *  obj,
const int  flags 
)
static

Definition at line 77 of file res_timing_timerfd.c.

References timerfd_timer::handle, and timer.

Referenced by load_module().

78 {
79  const struct timerfd_timer *timer = obj;
80 
81  return timer->handle;
82 }
static struct ast_timer * timer
Definition: chan_iax2.c:313
static int timerfd_timer_open ( void  )
static

Definition at line 97 of file res_timing_timerfd.c.

References ao2_alloc, ao2_link, ao2_ref, ast_log(), errno, timerfd_timer::handle, LOG_ERROR, timer, and timer_destroy().

98 {
99  struct timerfd_timer *timer;
100  int handle;
101 
102  if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) {
103  ast_log(LOG_ERROR, "Could not allocate memory for timerfd_timer structure\n");
104  return -1;
105  }
106  if ((handle = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
107  ast_log(LOG_ERROR, "Failed to create timerfd timer: %s\n", strerror(errno));
108  ao2_ref(timer, -1);
109  return -1;
110  }
111 
112  timer->handle = handle;
113  ao2_link(timerfd_timers, timer);
114  /* Get rid of the reference from the allocation */
115  ao2_ref(timer, -1);
116  return handle;
117 }
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
static struct ao2_container * timerfd_timers
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
int errno
static void timer_destroy(void *obj)
static struct ast_timer * timer
Definition: chan_iax2.c:313
static int timerfd_timer_set_rate ( int  handle,
unsigned int  rate 
)
static

Definition at line 139 of file res_timing_timerfd.c.

References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_log(), timerfd_timer::handle, timerfd_timer::is_continuous, LOG_ERROR, OBJ_POINTER, and timerfd_timer::saved_timer.

140 {
141  struct timerfd_timer *our_timer, find_helper = {
142  .handle = handle,
143  };
144  int res = 0;
145 
146  if (handle == -1) {
147  ast_log(LOG_ERROR, "Attempting to set rate on timerfd handle -1");
148  return -1;
149  }
150 
151  if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
152  ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
153  return -1;
154  }
155  ao2_lock(our_timer);
156 
157  our_timer->saved_timer.it_value.tv_sec = 0;
158  our_timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L;
159  our_timer->saved_timer.it_interval.tv_sec = our_timer->saved_timer.it_value.tv_sec;
160  our_timer->saved_timer.it_interval.tv_nsec = our_timer->saved_timer.it_value.tv_nsec;
161 
162  if (!our_timer->is_continuous) {
163  res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL);
164  }
165 
166  ao2_unlock(our_timer);
167  ao2_ref(our_timer, -1);
168 
169  return res;
170 }
#define ao2_unlock(a)
Definition: astobj2.h:497
static struct ao2_container * timerfd_timers
unsigned int is_continuous
struct itimerspec saved_timer
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define ao2_lock(a)
Definition: astobj2.h:488
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
static int unload_module ( void  )
static

Definition at line 360 of file res_timing_timerfd.c.

References ao2_ref, ast_unregister_timing_interface(), and timing_funcs_handle.

361 {
362  int res;
363 
365  ao2_ref(timerfd_timers, -1);
366  timerfd_timers = NULL;
367  }
368 
369  return res;
370 }
int ast_unregister_timing_interface(void *handle)
Unregister a previously registered timing interface.
Definition: timing.c:105
static void * timing_funcs_handle
static struct ao2_container * timerfd_timers
#define ao2_ref(o, delta)
Definition: astobj2.h:472

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Timerfd Timing Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_TIMING, }
static

Definition at line 376 of file res_timing_timerfd.c.

Definition at line 376 of file res_timing_timerfd.c.

struct ao2_container* timerfd_timers
static

Definition at line 66 of file res_timing_timerfd.c.

struct ast_timing_interface timerfd_timing
static

Definition at line 53 of file res_timing_timerfd.c.

void* timing_funcs_handle
static

Definition at line 42 of file res_timing_timerfd.c.

Referenced by load_module(), and unload_module().