qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Michael Roth <mdroth@linux.vnet.ibm.com>
To: qemu-devel@nongnu.org
Cc: peter.maydell@linaro.org, Bishara AbuHattoum <bishara@daynix.com>,
	Sameeh Jubran <sameeh@daynix.com>
Subject: [Qemu-devel] [PULL 24/24] qga-win: changing --retry-path option behavior
Date: Tue, 30 Oct 2018 09:43:58 -0500	[thread overview]
Message-ID: <20181030144358.23144-25-mdroth@linux.vnet.ibm.com> (raw)
In-Reply-To: <20181030144358.23144-1-mdroth@linux.vnet.ibm.com>

From: Bishara AbuHattoum <bishara@daynix.com>

Currently whenever the qemu-ga's service doesn't find the virtio-serial
the run_agent() loops in a QGA_RETRY_INTERVAL (default 5 seconds)
intervals and try to restart the qemu-ga which causes a synchronous loop.
Changed to wait and listen for the serial events by registering for
notifications a proper serial event handler that deals with events:
  DBT_DEVICEARRIVAL        indicates that the device has been inserted and
                           is available
  DBT_DEVICEREMOVECOMPLETE indicates that the devive has been removed
Which allow us to determine when the channel path is available for the
qemu-ga to restart.

Signed-off-by: Bishara AbuHattoum <bishara@daynix.com>
Signed-off-by: Sameeh Jubran <sameeh@daynix.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qga/main.c          | 86 ++++++++++++++++++++++++++++++++++++++++++++-
 qga/service-win32.h |  4 +++
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/qga/main.c b/qga/main.c
index 506a314140..87a0711c14 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -34,6 +34,7 @@
 #include "qemu/systemd.h"
 #include "qemu-version.h"
 #ifdef _WIN32
+#include <dbt.h>
 #include "qga/service-win32.h"
 #include "qga/vss-win32.h"
 #endif
@@ -83,6 +84,7 @@ struct GAState {
     bool logging_enabled;
 #ifdef _WIN32
     GAService service;
+    HANDLE wakeup_event;
 #endif
     bool delimit_response;
     bool frozen;
@@ -119,6 +121,7 @@ static const char *ga_freeze_whitelist[] = {
 #ifdef _WIN32
 DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
                                   LPVOID ctx);
+DWORD WINAPI handle_serial_device_events(DWORD type, LPVOID data);
 VOID WINAPI service_main(DWORD argc, TCHAR *argv[]);
 #endif
 static int run_agent(GAState *s);
@@ -677,6 +680,36 @@ static gboolean channel_init(GAState *s, const gchar *method, const gchar *path,
 }
 
 #ifdef _WIN32
+DWORD WINAPI handle_serial_device_events(DWORD type, LPVOID data)
+{
+    DWORD ret = NO_ERROR;
+    PDEV_BROADCAST_HDR broadcast_header = (PDEV_BROADCAST_HDR)data;
+
+    if (broadcast_header->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
+        switch (type) {
+            /* Device inserted */
+        case DBT_DEVICEARRIVAL:
+            /* Start QEMU-ga's service */
+            if (!SetEvent(ga_state->wakeup_event)) {
+                ret = GetLastError();
+            }
+            break;
+            /* Device removed */
+        case DBT_DEVICEQUERYREMOVE:
+        case DBT_DEVICEREMOVEPENDING:
+        case DBT_DEVICEREMOVECOMPLETE:
+            /* Stop QEMU-ga's service */
+            if (!ResetEvent(ga_state->wakeup_event)) {
+                ret = GetLastError();
+            }
+            break;
+        default:
+            ret = ERROR_CALL_NOT_IMPLEMENTED;
+        }
+    }
+    return ret;
+}
+
 DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
                                   LPVOID ctx)
 {
@@ -688,9 +721,13 @@ DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
         case SERVICE_CONTROL_STOP:
         case SERVICE_CONTROL_SHUTDOWN:
             quit_handler(SIGTERM);
+            SetEvent(ga_state->wakeup_event);
             service->status.dwCurrentState = SERVICE_STOP_PENDING;
             SetServiceStatus(service->status_handle, &service->status);
             break;
+        case SERVICE_CONTROL_DEVICEEVENT:
+            handle_serial_device_events(type, data);
+            break;
 
         default:
             ret = ERROR_CALL_NOT_IMPLEMENTED;
@@ -717,10 +754,24 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
     service->status.dwServiceSpecificExitCode = NO_ERROR;
     service->status.dwCheckPoint = 0;
     service->status.dwWaitHint = 0;
+    DEV_BROADCAST_DEVICEINTERFACE notification_filter;
+    ZeroMemory(&notification_filter, sizeof(notification_filter));
+    notification_filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+    notification_filter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
+    notification_filter.dbcc_classguid = GUID_VIOSERIAL_PORT;
+
+    service->device_notification_handle =
+        RegisterDeviceNotification(service->status_handle,
+            &notification_filter, DEVICE_NOTIFY_SERVICE_HANDLE);
+    if (!service->device_notification_handle) {
+        g_critical("Failed to register device notification handle!\n");
+        return;
+    }
     SetServiceStatus(service->status_handle, &service->status);
 
     run_agent(ga_state);
 
+    UnregisterDeviceNotification(service->device_notification_handle);
     service->status.dwCurrentState = SERVICE_STOPPED;
     SetServiceStatus(service->status_handle, &service->status);
 }
