/*
* Copyright (c) 2002-2006 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: sighdl.c,v 1.16 2006/01/19 19:29:35 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/memops.h"
#include "sm/heap.h"
#include "sm/signal.h"
#include "sm/evthr.h"
#include "evthr-int.h"
#include "log.h"
#define MAX_FAILS_T 10
/*
** EVTHR_GOTSIGNAL -- write signal type to internal pipe to notify main loop
**
** Parameters:
** evthr_ctx -- evthr context
** why -- which signal (EVTHR_signal)
**
** Returns:
** usual sm_error code
**
** Called by signal handler. BE CAREFUL!
*/
static sm_ret_T
evthr_gotsignal(sm_evthr_ctx_P evthr_ctx, int why)
{
ssize_t r;
char c;
SM_IS_EVTHR_CTX(evthr_ctx);
c = (char) why;
r = write(wrpipe(evthr_ctx), (void *) &c, 1);
if (r != 1)
return sm_error_perm(SM_EM_EVTHR, errno);
return SM_SUCCESS;
}
/*
** EVTHR_SIGNAL -- thread to deal with signals
**
** Parameters:
** ctx -- evthr context
**
** Returns:
** NULL
*/
static void *
evthr_signal(void *ctx)
{
#if WIN32
hShutdownEvt = CreateEvent(NULL, true, false, EVTHR_SHUTDOWN_EVENT);
if (hShutdownEvt == NULL)
return NULL;
if (SetConsoleCtrlHandler(et_console_handler, true) == 0)
{
CloseHandle(hShutdownEvt);
hShutdownEvt = NULL;
return NULL;
}
for( ; WAIT_OBJECT_0 != WaitForSingleObject(hShutdownEvt, INFINITE); )
continue;
CloseHandle(hShutdownEvt);
hShutdownEvt = NULL;
evthr_term(ctx, EVTHR_STOP);
#else /* WIN32 */
int sig, errs;
sigset_t set;
sm_evthr_ctx_P evthr_ctx;
(void) pthread_detach(pthread_self());
sigemptyset(&set);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGTERM);
/* Handle Ctrl-C gracefully for debugging */
sigaddset(&set, SIGINT);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
errs = 0;
evthr_ctx = (sm_evthr_ctx_P) ctx;
while (true)
{
sig = 0;
if (sigwait(&set, &sig) != 0)
{
evthr_ctx->evthr_sige_where = EVTHR_SHE_SIGWAIT;
evthr_ctx->evthr_sige_what = errno;
if (++errs > MAX_FAILS_T)
{
evthr_gotsignal(evthr_ctx, EVTHR_ABRT);
return NULL;
}
evthr_gotsignal(evthr_ctx, EVTHR_ERROR);
continue;
}
errs = 0;
switch (sig)
{
case SIGHUP:
case SIGTERM:
evthr_gotsignal(evthr_ctx, EVTHR_STOP);
return NULL;
case SIGINT:
evthr_gotsignal(evthr_ctx, EVTHR_ABRT);
return NULL;
case SIGUSR1:
evthr_gotsignal(evthr_ctx, EVTHR_USR1);
break;
case SIGUSR2:
evthr_gotsignal(evthr_ctx, EVTHR_USR2);
break;
default:
evthr_ctx->evthr_sige_where = EVTHR_SHE_UNKSIG;
evthr_ctx->evthr_sige_what = sig;
break;
}
}
#endif /* WIN32 */
return NULL;
}
/*
** EVTHR_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
**
** Parameters:
** evthr_ctx -- evthr context
**
** Returns:
*/
static sm_ret_T
evthr_spawn_signal_thread(sm_evthr_ctx_P evthr_ctx)
{
pthread_t tid;
#if !WIN32
int status;
sigset_t set;
struct sigaction sigact;
/* Ignore SIGPIPE */
sigact.sa_handler = SIG_IGN;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
if (sigaction(SIGPIPE, &sigact, NULL) < 0)
{
status = errno;
sm_log_write(evthr_ctx->evthr_c_lctx,
EVTHR_LCAT_SIGNAL, EVTHR_LMOD_SIGNAL,
SM_LOG_ERROR, 1,
"sev=ERROR, func=evthr_spawn_signal_thread, "
"status=could_not_ignore_PIPE_signal, stat=%d",
status);
return sm_error_perm(SM_EM_EVTHR, status);
}
/* Mask HUP and KILL signals */
sigemptyset(&set);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
status = pthread_sigmask(SIG_BLOCK, &set, NULL);
if (status != 0)
{
sm_log_write(evthr_ctx->evthr_c_lctx,
EVTHR_LCAT_SIGNAL, EVTHR_LMOD_SIGNAL,
SM_LOG_ERROR, 1,
"sev=ERROR, func=evthr_spawn_signal_thread, "
"status=could_not_mask_HUP_and_KILL_signals, stat=%d",
status);
return sm_error_perm(SM_EM_EVTHR, status);
}
#endif /* WIN32 */
#if WIN32
#pragma warning ( disable : 4024 4047 )
#endif /* WIN32 */
status = pthread_create(&tid, NULL, evthr_signal, (void *)evthr_ctx);
if (status != 0)
#if WIN32
#pragma warning ( default : 4024 4047 )
#endif /* WIN32 */
{
sm_log_write(evthr_ctx->evthr_c_lctx,
EVTHR_LCAT_SIGNAL, EVTHR_LMOD_SIGNAL,
SM_LOG_ERROR, 1,
"sev=ERROR, func=evthr_spawn_signal_thread, "
"status=could_not_start_signal_thread, stat=%d",
status);
return sm_error_perm(SM_EM_EVTHR, status);
}
#if WIN32
/* release the thread handle */
_unused_proc_handle((int) thread_id);
#endif /* WIN32 */
return SM_SUCCESS;
}
/*
** EVTHR_SIGNAL_INIT -- startup for thread to handle signals
**
** Parameters:
** evthr_ctx -- context
**
** Returns:
** usual sm_error code
*/
sm_ret_T
evthr_signal_init(sm_evthr_ctx_P evthr_ctx)
{
sm_ret_T ret;
/*
** spawn_signal_thread must happen before other threads are spawned
** off so that it can mask the right signals and other threads
** will inherit that mask.
*/
ret = evthr_spawn_signal_thread(evthr_ctx);
if (sm_is_err(ret))
{
sm_log_write(evthr_ctx->evthr_c_lctx,
EVTHR_LCAT_SIGNAL, EVTHR_LMOD_SIGNAL,
SM_LOG_ERROR, 1,
"sev=ERROR, func=evthr_signal_init, status="
"could_not_spawn_signal_thread, stat=%d", ret);
}
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1