Skip to content

Commit 744e89f

Browse files
committed
Fixes microsoft#57820: Switch to using native Promises
1 parent 6272a7f commit 744e89f

1 file changed

Lines changed: 62 additions & 4 deletions

File tree

src/vs/workbench/services/extensions/electron-browser/extensionHost.ts

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { isMessageOfType, MessageType, createMessageOfType } from 'vs/workbench/
4141
import { ILabelService } from 'vs/platform/label/common/label';
4242
import { URI } from 'vs/base/common/uri';
4343
import { Schemas } from 'vs/base/common/network';
44+
import { onUnexpectedError } from 'vs/base/common/errors';
4445

4546
export interface IExtensionHostStarter {
4647
readonly onCrashed: Event<[number, string]>;
@@ -316,9 +317,9 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
316317
});
317318
}
318319

319-
private _tryExtHostHandshake(): TPromise<IMessagePassingProtocol> {
320+
private _tryExtHostHandshake(): Promise<IMessagePassingProtocol> {
320321

321-
return new TPromise<IMessagePassingProtocol>((resolve, reject) => {
322+
return new Promise<IMessagePassingProtocol>((resolve, reject) => {
322323

323324
// Wait for the extension host to connect to our named pipe
324325
// and wrap the socket in the message passing protocol
@@ -340,7 +341,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
340341

341342
// 1) wait for the incoming `ready` event and send the initialization data.
342343
// 2) wait for the incoming `initialized` event.
343-
return new TPromise<IMessagePassingProtocol>((resolve, reject) => {
344+
return new Promise<IMessagePassingProtocol>((resolve, reject) => {
344345

345346
let handle = setTimeout(() => {
346347
reject('timeout');
@@ -363,7 +364,10 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
363364
disposable.dispose();
364365

365366
// release this promise
366-
resolve(protocol);
367+
// using a buffered message protocol here because between now
368+
// and the first time a `then` executes some messages might be lost
369+
// unless we immediately register a listener for `onMessage`.
370+
resolve(new BufferedMessagePassingProtocol(protocol));
367371
return;
368372
}
369373

@@ -530,3 +534,57 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
530534
}
531535
}
532536
}
537+
538+
/**
539+
* Will ensure no messages are lost from creation time until the first user of onMessage comes in.
540+
*/
541+
class BufferedMessagePassingProtocol implements IMessagePassingProtocol {
542+
543+
private readonly _actual: IMessagePassingProtocol;
544+
private _bufferedMessagesListener: IDisposable;
545+
private _bufferedMessages: Buffer[];
546+
547+
constructor(actual: IMessagePassingProtocol) {
548+
this._actual = actual;
549+
this._bufferedMessages = [];
550+
this._bufferedMessagesListener = this._actual.onMessage((buff) => this._bufferedMessages.push(buff));
551+
}
552+
553+
public send(buffer: Buffer): void {
554+
this._actual.send(buffer);
555+
}
556+
557+
public onMessage(listener: (e: Buffer) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable {
558+
if (!this._bufferedMessages) {
559+
// second caller gets nothing
560+
return this._actual.onMessage(listener, thisArgs, disposables);
561+
}
562+
563+
// prepare result
564+
const result = this._actual.onMessage(listener, thisArgs, disposables);
565+
566+
// stop listening to buffered messages
567+
this._bufferedMessagesListener.dispose();
568+
569+
// capture buffered messages
570+
const bufferedMessages = this._bufferedMessages;
571+
this._bufferedMessages = null;
572+
573+
// it is important to deliver these messages after this call, but before
574+
// other messages have a chance to be received (to guarantee in order delivery)
575+
// that's why we're using here nextTick and not other types of timeouts
576+
process.nextTick(() => {
577+
// deliver buffered messages
578+
while (bufferedMessages.length > 0) {
579+
const msg = bufferedMessages.shift();
580+
try {
581+
listener.call(thisArgs, msg);
582+
} catch (e) {
583+
onUnexpectedError(e);
584+
}
585+
}
586+
});
587+
588+
return result;
589+
}
590+
}

0 commit comments

Comments
 (0)