| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2008, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Mark Michelson <mmichelson@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \file | 
					
						
							|  |  |  |  * \author Mark Michelson <mmichelson@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \brief timerfd timing interface | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<depend>timerfd</depend> | 
					
						
							| 
									
										
										
										
											2011-07-14 20:28:54 +00:00
										 |  |  | 	<support_level>core</support_level> | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <sys/timerfd.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/astobj2.h"
 | 
					
						
							|  |  |  | #include "asterisk/timing.h"
 | 
					
						
							|  |  |  | #include "asterisk/logger.h"
 | 
					
						
							|  |  |  | #include "asterisk/utils.h"
 | 
					
						
							|  |  |  | #include "asterisk/time.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void *timing_funcs_handle; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static void *timerfd_timer_open(void); | 
					
						
							|  |  |  | static void timerfd_timer_close(void *data); | 
					
						
							|  |  |  | static int timerfd_timer_set_rate(void *data, unsigned int rate); | 
					
						
							|  |  |  | static int timerfd_timer_ack(void *data, unsigned int quantity); | 
					
						
							|  |  |  | static int timerfd_timer_enable_continuous(void *data); | 
					
						
							|  |  |  | static int timerfd_timer_disable_continuous(void *data); | 
					
						
							|  |  |  | static enum ast_timer_event timerfd_timer_get_event(void *data); | 
					
						
							|  |  |  | static unsigned int timerfd_timer_get_max_rate(void *data); | 
					
						
							|  |  |  | static int timerfd_timer_fd(void *data); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-17 21:22:40 +00:00
										 |  |  | static struct ast_timing_interface timerfd_timing = { | 
					
						
							|  |  |  | 	.name = "timerfd", | 
					
						
							|  |  |  | 	.priority = 200, | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	.timer_open = timerfd_timer_open, | 
					
						
							|  |  |  | 	.timer_close = timerfd_timer_close, | 
					
						
							|  |  |  | 	.timer_set_rate = timerfd_timer_set_rate, | 
					
						
							|  |  |  | 	.timer_ack = timerfd_timer_ack, | 
					
						
							|  |  |  | 	.timer_enable_continuous = timerfd_timer_enable_continuous, | 
					
						
							|  |  |  | 	.timer_disable_continuous = timerfd_timer_disable_continuous, | 
					
						
							|  |  |  | 	.timer_get_event = timerfd_timer_get_event, | 
					
						
							|  |  |  | 	.timer_get_max_rate = timerfd_timer_get_max_rate, | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	.timer_fd = timerfd_timer_fd, | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define TIMERFD_MAX_RATE 1000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct timerfd_timer { | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	int fd; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	struct itimerspec saved_timer; | 
					
						
							|  |  |  | 	unsigned int is_continuous:1; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void timer_destroy(void *obj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct timerfd_timer *timer = obj; | 
					
						
							| 
									
										
										
										
											2015-07-02 11:57:44 +02:00
										 |  |  | 	if (timer->fd > -1) { | 
					
						
							|  |  |  | 		close(timer->fd); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static void *timerfd_timer_open(void) | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct timerfd_timer *timer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Could not allocate memory for timerfd_timer structure\n"); | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	if ((timer->fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) { | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Failed to create timerfd timer: %s\n", strerror(errno)); | 
					
						
							|  |  |  | 		ao2_ref(timer, -1); | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	return timer; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static void timerfd_timer_close(void *data) | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	ao2_ref(data, -1); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static int timerfd_timer_set_rate(void *data, unsigned int rate) | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	struct timerfd_timer *timer = data; | 
					
						
							| 
									
										
										
										
											2009-05-11 22:04:40 +00:00
										 |  |  | 	int res = 0; | 
					
						
							| 
									
										
										
										
											2009-01-16 19:54:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	ao2_lock(timer); | 
					
						
							| 
									
										
										
										
											2012-11-05 23:10:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	timer->saved_timer.it_value.tv_sec = 0; | 
					
						
							|  |  |  | 	timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L; | 
					
						
							|  |  |  | 	timer->saved_timer.it_interval.tv_sec = timer->saved_timer.it_value.tv_sec; | 
					
						
							|  |  |  | 	timer->saved_timer.it_interval.tv_nsec = timer->saved_timer.it_value.tv_nsec; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	if (!timer->is_continuous) { | 
					
						
							|  |  |  | 		res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL); | 
					
						
							| 
									
										
										
										
											2009-05-11 22:04:40 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-03-02 23:06:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	ao2_unlock(timer); | 
					
						
							| 
									
										
										
										
											2009-03-02 23:06:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static int timerfd_timer_ack(void *data, unsigned int quantity) | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	struct timerfd_timer *timer = data; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	uint64_t expirations; | 
					
						
							|  |  |  | 	int read_result = 0; | 
					
						
							| 
									
										
										
										
											2012-11-05 23:10:14 +00:00
										 |  |  | 	int res = 0; | 
					
						
							| 
									
										
										
										
											2011-08-17 18:31:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	ao2_lock(timer); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							| 
									
										
										
										
											2011-08-17 18:31:39 +00:00
										 |  |  | 		struct itimerspec timer_status; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 		if (timerfd_gettime(timer->fd, &timer_status)) { | 
					
						
							|  |  |  | 			ast_log(LOG_ERROR, "Call to timerfd_gettime() using handle %d error: %s\n", timer->fd, strerror(errno)); | 
					
						
							| 
									
										
										
										
											2011-08-17 18:31:39 +00:00
										 |  |  | 			expirations = 0; | 
					
						
							| 
									
										
										
										
											2012-11-05 23:10:14 +00:00
										 |  |  | 			res = -1; | 
					
						
							| 
									
										
										
										
											2011-08-17 18:31:39 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) { | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 			ast_debug(1, "Avoiding read on disarmed timerfd %d\n", timer->fd); | 
					
						
							| 
									
										
										
										
											2011-08-17 18:31:39 +00:00
										 |  |  | 			expirations = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 		read_result = read(timer->fd, &expirations, sizeof(expirations)); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 		if (read_result == -1) { | 
					
						
							| 
									
										
										
										
											2011-01-19 17:15:40 +00:00
										 |  |  | 			if (errno == EINTR || errno == EAGAIN) { | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				ast_log(LOG_ERROR, "Read error: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2012-11-05 23:10:14 +00:00
										 |  |  | 				res = -1; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while (read_result != sizeof(expirations)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	ao2_unlock(timer); | 
					
						
							| 
									
										
										
										
											2011-08-17 18:31:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	if (expirations != quantity) { | 
					
						
							| 
									
										
										
										
											2008-11-19 21:55:25 +00:00
										 |  |  | 		ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-05 23:10:14 +00:00
										 |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static int timerfd_timer_enable_continuous(void *data) | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	struct timerfd_timer *timer = data; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	int res; | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	static const struct itimerspec continuous_timer = { | 
					
						
							| 
									
										
										
										
											2008-11-20 00:06:46 +00:00
										 |  |  | 		.it_value.tv_nsec = 1L, | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	ao2_lock(timer); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	if (timer->is_continuous) { | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 		/*It's already in continous mode, no need to do
 | 
					
						
							|  |  |  | 		 * anything further | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 		ao2_unlock(timer); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	res = timerfd_settime(timer->fd, 0, &continuous_timer, &timer->saved_timer); | 
					
						
							|  |  |  | 	timer->is_continuous = 1; | 
					
						
							|  |  |  | 	ao2_unlock(timer); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static int timerfd_timer_disable_continuous(void *data) | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	struct timerfd_timer *timer = data; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	ao2_lock(timer); | 
					
						
							| 
									
										
										
										
											2012-11-05 23:10:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	if (!timer->is_continuous) { | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 		/* No reason to do anything if we're not
 | 
					
						
							|  |  |  | 		 * in continuous mode | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 		ao2_unlock(timer); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL); | 
					
						
							|  |  |  | 	timer->is_continuous = 0; | 
					
						
							|  |  |  | 	memset(&timer->saved_timer, 0, sizeof(timer->saved_timer)); | 
					
						
							|  |  |  | 	ao2_unlock(timer); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static enum ast_timer_event timerfd_timer_get_event(void *data) | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	struct timerfd_timer *timer = data; | 
					
						
							| 
									
										
										
										
											2009-02-17 21:22:40 +00:00
										 |  |  | 	enum ast_timer_event res; | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	ao2_lock(timer); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	if (timer->is_continuous) { | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 		res = AST_TIMING_EVENT_CONTINUOUS; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		res = AST_TIMING_EVENT_EXPIRED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	ao2_unlock(timer); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static unsigned int timerfd_timer_get_max_rate(void *data) | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	return TIMERFD_MAX_RATE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | static int timerfd_timer_fd(void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct timerfd_timer *timer = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return timer->fd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | static int load_module(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-01-14 20:30:03 +00:00
										 |  |  | 	int fd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Make sure we support the necessary clock type */ | 
					
						
							|  |  |  | 	if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) { | 
					
						
							| 
									
										
										
										
											2010-01-15 22:07:31 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "timerfd_create() not supported by the kernel.  Not loading.\n"); | 
					
						
							| 
									
										
										
										
											2010-01-14 20:30:03 +00:00
										 |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	close(fd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-17 21:22:40 +00:00
										 |  |  | 	if (!(timing_funcs_handle = ast_register_timing_interface(&timerfd_timing))) { | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return AST_MODULE_LOAD_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int unload_module(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-07 20:01:45 +00:00
										 |  |  | 	return ast_unregister_timing_interface(timing_funcs_handle); | 
					
						
							| 
									
										
										
										
											2008-11-19 19:37:32 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-09 16:22:04 +00:00
										 |  |  | AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Timerfd Timing Interface", | 
					
						
							| 
									
										
										
										
											2015-05-05 20:49:04 -04:00
										 |  |  | 	.support_level = AST_MODULE_SUPPORT_CORE, | 
					
						
							|  |  |  | 	.load = load_module, | 
					
						
							|  |  |  | 	.unload = unload_module, | 
					
						
							|  |  |  | 	.load_pri = AST_MODPRI_TIMING, | 
					
						
							|  |  |  | ); |