PERFORCE change 110304 for review

Michael Bushkov bushman at FreeBSD.org
Tue Nov 21 17:25:44 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=110304

Change 110304 by bushman at bushman_nss_ldap_cached on 2006/11/20 15:56:29

	Some basic signal-handling added, graceful restart and shutdown (on
	SIGHUP and SIGTERM signals respectively) implemented. Still need some
	code to properly handle blocked threads (will be useful with
	perform-actuall-lookups option set to "yes").

Affected files ...

.. //depot/projects/soc2006/nss_ldap_cached/src/usr.sbin/cached/cached.c#12 edit

Differences ...

==== //depot/projects/soc2006/nss_ldap_cached/src/usr.sbin/cached/cached.c#12 (text) ====

@@ -91,14 +91,16 @@
 #endif
 static void precache_entries(struct configuration *);
 static void print_version_info(void);
-static void processing_loop(cache, struct runtime_env *,
+static int processing_loop(cache, struct runtime_env *,
 	struct configuration *);
 static void process_socket_event(struct kevent *, struct runtime_env *,
 	struct configuration *);
 static void process_timer_event(struct kevent *, struct runtime_env *,
 	struct configuration *);
 static void *processing_thread(void *);
+static void tune_runtime_env_kqueue(struct runtime_env *);
 static void usage(void);
+static int wait_for_hup_term(void);
 
 void get_time_func(struct timeval *);
 
@@ -175,6 +177,23 @@
 	TRACE_OUT(destroy_cache_);
 }
 
+static void 
+tune_runtime_env_kqueue(struct runtime_env *env)
+{
+	struct kevent eventlist[3];
+	struct timespec timeout;
+
+	EV_SET(&eventlist[0], env->sockfd, EVFILT_READ, EV_ADD | EV_ONESHOT,
+		0, 0, 0);
+	EV_SET(&eventlist[1], SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT,
+		0, 0, 0);
+	EV_SET(&eventlist[2], SIGHUP, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT,
+		0, 0, 0);
+	memset(&timeout, 0, sizeof(struct timespec));
+	kevent(env->queue, eventlist,
+		sizeof(eventlist) / sizeof(struct kevent), NULL, 0, &timeout);
+}
+
 /*
  * Socket and kqueues are prepared here. We have one global queue for both
  * socket and timers events.
@@ -185,9 +204,6 @@
 	int serv_addr_len;
 	struct sockaddr_un serv_addr;
 
-	struct kevent eventlist;
-	struct timespec timeout;
-
 	struct runtime_env *retval;
 
 	TRACE_IN(init_runtime_env);
@@ -238,12 +254,8 @@
 		TRACE_OUT(init_runtime_env);
 		return (NULL);
 	}
+	tune_runtime_env_kqueue(retval);
 
-	EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD | EV_ONESHOT,
-		0, 0, 0);
-	memset(&timeout, 0, sizeof(struct timespec));
-	kevent(retval->queue, &eventlist, 1, NULL, 0, &timeout);
-
 	LOG_MSG_2("runtime environment", "successfully initialized");
 	TRACE_OUT(init_runtime_env);
 	return (retval);
@@ -259,8 +271,6 @@
 duplicate_runtime_env(struct runtime_env *env)
 {
         struct runtime_env *retval;
-        struct timespec timeout;
-        struct kevent eventlist;
 
 	TRACE_IN(duplicate_runtime_env);
  	retval = malloc(sizeof(struct runtime_env));
@@ -276,10 +286,7 @@
 		TRACE_OUT(duplicate_runtime_env);
 		return (NULL);
 	}
-	EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD | EV_ONESHOT,
-		0, 0, 0);
-	memset(&timeout, 0, sizeof(struct timespec));
-	kevent(retval->queue, &eventlist, 1, NULL, 0, &timeout);
+	tune_runtime_env_kqueue(retval);
 
 	TRACE_OUT(duplicate_runtime_env);
 	return (retval);
@@ -600,9 +607,10 @@
 
 /*
  * Processing loop is the basic processing routine, that forms a body of each
- * procssing thread
+ * procssing thread. It works till its thread receives a signal and returns
+ * the signal number.
  */
-static void
+static int
 processing_loop(cache the_cache, struct runtime_env *env,
 	struct configuration *config)
 {
@@ -648,6 +656,8 @@
 					process_timer_event(event_data,
 						env, config);
 					break;
+				case EVFILT_SIGNAL:
+					return (event_data->ident);
 				default:
 					break;
 				}
@@ -675,6 +685,8 @@
 
 	sigemptyset(&new);
 	sigaddset(&new, SIGPIPE);
+	sigaddset(&new, SIGTERM);
+	sigaddset(&new, SIGHUP);
 	if (pthread_sigmask(SIG_BLOCK, &new, NULL) != 0)
 		LOG_ERR_1("processing thread",
 			"thread can't block the SIGPIPE signal");
@@ -700,6 +712,51 @@
 	time->tv_usec = 0;
 }
 
+int
+wait_for_hup_term()
+{
+	struct kevent eventlist[2];
+	int queue, nevents;
+	
+	queue = kqueue();
+	if (queue == -1) {
+		LOG_ERR_2("wait_for_hup_term", "can't create kqueue");
+		return (-1);
+	}
+	
+	EV_SET(&eventlist[0], SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT,
+		0, 0, 0);
+	EV_SET(&eventlist[1], SIGHUP, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT,
+		0, 0, 0);
+	
+	nevents = kevent(queue, eventlist,
+		sizeof(eventlist) / sizeof(struct kevent), eventlist, 
+		sizeof(eventlist) / sizeof(struct kevent), NULL);
+	if (nevents == 0) {
+		LOG_ERR_2("wait_for_hup_term", "kevent() returned 0 events");
+		close(queue);
+		return (-1);
+	} else {
+		if (nevents != 1) {
+			LOG_ERR_2("wait_for_hup_term", "kevent() returned more "
+			    "than 1 event");
+			close(queue);
+			return (-1);
+		}
+		
+		if (eventlist[0].flags & EV_ERROR) {
+			LOG_ERR_2("wait_for_hup_term", "error while registering"
+			    " event with kevent()");
+			close(queue);
+			return (-1);
+		}
+		
+		assert(eventlist[0].filter == EVFILT_SIGNAL);
+		close(queue);
+		return (eventlist[0].ident);
+	}
+}
+
 /*
  * The idea of _nss_cache_cycle_prevention_function is that nsdispatch will
  * search for this symbol in the executable. This symbol is the attribute of
@@ -721,11 +778,13 @@
 
 	struct pidfh *pidfile;
 	pid_t pid;
+	sigset_t psigmask;
 
 	char const *config_file;
 	char const *error_str;
 	int error_line;
 	int i, res;
+	int do_gracerestart;
 
 	int trace_mode_enabled;
 	int force_single_threaded;
@@ -735,7 +794,6 @@
 	int show_statistics;
 	int daemon_mode, interactive_mode;
 
-
 	/* by default all debug messages are omitted */
 	TRACE_OFF();
 
@@ -884,8 +942,14 @@
 	if (trace_mode_enabled == 1)
 		TRACE_ON();
 
-	/* blocking the main thread from receiving SIGPIPE signal */
-	sigblock(sigmask(SIGPIPE));
+	sigemptyset(&psigmask);
+	sigaddset(&psigmask, SIGPIPE);
+	sigaddset(&psigmask, SIGTERM);
+	sigaddset(&psigmask, SIGHUP);
+	if (pthread_sigmask(SIG_BLOCK, &psigmask, NULL) != 0) {
+		LOG_ERR_1("main", "can't set process signal mask");
+		return (-1);
+	}
 
 	/* daemonization */
 	if (do_not_daemonize == 0) {
@@ -921,6 +985,9 @@
 	}
 	LOG_MSG_1("main", "request agents registered successfully");
 
+gracerestart:
+	do_gracerestart = 0;
+	
 	/* configuration initialization */
 	s_configuration = init_configuration();
 	if (s_configuration == NULL) {
@@ -1029,14 +1096,30 @@
 			thread_args = NULL;
 		}
 
-		for (i = 0; i < s_configuration->threads_num; ++i) {
-			if (threads[i] != NULL)
-				pthread_join(threads[i], NULL);
+		switch (wait_for_hup_term()) {
+		case SIGHUP:
+			do_gracerestart = 1;
+			break;
+		case SIGTERM:
+			break;
+		default:
+			LOG_ERR_1("main", "wait_for_hup_term() failed");
+			break;
 		}
 	} else {
 		LOG_MSG_1("main", "working in single-threaded mode");
 		precache_entries(s_configuration);
-		processing_loop(s_cache, s_runtime_env, s_configuration);
+		res = processing_loop(s_cache, s_runtime_env, s_configuration);
+		switch (res) {
+		case SIGHUP:
+			do_gracerestart = 1;
+			break;
+		case SIGTERM:
+			break;
+		default:
+			LOG_ERR_1("main", "processing_loop() returned %d", res);
+			break;
+		}
 	}
 
 fin:
@@ -1048,6 +1131,9 @@
 
 	/* configuration destruction */
 	destroy_configuration(s_configuration);
+	
+	if (do_gracerestart != 0)
+		goto gracerestart;
 
 	/* agents table destruction */
 	destroy_agent_table(s_agent_table);


More information about the p4-projects mailing list