From c2dfa6ca6b3e2453d5c27648dd4888a9c677c618 Mon Sep 17 00:00:00 2001 From: John Knox Date: Fri, 21 Feb 2020 06:52:04 -0800 Subject: [PATCH] Kill orphaned instruments processes (#819) Summary: Fix https://github.com/facebook/flipper/issues/808 Kills any orphaned Instruments processes belonging to the user. In some cases, we've seen interactions between Instruments and the iOS simulator that cause hung instruments and DTServiceHub processes. If enough instances pile up, the host machine eventually becomes unresponsive. Until the underlying issue is resolved, manually kill any orphaned instances (where the parent process has died and PPID is 1) before launching another instruments run. Taking the same approach as done by flutter here. Reviewed By: passy Differential Revision: D20030005 Pulled By: jknoxville fbshipit-source-id: aa80be78c80f7797e88bf29b15f90d4aad0c66e4 --- src/fb-stubs/iOSContainerUtility.tsx | 2 ++ src/utils/processCleanup.tsx | 41 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/utils/processCleanup.tsx diff --git a/src/fb-stubs/iOSContainerUtility.tsx b/src/fb-stubs/iOSContainerUtility.tsx index 3cea4468b..dbf62b7c4 100644 --- a/src/fb-stubs/iOSContainerUtility.tsx +++ b/src/fb-stubs/iOSContainerUtility.tsx @@ -10,6 +10,7 @@ import {DeviceType} from '../devices/BaseDevice'; import {exec} from 'promisify-child-process'; import {notNull} from '../utils/typeUtils'; +import {killOrphanedInstrumentsProcesses} from '../utils/processCleanup'; const errorMessage = 'Physical iOS devices not yet supported'; @@ -24,6 +25,7 @@ function isAvailable(): boolean { } async function targets(): Promise> { + await killOrphanedInstrumentsProcesses(); const {stdout} = await exec('instruments -s devices'); if (!stdout) { return []; diff --git a/src/utils/processCleanup.tsx b/src/utils/processCleanup.tsx new file mode 100644 index 000000000..889253ca0 --- /dev/null +++ b/src/utils/processCleanup.tsx @@ -0,0 +1,41 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import {exec} from 'promisify-child-process'; +import {notNull} from '../utils/typeUtils'; +import {kill} from 'process'; + +// Kills any orphaned Instruments processes belonging to the user. +// +// In some cases, we've seen interactions between Instruments and the iOS +// simulator that cause hung instruments and DTServiceHub processes. If +// enough instances pile up, the host machine eventually becomes +// unresponsive. Until the underlying issue is resolved, manually kill any +// orphaned instances (where the parent process has died and PPID is 1) +// before launching another instruments run. +export async function killOrphanedInstrumentsProcesses() { + const result = await exec('ps -e -o user,ppid,pid,comm'); + result.stdout + ?.toString() + .split('\n') + .filter(notNull) + .map(a => /^(\S+)\s+1\s+(\d+)\s+(.+)$/.exec(a)) + .filter(notNull) + .filter(m => m[1] === process.env.USER) + .filter( + m => + m[3] && + ['/instruments', '/DTServiceHub'].some(name => m[3].endsWith(name)), + ) + .forEach(m => { + const pid = m[2]; + console.debug(`Killing orphaned Instruments process: ${pid}`); + kill(parseInt(pid, 10), 'SIGKILL'); + }); +}