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: 369001 $")
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 ast_module_unref(handle->holder->mod);
00154 ast_free(handle);
00155 }
00156
00157 int ast_timer_fd(const struct ast_timer *handle)
00158 {
00159 return handle->fd;
00160 }
00161
00162 int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
00163 {
00164 int res = -1;
00165
00166 res = handle->holder->iface->timer_set_rate(handle->fd, rate);
00167
00168 return res;
00169 }
00170
00171 void ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
00172 {
00173 handle->holder->iface->timer_ack(handle->fd, quantity);
00174 }
00175
00176 int ast_timer_enable_continuous(const struct ast_timer *handle)
00177 {
00178 int res = -1;
00179
00180 res = handle->holder->iface->timer_enable_continuous(handle->fd);
00181
00182 return res;
00183 }
00184
00185 int ast_timer_disable_continuous(const struct ast_timer *handle)
00186 {
00187 int res = -1;
00188
00189 res = handle->holder->iface->timer_disable_continuous(handle->fd);
00190
00191 return res;
00192 }
00193
00194 enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle)
00195 {
00196 enum ast_timer_event res = -1;
00197
00198 res = handle->holder->iface->timer_get_event(handle->fd);
00199
00200 return res;
00201 }
00202
00203 unsigned int ast_timer_get_max_rate(const struct ast_timer *handle)
00204 {
00205 unsigned int res = 0;
00206
00207 res = handle->holder->iface->timer_get_max_rate(handle->fd);
00208
00209 return res;
00210 }
00211
00212 const char *ast_timer_get_name(const struct ast_timer *handle)
00213 {
00214 return handle->holder->iface->name;
00215 }
00216
00217 static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00218 {
00219 struct ast_timer *timer;
00220 int count = 0;
00221 struct timeval start, end;
00222 unsigned int test_rate = 50;
00223
00224 switch (cmd) {
00225 case CLI_INIT:
00226 e->command = "timing test";
00227 e->usage = "Usage: timing test <rate>\n"
00228 " Test a timer with a specified rate, 50/sec by default.\n"
00229 "";
00230 return NULL;
00231 case CLI_GENERATE:
00232 return NULL;
00233 }
00234
00235 if (a->argc != 2 && a->argc != 3) {
00236 return CLI_SHOWUSAGE;
00237 }
00238
00239 if (a->argc == 3) {
00240 unsigned int rate;
00241 if (sscanf(a->argv[2], "%30u", &rate) == 1) {
00242 test_rate = rate;
00243 } else {
00244 ast_cli(a->fd, "Invalid rate '%s', using default of %u\n", a->argv[2], test_rate);
00245 }
00246 }
00247
00248 ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate);
00249
00250 if (!(timer = ast_timer_open())) {
00251 ast_cli(a->fd, "Failed to open timing fd\n");
00252 return CLI_FAILURE;
00253 }
00254
00255 ast_cli(a->fd, "Using the '%s' timing module for this test.\n", timer->holder->iface->name);
00256
00257 start = ast_tvnow();
00258
00259 ast_timer_set_rate(timer, test_rate);
00260
00261 while (ast_tvdiff_ms((end = ast_tvnow()), start) < 1000) {
00262 int res;
00263 struct pollfd pfd = {
00264 .fd = ast_timer_fd(timer),
00265 .events = POLLIN | POLLPRI,
00266 };
00267
00268 res = ast_poll(&pfd, 1, 100);
00269
00270 if (res == 1) {
00271 count++;
00272 ast_timer_ack(timer, 1);
00273 } else if (!res) {
00274 ast_cli(a->fd, "poll() timed out! This is bad.\n");
00275 } else if (errno != EAGAIN && errno != EINTR) {
00276 ast_cli(a->fd, "poll() returned error: %s\n", strerror(errno));
00277 }
00278 }
00279
00280 ast_timer_close(timer);
00281
00282 ast_cli(a->fd, "It has been %" PRIi64 " milliseconds, and we got %d timer ticks\n",
00283 ast_tvdiff_ms(end, start), count);
00284
00285 return CLI_SUCCESS;
00286 }
00287
00288 static struct ast_cli_entry cli_timing[] = {
00289 AST_CLI_DEFINE(timing_test, "Run a timing test"),
00290 };
00291
00292 int ast_timing_init(void)
00293 {
00294 if (!(timing_interfaces = ast_heap_create(2, timing_holder_cmp, 0))) {
00295 return -1;
00296 }
00297
00298 return ast_cli_register_multiple(cli_timing, ARRAY_LEN(cli_timing));
00299 }