Skip to content

Commit b6d859d

Browse files
authored
Merge pull request microsoft#90136 from microsoft/ben/shared-process-ipc-ready
Separate shared process ipc (client) ready and server ready
2 parents 8d17dc1 + f26de90 commit b6d859d

File tree

3 files changed

+52
-16
lines changed

3 files changed

+52
-16
lines changed

src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentia
6161
import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-browser/userDataAutoSyncService';
6262
import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync';
6363
import { UserDataAuthTokenService } from 'vs/platform/userDataSync/common/userDataAuthTokenService';
64+
import { NativeStorageService } from 'vs/platform/storage/node/storageService';
65+
import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc';
66+
import { IStorageService } from 'vs/platform/storage/common/storage';
6467

6568
export interface ISharedProcessConfiguration {
6669
readonly machineId: string;
@@ -100,7 +103,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
100103

101104
const onExit = () => disposables.dispose();
102105
process.once('exit', onExit);
103-
ipcRenderer.once('handshake:goodbye', onExit);
106+
ipcRenderer.once('electron-main->shared-process: exit', onExit);
104107

105108
disposables.add(server);
106109

@@ -119,6 +122,11 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
119122
disposables.add(configurationService);
120123
await configurationService.initialize();
121124

125+
const storageService = new NativeStorageService(new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage')), logService, environmentService);
126+
await storageService.initialize();
127+
services.set(IStorageService, storageService);
128+
disposables.add(toDisposable(() => storageService.flush()));
129+
122130
services.set(IEnvironmentService, environmentService);
123131
services.set(IProductService, { _serviceBrand: undefined, ...product });
124132
services.set(ILogService, logService);
@@ -271,13 +279,20 @@ function setupIPC(hook: string): Promise<Server> {
271279
}
272280

273281
async function handshake(configuration: ISharedProcessConfiguration): Promise<void> {
282+
283+
// receive payload from electron-main to start things
274284
const data = await new Promise<ISharedProcessInitData>(c => {
275-
ipcRenderer.once('handshake:hey there', (_: any, r: ISharedProcessInitData) => c(r));
276-
ipcRenderer.send('handshake:hello');
285+
ipcRenderer.once('electron-main->shared-process: payload', (_: any, r: ISharedProcessInitData) => c(r));
286+
287+
// tell electron-main we are ready to receive payload
288+
ipcRenderer.send('shared-process->electron-main: ready-for-payload');
277289
});
278290

291+
// await IPC connection and signal this back to electron-main
279292
const server = await setupIPC(data.sharedIPCHandle);
293+
ipcRenderer.send('shared-process->electron-main: ipc-ready');
280294

295+
// await initialization and signal this back to electron-main
281296
await main(server, data, configuration);
282-
ipcRenderer.send('handshake:im ready');
297+
ipcRenderer.send('shared-process->electron-main: init-done');
283298
}

src/vs/code/electron-main/app.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,14 @@ export class CodeApplication extends Disposable {
364364

365365
// Spawn shared process after the first window has opened and 3s have passed
366366
const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv);
367-
const sharedProcessClient = sharedProcess.whenReady().then(() => connect(this.environmentService.sharedIPCHandle, 'main'));
367+
const sharedProcessClient = sharedProcess.whenIpcReady().then(() => {
368+
this.logService.trace('Shared process: IPC ready');
369+
return connect(this.environmentService.sharedIPCHandle, 'main');
370+
});
371+
const sharedProcessReady = sharedProcess.whenReady().then(() => {
372+
this.logService.trace('Shared process: init ready');
373+
return sharedProcessClient;
374+
});
368375
this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => {
369376
this._register(new RunOnceScheduler(async () => {
370377
const userEnv = await getShellEnvironment(this.logService, this.environmentService);
@@ -374,7 +381,7 @@ export class CodeApplication extends Disposable {
374381
});
375382

376383
// Services
377-
const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessClient);
384+
const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessReady);
378385

379386
// Create driver
380387
if (this.environmentService.driverHandle) {
@@ -424,7 +431,7 @@ export class CodeApplication extends Disposable {
424431
return { machineId, trueMachineId };
425432
}
426433

427-
private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessClient: Promise<Client<string>>): Promise<IInstantiationService> {
434+
private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessReady: Promise<Client<string>>): Promise<IInstantiationService> {
428435
const services = new ServiceCollection();
429436

430437
const fileService = this._register(new FileService(this.logService));
@@ -456,7 +463,7 @@ export class CodeApplication extends Disposable {
456463
services.set(ISharedProcessMainService, new SyncDescriptor(SharedProcessMainService, [sharedProcess]));
457464
services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService));
458465

459-
const diagnosticsChannel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('diagnostics')));
466+
const diagnosticsChannel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('diagnostics')));
460467
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, [diagnosticsChannel]));
461468

