[PATCH 05/10] rpc: finish all threads before exiting main loop
Daniel P. Berrangé
berrange at redhat.com
Tue Jul 21 15:46:36 UTC 2020
On Tue, Jul 14, 2020 at 12:32:56PM +0300, Nikolay Shirokovskiy wrote:
> Currently we have issues like [1] on libvirtd shutdown as we cleanup while RPC
> and other threads are still running. Let's finish all threads other then main
> before cleanup.
>
> The approach to finish threads is suggested in [2]. In order to finish RPC
> threads serving API calls we let the event loop run but stop accepting new API
> calls and block processing any pending API calls. We also inform all drivers of
> shutdown so they can prepare for shutdown too. Then we wait for all RPC threads
> and driver's background thread to finish. If finishing takes more then 15s we
> just exit as we can't safely cleanup in time.
>
> [1] https://bugzilla.redhat.com/show_bug.cgi?id=1828207
> [2] https://www.redhat.com/archives/libvir-list/2020-April/msg01328.html
>
> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at virtuozzo.com>
> ---
> src/remote/remote_daemon.c | 3 --
> src/rpc/virnetdaemon.c | 82 +++++++++++++++++++++++++++++++++++++++++++++-
> src/rpc/virnetserver.c | 8 +++++
> src/rpc/virnetserver.h | 1 +
> 4 files changed, 90 insertions(+), 4 deletions(-)
>
> diff --git a/src/remote/remote_daemon.c b/src/remote/remote_daemon.c
> index 1aa9bfc..222bb5f 100644
> --- a/src/remote/remote_daemon.c
> +++ b/src/remote/remote_daemon.c
> @@ -1201,9 +1201,6 @@ int main(int argc, char **argv) {
> 0, "shutdown", NULL, NULL);
>
> cleanup:
> - /* Keep cleanup order in inverse order of startup */
> - virNetDaemonClose(dmn);
> -
> virNetlinkEventServiceStopAll();
>
> if (driversInitialized) {
> diff --git a/src/rpc/virnetdaemon.c b/src/rpc/virnetdaemon.c
> index bb81a43..c4b31c6 100644
> --- a/src/rpc/virnetdaemon.c
> +++ b/src/rpc/virnetdaemon.c
> @@ -23,6 +23,7 @@
> #include <unistd.h>
> #include <fcntl.h>
>
> +#include "libvirt_internal.h"
> #include "virnetdaemon.h"
> #include "virlog.h"
> #include "viralloc.h"
> @@ -69,7 +70,10 @@ struct _virNetDaemon {
> virHashTablePtr servers;
> virJSONValuePtr srvObject;
>
> + int finishTimer;
> bool quit;
> + bool finished;
> + bool graceful;
>
> unsigned int autoShutdownTimeout;
> size_t autoShutdownInhibitions;
> @@ -80,6 +84,11 @@ struct _virNetDaemon {
>
> static virClassPtr virNetDaemonClass;
>
> +static int
> +daemonServerClose(void *payload,
> + const void *key G_GNUC_UNUSED,
> + void *opaque G_GNUC_UNUSED);
> +
> static void
> virNetDaemonDispose(void *obj)
> {
> @@ -796,11 +805,53 @@ daemonServerProcessClients(void *payload,
> return 0;
> }
>
> +static int
> +daemonServerShutdownWait(void *payload,
> + const void *key G_GNUC_UNUSED,
> + void *opaque G_GNUC_UNUSED)
> +{
> + virNetServerPtr srv = payload;
> +
> + virNetServerShutdownWait(srv);
> + return 0;
> +}
> +
> +static void
> +daemonShutdownWait(void *opaque)
> +{
> + virNetDaemonPtr dmn = opaque;
> + bool graceful = false;
> +
> + virHashForEach(dmn->servers, daemonServerShutdownWait, NULL);
> + if (virStateShutdownWait() < 0)
This code can't have any dependancy on virStateShutdownWait because
it is used in virtlockd and virtlogd, neither of which use the
virState infrastructure.
> + goto finish;
> +
> + graceful = true;
> +
> + finish:
> + virObjectLock(dmn);
> + dmn->graceful = graceful;
> + virEventUpdateTimeout(dmn->finishTimer, 0);
> + virObjectUnlock(dmn);
> +}
> +
> +static void
> +virNetDaemonFinishTimer(int timerid G_GNUC_UNUSED,
> + void *opaque)
> +{
> + virNetDaemonPtr dmn = opaque;
> +
> + virObjectLock(dmn);
> + dmn->finished = true;
> + virObjectUnlock(dmn);
> +}
> +
> void
> virNetDaemonRun(virNetDaemonPtr dmn)
> {
> int timerid = -1;
> bool timerActive = false;
> + virThread shutdownThread;
>
> virObjectLock(dmn);
>
> @@ -811,6 +862,9 @@ virNetDaemonRun(virNetDaemonPtr dmn)
> }
>
> dmn->quit = false;
> + dmn->finishTimer = -1;
> + dmn->finished = false;
> + dmn->graceful = false;
>
> if (dmn->autoShutdownTimeout &&
> (timerid = virEventAddTimeout(-1,
> @@ -826,7 +880,7 @@ virNetDaemonRun(virNetDaemonPtr dmn)
> virSystemdNotifyStartup();
>
> VIR_DEBUG("dmn=%p quit=%d", dmn, dmn->quit);
> - while (!dmn->quit) {
> + while (!dmn->finished) {
> /* A shutdown timeout is specified, so check
> * if any drivers have active state, if not
> * shutdown after timeout seconds
> @@ -857,6 +911,32 @@ virNetDaemonRun(virNetDaemonPtr dmn)
> virObjectLock(dmn);
>
> virHashForEach(dmn->servers, daemonServerProcessClients, NULL);
> +
> + if (dmn->quit && dmn->finishTimer == -1) {
> + virHashForEach(dmn->servers, daemonServerClose, NULL);
> + if (virStateShutdown() < 0)
> + break;
Again, we cna't have this direct call here.
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
More information about the libvir-list
mailing list