/*********************************************************
- * Copyright (c) 2008-2020,2023 VMware, Inc. All rights reserved.
+ * Copyright (c) 2008-2024 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
*/
#define TOOLS_CORE_SIG_SET_OPTION "tcs_set_option"
+/**
+ * Signal sent when the service is going to be shutdown. Allow for listeners to
+ * prepare for a pending shutdown. Signal occurs before the service thread pool
+ * gets shutdown. The signal handler must not perform long running and/or
+ * blocking operation, as well as not perform core resource releases.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx ToolsAppCtx *: The application context.
+ * @param[in] data Client data.
+ */
+#define TOOLS_CORE_SIG_PRE_SHUTDOWN "tcs_pre_shutdown"
+
/**
* Signal sent when shutting down the service.
*
/*********************************************************
- * Copyright (c) 2020-2021,2023-2024 Broadcom. All Rights Reserved.
+ * Copyright (c) 2020-2024 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
* This program is free software; you can redistribute it and/or modify it
* FALSE: otherwise
* Transitions from FALSE to TRUE only */
+ Atomic_Bool stopping; /* TRUE : Guest data publishing is stopping
+ * FALSE: otherwise
+ * Transitions from FALSE to TRUE only */
+
GdpEvent eventConfig; /* The config event object:
* Signalled to update config */
} PluginState;
{
gPluginState.ctx = ctx;
Atomic_WriteBool(&gPluginState.started, FALSE);
+ Atomic_WriteBool(&gPluginState.stopping, FALSE);
#if defined(_WIN32)
gPluginState.wsaStarted = FALSE;
GdpThreadTask,
GdpThreadInterrupt,
NULL, NULL)) {
- g_critical("%s: Failed to start the gdp task thread.\n", __FUNCTION__);
+ /*
+ * Is the failure to start caused by pending service stop?
+ * - stopping is true if a pre-shutdown signal was handled
+ * - stopped is true if a shutdown signal was handled
+ *
+ * During the transition from stopping to stopped, the thread pool can
+ * be/become inactive resulting in a failure to start the gdp task thread.
+ *
+ * This is an expected failure, log it as a warning.
+ */
+ if (Atomic_ReadBool(&gPluginState.stopping)) {
+ g_debug(
+ "%s: gdp: start=%s, stop=%s, pre=%s; task: pool=%s\n",
+ __FUNCTION__,
+ Atomic_ReadBool(&gPluginState.started) ? "true" : "false",
+ Atomic_ReadBool(&gPluginState.stopped) ? "true" : "false",
+ Atomic_ReadBool(&gPluginState.stopping) ? "true" : "false",
+ (ToolsCorePool_GetPool(gPluginState.ctx) == NULL) ? "no":"yes");
+
+ g_warning("%s: Failed to start the gdp task thread.\n",
+ __FUNCTION__);
+ } else {
+ g_critical("%s: Failed to start the gdp task thread.\n",
+ __FUNCTION__);
+ }
goto exit;
}
g_mutex_lock(&gPublishState.mutex);
- if (Atomic_ReadBool(&gPluginState.stopped)) {
+ if (Atomic_ReadBool(&gPluginState.stopping)) {
+ /*
+ * Do not publish when publishing is stopped or gdp is stopping in
+ * preparation for stopping.
+ */
+ g_debug(
+ "%s: gdp: start=%s, stop=%s, pre=%s; task: pool=%s\n",
+ __FUNCTION__,
+ Atomic_ReadBool(&gPluginState.started) ? "true" : "false",
+ Atomic_ReadBool(&gPluginState.stopped) ? "true" : "false",
+ Atomic_ReadBool(&gPluginState.stopping) ? "true" : "false",
+ (ToolsCorePool_GetPool(gPluginState.ctx) == NULL) ? "no":"yes");
gdpErr = GDP_ERROR_STOP;
goto exit;
}
if (!Atomic_ReadBool(&gPluginState.started) &&
!GdpStart()) {
- gdpErr = GDP_ERROR_GENERAL;
+ if (Atomic_ReadBool(&gPluginState.stopping)) {
+ gdpErr = GDP_ERROR_STOP;
+ } else {
+ gdpErr = GDP_ERROR_GENERAL;
+ }
goto exit;
}
}
+/*
+ ******************************************************************************
+ * GdpPreShutdown --
+ *
+ * Prepare for shutdown. Set 'stopping' to TRUE to prevent new publications,
+ * or starting the gdp task thread in the case of a first publication.
+ *
+ * @param[in] src The source object, unused
+ * @param[in] ctx The application context
+ * @param[in] data Unused
+ *
+ ******************************************************************************
+ */
+
+static void
+GdpPreShutdown(gpointer src, // IN
+ ToolsAppCtx *ctx, // IN
+ gpointer data) // IN
+{
+ g_info("%s: Entering ...\n", __FUNCTION__);
+ Atomic_WriteBool(&gPluginState.stopping, TRUE);
+ g_debug("%s: Exiting ...\n", __FUNCTION__);
+}
+
+
/*
******************************************************************************
* GdpShutdown --
Atomic_ReadBool(&gPluginState.stopped));
g_object_set(ctx->serviceObj, TOOLS_PLUGIN_SVC_PROP_GDP, NULL, NULL);
GdpDestroy();
+ g_debug("%s: Exiting ...\n", __FUNCTION__);
}
ToolsPluginSignalCb sigs[] = {
{ TOOLS_CORE_SIG_CONF_RELOAD, GdpConfReload, NULL },
+ { TOOLS_CORE_SIG_PRE_SHUTDOWN, GdpPreShutdown, NULL },
{ TOOLS_CORE_SIG_SHUTDOWN, GdpShutdown, NULL },
};
ToolsAppReg regs[] = {
/*********************************************************
- * Copyright (c) 2020-2021,2023 VMware, Inc. All rights reserved.
+ * Copyright (c) 2020-2024 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
if (gdpErr != GDP_ERROR_SUCCESS) {
g_info("%s: ToolsPluginSvcGdp_Publish error: %s\n",
__FUNCTION__, gdpErrMsgs[gdpErr]);
- /* NOTE to SD maintainer: gdpErr == GDP_ERROR_NO_SUBSCRIBERS to be handled here when ready*/
+ /*
+ * NOTE to SD maintainer:
+ * GDP_ERROR_NO_SUBSCRIBERS to be handled here when ready
+ */
if (gdpErr == GDP_ERROR_STOP ||
+ gdpErr == GDP_ERROR_GENERAL ||
gdpErr == GDP_ERROR_UNREACH ||
gdpErr == GDP_ERROR_TIMEOUT) {
gSkipThisTask = TRUE;
static void
ToolsCoreCleanup(ToolsServiceState *state)
{
+ g_info("%s: Entering\n", __FUNCTION__);
+ /*
+ * Emit the early shutdown signal.
+ */
+ g_signal_emit_by_name(state->ctx.serviceObj,
+ TOOLS_CORE_SIG_PRE_SHUTDOWN,
+ &state->ctx);
#if (defined(_WIN32) && !defined(_ARM64_)) || \
(defined(__linux__) && !defined(USERWORLD))
if (state->mainService) {
ToolsCoreService_RegisterProperty(state->ctx.serviceObj,
&ctxProp);
g_object_set(state->ctx.serviceObj, TOOLS_CORE_PROP_CTX, &state->ctx, NULL);
+
/* Initialize the environment from config. */
ToolsCoreInitEnv(&state->ctx);
ToolsCorePool_Init(&state->ctx);
/*********************************************************
- * Copyright (C) 2008-2019, 2021 VMware, Inc. All rights reserved.
+ * Copyright (c) 2008-2024 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
G_TYPE_POINTER,
G_TYPE_STRING,
G_TYPE_STRING);
+ g_signal_new(TOOLS_CORE_SIG_PRE_SHUTDOWN,
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
g_signal_new(TOOLS_CORE_SIG_SHUTDOWN,
G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_LAST,
/*********************************************************
- * Copyright (C) 2008-2016 VMware, Inc. All rights reserved.
+ * Copyright (c) 2008-2024 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
#endif
+/**
+ * Handles a pre-shutdown callback; just logs debug information. This is called
+ * at the start of a service shutdown prior to the shut down signal, and should
+ * be used to prepare for an incoming shutdown signal.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The app context.
+ * @param[in] plugin Plugin registration data.
+ */
+
+static void
+TestPluginPreShutdown(gpointer src,
+ ToolsAppCtx *ctx,
+ ToolsPluginData *plugin)
+{
+ vm_debug("pre-shutdown signal.");
+ CU_ASSERT(gInvalidSigError);
+ CU_ASSERT(gInvalidAppError);
+ CU_ASSERT(gInvalidAppProvider);
+ CU_ASSERT(gValidAppRegistration);
+}
+
+
+
/**
* Handles a shutdown callback; just logs debug information. This is called
* before the service is shut down, and should be used to clean up any resources
};
ToolsPluginSignalCb sigs[] = {
{ TOOLS_CORE_SIG_RESET, TestPluginReset, ®Data },
+ { TOOLS_CORE_SIG_SHUTDOWN, TestPluginPreShutdown, ®Data },
{ TOOLS_CORE_SIG_SHUTDOWN, TestPluginShutdown, ®Data },
{ TOOLS_CORE_SIG_CAPABILITIES, TestPluginCapabilities, ®Data },
{ TOOLS_CORE_SIG_SET_OPTION, TestPluginSetOption, ®Data },