Skip to content

Commit e63fa5e

Browse files
committed
extension/service: handle concurrent .start() calls and cancellation
1 parent ff1957e commit e63fa5e

File tree

1 file changed

+35
-30
lines changed

1 file changed

+35
-30
lines changed

ddterm/shell/service.js

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import GObject from 'gi://GObject';
66
import Gio from 'gi://Gio';
77

88
import { Subprocess, WaylandSubprocess } from './subprocess.js';
9+
import { wait_property } from '../util/promise.js';
910

1011
export const Service = GObject.registerClass({
1112
Properties: {
@@ -217,15 +218,22 @@ export const Service = GObject.registerClass({
217218
}
218219

219220
async start(cancellable = null) {
220-
if (this.is_registered)
221-
return;
222-
223-
this.#starting = true;
224-
this.notify('starting');
221+
const inner_cancellable = Gio.Cancellable.new();
222+
const cancellable_chain = cancellable?.connect(() => inner_cancellable.cancel());
225223

226224
try {
227-
const inner_cancellable = Gio.Cancellable.new();
228-
const cancellable_chain = cancellable?.connect(() => inner_cancellable.cancel());
225+
inner_cancellable.set_error_if_cancelled();
226+
227+
while (this.starting) {
228+
// eslint-disable-next-line no-await-in-loop
229+
await wait_property(this, 'starting', starting => !starting, inner_cancellable);
230+
}
231+
232+
if (this.is_registered)
233+
return;
234+
235+
this.#starting = true;
236+
this.notify('starting');
229237

230238
try {
231239
if (!this.is_running) {
@@ -236,34 +244,31 @@ export const Service = GObject.registerClass({
236244
this.#subprocess_wait = this.#wait_subprocess();
237245
}
238246

239-
const registered = new Promise(resolve => {
240-
const handler = this.connect('notify::is-registered', () => {
241-
if (this.is_registered)
242-
resolve();
243-
});
247+
await Promise.race([
248+
wait_property(this, 'is-registered', Boolean, inner_cancellable),
249+
this.#subprocess_wait,
250+
]);
244251

245-
inner_cancellable.connect(() => {
246-
this.disconnect(handler);
247-
});
248-
});
252+
inner_cancellable.set_error_if_cancelled();
249253

250-
await Promise.race([registered, this.#subprocess_wait]);
251-
} finally {
252-
cancellable?.disconnect(cancellable_chain);
253-
inner_cancellable.cancel();
254-
}
254+
if (!this.is_running) {
255+
throw new Error(
256+
`${this.bus_name}: subprocess terminated without registering on D-Bus`
257+
);
258+
}
255259

256-
if (!this.is_registered) {
257-
throw new Error(
258-
`${this.bus_name}: subprocess terminated without registering on D-Bus`
259-
);
260+
if (!this.is_registered)
261+
throw new Error(`${this.bus_name}: subprocess failed to register on D-Bus`);
262+
} catch (ex) {
263+
this.emit('error', ex);
264+
throw ex;
265+
} finally {
266+
this.#starting = false;
267+
this.notify('starting');
260268
}
261-
} catch (ex) {
262-
this.emit('error', ex);
263-
throw ex;
264269
} finally {
265-
this.#starting = false;
266-
this.notify('starting');
270+
cancellable?.disconnect(cancellable_chain);
271+
inner_cancellable.cancel();
267272
}
268273
}
269274
});

0 commit comments

Comments
 (0)