@@ -675,13 +675,31 @@ func (j runcJailer) Stop(force bool) error {
675675 return j .runcClient .Kill (j .ctx , j .vmID , int (signal ), & runc.KillOpts {All : true })
676676}
677677
678- // IsRunning checks if the runc container is still running .
678+ // IsRunning checks if the runc container's init process is still alive and not a zombie .
679679func (j * runcJailer ) IsRunning (ctx context.Context ) bool {
680680 state , err := j .runcClient .State (ctx , j .vmID )
681681 if err != nil {
682682 return false
683683 }
684- return state .Status == "running" || state .Status == "created" || state .Status == "paused"
684+ if state .Pid <= 0 {
685+ return false
686+ }
687+ // Check /proc/[pid]/stat to see if process is running (not zombie or dead)
688+ statPath := fmt .Sprintf ("/proc/%d/stat" , state .Pid )
689+ data , err := os .ReadFile (statPath )
690+ if err != nil {
691+ return false // Process doesn't exist
692+ }
693+ // Format: pid (comm) state ...
694+ // Find the state character after the last ')'
695+ statStr := string (data )
696+ idx := strings .LastIndex (statStr , ")" )
697+ if idx == - 1 || idx + 2 >= len (statStr ) {
698+ return false
699+ }
700+ procState := statStr [idx + 2 ] // Skip ") " to get state char
701+ // Z = zombie, X = dead, x = dead
702+ return procState != 'Z' && procState != 'X' && procState != 'x'
685703}
686704
687705// setupCacheTopology will copy indexed contents from the cacheTopologyPath to
0 commit comments