[asterisk-commits] mjordan: branch 1.8 r376428 - in /branches/1.8/main: ./ stdtime/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sun Nov 18 14:11:25 CST 2012


Author: mjordan
Date: Sun Nov 18 14:11:18 2012
New Revision: 376428

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=376428
Log:
Reorder startup sequence to prevent lockups when process is sent to background

Although it is very rare and timing dependent, the potential exists for the
call to 'daemon' to cause what appears to be a deadlock in Asterisk during
startup.  This can occur when a recursive mutex is obtained prior to the
daemon call executing.  Since daemon uses fork to send the process into the
background, any threading primitives are unsafe to re-use after the call.
Implementations of pthread recursive mutexes are highly likely to store the
thread identifier of the thread that previously obtained the mutex.  If
the mutex was locked prior to the fork, a subsequent unlock operation will
potentially fail as the thread identifier is no longer valid.  Since the
mutex is still locked, all subsequent attempts to grab the mutex by other
threads will block.

This behavior exhibited itself most often when DEBUG_THREADS was enabled, as
this compile time option surrounds the mutexes in Asterisk with another
recursive mutex that protects the storage of thread related information.  This
made it much more likely that a recursive mutex would be obtained prior to
daemon and unlocked after the call.

This patch does the following:
a) It backports a patch from Asterisk 11 that prevents the spawning of the
   localtime monitoring thread.  This thread is now spawned after Asterisk has
   fully booted.
b) It re-orders the startup sequence to call daemon earlier during Asterisk
   startup.  This limits the potential of threading primitives being accessed
   by initialization calls before daemon is called.
c) It removes calls to ast_verbose/ast_log/etc. prior to daemon being called.
   Developers should send error messages directly to stderr prior to daemon,
   as calls to ast_log may access recursive mutexes that store thread related
   information.
d) It reorganizes when thread local storage is created for storing lock
   information during the creation of threads.  Prior to this patch, the
   read/write lock protecting the list of threads in ast_register_thread would
   utilize the lock in the thread local storage prior to it being initialized;
   this patch prevents that.

On a very related note, this patch will *greatly* improve the stability of the
Asterisk Test Suite.

Review: https://reviewboard.asterisk.org/r/2197

(closes issue ASTERISK-19463)
Reported by: mjordan
Tested by: mjordan


Modified:
    branches/1.8/main/asterisk.c
    branches/1.8/main/stdtime/localtime.c
    branches/1.8/main/utils.c

Modified: branches/1.8/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/main/asterisk.c?view=diff&rev=376428&r1=376427&r2=376428
==============================================================================
--- branches/1.8/main/asterisk.c (original)
+++ branches/1.8/main/asterisk.c Sun Nov 18 14:11:18 2012
@@ -294,6 +294,7 @@
 static pthread_t mon_sig_flags;
 static int canary_pid = 0;
 static char canary_filename[128];
+static int multi_thread_safe;
 
 static char randompool[256];
 
@@ -402,6 +403,8 @@
 
 	if (!new)
 		return;
+
+	ast_assert(multi_thread_safe);
 	new->id = pthread_self();
 	new->name = name; /* steal the allocated memory for the thread name */
 	AST_RWLIST_WRLOCK(&thread_list);
@@ -1502,7 +1505,7 @@
 	int res;
 	ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
 	if (ast_consock < 0) {
-		ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
+		fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
 		return 0;
 	}
 	memset(&sunaddr, 0, sizeof(sunaddr));
@@ -2264,7 +2267,7 @@
 				break;
 			if (errno == EINTR)
 				continue;
-			ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
+			fprintf(stderr, "poll failed: %s\n", strerror(errno));
 			break;
 		}
 
@@ -2978,10 +2981,12 @@
 
 	if (ast_opt_override_config) {
 		cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
-		if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
-			ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
-	} else 
+		if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
+			fprintf(stderr, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
+		}
+	} else {
 		cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
+	}
 
 	/* init with buildtime config */
 	ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
