@@ -420,7 +420,9 @@ static int virCHProcessSetupThreads(virDomainObjPtr vm)
420420 virCHDomainObjPrivatePtr priv = vm -> privateData ;
421421 int ret ;
422422
423- virCHMonitorRefreshThreadInfo (priv -> monitor );
423+ ret = virCHMonitorRefreshThreadInfo (priv -> monitor );
424+ if (ret <= 0 )
425+ return ret ;
424426
425427 VIR_DEBUG ("Setting emulator tuning/settings" );
426428 ret = virCHProcessSetupEmulatorThreads (vm );
@@ -438,6 +440,87 @@ static int virCHProcessSetupThreads(virDomainObjPtr vm)
438440 return ret ;
439441}
440442
443+ /*
444+ * Procfs Thread watcher
445+ * This thread is started when a Domain boots up and
446+ * exists as long as the domain is active. The duty
447+ * of the thread is to watch for any tid changes for
448+ * the VM and then update the cgroups accordingly.
449+ * Threads can change in the case of following events:
450+ * - VM reboot
451+ * - Device activation
452+ *
453+ * TODO: Parsing procfs frequently is ugly and not scalable
454+ * Better option would be to have cloud-hypervisor
455+ * return the thread information via API query or
456+ * probably to have a monitor interface like what
457+ * qemu has.
458+ */
459+
460+ /*
461+ * Hard coding the polling interval for the watcher thread
462+ * to be 1 second.
463+ */
464+ #define THREAD_WATCHER_POLL_INTERVAL G_USEC_PER_SEC
465+
466+ static void chProcessWatchThreads (void * data )
467+ {
468+ virDomainObjPtr vm = (virDomainObjPtr )data ;
469+ virCHDomainObjPrivatePtr priv ;
470+
471+ VIR_DEBUG ("VM Thread watcher starting" );
472+
473+ virObjectLock (vm );
474+ priv = vm -> privateData ;
475+ while (g_atomic_int_get (& priv -> vmThreadWatcherStop ) == 0 &&
476+ virDomainObjIsActive (vm )) {
477+
478+ if (virCHDomainObjBeginJob (vm , CH_JOB_MODIFY ) < 0 ) {
479+ VIR_WARN ("VRP: Failed to Lock vm state" );
480+ } else {
481+ virCHProcessSetupThreads (vm );
482+ virCHDomainObjEndJob (vm );
483+ }
484+
485+ virObjectUnlock (vm );
486+ g_usleep (G_USEC_PER_SEC );
487+ virObjectLock (vm );
488+ }
489+ VIR_DEBUG ("VM Thread watcher exiting" );
490+
491+ virDomainObjEndAPI (& vm );
492+ return ;
493+ }
494+
495+ static int virCHProcessStartWatchThreads (virDomainObjPtr vm )
496+ {
497+ virCHDomainObjPrivatePtr priv = vm -> privateData ;
498+ g_autofree char * name = NULL ;
499+
500+ name = g_strdup_printf ("threadwatcher-%d" , vm -> pid );
501+
502+ virObjectRef (vm );
503+ if (virThreadCreateFull (& priv -> vmThreadWatcher ,
504+ false,
505+ chProcessWatchThreads ,
506+ name ,
507+ false,
508+ vm ) < 0 ) {
509+ virObjectUnref (vm );
510+ return -1 ;
511+
512+ }
513+
514+ g_atomic_int_set (& priv -> vmThreadWatcherStop , 0 );
515+ return 0 ;
516+ }
517+
518+ static void virCHProcessStopWatchThreads (virDomainObjPtr vm )
519+ {
520+ virCHDomainObjPrivatePtr priv = vm -> privateData ;
521+ g_atomic_int_set (& priv -> vmThreadWatcherStop , 1 );
522+ }
523+
441524/**
442525 * chProcessNetworkPrepareDevices
443526 */
@@ -593,6 +676,10 @@ int virCHProcessStart(virCHDriverPtr driver,
593676 if (chSetupGlobalCpuCgroup (vm ) < 0 )
594677 goto cleanup ;
595678
679+ VIR_DEBUG ("Starting the thread watcher thread" );
680+ if (virCHProcessStartWatchThreads (vm ) < 0 )
681+ goto cleanup ;
682+
596683 virDomainObjSetState (vm , VIR_DOMAIN_RUNNING , reason );
597684
598685 return 0 ;
@@ -615,6 +702,8 @@ int virCHProcessStop(virCHDriverPtr driver G_GNUC_UNUSED,
615702 VIR_DEBUG ("Stopping VM name=%s pid=%d reason=%d" ,
616703 vm -> def -> name , (int )vm -> pid , (int )reason );
617704
705+ virCHProcessStopWatchThreads (vm );
706+
618707 if (priv -> monitor ) {
619708 virCHMonitorClose (priv -> monitor );
620709 priv -> monitor = NULL ;
0 commit comments