[Asterisk-cvs] asterisk asterisk.c,1.180,1.181

kpfleming kpfleming
Wed Sep 14 18:42:25 CDT 2005


Update of /usr/cvsroot/asterisk
In directory mongoose.digium.com:/tmp/cvs-serv6182

Modified Files:
	asterisk.c 
Log Message:
ensure that ast_safe_system() is thread-safe (issue #4947)


Index: asterisk.c
===================================================================
RCS file: /usr/cvsroot/asterisk/asterisk.c,v
retrieving revision 1.180
retrieving revision 1.181
diff -u -d -r1.180 -r1.181
--- asterisk.c	14 Sep 2005 20:46:49 -0000	1.180
+++ asterisk.c	14 Sep 2005 22:40:54 -0000	1.181
@@ -349,42 +349,62 @@
 
 }
 
+AST_MUTEX_DEFINE_STATIC(safe_system_lock);
+static unsigned int safe_system_level = 0;
+static void *safe_system_prev_handler;
+
 int ast_safe_system(const char *s)
 {
-	/* XXX This function needs some optimization work XXX */
 	pid_t pid;
 	int x;
 	int res;
 	struct rusage rusage;
 	int status;
-	void (*prev_handler) = signal(SIGCHLD, null_sig_handler);
+	unsigned int level;
+
+	/* keep track of how many ast_safe_system() functions
+	   are running at this moment
+	*/
+	ast_mutex_lock(&safe_system_lock);
+	level = safe_system_level++;
+
+	/* only replace the handler if it has not already been done */
+	if (level == 0)
+		safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
+
+	ast_mutex_unlock(&safe_system_lock);
+
 	pid = fork();
+
 	if (pid == 0) {
 		/* Close file descriptors and launch system command */
-		for (x=STDERR_FILENO + 1; x<4096;x++) {
+		for (x = STDERR_FILENO + 1; x < 4096; x++)
 			close(x);
-		}
-		res = execl("/bin/sh", "/bin/sh", "-c", s, NULL);
+		execl("/bin/sh", "/bin/sh", "-c", s, NULL);
 		exit(1);
 	} else if (pid > 0) {
 		for(;;) {
 			res = wait4(pid, &status, 0, &rusage);
 			if (res > -1) {
-				if (WIFEXITED(status))
-					res = WEXITSTATUS(status);
-				else
-					res = -1;
+				res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+				break;
+			} else if (errno != EINTR) 
 				break;
-			} else {
-				if (errno != EINTR) 
-					break;
-			}
 		}
 	} else {
 		ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
 		res = -1;
 	}
-	signal(SIGCHLD, prev_handler);
+
+	ast_mutex_lock(&safe_system_lock);
+	level = --safe_system_level;
+
+	/* only restore the handler if we are the last one */
+	if (level == 0)
+		signal(SIGCHLD, safe_system_prev_handler);
+
+	ast_mutex_unlock(&safe_system_lock);
+
 	return res;
 }
 




More information about the svn-commits mailing list