Skip to content

Commit 599b29c

Browse files
committed
alert the user when the shared process crashes
fixes microsoft#2785
1 parent eb1524a commit 599b29c

4 files changed

Lines changed: 51 additions & 8 deletions

File tree

src/vs/base/node/service.net.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import net = require('net');
99
import { IDisposable } from 'vs/base/common/lifecycle';
10+
import Event, { Emitter } from 'vs/base/common/event';
1011
import { Server as IPCServer, Client as IPCClient, IServiceCtor, IServiceMap, IMessagePassingProtocol } from 'vs/base/common/service';
1112
import { TPromise } from 'vs/base/common/winjs.base';
1213

@@ -94,9 +95,12 @@ export class Server implements IDisposable {
9495
export class Client implements IDisposable {
9596

9697
private ipcClient: IPCClient;
98+
private _onClose = new Emitter<void>();
99+
get onClose() { return this._onClose.event; }
97100

98101
constructor(private socket: net.Socket) {
99102
this.ipcClient = new IPCClient(new Protocol(socket));
103+
socket.once('close', () => this._onClose.fire());
100104
}
101105

102106
getService<TService>(serviceName: string, serviceCtor: IServiceCtor<TService>): TService {

src/vs/workbench/electron-browser/shell.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'vs/css!vs/workbench/browser/media/vs-theme';
1414
import 'vs/css!vs/workbench/browser/media/vs-dark-theme';
1515
import 'vs/css!vs/workbench/browser/media/hc-black-theme';
1616

17+
import * as nls from 'vs/nls';
1718
import {TPromise} from 'vs/base/common/winjs.base';
1819
import {Dimension, Builder, $} from 'vs/base/browser/builder';
1920
import objects = require('vs/base/common/objects');
@@ -100,6 +101,7 @@ import { IServiceCtor, isServiceEvent } from 'vs/base/common/service';
100101
import { connect, Client } from 'vs/base/node/service.net';
101102
import { IExtensionsService } from 'vs/workbench/parts/extensions/common/extensions';
102103
import { ExtensionsService } from 'vs/workbench/parts/extensions/node/extensionsService';
104+
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
103105

104106
/**
105107
* This ugly code is needed because at the point when we need shared services
@@ -149,7 +151,7 @@ export function getDelayedService<TService>(clientPromise: TPromise<Client>, ser
149151
return servicePromise().then(service => service[key](...args));
150152
}
151153
});
152-
}, <TService>{});
154+
}, {} as TService);
153155
}
154156

155157
/**
@@ -200,20 +202,28 @@ export class WorkbenchShell {
200202
let workbenchContainer = $(parent).div();
201203

202204
// Instantiation service with services
203-
let service = this.initInstantiationService();
205+
let instantiationService = this.initInstantiationService();
204206

205207
//crash reporting
206208
if (!!this.configuration.env.crashReporter) {
207-
let crashReporter = service.createInstance(CrashReporter, this.configuration.env.version, this.configuration.env.commitHash);
209+
let crashReporter = instantiationService.createInstance(CrashReporter, this.configuration.env.version, this.configuration.env.commitHash);
208210
crashReporter.start(this.configuration.env.crashReporter);
209211
}
210212

211213
const sharedProcessClientPromise = connect(process.env['VSCODE_SHARED_IPC_HOOK']);
212-
sharedProcessClientPromise.done(null, errors.onUnexpectedError);
213-
service.addSingleton(IExtensionsService, getDelayedService<IExtensionsService>(sharedProcessClientPromise, 'ExtensionService', ExtensionsService));
214+
sharedProcessClientPromise.done(service => {
215+
service.onClose(() => {
216+
this.messageService.show(Severity.Error, {
217+
message: nls.localize('sharedProcessCrashed', "The shared process terminated unexpectedly. Please reload the window."),
218+
actions: [instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL)]
219+
});
220+
});
221+
}, errors.onUnexpectedError);
222+
223+
instantiationService.addSingleton(IExtensionsService, getDelayedService<IExtensionsService>(sharedProcessClientPromise, 'ExtensionService', ExtensionsService));
214224

215225
// Workbench
216-
this.workbench = new Workbench(workbenchContainer.getHTMLElement(), this.workspace, this.configuration, this.options, service);
226+
this.workbench = new Workbench(workbenchContainer.getHTMLElement(), this.workspace, this.configuration, this.options, instantiationService);
217227
this.workbench.startup({
218228
onServicesCreated: () => {
219229
this.initPluginSystem();

src/vs/workbench/electron-main/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ function main(ipcServer: Server, userEnv: env.IProcessEnvironment): void {
125125
ipcServer = null;
126126
}
127127

128-
sharedProcess.kill();
128+
sharedProcess.dispose();
129+
129130
if (windowsMutex) {
130131
windowsMutex.release();
131132
}

src/vs/workbench/electron-main/sharedProcess.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import * as cp from 'child_process';
77
import URI from 'vs/base/common/uri';
8+
import { IDisposable } from 'vs/base/common/lifecycle';
89
import { assign } from 'vs/base/common/objects';
910
import { IEnvironment } from 'vs/platform/workspace/common/workspace';
1011
import env = require('vs/workbench/electron-main/env');
@@ -35,7 +36,7 @@ function getEnvironment(): IEnvironment {
3536
// The amd loader has the global scope assigned to this.
3637
const globalRequire = this.require;
3738

38-
export function spawnSharedProcess(): cp.ChildProcess {
39+
function _spawnSharedProcess(): cp.ChildProcess {
3940
// Make sure the nls configuration travels to the plugin host.
4041
const opts = {
4142
env: assign(assign({}, process.env), {
@@ -58,4 +59,31 @@ export function spawnSharedProcess(): cp.ChildProcess {
5859
});
5960

6061
return result;
62+
}
63+
64+
let spawnCount = 0;
65+
66+
export function spawnSharedProcess(): IDisposable {
67+
let child: cp.ChildProcess;
68+
69+
const spawn = () => {
70+
if (++spawnCount > 10) {
71+
return;
72+
}
73+
74+
child = _spawnSharedProcess();
75+
child.on('exit', spawn);
76+
};
77+
78+
spawn();
79+
80+
return {
81+
dispose: () => {
82+
if (child) {
83+
child.removeListener('exit', spawn);
84+
child.kill();
85+
child = null;
86+
}
87+
}
88+
};
6189
}

0 commit comments

Comments
 (0)