From: W.C.A. Wijngaards Date: Tue, 7 Nov 2023 14:07:02 +0000 (+0100) Subject: - fast-reload, send done and exited notification. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43ff8e112f6a560eb2e1a2bd39ae89209068b7ed;p=thirdparty%2Funbound.git - fast-reload, send done and exited notification. --- diff --git a/daemon/remote.c b/daemon/remote.c index 5f9d9064f..65183878f 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -3379,7 +3379,6 @@ int remote_control_callback(struct comm_point* c, void* arg, int err, return 0; } -#ifdef USE_WINSOCK /** * This routine polls a socket for readiness. * @param fd: file descriptor, -1 uses no fd for a timer only. @@ -3454,7 +3453,141 @@ sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event) *event = 1; return 1; } -#endif /* USE_WINSOCK */ + +/** fast reload convert fast reload notification status to string */ +static const char* +fr_notification_to_string(enum fast_reload_notification status) +{ + switch(status) { + case fast_reload_notification_none: + return "none"; + case fast_reload_notification_done: + return "done"; + case fast_reload_notification_done_error: + return "done_error"; + case fast_reload_notification_exit: + return "exit"; + case fast_reload_notification_exited: + return "exited"; + case fast_reload_notification_printout: + return "printout"; + default: + break; + } + return "unknown"; +} + +/** fast reload, poll for notification incoming. True if quit */ +static int +fr_poll_for_quit(struct fast_reload_thread* fr) +{ + int inevent, loopexit = 0; + uint32_t cmd; + ssize_t ret; + + /* Is there data? */ + if(!sock_poll_timeout(fr->commpair[1], 0, 1, 0, &inevent)) { + log_err("fr_poll_for_quit: poll failed"); + return 0; + } + if(!inevent) + return 0; + + /* Read the data */ + while(1) { + if(++loopexit > 200) { + log_err("fr_poll_for_quit: recv loops %s", + sock_strerror(errno)); + return 0; + } + ret = recv(fr->commpair[1], &cmd, sizeof(cmd), 0); + if(ret == -1) { + if( +#ifndef USE_WINSOCK + errno == EINTR || errno == EAGAIN +# ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +# endif +#else + WSAGetLastError() == WSAEINTR || + WSAGetLastError() == WSAEINPROGRESS || + WSAGetLastError() == WSAEWOULDBLOCK +#endif + ) + continue; /* Try again. */ + log_err("fr_poll_for_quit: recv: %s", + sock_strerror(errno)); + return 0; + } if(ret != sizeof(cmd)) { + log_err("fr_poll_for_quit: partial read"); + return 0; + } + break; + } + if(cmd == fast_reload_notification_exit) { + fr->need_to_quit = 1; + verbose(VERB_ALGO, "fast reload: exit notification received"); + return 1; + } + log_err("fr_poll_for_quit: unknown notification status received: %d %s", + cmd, fr_notification_to_string(cmd)); + return 0; +} + +/** fast reload thread. Send notification from the fast reload thread */ +static void +fr_send_notification(struct fast_reload_thread* fr, + enum fast_reload_notification status) +{ + int outevent, loopexit = 0; + uint32_t cmd; + ssize_t ret; + verbose(VERB_ALGO, "fast reload: send notification %s", + fr_notification_to_string(status)); + /* Make a blocking attempt to send. But meanwhile stay responsive, + * once in a while for quit commands. In case the server has to quit. */ + /* see if there is incoming quit signals */ + if(fr_poll_for_quit(fr)) + return; + while(1) { + if(++loopexit > 200) { + log_err("fast reload: could not send notification"); + return; + } + if(!sock_poll_timeout(fr->commpair[1], 200, 0, 1, &outevent)) { + log_err("fast reload: poll failed"); + return; + } + if(fr_poll_for_quit(fr)) + return; + if(!outevent) + continue; + cmd = status; + ret = send(fr->commpair[1], &cmd, sizeof(cmd), 0); + if(ret == -1) { + if( +#ifndef USE_WINSOCK + errno == EINTR || errno == EAGAIN +# ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +# endif +#else + WSAGetLastError() == WSAEINTR || + WSAGetLastError() == WSAEINPROGRESS || + WSAGetLastError() == WSAEWOULDBLOCK +#endif + ) + continue; /* Try again. */ + log_err("fast reload send notification: send: %s", + sock_strerror(errno)); + return; + } else if(ret != sizeof(cmd)) { + log_err("fast reload send notification: partial send"); + return; + } + break; + } +} #ifndef THREADS_DISABLED /** fast reload thread. the thread main function */ @@ -3465,7 +3598,21 @@ static void* fast_reload_thread_main(void* arg) verbose(VERB_ALGO, "start fast reload thread"); + if(fr_poll_for_quit(fast_reload_thread)) + goto done; + verbose(VERB_ALGO, "stop fast reload thread"); + /* If this is not an exit due to quit earlier, send regular done. */ + if(!fast_reload_thread->need_to_quit) + fr_send_notification(fast_reload_thread, + fast_reload_notification_done); + /* If during the fast_reload_notification_done send, + * fast_reload_notification_exit was received, ack it. If the + * thread is exiting due to quit received earlier, also ack it.*/ +done: + if(fast_reload_thread->need_to_quit) + fr_send_notification(fast_reload_thread, + fast_reload_notification_exited); return NULL; } #endif /* !THREADS_DISABLED */ diff --git a/daemon/remote.h b/daemon/remote.h index c257916a3..c120643dc 100644 --- a/daemon/remote.h +++ b/daemon/remote.h @@ -119,6 +119,26 @@ struct remote_stream { }; typedef struct remote_stream RES; +/** + * Notification status. This is exchanged between the fast reload thread + * and the server thread, over the commpair sockets. + */ +enum fast_reload_notification { + /** nothing, not used */ + fast_reload_notification_none = 0, + /** the fast reload thread is done */ + fast_reload_notification_done = 1, + /** the fast reload thread is done but with an error, it failed */ + fast_reload_notification_done_error = 2, + /** the fast reload thread is told to exit by the server thread. + * Sent on server quit while the reload is running. */ + fast_reload_notification_exit = 3, + /** the fast reload thread has exited, after being told to exit */ + fast_reload_notification_exited = 4, + /** the fast reload thread has information to print out */ + fast_reload_notification_printout = 5 +}; + /** * Fast reload thread structure */ @@ -132,6 +152,8 @@ struct fast_reload_thread { ub_thread_type tid; /** if the io processing has started */ int started; + /** if the thread has to quit */ + int need_to_quit; /** the event that listens on the remote service worker to the * commpair, it receives content from the fast reload thread. */