[asterisk-commits] tilghman: trunk r178605 - in /trunk: ./ include/asterisk/ main/stdtime/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Feb 25 13:24:45 CST 2009


Author: tilghman
Date: Wed Feb 25 13:24:44 2009
New Revision: 178605

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=178605
Log:
Use notification when timezone files change and re-scan then.
(closes issue #14300)
 Reported by: jamessan
 Patches: 
       20090127__bug14300.diff.txt uploaded by tilghman (license 14)
       20090224__bug14300.diff uploaded by jamessan (license 246)
 Tested by: jamessan
 Review: http://reviewboard.digium.com/r/136/

Modified:
    trunk/configure
    trunk/configure.ac
    trunk/include/asterisk/autoconfig.h.in
    trunk/main/stdtime/localtime.c

Modified: trunk/configure.ac
URL: http://svn.digium.com/svn-view/asterisk/trunk/configure.ac?view=diff&rev=178605&r1=178604&r2=178605
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Wed Feb 25 13:24:44 2009
@@ -243,6 +243,7 @@
 AST_EXT_LIB_SETUP([ICONV], [Iconv Library], [iconv])
 AST_EXT_LIB_SETUP([IKSEMEL], [Iksemel Jabber Library], [iksemel])
 AST_EXT_LIB_SETUP([IMAP_TK], [UW IMAP Toolkit], [imap])
+AST_EXT_LIB_SETUP([INOTIFY], [inotify support], [inotify])
 AST_EXT_LIB_SETUP([IODBC], [iODBC], [iodbc])
 AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux Library], [isdnnet])
 AST_EXT_LIB_SETUP([JACK], [Jack Audio Connection Kit], [jack])
@@ -1273,6 +1274,8 @@
 
 AST_EXT_LIB_CHECK([IODBC], [iodbc], [SQLConnect], [sql.h], [-lpthread])
 
+AST_EXT_LIB_CHECK([INOTIFY], [c], [inotify_init], [sys/inotify.h])
+
 AST_EXT_LIB_CHECK([JACK], [jack], [jack_activate], [jack/jack.h])
 
 # Needed by unixodbc

Modified: trunk/include/asterisk/autoconfig.h.in
URL: http://svn.digium.com/svn-view/asterisk/trunk/include/asterisk/autoconfig.h.in?view=diff&rev=178605&r1=178604&r2=178605
==============================================================================
--- trunk/include/asterisk/autoconfig.h.in (original)
+++ trunk/include/asterisk/autoconfig.h.in Wed Feb 25 13:24:44 2009
@@ -397,6 +397,12 @@
 
 /* Define to 1 if you have the `inet_ntoa' function. */
 #undef HAVE_INET_NTOA
+
+/* Define this to indicate the ${INOTIFY_DESCRIP} library */
+#undef HAVE_INOTIFY
+
+/* Define to indicate the ${INOTIFY_DESCRIP} library version */
+#undef HAVE_INOTIFY_VERSION
 
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H

Modified: trunk/main/stdtime/localtime.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/main/stdtime/localtime.c?view=diff&rev=178605&r1=178604&r2=178605
==============================================================================
--- trunk/main/stdtime/localtime.c (original)
+++ trunk/main/stdtime/localtime.c Wed Feb 25 13:24:44 2009
@@ -51,6 +51,9 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <float.h>
+#ifdef HAVE_INOTIFY
+#include <sys/inotify.h>
+#endif
 
 #include "private.h"
 #include "tzfile.h"
@@ -147,6 +150,11 @@
 	char		chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
 				(2 * (MY_TZNAME_MAX + 1)))];
 	struct lsinfo	lsis[TZ_MAX_LEAPS];
+#ifdef HAVE_INOTIFY
+	int wd[2];
+#else
+	time_t  mtime[2];
+#endif
 	AST_LIST_ENTRY(state) list;
 };
 
@@ -217,6 +225,156 @@
 #define TZ_STRLEN_MAX 255
 #endif /* !defined TZ_STRLEN_MAX */
 
