Commit efff347f authored by Ondřej Surý's avatar Ondřej Surý
Browse files

Merge branch '1023-make-app.c-TSAN-clean' into 'master'

Make isc_app_t opaque and thread-safe

Closes #1023

See merge request !1936
parents 4d30aee3 93aa9766
Pipeline #14817 passed with stages
in 1 minute and 5 seconds
5235. [cleanup] Refactor lib/isc/app.c to be thread-safe, unused
parts of the API has been removed and the
isc_appctx_t data type has been changed to be
fully opaque. [GL #1023]
5234. [port] arm: just use the compiler's default support for 5234. [port] arm: just use the compiler's default support for
yield. [GL #981] yield. [GL #981]
   
......
...@@ -1622,9 +1622,9 @@ main(int argc, char *argv[]) { ...@@ -1622,9 +1622,9 @@ main(int argc, char *argv[]) {
fatal("failed to create mctx"); fatal("failed to create mctx");
CHECK(isc_appctx_create(mctx, &actx)); CHECK(isc_appctx_create(mctx, &actx));
CHECK(isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr)); CHECK(isc_taskmgr_createinctx(mctx, 1, 0, &taskmgr));
CHECK(isc_socketmgr_createinctx(mctx, actx, &socketmgr)); CHECK(isc_socketmgr_createinctx(mctx, &socketmgr));
CHECK(isc_timermgr_createinctx(mctx, actx, &timermgr)); CHECK(isc_timermgr_createinctx(mctx, &timermgr));
parse_args(argc, argv); parse_args(argc, argv);
......
...@@ -278,7 +278,7 @@ rndc_senddone(isc_task_t *task, isc_event_t *event) { ...@@ -278,7 +278,7 @@ rndc_senddone(isc_task_t *task, isc_event_t *event) {
if (sends == 0 && recvs == 0) { if (sends == 0 && recvs == 0) {
isc_socket_detach(&sock); isc_socket_detach(&sock);
isc_task_shutdown(task); isc_task_shutdown(task);
RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS); isc_app_shutdown();
} }
} }
...@@ -347,7 +347,7 @@ rndc_recvdone(isc_task_t *task, isc_event_t *event) { ...@@ -347,7 +347,7 @@ rndc_recvdone(isc_task_t *task, isc_event_t *event) {
if (sends == 0 && recvs == 0) { if (sends == 0 && recvs == 0) {
isc_socket_detach(&sock); isc_socket_detach(&sock);
isc_task_shutdown(task); isc_task_shutdown(task);
RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS); isc_app_shutdown();
} }
} }
......
...@@ -98,7 +98,7 @@ tick(isc_task_t *task, isc_event_t *event) { ...@@ -98,7 +98,7 @@ tick(isc_task_t *task, isc_event_t *event) {
info->ticks++; info->ticks++;
if (strcmp(info->name, "1") == 0) { if (strcmp(info->name, "1") == 0) {
if (info->ticks == 10) { if (info->ticks == 10) {
RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS); isc_app_shutdown();
} else if (info->ticks >= 15 && info->exiting) { } else if (info->ticks >= 15 && info->exiting) {
isc_timer_detach(&info->timer); isc_timer_detach(&info->timer);
isc_task_detach(&info->task); isc_task_detach(&info->task);
......
...@@ -635,10 +635,7 @@ LIBS="$PTHREAD_LIBS $LIBS" ...@@ -635,10 +635,7 @@ LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
CC="$PTHREAD_CC" CC="$PTHREAD_CC"
# AC_CHECK_FUNCS([pthread_attr_getstacksize pthread_attr_setstacksize])
# We'd like to use sigwait() too
#
AC_CHECK_FUNCS([sigwait pthread_attr_getstacksize pthread_attr_setstacksize])
AC_ARG_WITH([locktype], AC_ARG_WITH([locktype],
AS_HELP_STRING([--with-locktype=ARG], AS_HELP_STRING([--with-locktype=ARG],
......
...@@ -420,13 +420,13 @@ dns_client_create(dns_client_t **clientp, unsigned int options) { ...@@ -420,13 +420,13 @@ dns_client_create(dns_client_t **clientp, unsigned int options) {
result = isc_app_ctxstart(actx); result = isc_app_ctxstart(actx);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup; goto cleanup;
result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr); result = isc_taskmgr_createinctx(mctx, 1, 0, &taskmgr);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup; goto cleanup;
result = isc_socketmgr_createinctx(mctx, actx, &socketmgr); result = isc_socketmgr_createinctx(mctx, &socketmgr);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup; goto cleanup;
result = isc_timermgr_createinctx(mctx, actx, &timermgr); result = isc_timermgr_createinctx(mctx, &timermgr);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup; goto cleanup;
#if 0 #if 0
......
...@@ -101,15 +101,15 @@ ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp, ...@@ -101,15 +101,15 @@ ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp,
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto fail; goto fail;
result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp); result = isc_taskmgr_createinctx(*mctxp, 1, 0, taskmgrp);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto fail; goto fail;
result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp); result = isc_socketmgr_createinctx(*mctxp, socketmgrp);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto fail; goto fail;
result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp); result = isc_timermgr_createinctx(*mctxp, timermgrp);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto fail; goto fail;
......
...@@ -103,14 +103,7 @@ typedef isc_event_t isc_appevent_t; ...@@ -103,14 +103,7 @@ typedef isc_event_t isc_appevent_t;
* of the isc_app_ routines to work. app implementations must maintain * of the isc_app_ routines to work. app implementations must maintain
* all app context invariants. * all app context invariants.
*/ */
struct isc_appctx { struct isc_appctx;
unsigned int impmagic;
unsigned int magic;
};
#define ISCAPI_APPCTX_MAGIC ISC_MAGIC('A','a','p','c')
#define ISCAPI_APPCTX_VALID(c) ((c) != NULL && \
(c)->magic == ISCAPI_APPCTX_MAGIC)
ISC_LANG_BEGINDECLS ISC_LANG_BEGINDECLS
...@@ -184,10 +177,10 @@ isc_app_isrunning(void); ...@@ -184,10 +177,10 @@ isc_app_isrunning(void);
*\li false App is not running. *\li false App is not running.
*/ */
isc_result_t void
isc_app_ctxshutdown(isc_appctx_t *ctx); isc_app_ctxshutdown(isc_appctx_t *ctx);
isc_result_t void
isc_app_shutdown(void); isc_app_shutdown(void);
/*!< /*!<
* \brief Request application shutdown. * \brief Request application shutdown.
...@@ -205,13 +198,13 @@ isc_app_shutdown(void); ...@@ -205,13 +198,13 @@ isc_app_shutdown(void);
*\li ISC_R_UNEXPECTED *\li ISC_R_UNEXPECTED
*/ */
isc_result_t void
isc_app_ctxsuspend(isc_appctx_t *ctx); isc_app_ctxsuspend(isc_appctx_t *ctx);
/*!< /*!<
* \brief This has the same behavior as isc_app_ctxsuspend(). * \brief This has the same behavior as isc_app_ctxsuspend().
*/ */
isc_result_t void
isc_app_reload(void); isc_app_reload(void);
/*!< /*!<
* \brief Request application reload. * \brief Request application reload.
...@@ -295,44 +288,6 @@ isc_appctx_destroy(isc_appctx_t **ctxp); ...@@ -295,44 +288,6 @@ isc_appctx_destroy(isc_appctx_t **ctxp);
*\li *ctxp == NULL. *\li *ctxp == NULL.
*/ */
void
isc_appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr);
/*!<
* \brief Associate a task manager with an application context.
*
* This must be done before running tasks within the application context.
*
* Requires:
*\li 'ctx' is a valid application context.
*\li 'taskmgr' is a valid task manager.
*/
void
isc_appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr);
/*!<
* \brief Associate a socket manager with an application context.
*
* This must be done before handling socket events within the application
* context.
*
* Requires:
*\li 'ctx' is a valid application context.
*\li 'socketmgr' is a valid socket manager.
*/
void
isc_appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr);
/*!<
* \brief Associate a socket timer with an application context.
*
* This must be done before handling timer events within the application
* context.
*
* Requires:
*\li 'ctx' is a valid application context.
*\li 'timermgr' is a valid timer manager.
*/
ISC_LANG_ENDDECLS ISC_LANG_ENDDECLS
#endif /* ISC_APP_H */ #endif /* ISC_APP_H */
...@@ -805,8 +805,7 @@ isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, ...@@ -805,8 +805,7 @@ isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
/*@}*/ /*@}*/
isc_result_t isc_result_t
isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, isc_socketmgr_createinctx(isc_mem_t *mctx, isc_socketmgr_t **managerp);
isc_socketmgr_t **managerp);
isc_result_t isc_result_t
isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp); isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp);
......
...@@ -630,7 +630,7 @@ isc_task_privilege(isc_task_t *task); ...@@ -630,7 +630,7 @@ isc_task_privilege(isc_task_t *task);
*****/ *****/
isc_result_t isc_result_t
isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_createinctx(isc_mem_t *mctx,
unsigned int workers, unsigned int default_quantum, unsigned int workers, unsigned int default_quantum,
isc_taskmgr_t **managerp); isc_taskmgr_t **managerp);
isc_result_t isc_result_t
......
...@@ -316,8 +316,7 @@ isc_timer_gettype(isc_timer_t *timer); ...@@ -316,8 +316,7 @@ isc_timer_gettype(isc_timer_t *timer);
*/ */
isc_result_t isc_result_t
isc_timermgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, isc_timermgr_createinctx(isc_mem_t *mctx, isc_timermgr_t **managerp);
isc_timermgr_t **managerp);
isc_result_t isc_result_t
isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp); isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp);
......
...@@ -1871,7 +1871,7 @@ isc_taskmgr_renderjson(isc_taskmgr_t *mgr0, json_object *tasks) { ...@@ -1871,7 +1871,7 @@ isc_taskmgr_renderjson(isc_taskmgr_t *mgr0, json_object *tasks) {
isc_result_t isc_result_t
isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_createinctx(isc_mem_t *mctx,
unsigned int workers, unsigned int default_quantum, unsigned int workers, unsigned int default_quantum,
isc_taskmgr_t **managerp) isc_taskmgr_t **managerp)
{ {
...@@ -1880,8 +1880,5 @@ isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, ...@@ -1880,8 +1880,5 @@ isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
result = isc_taskmgr_create(mctx, workers, default_quantum, result = isc_taskmgr_create(mctx, workers, default_quantum,
managerp); managerp);
if (result == ISC_R_SUCCESS)
isc_appctx_settaskmgr(actx, *managerp);
return (result); return (result);
} }
...@@ -784,15 +784,11 @@ isc_timermgr_destroy(isc_timermgr_t **managerp) { ...@@ -784,15 +784,11 @@ isc_timermgr_destroy(isc_timermgr_t **managerp) {
} }
isc_result_t isc_result_t
isc_timermgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, isc_timermgr_createinctx(isc_mem_t *mctx, isc_timermgr_t **managerp)
isc_timermgr_t **managerp)
{ {
isc_result_t result; isc_result_t result;
result = isc_timermgr_create(mctx, managerp); result = isc_timermgr_create(mctx, managerp);
if (result == ISC_R_SUCCESS)
isc_appctx_settimermgr(actx, *managerp);
return (result); return (result);
} }
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#endif #endif
#include <isc/platform.h> #include <isc/platform.h>
#include <isc/atomic.h>
#include <isc/app.h> #include <isc/app.h>
#include <isc/condition.h> #include <isc/condition.h>
#include <isc/mem.h> #include <isc/mem.h>
...@@ -48,7 +49,7 @@ ...@@ -48,7 +49,7 @@
* as an event loop dispatching various events. * as an event loop dispatching various events.
*/ */
static pthread_t blockedthread; static pthread_t blockedthread;
static bool is_running; static atomic_bool is_running;
/* /*
* The application context of this module. This implementation actually * The application context of this module. This implementation actually
...@@ -57,72 +58,41 @@ static bool is_running; ...@@ -57,72 +58,41 @@ static bool is_running;
#define APPCTX_MAGIC ISC_MAGIC('A', 'p', 'c', 'x') #define APPCTX_MAGIC ISC_MAGIC('A', 'p', 'c', 'x')
#define VALID_APPCTX(c) ISC_MAGIC_VALID(c, APPCTX_MAGIC) #define VALID_APPCTX(c) ISC_MAGIC_VALID(c, APPCTX_MAGIC)
typedef struct isc__appctx { struct isc_appctx {
isc_appctx_t common; unsigned int magic;
isc_mem_t *mctx; isc_mem_t *mctx;
isc_mutex_t lock; isc_mutex_t lock;
isc_eventlist_t on_run; isc_eventlist_t on_run;
bool shutdown_requested; atomic_bool shutdown_requested;
bool running; atomic_bool running;
atomic_bool want_shutdown;
/*! atomic_bool want_reload;
* We assume that 'want_shutdown' can be read and written atomically. atomic_bool blocked;
*/
bool want_shutdown;
/*
* We assume that 'want_reload' can be read and written atomically.
*/
bool want_reload;
bool blocked;
isc_taskmgr_t *taskmgr;
isc_socketmgr_t *socketmgr;
isc_timermgr_t *timermgr;
isc_mutex_t readylock; isc_mutex_t readylock;
isc_condition_t ready; isc_condition_t ready;
} isc__appctx_t; };
static isc__appctx_t isc_g_appctx;
#ifndef HAVE_SIGWAIT static isc_appctx_t isc_g_appctx;
static void
exit_action(int arg) {
UNUSED(arg);
isc_g_appctx.want_shutdown = true;
}
static void static void
reload_action(int arg) {
UNUSED(arg);
isc_g_appctx.want_reload = true;
}
#endif
static isc_result_t
handle_signal(int sig, void (*handler)(int)) { handle_signal(int sig, void (*handler)(int)) {
struct sigaction sa; struct sigaction sa;
char strbuf[ISC_STRERRORSIZE];
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler; sa.sa_handler = handler;
if (sigfillset(&sa.sa_mask) != 0 || if (sigfillset(&sa.sa_mask) != 0 ||
sigaction(sig, &sa, NULL) < 0) { sigaction(sig, &sa, NULL) < 0) {
char strbuf[ISC_STRERRORSIZE];
strerror_r(errno, strbuf, sizeof(strbuf)); strerror_r(errno, strbuf, sizeof(strbuf));
UNEXPECTED_ERROR(__FILE__, __LINE__, isc_error_fatal(__FILE__, __LINE__,
"handle_signal() %d setup: %s", "handle_signal() %d setup: %s",
sig, strbuf); sig, strbuf);
return (ISC_R_UNEXPECTED);
} }
return (ISC_R_SUCCESS);
} }
isc_result_t isc_result_t
isc_app_ctxstart(isc_appctx_t *ctx0) { isc_app_ctxstart(isc_appctx_t *ctx) {
isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
isc_result_t result;
int presult; int presult;
sigset_t sset; sigset_t sset;
char strbuf[ISC_STRERRORSIZE]; char strbuf[ISC_STRERRORSIZE];
...@@ -133,64 +103,27 @@ isc_app_ctxstart(isc_appctx_t *ctx0) { ...@@ -133,64 +103,27 @@ isc_app_ctxstart(isc_appctx_t *ctx0) {
* Start an ISC library application. * Start an ISC library application.
*/ */
isc_mutex_init(&ctx->readylock); isc_mutex_init(&ctx->lock);
isc_mutex_init(&ctx->readylock);
isc_condition_init(&ctx->ready); isc_condition_init(&ctx->ready);
isc_mutex_init(&ctx->lock);
ISC_LIST_INIT(ctx->on_run); ISC_LIST_INIT(ctx->on_run);
ctx->shutdown_requested = false; atomic_init(&ctx->shutdown_requested, false);
ctx->running = false; atomic_init(&ctx->running, false);
ctx->want_shutdown = false; atomic_init(&ctx->want_shutdown, false);
ctx->want_reload = false; atomic_init(&ctx->want_reload, false);
ctx->blocked = false; atomic_init(&ctx->blocked, false);
#ifndef HAVE_SIGWAIT
/*
* Install do-nothing handlers for SIGINT and SIGTERM.
*
* We install them now because BSDI 3.1 won't block
* the default actions, regardless of what we do with
* pthread_sigmask().
*/
result = handle_signal(SIGINT, exit_action);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = handle_signal(SIGTERM, exit_action);
if (result != ISC_R_SUCCESS)
goto cleanup;
#endif
/* /*
* Always ignore SIGPIPE. * Always ignore SIGPIPE.
*/ */
result = handle_signal(SIGPIPE, SIG_IGN); handle_signal(SIGPIPE, SIG_IGN);
if (result != ISC_R_SUCCESS)
goto cleanup;
/* handle_signal(SIGHUP, SIG_DFL);
* On Solaris 2, delivery of a signal whose action is SIG_IGN handle_signal(SIGTERM, SIG_DFL);
* will not cause sigwait() to return. We may have inherited handle_signal(SIGINT, SIG_DFL);
* unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent
* process (e.g, Solaris cron). Set an action of SIG_DFL to make
* sure sigwait() works as expected. Only do this for SIGTERM and
* SIGINT if we don't have sigwait(), since a different handler is
* installed above.
*/
result = handle_signal(SIGHUP, SIG_DFL);
if (result != ISC_R_SUCCESS)
goto cleanup;
#ifdef HAVE_SIGWAIT
result = handle_signal(SIGTERM, SIG_DFL);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = handle_signal(SIGINT, SIG_DFL);
if (result != ISC_R_SUCCESS)
goto cleanup;
#endif
/* /*
* Block SIGHUP, SIGINT, SIGTERM. * Block SIGHUP, SIGINT, SIGTERM.
...@@ -206,61 +139,45 @@ isc_app_ctxstart(isc_appctx_t *ctx0) { ...@@ -206,61 +139,45 @@ isc_app_ctxstart(isc_appctx_t *ctx0) {
sigaddset(&sset, SIGINT) != 0 || sigaddset(&sset, SIGINT) != 0 ||
sigaddset(&sset, SIGTERM) != 0) { sigaddset(&sset, SIGTERM) != 0) {
strerror_r(errno, strbuf, sizeof(strbuf)); strerror_r(errno, strbuf, sizeof(strbuf));
UNEXPECTED_ERROR(__FILE__, __LINE__, isc_error_fatal(__FILE__, __LINE__,
"isc_app_start() sigsetops: %s", strbuf); "isc_app_start() sigsetops: %s", strbuf);
result = ISC_R_UNEXPECTED;
goto cleanup;
} }
presult = pthread_sigmask(SIG_BLOCK, &sset, NULL); presult = pthread_sigmask(SIG_BLOCK, &sset, NULL);
if (presult != 0) { if (presult != 0) {
strerror_r(presult, strbuf, sizeof(strbuf)); strerror_r(presult, strbuf, sizeof(strbuf));
UNEXPECTED_ERROR(__FILE__, __LINE__, isc_error_fatal(__FILE__, __LINE__,
"isc_app_start() pthread_sigmask: %s", "isc_app_start() pthread_sigmask: %s",
strbuf); strbuf);
result = ISC_R_UNEXPECTED;
goto cleanup;
} }
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
cleanup:
(void)isc_condition_destroy(&ctx->ready);
(void)isc_mutex_destroy(&ctx->readylock);
return (result);
} }
isc_result_t isc_result_t
isc_app_start(void) { isc_app_start(void) {
isc_g_appctx.common.impmagic = APPCTX_MAGIC; isc_g_appctx.magic = APPCTX_MAGIC;
isc_g_appctx.common.magic = ISCAPI_APPCTX_MAGIC;
isc_g_appctx.mctx = NULL; isc_g_appctx.mctx = NULL;
/* The remaining members will be initialized in ctxstart() */