diff --git a/build/modules.conf.in b/build/modules.conf.in
index b775a35bac..bb8bc7169a 100644
--- a/build/modules.conf.in
+++ b/build/modules.conf.in
@@ -120,6 +120,7 @@ say/mod_say_en
#say/mod_say_th
#say/mod_say_he
#timers/mod_timerfd
+#timers/mod_posix_timer
## Experimental Modules (don't cry if they're broken)
#../../contrib/mod/xml_int/mod_xml_odbc
diff --git a/conf/autoload_configs/modules.conf.xml b/conf/autoload_configs/modules.conf.xml
index 5758c1cf89..de4bc40897 100644
--- a/conf/autoload_configs/modules.conf.xml
+++ b/conf/autoload_configs/modules.conf.xml
@@ -97,6 +97,7 @@
+
diff --git a/src/mod/timers/mod_posix_timer/mod_posix_timer.c b/src/mod/timers/mod_posix_timer/mod_posix_timer.c
new file mode 100644
index 0000000000..46ff72b9ce
--- /dev/null
+++ b/src/mod/timers/mod_posix_timer/mod_posix_timer.c
@@ -0,0 +1,288 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Chris Rienzo
+ * Timo Teräs (based on mod_timerfd.c)
+ *
+ * mod_posix_timer.c -- soft timer implemented with POSIX timers (timer_create/timer_settime/timer_getoverrun)
+ *
+ */
+#include
+#include
+#include
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_posix_timer_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_posix_timer_shutdown);
+SWITCH_MODULE_DEFINITION(mod_posix_timer, mod_posix_timer_load, mod_posix_timer_shutdown, NULL);
+
+#define MAX_INTERVAL 2000 /* ms */
+#define TIMERS_PER_INTERVAL 4
+
+typedef struct {
+ int users;
+ timer_t timer;
+ switch_size_t tick;
+ switch_mutex_t *mutex;
+ switch_thread_cond_t *cond;
+} interval_timer_t;
+
+static struct {
+ switch_memory_pool_t *pool;
+ int shutdown;
+ interval_timer_t interval_timers[MAX_INTERVAL + 1][TIMERS_PER_INTERVAL];
+ int next_interval_timer_id[MAX_INTERVAL + 1];
+ switch_mutex_t *interval_timers_mutex;
+} globals;
+
+/**
+ * Notified by POSIX timer of a tick
+ */
+static void posix_timer_notify(sigval_t data)
+{
+ interval_timer_t *it = (interval_timer_t *)data.sival_ptr;
+ switch_mutex_lock(it->mutex);
+ it->tick += 1 + timer_getoverrun(it->timer);
+ switch_thread_cond_broadcast(it->cond);
+ switch_mutex_unlock(it->mutex);
+
+ if (globals.shutdown) {
+ timer_delete(it->timer);
+ }
+}
+
+/**
+ * Start a new timer
+ */
+static switch_status_t posix_timer_start_interval(interval_timer_t *it, int interval)
+{
+ struct sigevent sigev;
+ struct itimerspec val;
+
+ if (globals.shutdown) {
+ return SWITCH_STATUS_GENERR;
+ }
+
+ it->users++;
+ if (it->users > 1) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ it->tick = 0;
+
+ switch_mutex_init(&it->mutex, SWITCH_MUTEX_NESTED, globals.pool);
+ switch_thread_cond_create(&it->cond, globals.pool);
+
+ /* create the POSIX timer. Will notify the posix_timer_notify thread on ticks. */
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.sigev_notify = SIGEV_THREAD;
+ sigev.sigev_notify_function = posix_timer_notify;
+ sigev.sigev_value.sival_ptr = (void *)it;
+ if (timer_create(CLOCK_MONOTONIC, &sigev, &it->timer) == -1) {
+ return SWITCH_STATUS_GENERR;
+ }
+
+ /* start the timer to tick at interval */
+ memset(&val, 0, sizeof(val));
+ 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 (timer_settime(it->timer, 0, &val, NULL) == -1) {
+ return SWITCH_STATUS_GENERR;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/**
+ * Stop a timer
+ */
+static switch_status_t posix_timer_stop_interval(interval_timer_t *it)
+{
+ it->users--;
+ if (it->users > 0)
+ return SWITCH_STATUS_SUCCESS;
+
+ timer_delete(it->timer);
+ memset(&it->timer, 0, sizeof(it->timer));
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/**
+ * Timer module interface: start a new timer
+ * @param timer the timer
+ * @return SWITCH_STATUS_SUCCESS if successful otherwise SWITCH_STATUS_GENERR
+ */
+static switch_status_t posix_timer_init(switch_timer_t *timer)
+{
+ interval_timer_t *it;
+ switch_status_t status;
+ int interval_timer_id;
+
+ if (timer->interval < 1 || timer->interval > MAX_INTERVAL) {
+ return SWITCH_STATUS_GENERR;
+ }
+
+ switch_mutex_lock(globals.interval_timers_mutex);
+ interval_timer_id = globals.next_interval_timer_id[timer->interval]++;
+ if (globals.next_interval_timer_id[timer->interval] >= TIMERS_PER_INTERVAL) {
+ globals.next_interval_timer_id[timer->interval] = 0;
+ }
+
+ it = &globals.interval_timers[timer->interval][interval_timer_id];
+ status = posix_timer_start_interval(it, timer->interval);
+ timer->private_info = it;
+ switch_mutex_unlock(globals.interval_timers_mutex);
+
+ return status;
+}
+
+/**
+ * Timer module interface: step the timer
+ * @param timer the timer
+ * @return SWITCH_STATUS_SUCCESS
+ */
+static switch_status_t posix_timer_step(switch_timer_t *timer)
+{
+ timer->tick++;
+ timer->samplecount += timer->samples;
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/**
+ * Timer module interface: wait for next tick
+ * @param timer the timer
+ * @return SWITCH_STATUS_SUCCESS if successful
+ */
+static switch_status_t posix_timer_next(switch_timer_t *timer)
+{
+ interval_timer_t *it = timer->private_info;
+
+ if ((int)(timer->tick - it->tick) < -1) {
+ timer->tick = it->tick;
+ }
+ posix_timer_step(timer);
+
+ switch_mutex_lock(it->mutex);
+ while ((int)(timer->tick - it->tick) > 0 && !globals.shutdown) {
+ switch_thread_cond_timedwait(it->cond, it->mutex, 20 * 1000);
+ }
+ switch_mutex_unlock(it->mutex);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/**
+ * Timer module interface: sync tick count
+ * @param timer the timer
+ * @return SWITCH_STATUS_SUCCESS
+ */
+static switch_status_t posix_timer_sync(switch_timer_t *timer)
+{
+ interval_timer_t *it = timer->private_info;
+ timer->tick = it->tick;
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/**
+ * Timer module interface: check if synched
+ * @param timer the timer
+ * @param step true if timer should be stepped
+ * @return SWITCH_STATUS_SUCCESS if synched, SWITCH_STATUS_FALSE otherwise
+ */
+static switch_status_t posix_timer_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;
+ }
+ /* timer pending */
+ timer->diff = 0;
+ if (step) {
+ posix_timer_step(timer);
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/**
+ * Timer module interface: destroy a timer
+ * @param timer the timer
+ * @return SWITCH_STATUS_SUCCESS if successful
+ */
+static switch_status_t posix_timer_destroy(switch_timer_t *timer)
+{
+ interval_timer_t *it = timer->private_info;
+ switch_status_t status;
+
+ switch_mutex_lock(globals.interval_timers_mutex);
+ status = posix_timer_stop_interval(it);
+ switch_mutex_unlock(globals.interval_timers_mutex);
+
+ return status;
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_posix_timer_load)
+{
+ switch_timer_interface_t *timer_interface;
+
+ memset(&globals, 0, sizeof(globals));
+
+ globals.pool = pool;
+ switch_mutex_init(&globals.interval_timers_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+
+ /* connect my internal structure to the blank pointer passed to me */
+ *module_interface = switch_loadable_module_create_module_interface(globals.pool, modname);
+ timer_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_TIMER_INTERFACE);
+ timer_interface->interface_name = "posix";
+ timer_interface->timer_init = posix_timer_init;
+ timer_interface->timer_next = posix_timer_next;
+ timer_interface->timer_step = posix_timer_step;
+ timer_interface->timer_sync = posix_timer_sync;
+ timer_interface->timer_check = posix_timer_check;
+ timer_interface->timer_destroy = posix_timer_destroy;
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_posix_timer_shutdown)
+{
+ globals.shutdown = 1;
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */