Skip to content

Commit

Permalink
Closing extension Code instance doesn't make Run stop #4239
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero committed Mar 30, 2016
1 parent 0ce7469 commit 2046573
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 24 deletions.
3 changes: 1 addition & 2 deletions src/vs/workbench/electron-browser/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,7 @@ export class WorkbenchShell {
let lifecycleService = new LifecycleService(this.messageService, this.windowService);
lifecycleService.onShutdown(() => fileService.dispose());

this.threadService = new MainThreadService(this.contextService, this.messageService, this.windowService);
lifecycleService.onShutdown(() => this.threadService.dispose());
this.threadService = new MainThreadService(this.contextService, this.messageService, this.windowService, lifecycleService);

let requestService = new RequestService(
this.contextService,
Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/parts/debug/electron-browser/debugService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { ITextFileService } from 'vs/workbench/parts/files/common/files';
import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IWindowService, IBroadcast } from 'vs/workbench/services/window/electron-browser/windowService';
import { ILogEntry, PLUGIN_LOG_BROADCAST_CHANNEL, PLUGIN_ATTACH_BROADCAST_CHANNEL } from 'vs/workbench/services/thread/electron-browser/threadService';
import { ILogEntry, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL } from 'vs/workbench/services/thread/electron-browser/threadService';
import { ipcRenderer as ipc } from 'electron';

const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
Expand Down Expand Up @@ -142,7 +142,7 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
private onBroadcast(broadcast: IBroadcast): void {

// attach: PH is ready to be attached to
if (broadcast.channel === PLUGIN_ATTACH_BROADCAST_CHANNEL) {
if (broadcast.channel === EXTENSION_ATTACH_BROADCAST_CHANNEL) {
this.rawAttach(broadcast.payload.port);

return;
Expand All @@ -155,7 +155,7 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
}

// a plugin logged output, show it inside the REPL
if (broadcast.channel === PLUGIN_LOG_BROADCAST_CHANNEL) {
if (broadcast.channel === EXTENSION_LOG_BROADCAST_CHANNEL) {
let extensionOutput: ILogEntry = broadcast.payload;
let sev = extensionOutput.severity === 'warn' ? severity.Warning : extensionOutput.severity === 'error' ? severity.Error : severity.Info;

Expand Down
57 changes: 38 additions & 19 deletions src/vs/workbench/services/thread/electron-browser/threadService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ import {IMainProcessExtHostIPC, create} from 'vs/platform/extensions/common/ipcR
import {SyncDescriptor0} from 'vs/platform/instantiation/common/descriptors';
import {IMessageService, Severity} from 'vs/platform/message/common/message';
import {MainThreadService as CommonMainThreadService} from 'vs/platform/thread/common/mainThreadService';
import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle';
import {IConfiguration, IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {IWindowService} from 'vs/workbench/services/window/electron-browser/windowService';
import {ChildProcess, fork} from 'child_process';
import {ipcRenderer as ipc} from 'electron';

export const PLUGIN_LOG_BROADCAST_CHANNEL = 'vscode:pluginLog';
export const PLUGIN_ATTACH_BROADCAST_CHANNEL = 'vscode:pluginAttach';
export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog';
export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach';
export const EXTENSION_TERMINATE_BROADCAST_CHANNEL = 'vscode:extensionTerminate';

// Enable to see detailed message communication between window and extension host
const logExtensionHostCommunication = false;
Expand All @@ -39,10 +41,10 @@ export class MainThreadService extends CommonMainThreadService {
private extensionHostProcessManager: ExtensionHostProcessManager;
private remoteCom: IMainProcessExtHostIPC;

constructor(contextService: IWorkspaceContextService, messageService: IMessageService, windowService: IWindowService) {
constructor(contextService: IWorkspaceContextService, messageService: IMessageService, windowService: IWindowService, lifecycleService: ILifecycleService) {
super(contextService, 'vs/editor/common/worker/editorWorkerServer', 1);

this.extensionHostProcessManager = new ExtensionHostProcessManager(contextService, messageService, windowService);
this.extensionHostProcessManager = new ExtensionHostProcessManager(contextService, messageService, windowService, lifecycleService);

let logCommunication = logExtensionHostCommunication || contextService.getConfiguration().env.logExtensionHostCommunication;

Expand All @@ -65,6 +67,8 @@ export class MainThreadService extends CommonMainThreadService {
});

this.remoteCom.setManyHandler(this);

lifecycleService.onShutdown(() => this.dispose());
}

public dispose(): void {
Expand All @@ -77,10 +81,6 @@ export class MainThreadService extends CommonMainThreadService {
}

class ExtensionHostProcessManager {
private messageService: IMessageService;
private contextService: IWorkspaceContextService;
private windowService: IWindowService;

private initializeExtensionHostProcess: TPromise<ChildProcess>;
private extensionHostProcessHandle: ChildProcess;
private initializeTimer: number;
Expand All @@ -90,22 +90,28 @@ class ExtensionHostProcessManager {
private terminating: boolean;

private isExtensionDevelopmentHost: boolean;
private isExtensionDevelopmentTest: boolean;

constructor(contextService: IWorkspaceContextService, messageService: IMessageService, windowService: IWindowService) {
this.messageService = messageService;
this.contextService = contextService;
this.windowService = windowService;
constructor(
private contextService: IWorkspaceContextService,
private messageService: IMessageService,
private windowService: IWindowService,
private lifecycleService: ILifecycleService
) {

// handle extension host lifecycle a bit special when we know we are developing an extension that runs inside
this.isExtensionDevelopmentHost = !!this.contextService.getConfiguration().env.extensionDevelopmentPath;
const config = this.contextService.getConfiguration();
this.isExtensionDevelopmentHost = !!config.env.extensionDevelopmentPath;
this.isExtensionDevelopmentTest = this.isExtensionDevelopmentHost && !!config.env.extensionTestsPath;

this.unsentMessages = [];

lifecycleService.addBeforeShutdownParticipant(this);
}

public startExtensionHostProcess(onExtensionHostMessage: (msg: any) => void): void {
let config = this.contextService.getConfiguration();
let isDev = !config.env.isBuilt || !!config.env.extensionDevelopmentPath;
let isTestingFromCli = !!config.env.extensionTestsPath && !config.env.debugBrkExtensionHost;

let opts: any = {
env: objects.mixin(objects.clone(process.env), { AMD_ENTRYPOINT: 'vs/workbench/node/extensionHostProcess', PIPE_LOGGING: 'true', VERBOSE_LOGGING: true })
Expand Down Expand Up @@ -135,7 +141,7 @@ class ExtensionHostProcessManager {
// Notify debugger that we are ready to attach to the process if we run a development extension
if (config.env.extensionDevelopmentPath && port) {
this.windowService.broadcast({
channel: PLUGIN_ATTACH_BROADCAST_CHANNEL,
channel: EXTENSION_ATTACH_BROADCAST_CHANNEL,
payload: {
port: port
}
Expand Down Expand Up @@ -194,19 +200,19 @@ class ExtensionHostProcessManager {
}

// Send to local console unless we run tests from cli
if (!isTestingFromCli) {
if (!this.isExtensionDevelopmentTest) {
console[logEntry.severity].apply(console, consoleArgs);
}

// Log on main side if running tests from cli
if (isTestingFromCli) {
if (this.isExtensionDevelopmentTest) {
ipc.send('vscode:log', logEntry);
}

// Broadcast to other windows if we are in development mode
else if (isDev) {
this.windowService.broadcast({
channel: PLUGIN_LOG_BROADCAST_CHANNEL,
channel: EXTENSION_LOG_BROADCAST_CHANNEL,
payload: logEntry
}, config.env.extensionDevelopmentPath /* target */);
}
Expand Down Expand Up @@ -248,7 +254,7 @@ class ExtensionHostProcessManager {
}

// Expected development extension termination: When the extension host goes down we also shutdown the window
else if (!isTestingFromCli) {
else if (!this.isExtensionDevelopmentTest) {
this.windowService.getWindow().close();
}

Expand Down Expand Up @@ -310,4 +316,17 @@ class ExtensionHostProcessManager {
});
}
}

public beforeShutdown(): boolean | TPromise<boolean> {
if (this.isExtensionDevelopmentHost && !this.isExtensionDevelopmentTest) {
this.windowService.broadcast({
channel: EXTENSION_TERMINATE_BROADCAST_CHANNEL,
payload: true
}, this.contextService.getConfiguration().env.extensionDevelopmentPath /* target */);

return TPromise.timeout(100 /* wait a bit for IPC to get delivered */).then(() => false);
}

return false;
}
}

0 comments on commit 2046573

Please sign in to comment.