From 8b70cb0ef8e654d09d0d2974ad72388f46be9fde 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. --- 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 cbbecb6f7..dd99442ae 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 a59c46046..785ad4e41 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1565,12 +1565,32 @@ 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(); +} + void doFastMemoryTest(void) { #if defined(HAVE_PROC_MAPS) if (server.memcheck_enabled) { /* 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 b0b12d59d..e8c51ee86 100644 --- a/src/server.c +++ b/src/server.c @@ -2879,6 +2879,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(); @@ -5174,7 +5175,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 4122008dc..d4d8de95a 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). */