462469
services.set(IIssueService, new SyncDescriptor(IssueMainService, [machineId, this.userEnv]));
@@ -477,7 +484,7 @@ export class CodeApplication extends Disposable {
477484

478485
// Telemetry
479486
if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
480-
const channel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('telemetryAppender')));
487+
const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender')));
481488
const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService));
482489
const commonProperties = resolveCommonProperties(product.commit, product.version, machineId, product.msftInternalDomains, this.environmentService.installSourcePath);
483490
const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot];
@@ -571,6 +578,7 @@ export class CodeApplication extends Disposable {
571578
const storageMainService = accessor.get(IStorageMainService);
572579
const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService));
573580
electronIpcServer.registerChannel('storage', storageChannel);
581+
sharedProcessClient.then(client => client.registerChannel('storage', storageChannel));
574582

575583
const loggerChannel = new LoggerChannel(accessor.get(ILogService));
576584
electronIpcServer.registerChannel('logger', loggerChannel);

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

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,22 @@ export class SharedProcess implements ISharedProcess {
2121

2222
private window: BrowserWindow | null = null;
2323

24+
private readonly _whenReady: Promise<void>;
25+
2426
constructor(
2527
private readonly machineId: string,
2628
private userEnv: NodeJS.ProcessEnv,
2729
@IEnvironmentService private readonly environmentService: IEnvironmentService,
2830
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
2931
@ILogService private readonly logService: ILogService,
3032
@IThemeMainService private readonly themeMainService: IThemeMainService
31-
) { }
33+
) {
34+
// overall ready promise when shared process signals initialization is done
35+
this._whenReady = new Promise<void>(c => ipcMain.once('shared-process->electron-main: init-done', () => c(undefined)));
36+
}
3237

3338
@memoize
34-
private get _whenReady(): Promise<void> {
39+
private get _whenIpcReady(): Promise<void> {
3540
this.window = new BrowserWindow({
3641
show: false,
3742
backgroundColor: this.themeMainService.getBackgroundColor(),
@@ -98,16 +103,19 @@ export class SharedProcess implements ISharedProcess {
98103
});
99104

100105
return new Promise<void>(c => {
101-
const onHello = Event.once(Event.fromNodeEventEmitter(ipcMain, 'handshake:hello', ({ sender }: { sender: WebContents }) => sender));
102-
disposables.add(onHello(sender => {
103-
sender.send('handshake:hey there', {
106+
// send payload once shared process is ready to receive it
107+
disposables.add(Event.once(Event.fromNodeEventEmitter(ipcMain, 'shared-process->electron-main: ready-for-payload', ({ sender }: { sender: WebContents }) => sender))(sender => {
108+
sender.send('electron-main->shared-process: payload', {
104109
sharedIPCHandle: this.environmentService.sharedIPCHandle,
105110
args: this.environmentService.args,
106111
logLevel: this.logService.getLevel()
107112
});
108113

109-
disposables.add(toDisposable(() => sender.send('handshake:goodbye')));
110-
ipcMain.once('handshake:im ready', () => c(undefined));
114+
// signal exit to shared process when we get disposed
115+
disposables.add(toDisposable(() => sender.send('electron-main->shared-process: exit')));
116+
117+
// complete IPC-ready promise when shared process signals this to us
118+
ipcMain.once('shared-process->electron-main: ipc-ready', () => c(undefined));
111119
}));
112120
});
113121
}
@@ -122,6 +130,11 @@ export class SharedProcess implements ISharedProcess {
122130
await this._whenReady;
123131
}
124132

133+
async whenIpcReady(): Promise<void> {
134+
await this.barrier.wait();
135+
await this._whenIpcReady;
136+
}
137+
125138
toggle(): void {
126139
if (!this.window || this.window.isVisible()) {
127140
this.hide();

0 commit comments

Comments
 (0)