From 5d9332266deb33c46a64abfcbbdfa025ab1100e1 Mon Sep 17 00:00:00 2001 From: WuYunlong Date: Tue, 15 Sep 2020 13:06:47 +0800 Subject: [PATCH] bio: fix doFastMemoryTest. If one thread got SIGSEGV, function sigsegvHandler() would be triggered, it would call bioKillThreads(). But call pthread_cancel() to cancel itself would make it block. Also note that if SIGSEGV is caught by bio thread, it should kill the main thread in order to give a positive report. (cherry picked from commit 8b70cb0ef8e654d09d0d2974ad72388f46be9fde) --- src/bio.c | 3 ++- src/debug.c | 22 +++++++++++++++++++++- src/server.c | 2 +- src/server.h | 1 + 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/bio.c b/src/bio.c index 69c62fc6f..33465a166 100644 --- a/src/bio.c +++ b/src/bio.c @@ -268,10 +268,11 @@ void bioKillThreads(void) { int err, j; for (j = 0; j < BIO_NUM_OPS; j++) { + if (bio_threads[j] == pthread_self()) continue; if (bio_threads[j] && pthread_cancel(bio_threads[j]) == 0) { if ((err = pthread_join(bio_threads[j],NULL)) != 0) { serverLog(LL_WARNING, - "Bio thread for job type #%d can be joined: %s", + "Bio thread for job type #%d can not be joined: %s", j, strerror(err)); } else { serverLog(LL_WARNING, diff --git a/src/debug.c b/src/debug.c index 921c681a5..178893bae 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1512,6 +1512,26 @@ int memtest_test_linux_anonymous_maps(void) { } #endif +static void killMainThread(void) { + int err; + if (pthread_self() != server.main_thread_id && pthread_cancel(server.main_thread_id) == 0) { + if ((err = pthread_join(server.main_thread_id,NULL)) != 0) { + serverLog(LL_WARNING, "main thread can not be joined: %s", strerror(err)); + } else { + serverLog(LL_WARNING, "main thread terminated"); + } + } +} + +/* Kill the running threads (other than current) in an unclean way. This function + * should be used only when it's critical to stop the threads for some reason. + * Currently Redis does this only on crash (for instance on SIGSEGV) in order + * to perform a fast memory check without other threads messing with memory. */ +static void killThreads(void) { + killMainThread(); + bioKillThreads(); +} + /* Scans the (assumed) x86 code starting at addr, for a max of `len` * bytes, searching for E8 (callq) opcodes, and dumping the symbols * and the call offset if they appear to be valid. */ @@ -1589,7 +1609,7 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) { #if defined(HAVE_PROC_MAPS) /* Test memory */ serverLogRaw(LL_WARNING|LL_RAW, "\n------ FAST MEMORY TEST ------\n"); - bioKillThreads(); + killThreads(); if (memtest_test_linux_anonymous_maps()) { serverLogRaw(LL_WARNING|LL_RAW, "!!! MEMORY ERROR DETECTED! Check your memory ASAP !!!\n"); diff --git a/src/server.c b/src/server.c index 06dcc5d9e..37e3c37df 100644 --- a/src/server.c +++ b/src/server.c @@ -2814,6 +2814,7 @@ void initServer(void) { server.aof_state = server.aof_enabled ? AOF_ON : AOF_OFF; server.hz = server.config_hz; server.pid = getpid(); + server.main_thread_id = pthread_self(); server.current_client = NULL; server.fixed_time_expire = 0; server.clients = listCreate(); @@ -5091,7 +5092,6 @@ int iAmMaster(void) { (server.cluster_enabled && nodeIsMaster(server.cluster->myself))); } - int main(int argc, char **argv) { struct timeval tv; int j; diff --git a/src/server.h b/src/server.h index 6a130879e..a1ce26cc2 100644 --- a/src/server.h +++ b/src/server.h @@ -1050,6 +1050,7 @@ struct clusterState; struct redisServer { /* General */ pid_t pid; /* Main process pid. */ + pthread_t main_thread_id; /* Main thread id */ char *configfile; /* Absolute config file path, or NULL */ char *executable; /* Absolute executable file path. */ char **exec_argv; /* Executable argv vector (copy). */