Skip to content

Commit c3c857d

Browse files
Lock SessionManager.start() so only one session is started (#4161)
Also correctly wait for disposal on extension deactivation, and more carefully dispose and set to undefined in `SessionManager.dispose()`.
1 parent 1c14527 commit c3c857d

File tree

2 files changed

+48
-24
lines changed

2 files changed

+48
-24
lines changed

src/main.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IPower
181181
};
182182
}
183183

184-
export function deactivate(): void {
184+
export async function deactivate(): Promise<void> {
185185
// Clean up all extension features
186186
for (const languageClientConsumer of languageClientConsumers) {
187187
languageClientConsumer.dispose();
@@ -192,11 +192,11 @@ export function deactivate(): void {
192192
};
193193

194194
// Dispose of the current session
195-
sessionManager.dispose();
195+
await sessionManager.dispose();
196196

197197
// Dispose of the logger
198198
logger.dispose();
199199

200200
// Dispose of telemetry reporter
201-
telemetryReporter.dispose();
201+
await telemetryReporter.dispose();
202202
}

src/session.ts

+45-21
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export class SessionManager implements Middleware {
103103
private sessionDetails: IEditorServicesSessionDetails;
104104
private sessionsFolder: vscode.Uri;
105105
private bundledModulesPath: string;
106+
private starting: boolean = false;
106107
private started: boolean = false;
107108

108109
// Initialized by the start() method, since this requires settings
@@ -160,6 +161,19 @@ export class SessionManager implements Middleware {
160161
}
161162

162163
public async start(exeNameOverride?: string) {
164+
// A simple lock because this function isn't re-entrant.
165+
if (this.started || this.starting) {
166+
return await this.waitUntilStarted();
167+
}
168+
try {
169+
this.starting = true;
170+
await this._start(exeNameOverride);
171+
} finally {
172+
this.starting = false;
173+
}
174+
}
175+
176+
private async _start(exeNameOverride?: string) {
163177
await Settings.validateCwdSetting();
164178
this.sessionSettings = Settings.load();
165179

@@ -275,31 +289,41 @@ Type 'help' to get help.
275289
public async stop() {
276290
this.log.write("Shutting down language client...");
277291

278-
if (this.sessionStatus === SessionStatus.Failed) {
279-
// Before moving further, clear out the client and process if
280-
// the process is already dead (i.e. it crashed).
281-
this.languageClient = undefined;
282-
this.languageServerProcess = undefined;
283-
}
292+
try {
293+
if (this.sessionStatus === SessionStatus.Failed) {
294+
// Before moving further, clear out the client and process if
295+
// the process is already dead (i.e. it crashed).
296+
this.languageClient.dispose();
297+
this.languageClient = undefined;
298+
this.languageServerProcess.dispose();
299+
this.languageServerProcess = undefined;
300+
}
284301

285-
this.sessionStatus = SessionStatus.Stopping;
302+
this.sessionStatus = SessionStatus.Stopping;
286303

287-
// Stop the language client.
288-
if (this.languageClient !== undefined) {
289-
await this.languageClient.stop();
290-
this.languageClient = undefined;
291-
}
304+
// Stop the language client.
305+
if (this.languageClient !== undefined) {
306+
await this.languageClient.stop();
307+
this.languageClient.dispose();
308+
this.languageClient = undefined;
309+
}
292310

293-
// Kill the PowerShell process(es) we spawned.
294-
if (this.debugSessionProcess) {
295-
this.debugSessionProcess.dispose();
296-
this.debugEventHandler.dispose();
297-
}
298-
if (this.languageServerProcess) {
299-
this.languageServerProcess.dispose();
300-
}
311+
// Kill the PowerShell process(es) we spawned.
312+
if (this.debugSessionProcess) {
313+
this.debugSessionProcess.dispose();
314+
this.debugSessionProcess = undefined;
315+
this.debugEventHandler.dispose();
316+
this.debugEventHandler = undefined;
317+
}
301318

302-
this.sessionStatus = SessionStatus.NotStarted;
319+
if (this.languageServerProcess) {
320+
this.languageServerProcess.dispose();
321+
this.languageServerProcess = undefined;
322+
}
323+
} finally {
324+
this.sessionStatus = SessionStatus.NotStarted;
325+
this.started = false;
326+
}
303327
}
304328

305329
public async restartSession(exeNameOverride?: string) {

0 commit comments

Comments
 (0)