mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
Funnel ext host pid to the renderer and do more logging
This commit is contained in:
parent
98417b150a
commit
1ace1a817a
|
@ -29,7 +29,7 @@ export interface IExtensionHostStarter {
|
|||
onDynamicExit(id: string): Event<{ code: number; signal: string }>;
|
||||
|
||||
createExtensionHost(): Promise<{ id: string }>;
|
||||
start(id: string, opts: IExtensionHostProcessOptions): Promise<void>;
|
||||
start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number | undefined }>;
|
||||
enableInspectPort(id: string): Promise<boolean>;
|
||||
kill(id: string): Promise<void>;
|
||||
|
||||
|
|
|
@ -97,11 +97,12 @@ export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter
|
|||
return { id };
|
||||
}
|
||||
|
||||
async start(id: string, opts: IExtensionHostProcessOptions): Promise<void> {
|
||||
async start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number | undefined }> {
|
||||
if (this._shutdown) {
|
||||
throw canceled();
|
||||
}
|
||||
this._getExtHost(id).start({
|
||||
const extHost = this._getExtHost(id);
|
||||
extHost.start({
|
||||
...opts,
|
||||
type: 'extensionHost',
|
||||
entryPoint: 'vs/workbench/api/node/extensionHostProcess',
|
||||
|
@ -111,6 +112,8 @@ export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter
|
|||
forceAllocationsToV8Sandbox: true,
|
||||
correlationId: id
|
||||
});
|
||||
const pid = await Event.toPromise(extHost.onSpawn);
|
||||
return { pid };
|
||||
}
|
||||
|
||||
async enableInspectPort(id: string): Promise<boolean> {
|
||||
|
|
|
@ -156,6 +156,9 @@ export class UtilityProcess extends Disposable {
|
|||
private readonly _onMessage = this._register(new Emitter<unknown>());
|
||||
readonly onMessage = this._onMessage.event;
|
||||
|
||||
private readonly _onSpawn = this._register(new Emitter<number | undefined>());
|
||||
readonly onSpawn = this._onSpawn.event;
|
||||
|
||||
private readonly _onExit = this._register(new Emitter<IUtilityProcessExitEvent>());
|
||||
readonly onExit = this._onExit.event;
|
||||
|
||||
|
@ -303,6 +306,7 @@ export class UtilityProcess extends Disposable {
|
|||
}
|
||||
|
||||
this.log('successfully created', Severity.Info);
|
||||
this._onSpawn.fire(process.pid);
|
||||
}));
|
||||
|
||||
// Exit
|
||||
|
|
|
@ -40,6 +40,7 @@ export interface IWebWorkerExtensionHostDataProvider {
|
|||
|
||||
export class WebWorkerExtensionHost extends Disposable implements IExtensionHost {
|
||||
|
||||
public readonly pid = null;
|
||||
public readonly remoteAuthority = null;
|
||||
public extensions: ExtensionHostExtensions | null = null;
|
||||
|
||||
|
|
|
@ -753,6 +753,11 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
const processManager: IExtensionHostManager = this._doCreateExtensionHostManager(extensionHost, initialActivationEvents);
|
||||
processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal));
|
||||
processManager.onDidChangeResponsiveState((responsiveState) => {
|
||||
if (responsiveState === ResponsiveState.Responsive) {
|
||||
this._logService.info(`Extension host (${extensionHostKindToString(processManager.kind)}) pid (${processManager.pid}) is unresponsive.`);
|
||||
} else {
|
||||
this._logService.info(`Extension host (${extensionHostKindToString(processManager.kind)}) pid (${processManager.pid}) is responsive.`);
|
||||
}
|
||||
this._onDidChangeResponsiveChange.fire({
|
||||
extensionHostKind: processManager.kind,
|
||||
isResponsive: responsiveState === ResponsiveState.Responsive,
|
||||
|
@ -852,9 +857,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
}
|
||||
|
||||
if (activatedExtensions.length > 0) {
|
||||
this._logService.error(`Extension host (${extensionHostKindToString(extensionHost.kind)}) terminated unexpectedly. The following extensions were running: ${activatedExtensions.map(id => id.value).join(', ')}`);
|
||||
this._logService.error(`Extension host (${extensionHostKindToString(extensionHost.kind)}) pid (${extensionHost.pid}) terminated unexpectedly. The following extensions were running: ${activatedExtensions.map(id => id.value).join(', ')}`);
|
||||
} else {
|
||||
this._logService.error(`Extension host (${extensionHostKindToString(extensionHost.kind)}) terminated unexpectedly. No extensions were activated.`);
|
||||
this._logService.error(`Extension host (${extensionHostKindToString(extensionHost.kind)}) pid (${extensionHost.pid}) terminated unexpectedly. No extensions were activated.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ const LOG_EXTENSION_HOST_COMMUNICATION = false;
|
|||
const LOG_USE_COLORS = true;
|
||||
|
||||
export interface IExtensionHostManager {
|
||||
readonly pid: number | null;
|
||||
readonly kind: ExtensionHostKind;
|
||||
readonly startup: ExtensionHostStartup;
|
||||
readonly onDidExit: Event<[number, string | null]>;
|
||||
|
@ -103,6 +104,10 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
private _proxy: Promise<IExtensionHostProxy | null> | null;
|
||||
private _hasStarted = false;
|
||||
|
||||
public get pid(): number | null {
|
||||
return this._extensionHost.pid;
|
||||
}
|
||||
|
||||
public get kind(): ExtensionHostKind {
|
||||
return this._extensionHost.runningLocation.kind;
|
||||
}
|
||||
|
@ -498,6 +503,13 @@ class LazyCreateExtensionHostManager extends Disposable implements IExtensionHos
|
|||
private _actual: ExtensionHostManager | null;
|
||||
private _lazyStartExtensions: ExtensionHostExtensions | null;
|
||||
|
||||
public get pid(): number | null {
|
||||
if (this._actual) {
|
||||
return this._actual.pid;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public get kind(): ExtensionHostKind {
|
||||
return this._extensionHost.runningLocation.kind;
|
||||
}
|
||||
|
|
|
@ -112,6 +112,7 @@ export const enum ExtensionHostStartup {
|
|||
}
|
||||
|
||||
export interface IExtensionHost {
|
||||
readonly pid: number | null;
|
||||
readonly runningLocation: ExtensionRunningLocation;
|
||||
readonly remoteAuthority: string | null;
|
||||
readonly startup: ExtensionHostStartup;
|
||||
|
|
|
@ -45,6 +45,7 @@ export interface IRemoteExtensionHostDataProvider {
|
|||
|
||||
export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
||||
|
||||
public readonly pid = null;
|
||||
public readonly remoteAuthority: string;
|
||||
public readonly startup = ExtensionHostStartup.EagerAutoStart;
|
||||
public extensions: ExtensionHostExtensions | null = null;
|
||||
|
|
|
@ -7,7 +7,7 @@ import { timeout } from 'vs/base/common/async';
|
|||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { CancellationError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { removeDangerousEnvVariables } from 'vs/base/common/processes';
|
||||
|
@ -18,7 +18,6 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
|||
import { BufferedEmitter } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
import { acquirePort } from 'vs/base/parts/ipc/electron-sandbox/ipc.mp';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { IExtensionHostProcessOptions, IExtensionHostStarter } from 'vs/platform/extensions/common/extensionHostStarter';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
|
@ -75,7 +74,7 @@ export class ExtensionHostProcess {
|
|||
this._id = id;
|
||||
}
|
||||
|
||||
public start(opts: IExtensionHostProcessOptions): Promise<void> {
|
||||
public start(opts: IExtensionHostProcessOptions): Promise<{ pid: number | undefined }> {
|
||||
return this._extensionHostStarter.start(this._id, opts);
|
||||
}
|
||||
|
||||
|
@ -90,6 +89,7 @@ export class ExtensionHostProcess {
|
|||
|
||||
export class NativeLocalProcessExtensionHost implements IExtensionHost {
|
||||
|
||||
public pid: number | null = null;
|
||||
public readonly remoteAuthority = null;
|
||||
public extensions: ExtensionHostExtensions | null = null;
|
||||
|
||||
|
@ -98,7 +98,7 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost {
|
|||
|
||||
private readonly _onDidSetInspectPort = new Emitter<void>();
|
||||
|
||||
protected readonly _toDispose = new DisposableStore();
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
|
||||
private readonly _isExtensionDevHost: boolean;
|
||||
private readonly _isExtensionDevDebug: boolean;
|
||||
|
@ -124,15 +124,14 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost {
|
|||
@INativeWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService,
|
||||
@IUserDataProfilesService private readonly _userDataProfilesService: IUserDataProfilesService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@ILogService protected readonly _logService: ILogService,
|
||||
@ILoggerService protected readonly _loggerService: ILoggerService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@ILoggerService private readonly _loggerService: ILoggerService,
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@IExtensionHostDebugService private readonly _extensionHostDebugService: IExtensionHostDebugService,
|
||||
@IHostService private readonly _hostService: IHostService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@IShellEnvironmentService private readonly _shellEnvironmentService: IShellEnvironmentService,
|
||||
@IExtensionHostStarter protected readonly _extensionHostStarter: IExtensionHostStarter,
|
||||
@IConfigurationService protected readonly _configurationService: IConfigurationService,
|
||||
@IExtensionHostStarter private readonly _extensionHostStarter: IExtensionHostStarter,
|
||||
) {
|
||||
const devOpts = parseExtensionDevOptions(this._environmentService);
|
||||
this._isExtensionDevHost = devOpts.isExtensionDevHost;
|
||||
|
@ -182,16 +181,9 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost {
|
|||
return this._messageProtocol;
|
||||
}
|
||||
|
||||
protected async _start(): Promise<IMessagePassingProtocol> {
|
||||
const communication = this._toDispose.add(new ExtHostMessagePortCommunication(this._logService));
|
||||
return this._startWithCommunication(communication);
|
||||
}
|
||||
|
||||
protected async _startWithCommunication<T>(communication: IExtHostCommunication<T>): Promise<IMessagePassingProtocol> {
|
||||
|
||||
const [extensionHostCreationResult, communicationPreparedData, portNumber, processEnv] = await Promise.all([
|
||||
private async _start(): Promise<IMessagePassingProtocol> {
|
||||
const [extensionHostCreationResult, portNumber, processEnv] = await Promise.all([
|
||||
this._extensionHostStarter.createExtensionHost(),
|
||||
communication.prepare(),
|
||||
this._tryFindDebugPort(),
|
||||
this._shellEnvironmentService.getShellEnv(),
|
||||
]);
|
||||
|
@ -322,7 +314,7 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost {
|
|||
}
|
||||
|
||||
// Initialize extension host process with hand shakes
|
||||
const protocol = await communication.establishProtocol(communicationPreparedData, this._extensionHostProcess, opts);
|
||||
const protocol = await this._establishProtocol(this._extensionHostProcess, opts);
|
||||
await this._performHandshake(protocol);
|
||||
clearTimeout(startupTimeoutHandle);
|
||||
return protocol;
|
||||
|
@ -358,6 +350,54 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost {
|
|||
return port || 0;
|
||||
}
|
||||
|
||||
private _establishProtocol(extensionHostProcess: ExtensionHostProcess, opts: IExtensionHostProcessOptions): Promise<IMessagePassingProtocol> {
|
||||
|
||||
writeExtHostConnection(new MessagePortExtHostConnection(), opts.env);
|
||||
|
||||
// Get ready to acquire the message port from the shared process worker
|
||||
const portPromise = acquirePort(undefined /* we trigger the request via service call! */, opts.responseChannel, opts.responseNonce);
|
||||
|
||||
return new Promise<IMessagePassingProtocol>((resolve, reject) => {
|
||||
|
||||
const handle = setTimeout(() => {
|
||||
reject('The local extension host took longer than 60s to connect.');
|
||||
}, 60 * 1000);
|
||||
|
||||
portPromise.then((port) => {
|
||||
this._toDispose.add(toDisposable(() => {
|
||||
// Close the message port when the extension host is disposed
|
||||
port.close();
|
||||
}));
|
||||
clearTimeout(handle);
|
||||
|
||||
const onMessage = new BufferedEmitter<VSBuffer>();
|
||||
port.onmessage = ((e) => onMessage.fire(VSBuffer.wrap(e.data)));
|
||||
port.start();
|
||||
|
||||
resolve({
|
||||
onMessage: onMessage.event,
|
||||
send: message => port.postMessage(message.buffer),
|
||||
});
|
||||
});
|
||||
|
||||
// Now that the message port listener is installed, start the ext host process
|
||||
const sw = StopWatch.create(false);
|
||||
extensionHostProcess.start(opts).then(({ pid }) => {
|
||||
if (pid) {
|
||||
this.pid = pid;
|
||||
}
|
||||
this._logService.info(`Started local extension host with pid ${pid}.`);
|
||||
const duration = sw.elapsed();
|
||||
if (platform.isCI) {
|
||||
this._logService.info(`IExtensionHostStarter.start() took ${duration} ms.`);
|
||||
}
|
||||
}, (err) => {
|
||||
// Starting the ext host process resulted in an error
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _performHandshake(protocol: IMessagePassingProtocol): Promise<void> {
|
||||
// 1) wait for the incoming `ready` event and send the initialization data.
|
||||
// 2) wait for the incoming `initialized` event.
|
||||
|
@ -540,64 +580,3 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface IExtHostCommunication<T> {
|
||||
prepare(): Promise<T>;
|
||||
establishProtocol(prepared: T, extensionHostProcess: ExtensionHostProcess, opts: IExtensionHostProcessOptions): Promise<IMessagePassingProtocol>;
|
||||
}
|
||||
|
||||
export class ExtHostMessagePortCommunication extends Disposable implements IExtHostCommunication<void> {
|
||||
|
||||
constructor(
|
||||
@ILogService private readonly _logService: ILogService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async prepare(): Promise<void> {
|
||||
}
|
||||
|
||||
establishProtocol(prepared: void, extensionHostProcess: ExtensionHostProcess, opts: IExtensionHostProcessOptions): Promise<IMessagePassingProtocol> {
|
||||
|
||||
writeExtHostConnection(new MessagePortExtHostConnection(), opts.env);
|
||||
|
||||
// Get ready to acquire the message port from the shared process worker
|
||||
const portPromise = acquirePort(undefined /* we trigger the request via service call! */, opts.responseChannel, opts.responseNonce);
|
||||
|
||||
return new Promise<IMessagePassingProtocol>((resolve, reject) => {
|
||||
|
||||
const handle = setTimeout(() => {
|
||||
reject('The local extension host took longer than 60s to connect.');
|
||||
}, 60 * 1000);
|
||||
|
||||
portPromise.then((port) => {
|
||||
this._register(toDisposable(() => {
|
||||
// Close the message port when the extension host is disposed
|
||||
port.close();
|
||||
}));
|
||||
clearTimeout(handle);
|
||||
|
||||
const onMessage = new BufferedEmitter<VSBuffer>();
|
||||
port.onmessage = ((e) => onMessage.fire(VSBuffer.wrap(e.data)));
|
||||
port.start();
|
||||
|
||||
resolve({
|
||||
onMessage: onMessage.event,
|
||||
send: message => port.postMessage(message.buffer),
|
||||
});
|
||||
});
|
||||
|
||||
// Now that the message port listener is installed, start the ext host process
|
||||
const sw = StopWatch.create(false);
|
||||
extensionHostProcess.start(opts).then(() => {
|
||||
const duration = sw.elapsed();
|
||||
if (platform.isCI) {
|
||||
this._logService.info(`IExtensionHostStarter.start() took ${duration} ms.`);
|
||||
}
|
||||
}, (err) => {
|
||||
// Starting the ext host process resulted in an error
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue