PERFORCE change 110304 for review
Michael Bushkov
bushman at FreeBSD.org
Tue Nov 21 16:20:29 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