@@ -3187,7 +3192,7 @@
 	for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
 		float version;
 		if (sscanf(v->value, "%30f", &version) != 1) {
-			ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
+			fprintf(stderr, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
 			continue;
 		}
 		if (!strcasecmp(v->name, "app_set")) {
@@ -3300,6 +3305,23 @@
 	setenv("AST_BUILD_OS", ast_build_os, 1);
 	setenv("AST_BUILD_USER", ast_build_user, 1);
 	setenv("AST_VERSION", ast_get_version(), 1);
+}
+
+static void print_intro_message(const char *runuser, const char *rungroup)
+{
+	if (ast_opt_console || option_verbose) {
+		if (ast_register_verbose(console_verboser)) {
+			fprintf(stderr, "Unable to register console verboser?\n");
+			return;
+		}
+		WELCOME_MESSAGE;
+		if (runuser) {
+			ast_verbose("Running as user '%s'\n", runuser);
+		}
+		if (rungroup) {
+			ast_verbose("Running under group '%s'\n", rungroup);
+		}
+	}
 }
 
 int main(int argc, char *argv[])
@@ -3320,10 +3342,6 @@
 	int moduleresult;         /*!< Result from the module load subsystem */
 	struct rlimit l;
 
-#if defined(__AST_DEBUG_MALLOC)
-	__ast_mm_init_phase_1();
-#endif	/* defined(__AST_DEBUG_MALLOC) */
-
 	/* Remember original args for restart */
 	if (argc > ARRAY_LEN(_argv) - 1) {
 		fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
@@ -3343,15 +3361,6 @@
 	if (gethostname(hostname, sizeof(hostname)-1))
 		ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
 	ast_mainpid = getpid();
-	ast_ulaw_init();
-	ast_alaw_init();
-	callerid_init();
-	ast_builtins_init();
-	ast_utils_init();
-	tdd_init();
-	ast_tps_init();
-	ast_fd_init();
-	ast_pbx_init();
 
 	if (getenv("HOME")) 
 		snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
@@ -3472,16 +3481,6 @@
 		}
 	}
 
-	if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
-		if (ast_register_verbose(console_verboser)) {
-			ast_log(LOG_WARNING, "Unable to register console verboser?\n");
-		}
-		WELCOME_MESSAGE;
-	}
-
-	if (ast_opt_console && !option_verbose) 
-		ast_verbose("[ Booting...\n");
-
 	/* For remote connections, change the name of the remote connection.
 	 * We do this for the benefit of init scripts (which need to know if/when
 	 * the main asterisk process has died yet). */
@@ -3492,21 +3491,18 @@
 		}
 	}
 
-	if (ast_opt_console && !option_verbose) {
-		ast_verbose("[ Reading Master Configuration ]\n");
-	}
-
 	ast_readconfig();
 	env_init();
 
 	if (ast_opt_remote && remotesock != NULL)
 		ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
 
-	if (!ast_language_is_prefix && !ast_opt_remote)
-		ast_log(LOG_WARNING, "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout.\n");
+	if (!ast_language_is_prefix && !ast_opt_remote) {
+		fprintf(stderr, "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout.\n");
+	}
 
 	if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
-		ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
+		fprintf(stderr, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
 		ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
 	}
 
@@ -3515,12 +3511,12 @@
 		l.rlim_cur = RLIM_INFINITY;
 		l.rlim_max = RLIM_INFINITY;
 		if (setrlimit(RLIMIT_CORE, &l)) {
-			ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
+			fprintf(stderr, "Unable to disable core size resource limit: %s\n", strerror(errno));
 		}
 	}
 
 	if (getrlimit(RLIMIT_NOFILE, &l)) {
-		ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
+		fprintf(stderr, "Unable to check file descriptor limit: %s\n", strerror(errno));
 	}
 
 #if !defined(CONFIGURE_RAN_AS_ROOT)
