Skip to content

Commit b70d6af

Browse files
bish22ahmdroth
authored andcommitted
qga-win: changing --retry-path option behavior
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 <[email protected]> Signed-off-by: Sameeh Jubran <[email protected]> Signed-off-by: Michael Roth <[email protected]>
1 parent a2c1ac4 commit b70d6af

File tree

2 files changed

+89
-1
lines changed

2 files changed

+89
-1
lines changed

qga/main.c

+85-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "qemu/systemd.h"
3535
#include "qemu-version.h"
3636
#ifdef _WIN32
37+
#include <dbt.h>
3738
#include "qga/service-win32.h"
3839
#include "qga/vss-win32.h"
3940
#endif
@@ -83,6 +84,7 @@ struct GAState {
8384
bool logging_enabled;
8485
#ifdef _WIN32
8586
GAService service;
87+
HANDLE wakeup_event;
8688
#endif
8789
bool delimit_response;
8890
bool frozen;
@@ -119,6 +121,7 @@ static const char *ga_freeze_whitelist[] = {
119121
#ifdef _WIN32
120122
DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
121123
LPVOID ctx);
124+
DWORD WINAPI handle_serial_device_events(DWORD type, LPVOID data);
122125
VOID WINAPI service_main(DWORD argc, TCHAR *argv[]);
123126
#endif
124127
static int run_agent(GAState *s);
@@ -677,6 +680,36 @@ static gboolean channel_init(GAState *s, const gchar *method, const gchar *path,
677680
}
678681

679682
#ifdef _WIN32
683+
DWORD WINAPI handle_serial_device_events(DWORD type, LPVOID data)
684+
{
685+
DWORD ret = NO_ERROR;
686+
PDEV_BROADCAST_HDR broadcast_header = (PDEV_BROADCAST_HDR)data;
687+
688+
if (broadcast_header->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
689+
switch (type) {
690+
/* Device inserted */
691+
case DBT_DEVICEARRIVAL:
692+
/* Start QEMU-ga's service */
693+
if (!SetEvent(ga_state->wakeup_event)) {
694+
ret = GetLastError();
695+
}
696+
break;
697+
/* Device removed */
698+
case DBT_DEVICEQUERYREMOVE:
699+
case DBT_DEVICEREMOVEPENDING:
700+
case DBT_DEVICEREMOVECOMPLETE:
701+
/* Stop QEMU-ga's service */
702+
if (!ResetEvent(ga_state->wakeup_event)) {
703+
ret = GetLastError();
704+
}
705+
break;
706+
default:
707+
ret = ERROR_CALL_NOT_IMPLEMENTED;
708+
}
709+
}
710+
return ret;
711+
}
712+
680713
DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
681714
LPVOID ctx)
682715
{
@@ -688,9 +721,13 @@ DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
688721
case SERVICE_CONTROL_STOP:
689722
case SERVICE_CONTROL_SHUTDOWN:
690723
quit_handler(SIGTERM);
724+
SetEvent(ga_state->wakeup_event);
691725
service->status.dwCurrentState = SERVICE_STOP_PENDING;
692726
SetServiceStatus(service->status_handle, &service->status);
693727
break;
728+
case SERVICE_CONTROL_DEVICEEVENT:
729+
handle_serial_device_events(type, data);
730+
break;
694731

695732
default:
696733
ret = ERROR_CALL_NOT_IMPLEMENTED;
@@ -717,10 +754,24 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
717754
service->status.dwServiceSpecificExitCode = NO_ERROR;
718755
service->status.dwCheckPoint = 0;
719756
service->status.dwWaitHint = 0;
757+
DEV_BROADCAST_DEVICEINTERFACE notification_filter;
758+
ZeroMemory(&notification_filter, sizeof(notification_filter));
759+
notification_filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
760+
notification_filter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
761+
notification_filter.dbcc_classguid = GUID_VIOSERIAL_PORT;
762+
763+
service->device_notification_handle =
764+
RegisterDeviceNotification(service->status_handle,
765+
&notification_filter, DEVICE_NOTIFY_SERVICE_HANDLE);
766+
if (!service->device_notification_handle) {
767+
g_critical("Failed to register device notification handle!\n");
768+
return;
769+
}
720770
SetServiceStatus(service->status_handle, &service->status);
721771

722772
run_agent(ga_state);
723773

774+
UnregisterDeviceNotification(service->device_notification_handle);
724775
service->status.dwCurrentState = SERVICE_STOPPED;
725776
SetServiceStatus(service->status_handle, &service->status);
726777
}
@@ -1328,12 +1379,24 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
13281379

13291380
s->config = config;
13301381
s->socket_activation = socket_activation;
1382+
1383+
#ifdef _WIN32
1384+
s->wakeup_event = CreateEvent(NULL, TRUE, FALSE, TEXT("WakeUp"));
1385+
if (s->wakeup_event == NULL) {
1386+
g_critical("CreateEvent failed");
1387+
return NULL;
1388+
}
1389+
#endif
1390+
13311391
ga_state = s;
13321392
return s;
13331393
}
13341394

13351395
static void cleanup_agent(GAState *s)
13361396
{
1397+
#ifdef _WIN32
1398+
CloseHandle(s->wakeup_event);
1399+
#endif
13371400
if (s->command_state) {
13381401
ga_command_state_cleanup_all(s->command_state);
13391402
ga_command_state_free(s->command_state);
@@ -1365,6 +1428,27 @@ static int run_agent_once(GAState *s)
13651428
return EXIT_SUCCESS;
13661429
}
13671430

1431+
static void wait_for_channel_availability(GAState *s)
1432+
{
1433+
g_warning("waiting for channel path...");
1434+
#ifndef _WIN32
1435+
sleep(QGA_RETRY_INTERVAL);
1436+
#else
1437+
DWORD dwWaitResult;
1438+
1439+
dwWaitResult = WaitForSingleObject(s->wakeup_event, INFINITE);
1440+
1441+
switch (dwWaitResult) {
1442+
case WAIT_OBJECT_0:
1443+
break;
1444+
case WAIT_TIMEOUT:
1445+
break;
1446+
default:
1447+
g_critical("WaitForSingleObject failed");
1448+
}
1449+
#endif
1450+
}
1451+
13681452
static int run_agent(GAState *s)
13691453
{
13701454
int ret = EXIT_SUCCESS;
@@ -1375,7 +1459,7 @@ static int run_agent(GAState *s)
13751459
ret = run_agent_once(s);
13761460
if (s->config->retry_path && !s->force_exit) {
13771461
g_warning("agent stopped unexpectedly, restarting...");
1378-
sleep(QGA_RETRY_INTERVAL);
1462+
wait_for_channel_availability(s);
13791463
}
13801464
} while (s->config->retry_path && !s->force_exit);
13811465

qga/service-win32.h

+4
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@
2020
#define QGA_SERVICE_NAME "qemu-ga"
2121
#define QGA_SERVICE_DESCRIPTION "Enables integration with QEMU machine emulator and virtualizer."
2222

23+
static const GUID GUID_VIOSERIAL_PORT = { 0x6fde7521, 0x1b65, 0x48ae,
24+
{ 0xb6, 0x28, 0x80, 0xbe, 0x62, 0x1, 0x60, 0x26 } };
25+
2326
typedef struct GAService {
2427
SERVICE_STATUS status;
2528
SERVICE_STATUS_HANDLE status_handle;
29+
HDEVNOTIFY device_notification_handle;
2630
} GAService;
2731

2832
int ga_install_service(const char *path, const char *logfile,

0 commit comments

Comments
 (0)