Asterisk - The Open Source Telephony Project GIT-master-a358458
timing.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2008 - 2009, Digium, Inc.
5 *
6 * Kevin P. Fleming <kpfleming@digium.com>
7 * Russell Bryant <russell@digium.com>
8 *
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
14 *
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
18 */
19
20/*! \file
21 *
22 * \brief Timing source management
23 *
24 * \author Kevin P. Fleming <kpfleming@digium.com>
25 * \author Russell Bryant <russell@digium.com>
26 */
27
28/*** MODULEINFO
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/_private.h"
35
36#include "asterisk/timing.h"
37#include "asterisk/lock.h"
38#include "asterisk/cli.h"
39#include "asterisk/utils.h"
40#include "asterisk/time.h"
41#include "asterisk/heap.h"
42#include "asterisk/module.h"
44
46 /*! Do _not_ move this from the beginning of the struct. */
47 ssize_t __heap_index;
48 struct ast_module *mod;
50};
51
53
54struct ast_timer {
55 void *data;
57};
58
59static int timing_holder_cmp(void *_h1, void *_h2)
60{
61 struct timing_holder *h1 = _h1;
62 struct timing_holder *h2 = _h2;
63
64 if (h1->iface->priority > h2->iface->priority) {
65 return 1;
66 } else if (h1->iface->priority == h2->iface->priority) {
67 return 0;
68 } else {
69 return -1;
70 }
71}
72
74 struct ast_module *mod)
75{
76 struct timing_holder *h;
77
78 if (!funcs->timer_open ||
79 !funcs->timer_close ||
80 !funcs->timer_set_rate ||
81 !funcs->timer_ack ||
82 !funcs->timer_get_event ||
83 !funcs->timer_get_max_rate ||
86 !funcs->timer_fd) {
87 return NULL;
88 }
89
90 if (!(h = ast_calloc(1, sizeof(*h)))) {
91 return NULL;
92 }
93
94 h->iface = funcs;
95 h->mod = mod;
96
100
101 return h;
102}
103
105{
106 struct timing_holder *h = handle;
107 int res = -1;
108
112
113 if (h) {
114 ast_free(h);
115 h = NULL;
116 res = 0;
117 }
118
119 return res;
120}
121
123{
124 void *data = NULL;
125 struct timing_holder *h;
126 struct ast_timer *t = NULL;
127 int idx = 1;
128
130
131 while ((h = ast_heap_peek(timing_interfaces, idx))) {
132 if (ast_module_running_ref(h->mod)) {
133 data = h->iface->timer_open();
134 break;
135 }
136 idx++;
137 }
138
139 if (data) {
140 if (!(t = ast_calloc(1, sizeof(*t)))) {
143 } else {
144 t->data = data;
145 t->holder = h;
146 }
147 }
148
150
151 return t;
152}
153
154void ast_timer_close(struct ast_timer *handle)
155{
156 handle->holder->iface->timer_close(handle->data);
157 ast_module_unref(handle->holder->mod);
158 ast_free(handle);
159}
160
161int ast_timer_fd(const struct ast_timer *handle)
162{
163 return handle->holder->iface->timer_fd(handle->data);
164}
165
166int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
167{
168 return handle->holder->iface->timer_set_rate(handle->data, rate);
169}
170
171int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
172{
173 return handle->holder->iface->timer_ack(handle->data, quantity);
174}
175
176int ast_timer_enable_continuous(const struct ast_timer *handle)
177{
178 return handle->holder->iface->timer_enable_continuous(handle->data);
179}
180
182{
183 return handle->holder->iface->timer_disable_continuous(handle->data);
184}
185
187{
188 return handle->holder->iface->timer_get_event(handle->data);
189}
190
191unsigned int ast_timer_get_max_rate(const struct ast_timer *handle)
192{
193 return handle->holder->iface->timer_get_max_rate(handle->data);
194}
195
196const char *ast_timer_get_name(const struct ast_timer *handle)
197{
198 return handle->holder->iface->name;
199}
200
201static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
202{
203 struct ast_timer *timer;
204 int count = 0;
205 struct timeval start, end;
206 unsigned int test_rate = 50;
207
208 switch (cmd) {
209 case CLI_INIT:
210 e->command = "timing test";
211 e->usage = "Usage: timing test <rate>\n"
212 " Test a timer with a specified rate, 50/sec by default.\n"
213 "";
214 return NULL;
215 case CLI_GENERATE:
216 return NULL;
217 }
218
219 if (a->argc != 2 && a->argc != 3) {
220 return CLI_SHOWUSAGE;
221 }
222
223 if (a->argc == 3) {
224 unsigned int rate;
225 if (sscanf(a->argv[2], "%30u", &rate) == 1) {
226 test_rate = rate;
227 } else {
228 ast_cli(a->fd, "Invalid rate '%s', using default of %u\n", a->argv[2], test_rate);
229 }
230 }
231
232 ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate);
233
234 if (!(timer = ast_timer_open())) {
235 ast_cli(a->fd, "Failed to open timing fd\n");
236 return CLI_FAILURE;
237 }
238
239 ast_cli(a->fd, "Using the '%s' timing module for this test.\n", timer->holder->iface->name);
240
241 start = ast_tvnow();
242
243 ast_timer_set_rate(timer, test_rate);
244
245 while (ast_tvdiff_ms((end = ast_tvnow()), start) < 1000) {
246 int res;
247 struct pollfd pfd = {
248 .fd = ast_timer_fd(timer),
249 .events = POLLIN | POLLPRI,
250 };
251
252 res = ast_poll(&pfd, 1, 100);
253
254 if (res == 1) {
255 count++;
256 if (ast_timer_ack(timer, 1) < 0) {
257 ast_cli(a->fd, "Timer failed to acknowledge.\n");
259 return CLI_FAILURE;
260 }
261 } else if (!res) {
262 ast_cli(a->fd, "poll() timed out! This is bad.\n");
263 } else if (errno != EAGAIN && errno != EINTR) {
264 ast_cli(a->fd, "poll() returned error: %s\n", strerror(errno));
265 }
266 }
267
269 timer = NULL;
270
271 ast_cli(a->fd, "It has been %" PRIi64 " milliseconds, and we got %d timer ticks\n",
272 ast_tvdiff_ms(end, start), count);
273
274 return CLI_SUCCESS;
275}
276
277static struct ast_cli_entry cli_timing[] = {
278 AST_CLI_DEFINE(timing_test, "Run a timing test"),
279};
280
281static void timing_shutdown(void)
282{
284
287}
288
290{
292 return -1;
293 }
294
296
298}
Prototypes for public functions only of internal interest,.
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static struct ast_timer * timer
Definition: chan_iax2.c:364
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
char * end
Definition: eagi_proxy.c:73
Max Heap data structure.
struct ast_heap * ast_heap_destroy(struct ast_heap *h)
Destroy a max heap.
Definition: heap.c:146
#define ast_heap_create(init_height, cmp_fn, index_offset)
Create a max heap.
Definition: heap.h:100
#define ast_heap_unlock(h)
Definition: heap.h:249
void * ast_heap_remove(struct ast_heap *h, void *elm)
Remove a specific element from a heap.
Definition: heap.c:251
#define ast_heap_rdlock(h)
Definition: heap.h:248
#define ast_heap_push(h, elm)
Push an element on to a heap.
Definition: heap.h:125
#define ast_heap_wrlock(h)
Definition: heap.h:247
void * ast_heap_peek(struct ast_heap *h, unsigned int index)
Peek at an element on a heap.
Definition: heap.c:267
Asterisk locking-related definitions:
int errno
Asterisk module definitions.
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
Definition: module.h:455
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
#define NULL
Definition: resample.c:96
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Definition: heap.c:36
void * data
Definition: timing.c:55
struct timing_holder * holder
Definition: timing.c:56
Timing module interface.
Definition: timing.h:69
unsigned int priority
Definition: timing.h:73
int(* timer_set_rate)(void *data, unsigned int rate)
Definition: timing.h:76
enum ast_timer_event(* timer_get_event)(void *data)
Definition: timing.h:80
int(* timer_disable_continuous)(void *data)
Definition: timing.h:79
int(* timer_enable_continuous)(void *data)
Definition: timing.h:78
void *(* timer_open)(void)
Definition: timing.h:74
void(* timer_close)(void *data)
Definition: timing.h:75
const char * name
Definition: timing.h:70
int(* timer_fd)(void *data)
Definition: timing.h:82
int(* timer_ack)(void *data, unsigned int quantity)
Definition: timing.h:77
unsigned int(* timer_get_max_rate)(void *data)
Definition: timing.h:81
ssize_t __heap_index
Definition: timing.c:47
struct ast_module * mod
Definition: timing.c:48
struct ast_timing_interface * iface
Definition: timing.c:49
static struct test_val a
Time-related functions and macros.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
static void timing_shutdown(void)
Definition: timing.c:281
int ast_timing_init(void)
Definition: timing.c:289
unsigned int ast_timer_get_max_rate(const struct ast_timer *handle)
Get maximum rate supported for a timer.
Definition: timing.c:191
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:154
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:171
static struct ast_heap * timing_interfaces
Definition: timing.c:52
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:166
int ast_unregister_timing_interface(void *handle)
Unregister a previously registered timing interface.
Definition: timing.c:104
enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle)
Retrieve timing event.
Definition: timing.c:186
int ast_timer_enable_continuous(const struct ast_timer *handle)
Enable continuous mode.
Definition: timing.c:176
const char * ast_timer_get_name(const struct ast_timer *handle)
Get name of timer in use.
Definition: timing.c:196
static char * timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: timing.c:201
int ast_timer_disable_continuous(const struct ast_timer *handle)
Disable continuous mode.
Definition: timing.c:181
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:122
static struct ast_cli_entry cli_timing[]
Definition: timing.c:277
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition: timing.c:161
void * _ast_register_timing_interface(struct ast_timing_interface *funcs, struct ast_module *mod)
Definition: timing.c:73
static int timing_holder_cmp(void *_h1, void *_h2)
Definition: timing.c:59
Timing source management.
ast_timer_event
Definition: timing.h:57
Utility functions.
#define ARRAY_LEN(a)
Definition: utils.h:666