◐ Shell
clean mode source ↗

lib: defer AbortSignal.any() following · nodejs/node@ada3ce8

@@ -85,17 +85,16 @@ function lazyMessageChannel() {

8585

}

86868787

const clearTimeoutRegistry = new SafeFinalizationRegistry(clearTimeout);

88-

const dependantSignalsCleanupRegistry = new SafeFinalizationRegistry((signalWeakRef) => {

89-

const signal = signalWeakRef.deref();

90-

if (signal === undefined) {

91-

return;

92-

}

93-

signal[kDependantSignals].forEach((ref) => {

94-

if (ref.deref() === undefined) {

95-

signal[kDependantSignals].delete(ref);

88+

const dependantSignalsCleanupRegistry = new SafeFinalizationRegistry(

89+

({ sourceSignalRef, dependantSignalRef, sourceSignalsCleanupToken }) => {

90+

sourceSignalsCleanupRegistry.unregister(sourceSignalsCleanupToken);

91+92+

const sourceSignal = sourceSignalRef.deref();

93+

if (sourceSignal === undefined) {

94+

return;

9695

}

96+

sourceSignal[kDependantSignals].delete(dependantSignalRef);

9797

});

98-

});

999810099

const gcPersistentSignals = new SafeSet();

101100

@@ -117,6 +116,8 @@ const kCloneData = Symbol('kCloneData');

117116

const kTimeout = Symbol('kTimeout');

118117

const kMakeTransferable = Symbol('kMakeTransferable');

119118

const kComposite = Symbol('kComposite');

119+

const kFollowing = Symbol('kFollowing');

120+

const kResultSignalWeakRef = Symbol('kResultSignalWeakRef');

120121

const kSourceSignals = Symbol('kSourceSignals');

121122

const kDependantSignals = Symbol('kDependantSignals');

122123

@@ -136,6 +137,60 @@ function validateThisAbortSignal(obj) {

136137

throw new ERR_INVALID_THIS('AbortSignal');

137138

}

138139140+

function refreshCompositeSignal(signal) {

141+

if (!signal[kComposite] || signal[kAborted] || !signal[kSourceSignals]?.size) {

142+

return;

143+

}

144+145+

for (const sourceSignalWeakRef of signal[kSourceSignals]) {

146+

const sourceSignal = sourceSignalWeakRef.deref();

147+

if (sourceSignal === undefined) {

148+

signal[kSourceSignals].delete(sourceSignalWeakRef);

149+

continue;

150+

}

151+152+

if (sourceSignal.aborted) {

153+

abortSignal(signal, sourceSignal.reason);

154+

return;

155+

}

156+

}

157+

}

158+159+

function followCompositeSignal(signal) {

160+

if (signal[kFollowing] || signal[kAborted] || !signal[kSourceSignals]?.size) {

161+

return;

162+

}

163+164+

const resultSignalWeakRef = signal[kResultSignalWeakRef] ??= new SafeWeakRef(signal);

165+166+

for (const sourceSignalWeakRef of signal[kSourceSignals]) {

167+

const sourceSignal = sourceSignalWeakRef.deref();

168+

if (sourceSignal === undefined) {

169+

signal[kSourceSignals].delete(sourceSignalWeakRef);

170+

continue;

171+

}

172+173+

if (sourceSignal.aborted) {

174+

abortSignal(signal, sourceSignal.reason);

175+

return;

176+

}

177+178+

sourceSignal[kDependantSignals] ??= new SafeSet();

179+

sourceSignal[kDependantSignals].add(resultSignalWeakRef);

180+

dependantSignalsCleanupRegistry.register(signal, {

181+

sourceSignalRef: sourceSignalWeakRef,

182+

dependantSignalRef: resultSignalWeakRef,

183+

sourceSignalsCleanupToken: sourceSignalWeakRef,

184+

});

185+

sourceSignalsCleanupRegistry.register(sourceSignal, {

186+

sourceSignalRef: sourceSignalWeakRef,

187+

composedSignalRef: resultSignalWeakRef,

188+

}, sourceSignalWeakRef);

189+

}

190+191+

signal[kFollowing] = true;

192+

}

193+139194

// Because the AbortSignal timeout cannot be canceled, we don't want the

140195

// presence of the timer alone to keep the AbortSignal from being garbage

141196

// collected if it otherwise no longer accessible. We also don't want the

@@ -148,6 +203,7 @@ function setWeakAbortSignalTimeout(weakRef, delay) {

148203

const timeout = setTimeout(() => {

149204

const signal = weakRef.deref();

150205

if (signal !== undefined) {

206+

clearTimeoutRegistry.unregister(signal);

151207

gcPersistentSignals.delete(signal);

152208

abortSignal(

153209

signal,

@@ -198,6 +254,7 @@ class AbortSignal extends EventTarget {

198254

*/

199255

get aborted() {

200256

validateThisAbortSignal(this);

257+

refreshCompositeSignal(this);

201258

return !!this[kAborted];

202259

}

203260

@@ -206,11 +263,13 @@ class AbortSignal extends EventTarget {

206263

*/

207264

get reason() {

208265

validateThisAbortSignal(this);

266+

refreshCompositeSignal(this);

209267

return this[kReason];

210268

}

211269212270

throwIfAborted() {

213271

validateThisAbortSignal(this);

272+

refreshCompositeSignal(this);

214273

if (this[kAborted]) {

215274

throw this[kReason];

216275

}

@@ -241,7 +300,8 @@ class AbortSignal extends EventTarget {

241300

signal[kTimeout] = true;

242301

clearTimeoutRegistry.register(

243302

signal,

244-

setWeakAbortSignalTimeout(new SafeWeakRef(signal), delay));

303+

setWeakAbortSignalTimeout(new SafeWeakRef(signal), delay),

304+

signal);

245305

return signal;

246306

}

247307

@@ -260,7 +320,6 @@ class AbortSignal extends EventTarget {

260320

return resultSignal;

261321

}

262322263-

const resultSignalWeakRef = new SafeWeakRef(resultSignal);

264323

resultSignal[kSourceSignals] = new SafeSet();

265324266325

// Track if we have any timeout signals

@@ -283,51 +342,51 @@ class AbortSignal extends EventTarget {

283342

return resultSignal;

284343

}

285344286-

signal[kDependantSignals] ??= new SafeSet();

287345

if (!signal[kComposite]) {

288346

const signalWeakRef = new SafeWeakRef(signal);

289347

resultSignal[kSourceSignals].add(signalWeakRef);

290-

signal[kDependantSignals].add(resultSignalWeakRef);

291-

dependantSignalsCleanupRegistry.register(resultSignal, signalWeakRef);

292-

sourceSignalsCleanupRegistry.register(signal, {

293-

sourceSignalRef: signalWeakRef,

294-

composedSignalRef: resultSignalWeakRef,

295-

});

296348

} else if (!signal[kSourceSignals]) {

297349

continue;

298350

} else {

351+

refreshCompositeSignal(signal);

352+

if (signal.aborted) {

353+

abortSignal(resultSignal, signal.reason);

354+

return resultSignal;

355+

}

299356

for (const sourceSignalWeakRef of signal[kSourceSignals]) {

300357

const sourceSignal = sourceSignalWeakRef.deref();

301358

if (!sourceSignal) {

302359

continue;

303360

}

304-

assert(!sourceSignal.aborted);

305361

assert(!sourceSignal[kComposite]);

306362363+

if (sourceSignal.aborted) {

364+

abortSignal(resultSignal, sourceSignal.reason);

365+

return resultSignal;

366+

}

367+307368

if (resultSignal[kSourceSignals].has(sourceSignalWeakRef)) {

308369

continue;

309370

}

310371

resultSignal[kSourceSignals].add(sourceSignalWeakRef);

311-

sourceSignal[kDependantSignals].add(resultSignalWeakRef);

312-

dependantSignalsCleanupRegistry.register(resultSignal, sourceSignalWeakRef);

313-

sourceSignalsCleanupRegistry.register(signal, {

314-

sourceSignalRef: sourceSignalWeakRef,

315-

composedSignalRef: resultSignalWeakRef,

316-

});

317372

}

318373

}

319374

}

320375321-

// If we have any timeout signals, add the composite signal to gcPersistentSignals

322376

if (hasTimeoutSignals && resultSignal[kSourceSignals].size > 0) {

323-

gcPersistentSignals.add(resultSignal);

377+

resultSignal[kTimeout] = true;

324378

}

325379326380

return resultSignal;

327381

}

328382329383

[kNewListener](size, type, listener, once, capture, passive, weak) {

330384

super[kNewListener](size, type, listener, once, capture, passive, weak);

385+386+

if (this[kComposite] && type === 'abort' && !this.aborted && size === 1) {

387+

followCompositeSignal(this);

388+

}

389+331390

const isTimeoutOrNonEmptyCompositeSignal = this[kTimeout] || (this[kComposite] && this[kSourceSignals]?.size);

332391

if (isTimeoutOrNonEmptyCompositeSignal &&

333392

type === 'abort' &&