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