]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add soft timer support for fd per timer use enable-softtimer-timerfd=broadcast in...
authorAnthony Minessale <anthm@freeswitch.org>
Fri, 15 Nov 2013 20:37:11 +0000 (01:37 +0500)
committerAnthony Minessale <anthm@freeswitch.org>
Fri, 15 Nov 2013 20:37:16 +0000 (01:37 +0500)
src/include/switch_core.h
src/switch_core.c
src/switch_time.c

index 43c872b5cfa070dcb65859ffaf14aa9a04011688..40f58ef26c42099fdfcd6840c13556d8708bb777 100644 (file)
@@ -2312,7 +2312,7 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload);
 SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token);
 #define switch_check_network_list_ip(_ip_str, _list_name) switch_check_network_list_ip_token(_ip_str, _list_name, NULL)
 SWITCH_DECLARE(void) switch_time_set_monotonic(switch_bool_t enable);
-SWITCH_DECLARE(void) switch_time_set_timerfd(switch_bool_t enable);
+SWITCH_DECLARE(void) switch_time_set_timerfd(int enable);
 SWITCH_DECLARE(void) switch_time_set_nanosleep(switch_bool_t enable);
 SWITCH_DECLARE(void) switch_time_set_matrix(switch_bool_t enable);
 SWITCH_DECLARE(void) switch_time_set_cond_yield(switch_bool_t enable);
index 8cefdd2e6367e38a321c88f2f3715ca8d7b24f89..848fbf215031a867c060bd591ca8e7b4d9dfa5f7 100644 (file)
@@ -1934,7 +1934,19 @@ static void switch_load_core_config(const char *file)
                                } else if (!strcasecmp(var, "enable-monotonic-timing")) {
                                        switch_time_set_monotonic(switch_true(val));
                                } else if (!strcasecmp(var, "enable-softtimer-timerfd")) {
-                                       switch_time_set_timerfd(switch_true(val));
+                                       int ival = 0;
+                                       if (val) {
+                                               if (switch_true(val)) {
+                                                       ival = 2;
+                                               } else {
+                                                       if (strcasecmp(val, "broadcast")) {
+                                                               ival = 1;
+                                                       } else if (strcasecmp(val, "fd-per-timer")) {
+                                                               ival = 2;
+                                                       }
+                                               }
+                                       }
+                                       switch_time_set_timerfd(ival);
                                } else if (!strcasecmp(var, "enable-clock-nanosleep")) {
                                        switch_time_set_nanosleep(switch_true(val));
                                } else if (!strcasecmp(var, "enable-cond-yield")) {
index 2a67a56b5e80f0eac583ee01dda84342d8b3cee2..69d45f442caa66c5a33f010a1fb1bec8dc865757 100644 (file)
@@ -77,7 +77,7 @@ static int SYSTEM_TIME = 0;
    timerfd seems to work well as long as it exists so if you have timerfd we'll also enable clock_nanosleep by default.
 */
 #if defined(HAVE_TIMERFD_CREATE)
-static int TFD = 1;
+static int TFD = 2;
 #if defined(HAVE_CLOCK_NANOSLEEP)
 static int NANO = 1;
 #else
@@ -351,10 +351,10 @@ SWITCH_DECLARE(void) switch_time_set_use_system_time(switch_bool_t enable)
 }
 
 
-SWITCH_DECLARE(void) switch_time_set_timerfd(switch_bool_t enable)
+SWITCH_DECLARE(void) switch_time_set_timerfd(int enable)
 {
 #if defined(HAVE_TIMERFD_CREATE)
-       TFD = enable ? 1 : 0;
+       TFD = enable;
        switch_time_sync();
 
 #else
@@ -385,6 +385,133 @@ SWITCH_DECLARE(void) switch_time_set_cond_yield(switch_bool_t enable)
        switch_time_sync();
 }
 
