34
34
#include "qemu/systemd.h"
35
35
#include "qemu-version.h"
36
36
#ifdef _WIN32
37
+ #include <dbt.h>
37
38
#include "qga/service-win32.h"
38
39
#include "qga/vss-win32.h"
39
40
#endif
@@ -83,6 +84,7 @@ struct GAState {
83
84
bool logging_enabled ;
84
85
#ifdef _WIN32
85
86
GAService service ;
87
+ HANDLE wakeup_event ;
86
88
#endif
87
89
bool delimit_response ;
88
90
bool frozen ;
@@ -119,6 +121,7 @@ static const char *ga_freeze_whitelist[] = {
119
121
#ifdef _WIN32
120
122
DWORD WINAPI service_ctrl_handler (DWORD ctrl , DWORD type , LPVOID data ,
121
123
LPVOID ctx );
124
+ DWORD WINAPI handle_serial_device_events (DWORD type , LPVOID data );
122
125
VOID WINAPI service_main (DWORD argc , TCHAR * argv []);
123
126
#endif
124
127
static int run_agent (GAState * s );
@@ -677,6 +680,36 @@ static gboolean channel_init(GAState *s, const gchar *method, const gchar *path,
677
680
}
678
681
679
682
#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
+
680
713
DWORD WINAPI service_ctrl_handler (DWORD ctrl , DWORD type , LPVOID data ,
681
714
LPVOID ctx )
682
715
{
@@ -688,9 +721,13 @@ DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type, LPVOID data,
688
721
case SERVICE_CONTROL_STOP :
689
722
case SERVICE_CONTROL_SHUTDOWN :
690
723
quit_handler (SIGTERM );
724
+ SetEvent (ga_state -> wakeup_event );
691
725
service -> status .dwCurrentState = SERVICE_STOP_PENDING ;
692
726
SetServiceStatus (service -> status_handle , & service -> status );
693
727
break ;
728
+ case SERVICE_CONTROL_DEVICEEVENT :
729
+ handle_serial_device_events (type , data );
730
+ break ;
694
731
695
732
default :
696
733
ret = ERROR_CALL_NOT_IMPLEMENTED ;
@@ -717,10 +754,24 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])
717
754
service -> status .dwServiceSpecificExitCode = NO_ERROR ;
718
755
service -> status .dwCheckPoint = 0 ;
719
756
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
+ }
720
770
SetServiceStatus (service -> status_handle , & service -> status );
721
771
722
772
run_agent (ga_state );
723
773
774
+ UnregisterDeviceNotification (service -> device_notification_handle );
724
775
service -> status .dwCurrentState = SERVICE_STOPPED ;
725
776
SetServiceStatus (service -> status_handle , & service -> status );
726
777
}
@@ -1328,12 +1379,24 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
1328
1379
1329
1380
s -> config = config ;
1330
1381
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
+
1331
1391
ga_state = s ;
1332
1392
return s ;
1333
1393
}
1334
1394
1335
1395
static void cleanup_agent (GAState * s )
1336
1396
{
1397
+ #ifdef _WIN32
1398
+ CloseHandle (s -> wakeup_event );
1399
+ #endif
1337
1400
if (s -> command_state ) {
1338
1401
ga_command_state_cleanup_all (s -> command_state );
1339
1402
ga_command_state_free (s -> command_state );
@@ -1365,6 +1428,27 @@ static int run_agent_once(GAState *s)
1365
1428
return EXIT_SUCCESS ;
1366
1429
}
1367
1430
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
+
1368
1452
static int run_agent (GAState * s )
1369
1453
{
1370
1454
int ret = EXIT_SUCCESS ;
@@ -1375,7 +1459,7 @@ static int run_agent(GAState *s)
1375
1459
ret = run_agent_once (s );
1376
1460
if (s -> config -> retry_path && !s -> force_exit ) {
1377
1461
g_warning ("agent stopped unexpectedly, restarting..." );
1378
- sleep ( QGA_RETRY_INTERVAL );
1462
+ wait_for_channel_availability ( s );
1379
1463
}
1380
1464
} while (s -> config -> retry_path && !s -> force_exit );
1381
1465
0 commit comments