@@ -1328,12 +1379,24 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
 
     s->config = config;
     s->socket_activation = socket_activation;
+
+#ifdef _WIN32
+    s->wakeup_event = CreateEvent(NULL, TRUE, FALSE, TEXT("WakeUp"));
+    if (s->wakeup_event == NULL) {
+        g_critical("CreateEvent failed");
+        return NULL;
+    }
+#endif
+
     ga_state = s;
     return s;
 }
 
 static void cleanup_agent(GAState *s)
 {
+#ifdef _WIN32
+    CloseHandle(s->wakeup_event);
+#endif
     if (s->command_state) {
         ga_command_state_cleanup_all(s->command_state);
         ga_command_state_free(s->command_state);
@@ -1365,6 +1428,27 @@ static int run_agent_once(GAState *s)
     return EXIT_SUCCESS;
 }
 
+static void wait_for_channel_availability(GAState *s)
+{
+    g_warning("waiting for channel path...");
+#ifndef _WIN32
+    sleep(QGA_RETRY_INTERVAL);
+#else
+    DWORD dwWaitResult;
+
+    dwWaitResult = WaitForSingleObject(s->wakeup_event, INFINITE);
+
+    switch (dwWaitResult) {
+    case WAIT_OBJECT_0:
+        break;
+    case WAIT_TIMEOUT:
+        break;
+    default:
+        g_critical("WaitForSingleObject failed");
+    }
+#endif
+}
+
 static int run_agent(GAState *s)
 {
     int ret = EXIT_SUCCESS;
@@ -1375,7 +1459,7 @@ static int run_agent(GAState *s)
         ret = run_agent_once(s);
         if (s->config->retry_path && !s->force_exit) {
             g_warning("agent stopped unexpectedly, restarting...");
-            sleep(QGA_RETRY_INTERVAL);
+            wait_for_channel_availability(s);
         }
     } while (s->config->retry_path && !s->force_exit);
 
diff --git a/qga/service-win32.h b/qga/service-win32.h
index 89e99dfede..7b16d69b57 100644
--- a/qga/service-win32.h
+++ b/qga/service-win32.h
@@ -20,9 +20,13 @@
 #define QGA_SERVICE_NAME         "qemu-ga"
 #define QGA_SERVICE_DESCRIPTION  "Enables integration with QEMU machine emulator and virtualizer."
 
+static const GUID GUID_VIOSERIAL_PORT = { 0x6fde7521, 0x1b65, 0x48ae,
+{ 0xb6, 0x28, 0x80, 0xbe, 0x62, 0x1, 0x60, 0x26 } };
+
 typedef struct GAService {
     SERVICE_STATUS status;
     SERVICE_STATUS_HANDLE status_handle;
+    HDEVNOTIFY device_notification_handle;
 } GAService;
 
 int ga_install_service(const char *path, const char *logfile,
-- 
2.17.1

  parent reply	other threads:[~2018-10-30 14:45 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-30 14:43 [Qemu-devel] [PULL 00/24] qemu-ga patch queue for soft-freeze Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 01/24] qga: Support Unicode paths in guest-file-open on win32 Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 02/24] qga-win: add support for qmp_guest_fsfreeze_freeze_list Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 03/24] qga: ignore non present cpus when handling qmp_guest_get_vcpus() Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 04/24] configure: add test for libudev Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 05/24] qga: linux: report disk serial number Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 06/24] qga: linux: return disk device in guest-get-fsinfo Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 07/24] qga-win: prevent crash when executing fsinfo command Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 08/24] qga-win: fsinfo: pci-info: allow partial info Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 09/24] build: rename CONFIG_QGA_NTDDDISK to CONFIG_QGA_NTDDSCSI Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 10/24] qga-win: add debugging information Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 11/24] qga-win: refactor disk properties (bus) Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 12/24] qga-win: report disk serial number Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 13/24] qga-win: refactor disk info Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 14/24] qga-win: handle multi-disk volumes Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 15/24] qga-win: return disk device in guest-get-fsinfo Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 16/24] qga-win: demystify namespace stripping Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 17/24] qga: fix an off-by-one issue Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 18/24] qga: group agent init/cleanup init separate routines Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 19/24] qga: hang GAConfig/socket_activation off of GAState global Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 20/24] qga: move w32 service handling out of run_agent() Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 21/24] qga: add --retry-path option for re-initializing channel on failure Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 22/24] qga-win: install service with --retry-path set by default Michael Roth
2018-10-30 14:43 ` [Qemu-devel] [PULL 23/24] qga-win: report specific error when failing to open channel Michael Roth
2018-10-30 14:43 ` Michael Roth [this message]
2018-10-30 18:49 ` [Qemu-devel] [PULL 00/24] qemu-ga patch queue for soft-freeze Peter Maydell
2018-10-30 20:57   ` Michael Roth
2018-10-31 13:23     ` Peter Maydell
2018-10-31 13:59       ` Michael Roth
2018-10-31 15:41 ` no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181030144358.23144-25-mdroth@linux.vnet.ibm.com \
    --to=mdroth@linux.vnet.ibm.com \
    --cc=bishara@daynix.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=sameeh@daynix.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).