00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 377881 $")
00035
00036 #include "asterisk/_private.h"
00037
00038 #include "asterisk/timing.h"
00039 #include "asterisk/lock.h"
00040 #include "asterisk/cli.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/time.h"
00043 #include "asterisk/heap.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/poll-compat.h"
00046
00047 struct timing_holder {
00048
00049 ssize_t __heap_index;
00050 struct ast_module *mod;
00051 struct ast_timing_interface *iface;
00052 };
00053
00054 static struct ast_heap *timing_interfaces;
00055
00056 struct ast_timer {
00057 int fd;
00058 struct timing_holder *holder;
00059 };
00060
00061 static int timing_holder_cmp(void *_h1, void *_h2)
00062 {
00063 struct timing_holder *h1 = _h1;
00064 struct timing_holder *h2 = _h2;
00065
00066 if (h1->iface->priority > h2->iface->priority) {
00067 return 1;
00068 } else if (h1->iface->priority == h2->iface->priority) {
00069 return 0;
00070 } else {
00071 return -1;
00072 }
00073 }
00074
00075 void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
00076 struct ast_module *mod)
00077 {
00078 struct timing_holder *h;
00079
00080 if (!funcs->timer_open ||
00081 !funcs->timer_close ||
00082 !funcs->timer_set_rate ||
00083 !funcs->timer_ack ||
00084 !funcs->timer_get_event ||
00085 !funcs->timer_get_max_rate ||
00086 !funcs->timer_enable_continuous ||
00087 !funcs->timer_disable_continuous) {
00088 return NULL;
00089 }
00090
00091 if (!(h = ast_calloc(1, sizeof(*h)))) {
00092 return NULL;
00093 }
00094
00095 h->iface = funcs;
00096 h->mod = mod;
00097
00098 ast_heap_wrlock(timing_interfaces);
00099 ast_heap_push(timing_interfaces, h);
00100 ast_heap_unlock(timing_interfaces);
00101
00102 return h;
00103 }
00104
00105 int ast_unregister_timing_interface(void *handle)
00106 {
00107 struct timing_holder *h = handle;
00108 int res = -1;
00109
00110 ast_heap_wrlock(timing_interfaces);
00111 h = ast_heap_remove(timing_interfaces, h);
00112 ast_heap_unlock(timing_interfaces);
00113
00114 if (h) {
00115 ast_free(h);
00116 h = NULL;
00117 res = 0;
00118 }
00119
00120 return res;
00121 }
00122
00123 struct ast_timer *ast_timer_open(void)
00124 {
00125 int fd = -1;
00126 struct timing_holder *h;
00127 struct ast_timer *t = NULL;
00128
00129 ast_heap_rdlock(timing_interfaces);
00130
00131 if ((h = ast_heap_peek(timing_interfaces, 1))) {
00132 fd = h->iface->timer_open();
00133 ast_module_ref(h->mod);
00134 }
00135
00136 if (fd != -1) {
00137 if (!(t = ast_calloc(1, sizeof(*t)))) {
00138 h->iface->timer_close(fd);
00139 } else {
00140 t->fd = fd;
00141 t->holder = h;
00142 }
00143 }
00144
00145 ast_heap_unlock(timing_interfaces);
00146
00147 return t;
00148 }
00149
00150 void ast_timer_close(struct ast_timer *handle)
00151 {
00152 handle->holder->iface->timer_close(handle->fd);
00153 handle->fd = -1;
00154 ast_module_unref(handle->holder->mod);
00155 ast_free(handle);
00156 }
00157
00158 int ast_timer_fd(const struct ast_timer *handle)
00159 {
00160 return handle->fd;
00161 }
00162
00163 int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
00164 {
00165 int res = -1;
00166
00167 res = handle->holder->iface->timer_set_rate(handle->fd, rate);
00168
00169 return res;
00170 }
00171
00172 int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
00173 {
00174 int res = -1;
00175
00176 res = handle->holder->iface->timer_ack(handle->fd, quantity);
00177
00178 return res;
00179 }
00180
00181 int ast_timer_enable_continuous(const struct ast_timer *handle)
00182 {
00183 int res = -1;
00184
00185 res = handle->holder->iface->timer_enable_continuous(handle->fd);
00186
00187 return res;
00188 }
00189
00190 int ast_timer_disable_continuous(const struct ast_timer *handle)
00191 {
00192 int res = -1;
00193
00194 res = handle->holder->iface->timer_disable_continuous(handle->fd);
00195
00196 return res;
00197 }
00198
00199 enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle)
00200 {
00201 enum ast_timer_event res = -1;
00202
00203 res = handle->holder->iface->timer_get_event(handle->fd);
00204
00205 return res;
00206 }
00207
00208 unsigned int ast_timer_get_max_rate(const struct ast_timer *handle)
00209 {
00210 unsigned int res = 0;
00211
00212 res = handle->holder->iface->timer_get_max_rate(handle->fd);
00213
00214 return res;
00215 }
00216
00217 const char *ast_timer_get_name(const struct ast_timer *handle)
00218 {
00219 return handle->holder->iface->name;
00220 }
00221
00222 static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00223 {
00224 struct ast_timer *timer;
00225 int count = 0;
00226 struct timeval start, end;
00227 unsigned int test_rate = 50;
00228
00229 switch (cmd) {
00230 case CLI_INIT:
00231 e->command = "timing test";
00232 e->usage = "Usage: timing test <rate>\n"
00233 " Test a timer with a specified rate, 50/sec by default.\n"
00234 "";
00235 return NULL;
00236 case CLI_GENERATE:
00237 return NULL;
00238 }
00239
00240 if (a->argc != 2 && a->argc != 3) {
00241 return CLI_SHOWUSAGE;
00242 }
00243
00244 if (a->argc == 3) {
00245 unsigned int rate;
00246 if (sscanf(a->argv[2], "%30u", &rate) == 1) {
00247 test_rate = rate;
00248 } else {
00249 ast_cli(a->fd, "Invalid rate '%s', using default of %u\n", a->argv[2], test_rate);
00250 }
00251 }
00252
00253 ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate);
00254
00255 if (!(timer = ast_timer_open())) {
00256 ast_cli(a->fd, "Failed to open timing fd\n");
00257 return CLI_FAILURE;
00258 }
00259
00260 ast_cli(a->fd, "Using the '%s' timing module for this test.\n", timer->holder->iface->name);
00261
00262 start = ast_tvnow();
00263
00264 ast_timer_set_rate(timer, test_rate);
00265
00266 while (ast_tvdiff_ms((end = ast_tvnow()), start) < 1000) {
00267 int res;
00268 struct pollfd pfd = {
00269 .fd = ast_timer_fd(timer),
00270 .events = POLLIN | POLLPRI,
00271 };
00272
00273 res = ast_poll(&pfd, 1, 100);
00274
00275 if (res == 1) {
00276 count++;
00277 if (ast_timer_ack(timer, 1) < 0) {
00278 ast_cli(a->fd, "Timer failed to acknowledge.\n");
00279 ast_timer_close(timer);
00280 return CLI_FAILURE;
00281 }
00282 } else if (!res) {
00283 ast_cli(a->fd, "poll() timed out! This is bad.\n");
00284 } else if (errno != EAGAIN && errno != EINTR) {
00285 ast_cli(a->fd, "poll() returned error: %s\n", strerror(errno));
00286 }
00287 }
00288
00289 ast_timer_close(timer);
00290 timer = NULL;
00291
00292 ast_cli(a->fd, "It has been %" PRIi64 " milliseconds, and we got %d timer ticks\n",
00293 ast_tvdiff_ms(end, start), count);
00294
00295 return CLI_SUCCESS;
00296 }
00297
00298 static struct ast_cli_entry cli_timing[] = {
00299 AST_CLI_DEFINE(timing_test, "Run a timing test"),
00300 };
00301
00302 static void timing_shutdown(void)
00303 {
00304 ast_cli_unregister_multiple(cli_timing, ARRAY_LEN(cli_timing));
00305
00306 ast_heap_destroy(timing_interfaces);
00307 timing_interfaces = NULL;
00308 }
00309
00310 int ast_timing_init(void)
00311 {
00312 if (!(timing_interfaces = ast_heap_create(2, timing_holder_cmp, 0))) {
00313 return -1;
00314 }
00315
00316 ast_register_atexit(timing_shutdown);
00317
00318 return ast_cli_register_multiple(cli_timing, ARRAY_LEN(cli_timing));
00319 }