@@ -3537,13 +3533,13 @@
 		}
 
 		if (!(fd = open("/dev/null", O_RDONLY))) {
-			ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
+			fprintf(stderr, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
 			break; /* XXX Should we exit() here? XXX */
 		}
 
 		fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
 		if (dup2(fd, fd2) < 0) {
-			ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
+			fprintf(stderr, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
 			close(fd);
 			break;
 		}
@@ -3551,7 +3547,7 @@
 		FD_ZERO(&readers);
 		FD_SET(fd2, &readers);
 		if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
-			ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
+			fprintf(stderr, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
 		}
 		ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
 		close(fd);
@@ -3577,7 +3573,7 @@
 		if (errno == EEXIST) {
 			rundir_exists = 1;
 		} else {
-			ast_log(LOG_WARNING, "Unable to create socket file directory.  Remote consoles will not be able to connect! (%s)\n", strerror(x));
+			fprintf(stderr, "Unable to create socket file directory.  Remote consoles will not be able to connect! (%s)\n", strerror(x));
 		}
 	}
 
@@ -3591,22 +3587,20 @@
 		struct group *gr;
 		gr = getgrnam(rungroup);
 		if (!gr) {
-			ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
+			fprintf(stderr, "No such group '%s'!\n", rungroup);
 			exit(1);
 		}
 		if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
-			ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
+			fprintf(stderr, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
 		}
 		if (setgid(gr->gr_gid)) {
-			ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
+			fprintf(stderr, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
 			exit(1);
 		}
 		if (setgroups(0, NULL)) {
-			ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
+			fprintf(stderr, "Unable to drop unneeded groups\n");
 			exit(1);
 		}
-		if (option_verbose)
-			ast_verbose("Running as group '%s'\n", rungroup);
 	}
 
 	if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
@@ -3616,11 +3610,11 @@
 		struct passwd *pw;
 		pw = getpwnam(runuser);
 		if (!pw) {
-			ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
+			fprintf(stderr, "No such user '%s'!\n", runuser);
 			exit(1);
 		}
 		if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
-			ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
+			fprintf(stderr, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
 		}
 #ifdef HAVE_CAP
 		if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
@@ -3629,36 +3623,35 @@
 		}
 #endif /* HAVE_CAP */
 		if (!isroot && pw->pw_uid != geteuid()) {
-			ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
+			fprintf(stderr, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
 			exit(1);
 		}
 		if (!rungroup) {
 			if (setgid(pw->pw_gid)) {
-				ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
+				fprintf(stderr, "Unable to setgid to %d!\n", (int)pw->pw_gid);
 				exit(1);
 			}
 			if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
-				ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
+				fprintf(stderr, "Unable to init groups for '%s'\n", runuser);
 				exit(1);
 			}
 		}
 		if (setuid(pw->pw_uid)) {
-			ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
+			fprintf(stderr, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
 			exit(1);
 		}
-		if (option_verbose)
-			ast_verbose("Running as user '%s'\n", runuser);
 #ifdef HAVE_CAP
 		if (has_cap) {
 			cap_t cap;
 
 			cap = cap_from_text("cap_net_admin=eip");
 
-			if (cap_set_proc(cap))
-				ast_log(LOG_WARNING, "Unable to install capabilities.\n");
-
-			if (cap_free(cap))
-				ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
+			if (cap_set_proc(cap)) {
+				fprintf(stderr, "Unable to install capabilities.\n");
+			}
+			if (cap_free(cap)) {
+				fprintf(stderr, "Unable to drop capabilities.\n");
+			}
 		}
 #endif /* HAVE_CAP */
 	}
@@ -3668,7 +3661,7 @@
 #ifdef linux
 	if (geteuid() && ast_opt_dump_core) {
 		if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
-			ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
+			fprintf(stderr, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
 		}
 	}
 #endif
@@ -3680,130 +3673,172 @@
 #endif
 		char dir[PATH_MAX];
 		if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