+static pthread_t inotify_thread = AST_PTHREADT_NULL;
+static ast_cond_t initialization;
+static ast_mutex_t initialization_lock;
+#ifdef HAVE_INOTIFY
+static int inotify_fd = -1;
+
+static void *inotify_daemon(void *data)
+{
+	struct {
+		struct inotify_event iev;
+		char name[FILENAME_MAX + 1];
+	} buf;
+	ssize_t res;
+	struct state *cur;
+
+	inotify_fd = inotify_init();
+
+	ast_mutex_lock(&initialization_lock);
+	ast_cond_signal(&initialization);
+	ast_mutex_unlock(&initialization_lock);
+
+	if (inotify_fd < 0) {
+		ast_log(LOG_ERROR, "Cannot initialize file notification service: %s (%d)\n", strerror(errno), errno);
+		inotify_thread = AST_PTHREADT_NULL;
+		return NULL;
+	}
+
+	for (;/*ever*/;) {
+		/* This read should block, most of the time. */
+		if ((res = read(inotify_fd, &buf, sizeof(buf))) < sizeof(buf.iev) && res > 0) {
+			/* This should never happen */
+			ast_log(LOG_ERROR, "Inotify read less than a full event (%d < %d)?!!\n", res, sizeof(buf.iev));
+			break;
+		} else if (res < 0) {
+			if (errno == EINTR || errno == EAGAIN) {
+				/* If read fails, then wait a bit, then continue */
+				poll(NULL, 0, 10000);
+				continue;
+			}
+			/* Sanity check -- this should never happen, either */
+			ast_log(LOG_ERROR, "Inotify failed: %s\n", strerror(errno));
+			break;
+		}
+		AST_LIST_LOCK(&zonelist);
+		AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
+			if (cur->wd[0] == buf.iev.wd || cur->wd[1] == buf.iev.wd) {
+				AST_LIST_REMOVE_CURRENT(list);
+				ast_free(cur);
+				break;
+			}
+		}
+		AST_LIST_TRAVERSE_SAFE_END
+		AST_LIST_UNLOCK(&zonelist);
+	}
+	close(inotify_fd);
+	inotify_thread = AST_PTHREADT_NULL;
+	return NULL;
+}
+
+static void add_notify(struct state *sp, const char *path)
+{
+	if (inotify_thread == AST_PTHREADT_NULL) {
+		ast_cond_init(&initialization, NULL);
+		ast_mutex_init(&initialization_lock);
+		ast_mutex_lock(&initialization_lock);
+		if (!(ast_pthread_create_background(&inotify_thread, NULL, inotify_daemon, NULL))) {
+			/* Give the thread a chance to initialize */
+			ast_cond_wait(&initialization, &initialization_lock);
+		} else {
+			ast_log(LOG_ERROR, "Unable to start notification thread\n");
+			ast_mutex_unlock(&initialization_lock);
+			return;
+		}
+		ast_mutex_unlock(&initialization_lock);
+	}
+
+	if (inotify_fd > -1) {
+		char fullpath[FILENAME_MAX + 1] = "";
+		if (readlink(path, fullpath, sizeof(fullpath) - 1) != -1) {
+			/* If file the symlink points to changes */
+			sp->wd[1] = inotify_add_watch(inotify_fd, fullpath, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE );
+		} else {
+			sp->wd[1] = -1;
+		}
+		/* or if the symlink itself changes (or the real file is here, if path is not a symlink) */
+		sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE | IN_DONT_FOLLOW);
+	}
+}
+#else
+static void *notify_daemon(void *data)
+{
+	struct stat st, lst;
+	struct state *cur;
+
+	ast_mutex_lock(&initialization_lock);
+	ast_cond_signal(&initialization);
+	ast_mutex_unlock(&initialization_lock);
+
+	for (;/*ever*/;) {
+		char		fullname[FILENAME_MAX + 1];
+
+		poll(NULL, 0, 60000);
+		AST_LIST_LOCK(&zonelist);
+		AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
+			char *name = cur->name;
+
+			if (name[0] == ':')
+				++name;
+			if (name[0] != '/') {
+				(void) strcpy(fullname, TZDIR "/");
+				(void) strcat(fullname, name);
+				name = fullname;
+			}
+			stat(name, &st);
+			lstat(name, &lst);
+			if (st.st_mtime > cur->mtime[0] || lst.st_mtime > cur->mtime[1]) {
+				AST_LIST_REMOVE_CURRENT(list);
+				ast_free(cur);
+				continue;
+			}
+		}
+		AST_LIST_TRAVERSE_SAFE_END
+		AST_LIST_UNLOCK(&zonelist);
+	}
+	inotify_thread = AST_PTHREADT_NULL;
+	return NULL;
+}
+
+static void add_notify(struct state *sp, const char *path)
+{
+	struct stat st;
+
+	if (inotify_thread == AST_PTHREADT_NULL) {
+		ast_cond_init(&initialization, NULL);
+		ast_mutex_init(&initialization_lock);
+		ast_mutex_lock(&initialization_lock);
+		if (!(ast_pthread_create_background(&inotify_thread, NULL, notify_daemon, NULL))) {
+			/* Give the thread a chance to initialize */
+			ast_cond_wait(&initialization, &initialization_lock);
+		}
+		ast_mutex_unlock(&initialization_lock);
+	}
+
+	stat(path, &st);
+	sp->mtime[0] = st.st_mtime;
+	lstat(path, &st);
+	sp->mtime[1] = st.st_mtime;
+}
+#endif
+
 /*! \note
 ** Section 4.12.3 of X3.159-1989 requires that
 **	Except for the strftime function, these functions [asctime,
@@ -305,6 +463,7 @@
 			return -1;
 		if ((fid = open(name, OPEN_MODE)) == -1)
 			return -1;
+		add_notify(sp, name);
 	}
 	nread = read(fid, u.buf, sizeof u.buf);
 	if (close(fid) < 0 || nread <= 0)




More information about the asterisk-commits mailing list