ports/152700: [patch] net/asterisk using 100% cpu with .call files

Florian Smeets flo at smeets.im
Tue Nov 30 10:40:09 UTC 2010


The following reply was made to PR ports/152700; it has been noted by GNATS.

From: Florian Smeets <flo at smeets.im>
To: Alexander Brovikov <alexander at brovikov.ru>
Cc: bug-followup at FreeBSD.org, Max Khon <fjoe at samodelkin.net>
Subject: Re: ports/152700: [patch] net/asterisk using 100% cpu with .call
 files
Date: Tue, 30 Nov 2010 11:37:43 +0100

 This is a multi-part message in MIME format.
 --------------000202090605060700080204
 Content-Type: text/plain; charset=ISO-8859-1
 Content-Transfer-Encoding: 7bit
 
 Hi Max,
 
 can you please commit the attached patch to net/asterisk as a workaround
 to digium bug 18089. This will be in 1.8.1.
 
 Thanks,
 Florian
 
 -- 
 Florian Smeets
 
 --------------000202090605060700080204
 Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0";
  name="asterisk.diff"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="asterisk.diff"
 
 ===> Generating patch
 ===> Viewing diff with more
 diff -ruN --exclude=CVS /usr/ports/net/asterisk.orig/Makefile /usr/ports/net/asterisk/Makefile
 --- /usr/ports/net/asterisk.orig/Makefile	2010-11-30 11:31:52.000000000 +0100
 +++ /usr/ports/net/asterisk/Makefile	2010-11-30 11:32:15.000000000 +0100
 @@ -7,6 +7,7 @@
  
  PORTNAME=	asterisk
  PORTVERSION=	1.8.0
 +PORTREVISION=	1
  CATEGORIES=	net
  MASTER_SITES=	http://downloads.asterisk.org/pub/telephony/asterisk/ \
  		http://downloads.asterisk.org/pub/telephony/asterisk/old-releases/
 diff -ruN --exclude=CVS /usr/ports/net/asterisk.orig/files/patch-pbx__pbx_spool.c /usr/ports/net/asterisk/files/patch-pbx__pbx_spool.c
 --- /usr/ports/net/asterisk.orig/files/patch-pbx__pbx_spool.c	1970-01-01 01:00:00.000000000 +0100
 +++ /usr/ports/net/asterisk/files/patch-pbx__pbx_spool.c	2010-11-30 11:14:30.000000000 +0100
 @@ -0,0 +1,240 @@
 +--- ./pbx/pbx_spool.c.orig	2010-10-18 17:32:40.000000000 +0200
 ++++ ./pbx/pbx_spool.c	2010-11-30 11:14:19.000000000 +0100
 +@@ -26,11 +26,6 @@
 + 
 + ASTERISK_FILE_VERSION(__FILE__, "$Revision: 292083 $")
 + 
 +-/* Handling of call files using inotify is not functioning correctly currently:
 +- * Issue 18089 - https://issues.asterisk.org/view.php?id=18089 
 +- */
 +-#undef HAVE_INOTIFY
 +-
 + #include <sys/stat.h>
 + #include <time.h>
 + #include <utime.h>
 +@@ -67,7 +62,7 @@
 + 	 */
 + 	SPOOL_FLAG_ALWAYS_DELETE = (1 << 0),
 + 	/* Don't unlink the call file after processing, move in qdonedir */
 +-	SPOOL_FLAG_ARCHIVE = (1 << 1)
 ++	SPOOL_FLAG_ARCHIVE = (1 << 1),
 + };
 + 
 + static char qdir[255];
 +@@ -260,24 +255,18 @@
 + 
 + static void safe_append(struct outgoing *o, time_t now, char *s)
 + {
 +-	int fd;
 + 	FILE *f;
 +-	struct utimbuf tbuf;
 +-
 +-	if ((fd = open(o->fn, O_WRONLY | O_APPEND)) < 0)
 +-		return;
 ++	struct utimbuf tbuf = { .actime = now, .modtime = now + o->retrytime };
 + 
 +-	if ((f = fdopen(fd, "a"))) {
 ++	if ((f = fopen(o->fn, "a"))) {
 + 		fprintf(f, "\n%s: %ld %d (%ld)\n", s, (long)ast_mainpid, o->retries, (long) now);
 + 		fclose(f);
 +-	} else
 +-		close(fd);
 ++	}
 + 
 + 	/* Update the file time */
 +-	tbuf.actime = now;
 +-	tbuf.modtime = now + o->retrytime;
 +-	if (utime(o->fn, &tbuf))
 ++	if (utime(o->fn, &tbuf)) {
 + 		ast_log(LOG_WARNING, "Unable to set utime on %s: %s\n", o->fn, strerror(errno));
 ++	}
 + }
 + 
 + /*!
 +@@ -288,7 +277,6 @@
 +  */
 + static int remove_from_queue(struct outgoing *o, const char *status)
 + {
 +-	int fd;
 + 	FILE *f;
 + 	char newfn[256];
 + 	const char *bname;
 +@@ -297,8 +285,9 @@
 + 		struct stat current_file_status;
 + 
 + 		if (!stat(o->fn, &current_file_status)) {
 +-			if (time(NULL) < current_file_status.st_mtime)
 ++			if (time(NULL) < current_file_status.st_mtime) {
 + 				return 0;
 ++			}
 + 		}
 + 	}
 + 
 +@@ -313,26 +302,28 @@
 + 		return -1;
 + 	}
 + 
 +-	if ((fd = open(o->fn, O_WRONLY | O_APPEND))) {
 +-		if ((f = fdopen(fd, "a"))) {
 +-			fprintf(f, "Status: %s\n", status);
 +-			fclose(f);
 +-		} else
 +-			close(fd);
 ++	if (!(bname = strrchr(o->fn, '/'))) {
 ++		bname = o->fn;
 ++	} else {
 ++		bname++;
 + 	}
 + 
 +-	if (!(bname = strrchr(o->fn, '/')))
 +-		bname = o->fn;
 +-	else
 +-		bname++;	
 + 	snprintf(newfn, sizeof(newfn), "%s/%s", qdonedir, bname);
 + 	/* a existing call file the archive dir is overwritten */
 + 	unlink(newfn);
 + 	if (rename(o->fn, newfn) != 0) {
 + 		unlink(o->fn);
 + 		return -1;
 +-	} else
 +-		return 0;
 ++	}
 ++
 ++	/* Only append to the file AFTER we move it out of the watched directory,
 ++	 * otherwise the fclose() causes another event for inotify(7) */
 ++	if ((f = fopen(newfn, "a"))) {
 ++		fprintf(f, "Status: %s\n", status);
 ++		fclose(f);
 ++	}
 ++
 ++	return 0;
 + }
 + 
 + static void *attempt_thread(void *data)
 +@@ -399,7 +390,7 @@
 + 	}
 + 
 + 	/* Attempt to open the file */
 +-	if (!(f = fopen(fn, "r+"))) {
 ++	if (!(f = fopen(fn, "r"))) {
 + 		remove_from_queue(o, "Failed");
 + 		free_outgoing(o);
 + 		ast_log(LOG_WARNING, "Unable to open %s: %s, deleting\n", fn, strerror(errno));
 +@@ -414,7 +405,7 @@
 + 		fclose(f);
 + 		return -1;
 + 	}
 +-	
 ++
 + #if 0
 + 	printf("Filename: %s, Retries: %d, max: %d\n", fn, o->retries, o->maxretries);
 + #endif
 +@@ -432,7 +423,7 @@
 + 			   so abort their retry and continue as we were... */
 + 			if (o->callingpid)
 + 				safe_append(o, time(NULL), "AbortRetry");
 +-			
 ++
 + 			safe_append(o, now, "StartRetry");
 + 			launch_service(o);
 + 		}
 +@@ -455,6 +446,7 @@
 + 
 + /* Only one thread is accessing this list, so no lock is necessary */
 + static AST_LIST_HEAD_NOLOCK_STATIC(dirlist, direntry);
 ++static AST_LIST_HEAD_NOLOCK_STATIC(createlist, direntry);
 + 
 + static void queue_file(const char *filename, time_t when)
 + {
 +@@ -482,14 +474,12 @@
 + 		when = st.st_mtime;
 + 	}
 + 
 +-#ifndef HAVE_INOTIFY
 +-	/* Need to check the existing list for kqueue(2), in order to avoid duplicates. */
 ++	/* Need to check the existing list in order to avoid duplicates. */
 + 	AST_LIST_TRAVERSE(&dirlist, cur, list) {
 + 		if (cur->mtime == when && !strcmp(filename, cur->name)) {
 + 			return;
 + 		}
 + 	}
 +-#endif
 + 
 + 	if ((res = when) > now || (res = scan_service(filename, now)) > 0) {
 + 		if (!(new = ast_calloc(1, sizeof(*new) + strlen(filename) + 1))) {
 +@@ -517,6 +507,40 @@
 + 	}
 + }
 + 
 ++#ifdef HAVE_INOTIFY
 ++static void queue_file_create(const char *filename)
 ++{
 ++	struct direntry *cur;
 ++
 ++	AST_LIST_TRAVERSE(&createlist, cur, list) {
 ++		if (!strcmp(cur->name, filename)) {
 ++			return;
 ++		}
 ++	}
 ++
 ++	if (!(cur = ast_calloc(1, sizeof(*cur) + strlen(filename) + 1))) {
 ++		return;
 ++	}
 ++	strcpy(cur->name, filename);
 ++	AST_LIST_INSERT_TAIL(&createlist, cur, list);
 ++}
 ++
 ++static void queue_file_write(const char *filename)
 ++{
 ++	struct direntry *cur;
 ++	/* Only queue entries where an IN_CREATE preceded the IN_CLOSE_WRITE */
 ++	AST_LIST_TRAVERSE_SAFE_BEGIN(&createlist, cur, list) {
 ++		if (!strcmp(cur->name, filename)) {
 ++			AST_LIST_REMOVE_CURRENT(list);
 ++			ast_free(cur);
 ++			queue_file(filename, 0);
 ++			break;
 ++		}
 ++	}
 ++	AST_LIST_TRAVERSE_SAFE_END
 ++}
 ++#endif
 ++
 + static void *scan_thread(void *unused)
 + {
 + 	DIR *dir;
 +@@ -557,7 +581,7 @@
 + 	}
 + 
 + #ifdef HAVE_INOTIFY
 +-	inotify_add_watch(inotify_fd, qdir, IN_CLOSE_WRITE | IN_MOVED_TO);
 ++	inotify_add_watch(inotify_fd, qdir, IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO);
 + #endif
 + 
 + 	/* First, run through the directory and clear existing entries */
 +@@ -567,7 +591,7 @@
 + 	}
 + 
 + #ifndef HAVE_INOTIFY
 +-	EV_SET(&kev, dirfd(dir), EVFILT_VNODE, EV_ADD | EV_ENABLE, NOTE_WRITE | NOTE_EXTEND | NOTE_DELETE | NOTE_REVOKE | NOTE_ATTRIB, 0, NULL);
 ++	EV_SET(&kev, dirfd(dir), EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_WRITE, 0, NULL);
 + 	if (kevent(inotify_fd, &kev, 1, NULL, 0, &nowait) < 0 && errno != 0) {
 + 		ast_log(LOG_ERROR, "Unable to watch directory %s: %s\n", qdir, strerror(errno));
 + 	}
 +@@ -598,7 +622,15 @@
 + 				(res = read(inotify_fd, &buf, sizeof(buf))) >= sizeof(buf.iev)) {
 + 				/* File(s) added to directory, add them to my list */
 + 				do {
 +-					queue_file(buf.iev.name, 0);
 ++					if (buf.iev.mask & IN_CREATE) {
 ++						queue_file_create(buf.iev.name);
 ++					} else if (buf.iev.mask & IN_CLOSE_WRITE) {
 ++						queue_file_write(buf.iev.name);
 ++					} else if (buf.iev.mask & IN_MOVED_TO) {
 ++						queue_file(buf.iev.name, 0);
 ++					} else {
 ++						ast_log(LOG_ERROR, "Unexpected event %d for file '%s'\n", (int) buf.iev.mask, buf.iev.name);
 ++					}
 + 					res -= sizeof(buf.iev) + buf.iev.len;
 + 					if (res >= sizeof(buf.iev)) {
 + 						memmove(&buf.iev, &buf.iev.name[buf.iev.len], res);
 ===> Done
 
 --------------000202090605060700080204--



More information about the freebsd-ports-bugs mailing list