Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/lifecycle/common/lifecycleService.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Emitter } from '../../../../base/common/event.js';
7
import { Barrier } from '../../../../base/common/async.js';
8
import { Disposable } from '../../../../base/common/lifecycle.js';
9
import { ILifecycleService, WillShutdownEvent, StartupKind, LifecyclePhase, LifecyclePhaseToString, ShutdownReason, BeforeShutdownErrorEvent, InternalBeforeShutdownEvent } from './lifecycle.js';
10
import { ILogService } from '../../../../platform/log/common/log.js';
11
import { mark } from '../../../../base/common/performance.js';
12
import { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from '../../../../platform/storage/common/storage.js';
13
14
export abstract class AbstractLifecycleService extends Disposable implements ILifecycleService {
15
16
private static readonly LAST_SHUTDOWN_REASON_KEY = 'lifecyle.lastShutdownReason';
17
18
declare readonly _serviceBrand: undefined;
19
20
protected readonly _onBeforeShutdown = this._register(new Emitter<InternalBeforeShutdownEvent>());
21
readonly onBeforeShutdown = this._onBeforeShutdown.event;
22
23
protected readonly _onWillShutdown = this._register(new Emitter<WillShutdownEvent>());
24
readonly onWillShutdown = this._onWillShutdown.event;
25
26
protected readonly _onDidShutdown = this._register(new Emitter<void>());
27
readonly onDidShutdown = this._onDidShutdown.event;
28
29
protected readonly _onBeforeShutdownError = this._register(new Emitter<BeforeShutdownErrorEvent>());
30
readonly onBeforeShutdownError = this._onBeforeShutdownError.event;
31
32
protected readonly _onShutdownVeto = this._register(new Emitter<void>());
33
readonly onShutdownVeto = this._onShutdownVeto.event;
34
35
private _startupKind: StartupKind;
36
get startupKind(): StartupKind { return this._startupKind; }
37
38
private _phase = LifecyclePhase.Starting;
39
get phase(): LifecyclePhase { return this._phase; }
40
41
protected _willShutdown = false;
42
get willShutdown(): boolean { return this._willShutdown; }
43
44
private readonly phaseWhen = new Map<LifecyclePhase, Barrier>();
45
46
protected shutdownReason: ShutdownReason | undefined;
47
48
constructor(
49
@ILogService protected readonly logService: ILogService,
50
@IStorageService protected readonly storageService: IStorageService
51
) {
52
super();
53
54
// Resolve startup kind
55
this._startupKind = this.resolveStartupKind();
56
57
// Save shutdown reason to retrieve on next startup
58
this._register(this.storageService.onWillSaveState(e => {
59
if (e.reason === WillSaveStateReason.SHUTDOWN) {
60
this.storageService.store(AbstractLifecycleService.LAST_SHUTDOWN_REASON_KEY, this.shutdownReason, StorageScope.WORKSPACE, StorageTarget.MACHINE);
61
}
62
}));
63
}
64
65
private resolveStartupKind(): StartupKind {
66
const startupKind = this.doResolveStartupKind() ?? StartupKind.NewWindow;
67
this.logService.trace(`[lifecycle] starting up (startup kind: ${startupKind})`);
68
69
return startupKind;
70
}
71
72
protected doResolveStartupKind(): StartupKind | undefined {
73
74
// Retrieve and reset last shutdown reason
75
const lastShutdownReason = this.storageService.getNumber(AbstractLifecycleService.LAST_SHUTDOWN_REASON_KEY, StorageScope.WORKSPACE);
76
this.storageService.remove(AbstractLifecycleService.LAST_SHUTDOWN_REASON_KEY, StorageScope.WORKSPACE);
77
78
// Convert into startup kind
79
let startupKind: StartupKind | undefined = undefined;
80
switch (lastShutdownReason) {
81
case ShutdownReason.RELOAD:
82
startupKind = StartupKind.ReloadedWindow;
83
break;
84
case ShutdownReason.LOAD:
85
startupKind = StartupKind.ReopenedWindow;
86
break;
87
}
88
89
return startupKind;
90
}
91
92
set phase(value: LifecyclePhase) {
93
if (value < this.phase) {
94
throw new Error('Lifecycle cannot go backwards');
95
}
96
97
if (this._phase === value) {
98
return;
99
}
100
101
this.logService.trace(`lifecycle: phase changed (value: ${value})`);
102
103
this._phase = value;
104
mark(`code/LifecyclePhase/${LifecyclePhaseToString(value)}`);
105
106
const barrier = this.phaseWhen.get(this._phase);
107
if (barrier) {
108
barrier.open();
109
this.phaseWhen.delete(this._phase);
110
}
111
}
112
113
async when(phase: LifecyclePhase): Promise<void> {
114
if (phase <= this._phase) {
115
return;
116
}
117
118
let barrier = this.phaseWhen.get(phase);
119
if (!barrier) {
120
barrier = new Barrier();
121
this.phaseWhen.set(phase, barrier);
122
}
123
124
await barrier.wait();
125
}
126
127
/**
128
* Subclasses to implement the explicit shutdown method.
129
*/
130
abstract shutdown(): Promise<void>;
131
}
132
133