-			ast_log(LOG_ERROR, "Unable to access the running directory (%s).  Changing to '/' for compatibility.\n", strerror(errno));
+			fprintf(stderr, "Unable to access the running directory (%s).  Changing to '/' for compatibility.\n", strerror(errno));
 			/* If we cannot access the CWD, then we couldn't dump core anyway,
 			 * so chdir("/") won't break anything. */
 			if (chdir("/")) {
 				/* chdir(/) should never fail, so this ends up being a no-op */
-				ast_log(LOG_ERROR, "chdir(\"/\") failed?!! %s\n", strerror(errno));
+				fprintf(stderr, "chdir(\"/\") failed?!! %s\n", strerror(errno));
 			}
 		} else
 #endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
 		if (!ast_opt_no_fork && !ast_opt_dump_core) {
 			/* Backgrounding, but no cores, so chdir won't break anything. */
 			if (chdir("/")) {
-				ast_log(LOG_ERROR, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
-			}
-		}
-	}
-
-	ast_term_init();
-	printf("%s", term_end());
-	fflush(stdout);
-
-	if (ast_opt_console && !option_verbose) 
-		ast_verbose("[ Initializing Custom Configuration Options ]\n");
-	/* custom config setup */
-	register_config_cli();
-	read_config_maps();
-	
-	if (ast_opt_console) {
-		if (el_hist == NULL || el == NULL)
-			ast_el_initialize();
-
-		if (!ast_strlen_zero(filename))
-			ast_el_read_history(filename);
+				fprintf(stderr, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
+			}
+		}
 	}
 
 	if (ast_tryconnect()) {
 		/* One is already running */
 		if (ast_opt_remote) {
+			multi_thread_safe = 1;
 			if (ast_opt_exec) {
 				ast_remotecontrol(xarg);
 				quit_handler(0, SHUTDOWN_FAST, 0);
 				exit(0);
 			}
+			print_intro_message(runuser, rungroup);
 			printf("%s", term_quit());
 			ast_remotecontrol(NULL);
 			quit_handler(0, SHUTDOWN_FAST, 0);
 			exit(0);
 		} else {
-			ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
+			fprintf(stderr, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
 			printf("%s", term_quit());
 			exit(1);
 		}
 	} else if (ast_opt_remote || ast_opt_exec) {
-		ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
+		fprintf(stderr, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
 		printf("%s", term_quit());
 		exit(1);
 	}
-	/* Blindly write pid file since we couldn't connect */
+
+	/* This needs to remain as high up in the initial start up as possible.
+	 * daemon causes a fork to occur, which has all sorts of unintended
+	 * consequences for things that interact with threads.  This call *must*
+	 * occur before anything in Asterisk spawns or manipulates thread related
+	 * primitives. */
+#if HAVE_WORKING_FORK
+	if (ast_opt_always_fork || !ast_opt_no_fork) {
+#ifndef HAVE_SBIN_LAUNCHD
+		if (daemon(1, 0) < 0) {
+			fprintf(stderr, "daemon() failed: %s\n", strerror(errno));
+		}
+#else
+		fprintf(stderr, "Mac OS X detected.  Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
+#endif
+	}
+#endif
+
+	/* At this point everything has been forked successfully,
+	 * we have determined that we aren't attempting to connect to
+	 * an Asterisk instance, and that there isn't one already running. */
+	multi_thread_safe = 1;
+
+	/* Spawning of astcanary must happen AFTER the call to daemon(3) */
+	if (isroot && ast_opt_high_priority) {
+		snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
+
+		/* Don't let the canary child kill Asterisk, if it dies immediately */
+		sigaction(SIGPIPE, &ignore_sig_handler, NULL);
+
+		canary_pid = fork();
+		if (canary_pid == 0) {
+			char canary_binary[128], *lastslash, ppid[12];
+
+			/* Reset signal handler */
+			signal(SIGCHLD, SIG_DFL);
+			signal(SIGPIPE, SIG_DFL);
+
+			ast_close_fds_above_n(0);
+			ast_set_priority(0);
+			snprintf(ppid, sizeof(ppid), "%d", (int) ast_mainpid);
+
+			execlp("astcanary", "astcanary", canary_filename, ppid, (char *)NULL);
+
+			/* If not found, try the same path as used to execute asterisk */
+			ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
+			if ((lastslash = strrchr(canary_binary, '/'))) {
+				ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
+				execl(canary_binary, "astcanary", canary_filename, ppid, (char *)NULL);
+			}
+
+			/* Should never happen */
+			_exit(1);
+		} else if (canary_pid > 0) {
+			pthread_t dont_care;
+			ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
+		}
+
+		/* Kill the canary when we exit */
+		ast_register_atexit(canary_exit);
+	}
+
+	/* Blindly write the PID file. */
+	ast_mainpid = getpid();
 	unlink(ast_config_AST_PID);
 	f = fopen(ast_config_AST_PID, "w");
 	if (f) {
 		fprintf(f, "%ld\n", (long)getpid());
 		fclose(f);
-	} else
-		ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
-
-#if HAVE_WORKING_FORK
-	if (ast_opt_always_fork || !ast_opt_no_fork) {
-#ifndef HAVE_SBIN_LAUNCHD
-		if (daemon(1, 0) < 0) {
-			ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
-		}
-		ast_mainpid = getpid();
-		/* Blindly re-write pid file since we are forking */
-		unlink(ast_config_AST_PID);
-		f = fopen(ast_config_AST_PID, "w");
-		if (f) {
-			fprintf(f, "%ld\n", (long)ast_mainpid);
-			fclose(f);
-		} else
-			ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
-#else
-		ast_log(LOG_WARNING, "Mac OS X detected.  Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
-#endif
-	}
-#endif
-
-	/* Spawning of astcanary must happen AFTER the call to daemon(3) */
-	if (isroot && ast_opt_high_priority) {
-		snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
-
-		/* Don't let the canary child kill Asterisk, if it dies immediately */
-		sigaction(SIGPIPE, &ignore_sig_handler, NULL);
-
-		canary_pid = fork();
-		if (canary_pid == 0) {
-			char canary_binary[128], *lastslash, ppid[12];
-
-			/* Reset signal handler */
-			signal(SIGCHLD, SIG_DFL);
-			signal(SIGPIPE, SIG_DFL);
-
-			ast_close_fds_above_n(0);
-			ast_set_priority(0);
-			snprintf(ppid, sizeof(ppid), "%d", (int) ast_mainpid);
-
-			execlp("astcanary", "astcanary", canary_filename, ppid, (char *)NULL);
-
-			/* If not found, try the same path as used to execute asterisk */
-			ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
-			if ((lastslash = strrchr(canary_binary, '/'))) {
-				ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
-				execl(canary_binary, "astcanary", canary_filename, ppid, (char *)NULL);
-			}
-
-			/* Should never happen */
-			_exit(1);
-		} else if (canary_pid > 0) {
-			pthread_t dont_care;
-			ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
-		}
-
-		/* Kill the canary when we exit */
-		ast_register_atexit(canary_exit);
+	} else {
+		fprintf(stderr, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
+	}
+
+	/* Initialize the terminal.  Since all processes have been forked,
+	 * we can now start using the standard log messages.
+	 */
+	ast_term_init();
+	printf("%s", term_end());
+	fflush(stdout);
+
+	print_intro_message(runuser, rungroup);
+
+	if (ast_opt_console && !option_verbose) {
+		ast_verbose("[ Initializing Custom Configuration Options ]\n");
+	}
+	/* custom config setup */
+	register_config_cli();
+	read_config_maps();
+
+	if (ast_opt_console) {
+		if (el_hist == NULL || el == NULL)
+			ast_el_initialize();
+
+		if (!ast_strlen_zero(filename))
+			ast_el_read_history(filename);
+	}
+
+#if defined(__AST_DEBUG_MALLOC)
+	__ast_mm_init_phase_1();
+#endif	/* defined(__AST_DEBUG_MALLOC) */
+
+	ast_ulaw_init();
+	ast_alaw_init();
+	tdd_init();
+	callerid_init();
+	ast_builtins_init();
+
+	if (ast_utils_init()) {
+		printf("%s", term_quit());
+		exit(1);
+	}
+
+	if (ast_tps_init()) {
+		printf("%s", term_quit());
+		exit(1);
+	}
+
+	if (ast_fd_init()) {
+		printf("%s", term_quit());
+		exit(1);
+	}
+
+	if (ast_pbx_init()) {
+		printf("%s", term_quit());
+		exit(1);
 	}
 
 	if (ast_event_init()) {
@@ -3985,9 +4020,9 @@
 
 	pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
 
-#if defined(__AST_DEBUG_MALLOC)
+#ifdef __AST_DEBUG_MALLOC
 	__ast_mm_init_phase_2();
-#endif	/* defined(__AST_DEBUG_MALLOC) */
+#endif
 
 	ast_lastreloadtime = ast_startuptime = ast_tvnow();
 	ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));

Modified: branches/1.8/main/stdtime/localtime.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/main/stdtime/localtime.c?view=diff&rev=376428&r1=376427&r2=376428
==============================================================================
--- branches/1.8/main/stdtime/localtime.c (original)
+++ branches/1.8/main/stdtime/localtime.c Sun Nov 18 14:11:18 2012
@@ -707,7 +707,14 @@
 			return -1;
 		if ((fid = open(name, OPEN_MODE)) == -1)
 			return -1;
-		add_notify(sp, name);
+		if (ast_fully_booted) {
+			/* If we don't wait until Asterisk is fully booted, it's possible
+			 * that the watcher thread gets started in the parent process,
+			 * before daemon(3) is called, and the thread won't propagate to
+			 * the child.  Given that bootup only takes a few seconds, it's
+			 * reasonable to only start the watcher later. */
+			add_notify(sp, name);
+		}
 	}
 	nread = read(fid, u.buf, sizeof u.buf);
 	if (close(fid) < 0 || nread <= 0)

Modified: branches/1.8/main/utils.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/main/utils.c?view=diff&rev=376428&r1=376427&r2=376428
==============================================================================
--- branches/1.8/main/utils.c (original)
+++ branches/1.8/main/utils.c Sun Nov 18 14:11:18 2012
@@ -981,7 +981,22 @@
 #ifdef DEBUG_THREADS
 	struct thr_lock_info *lock_info;
 	pthread_mutexattr_t mutex_attr;
-#endif
+
+	if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
+		return NULL;
+
+	lock_info->thread_id = pthread_self();
+	lock_info->thread_name = strdup(a.name);
+
+	pthread_mutexattr_init(&mutex_attr);
+	pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND);
+	pthread_mutex_init(&lock_info->lock, &mutex_attr);
+	pthread_mutexattr_destroy(&mutex_attr);
+
+	pthread_mutex_lock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
+	AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
+	pthread_mutex_unlock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
+#endif /* DEBUG_THREADS */
 
 	/* note that even though data->name is a pointer to allocated memory,
 	   we are not freeing it here because ast_register_thread is going to
@@ -991,23 +1006,6 @@
 	ast_free(data);
 	ast_register_thread(a.name);
 	pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self());
-
-#ifdef DEBUG_THREADS
-	if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
-		return NULL;
-
-	lock_info->thread_id = pthread_self();
-	lock_info->thread_name = strdup(a.name);
-
-	pthread_mutexattr_init(&mutex_attr);
-	pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND);
-	pthread_mutex_init(&lock_info->lock, &mutex_attr);
-	pthread_mutexattr_destroy(&mutex_attr);
-
-	pthread_mutex_lock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
-	AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
-	pthread_mutex_unlock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
-#endif /* DEBUG_THREADS */
 
 	ret = a.start_routine(a.data);
 




More information about the asterisk-commits mailing list