+/////////
+#ifdef HAVE_TIMERFD_CREATE
+
+#define MAX_INTERVAL           2000 /* ms */
+
+struct interval_timer {
+       int                     fd;
+       switch_size_t           tick;
+};
+typedef struct interval_timer interval_timer_t;
+
+static switch_status_t timerfd_start_interval(interval_timer_t *it, int interval)
+{
+       struct itimerspec val;
+       int fd;
+
+       it->tick = 0;
+
+       fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+
+       if (fd < 0) {
+               return SWITCH_STATUS_GENERR;
+       }
+
+       val.it_interval.tv_sec = interval / 1000;
+       val.it_interval.tv_nsec = (interval % 1000) * 1000000;
+       val.it_value.tv_sec = 0;
+       val.it_value.tv_nsec = 100000;
+
+       if (timerfd_settime(fd, 0, &val, NULL) < 0) {
+               close(fd);
+               return SWITCH_STATUS_GENERR;
+       }
+
+       it->fd = fd;
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t timerfd_stop_interval(interval_timer_t *it)
+{
+       close(it->fd);
+       it->fd = -1;
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t _timerfd_init(switch_timer_t *timer)
+{
+       interval_timer_t *it;
+       int rc;
+
+       if (timer->interval < 1 || timer->interval > MAX_INTERVAL)
+               return SWITCH_STATUS_GENERR;
+
+       it = switch_core_alloc(timer->memory_pool, sizeof(*it));
+       if ((rc = timerfd_start_interval(it, timer->interval)) == SWITCH_STATUS_SUCCESS) {
+               timer->private_info = it;
+       }
+
+       return rc;
+}
+
+static switch_status_t _timerfd_step(switch_timer_t *timer)
+{
+       timer->tick++;
+       timer->samplecount += timer->samples;
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t _timerfd_next(switch_timer_t *timer)
+{
+       interval_timer_t *it = timer->private_info;
+       uint64_t x, u64  = 0;
+
+       if (read(it->fd, &u64, sizeof(u64)) < 0) {
+               return SWITCH_STATUS_GENERR;
+       } else {
+               for (x = 0; x < u64; x++) {
+                       it->tick++;
+                       _timerfd_step(timer);
+               }
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t _timerfd_sync(switch_timer_t *timer)
+{
+       interval_timer_t *it = timer->private_info;
+
+       timer->tick = it->tick;
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t _timerfd_check(switch_timer_t *timer, switch_bool_t step)
+{
+       interval_timer_t *it = timer->private_info;
+       int diff = (int)(timer->tick - it->tick);
+
+       if (diff > 0) {
+               /* still pending */
+               timer->diff = diff;
+               return SWITCH_STATUS_FALSE;
+       } else {
+               /* timer pending */
+               timer->diff = 0;
+               if (step) {
+                       _timerfd_step(timer);
+               }
+               return SWITCH_STATUS_SUCCESS;
+       }
+}
+
+static switch_status_t _timerfd_destroy(switch_timer_t *timer)
+{
+       interval_timer_t *it = timer->private_info;
+       int rc;
+
+       rc = timerfd_stop_interval(it);
+       return rc;
+}
+
+#endif
+////////
+
+
 static switch_time_t time_now(int64_t offset)
 {
        switch_time_t now;
@@ -549,6 +676,10 @@ static switch_status_t timer_init(switch_timer_t *timer)
        timer_private_t *private_info;
        int sanity = 0;
 
+       if (TFD == 2) {
+               return _timerfd_init(timer);
+       }
+
        while (globals.STARTED == 0) {
                do_sleep(100000);
                if (++sanity == 300) {
@@ -607,9 +738,15 @@ static switch_status_t timer_init(switch_timer_t *timer)
 
 static switch_status_t timer_step(switch_timer_t *timer)
 {
-       timer_private_t *private_info = timer->private_info;
+       timer_private_t *private_info;
        uint64_t samples;
 
+       if (TFD == 2) {
+               return _timerfd_step(timer);
+       }
+
+       private_info = timer->private_info;
+
        if (globals.RUNNING != 1 || private_info->ready == 0) {
                return SWITCH_STATUS_FALSE;
        }
@@ -630,7 +767,13 @@ static switch_status_t timer_step(switch_timer_t *timer)
 
 static switch_status_t timer_sync(switch_timer_t *timer)
 {
-       timer_private_t *private_info = timer->private_info;
+       timer_private_t *private_info;
+
+       if (TFD == 2) {
+               return _timerfd_sync(timer);
+       }
+
+       private_info = timer->private_info;
 
        if (globals.RUNNING != 1 || private_info->ready == 0) {
                return SWITCH_STATUS_FALSE;
@@ -648,14 +791,24 @@ static switch_status_t timer_sync(switch_timer_t *timer)
 
 static switch_status_t timer_next(switch_timer_t *timer)
 {
-       timer_private_t *private_info = timer->private_info;
+       timer_private_t *private_info;
 
 #ifdef DISABLE_1MS_COND
        int cond_index = timer->interval;
 #else
        int cond_index = 1;
 #endif
-       int delta = (int) (private_info->reference - TIMER_MATRIX[timer->interval].tick);
+       int delta;
+
+       if (TFD == 2) {
+               return _timerfd_next(timer);
+       }
+
+       private_info = timer->private_info;
+
+       delta = (int) (private_info->reference - TIMER_MATRIX[timer->interval].tick);
+
+
 
        /* sync up timer if it's not been called for a while otherwise it will return instantly several times until it catches up */
        if (delta < -1) {
@@ -695,9 +848,15 @@ static switch_status_t timer_next(switch_timer_t *timer)
 
 static switch_status_t timer_check(switch_timer_t *timer, switch_bool_t step)
 {
-       timer_private_t *private_info = timer->private_info;
+       timer_private_t *private_info;
        switch_status_t status = SWITCH_STATUS_SUCCESS;
 
+       if (TFD == 2) {
+               return _timerfd_check(timer, step);
+       }
+
+       private_info = timer->private_info;
+
        if (globals.RUNNING != 1 || !private_info->ready) {
                return SWITCH_STATUS_SUCCESS;
        }
@@ -724,7 +883,14 @@ static switch_status_t timer_check(switch_timer_t *timer, switch_bool_t step)
 
 static switch_status_t timer_destroy(switch_timer_t *timer)
 {
-       timer_private_t *private_info = timer->private_info;
+       timer_private_t *private_info;
+
+       if (TFD == 2) {
+               return _timerfd_destroy(timer);
+       }
+
+       private_info = timer->private_info;
+
        if (timer->interval < MAX_ELEMENTS) {
                switch_mutex_lock(globals.mutex);
                TIMER_MATRIX[timer->interval].count--;