mirror of
https://github.com/morluto/rea.git
synced 2026-11-03 05:16:16 +00:00
fix(lifecycle): reject session work once close has started (#6411)
* fix(lifecycle): reject session work once close has started Process shutdown closed the shared binary session without sealing it, so a stdio tool call could open a provider after that close and leave the child running. GDB ran a queued console command or a second close after the session had started closing because the queued turn did not repeat admission checks. Shutdown now refuses later target acquisition, and a queued GDB command or duplicate close fails as unavailable once its turn finds the session closing or gone. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(gdb): block console admission after cleanup starts --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: morluto <morluto@users.noreply.github.com>
This commit is contained in:
5 files changed
+436
-44
No files matched your search
@@ -154,6 +154,8 @@ export class BinarySession
|
||||
#transition: Promise<void> = Promise.resolve();
|
||||
#transitionGeneration = 0;
|
||||
#transitionPending = 0;
|
||||
/** Process shutdown has begun; later target acquisition must not outlive it. */
|
||||
#shutdownStarted = false;
|
||||
readonly #calls = new Map<Promise<unknown>, number>();
|
||||
readonly #promptCompletionControllers = new Set<AbortController>();
|
||||
readonly #providerRouter: SessionProviderRouter;
|
||||
@@ -182,6 +184,8 @@ export class BinarySession
|
||||
options: Pick<ExecutionOptions, "signal"> = {},
|
||||
): Promise<Result<ResolvedAppBundleResourceRoot, AnalysisError>> {
|
||||
return this.#serialize(async (admittedThrough) => {
|
||||
const refused = this.#targetAcquisitionRefused("open_bundle_resources");
|
||||
if (refused !== undefined) return refused;
|
||||
await this.#drainCalls(admittedThrough);
|
||||
if (isAborted(options.signal))
|
||||
return err(
|
||||
@@ -498,6 +502,8 @@ export class BinarySession
|
||||
options: BinarySessionOpenOptions,
|
||||
): Promise<Result<BinaryTarget, AnalysisError>> {
|
||||
return this.#serialize(async (admittedThrough) => {
|
||||
const refused = this.#targetAcquisitionRefused("open_binary");
|
||||
if (refused !== undefined) return refused;
|
||||
const admitted = await this.#withLoadedSnapshot(options);
|
||||
if (!admitted.ok) return admitted;
|
||||
return this.#openWithinTransition(
|
||||
@@ -757,6 +763,22 @@ export class BinarySession
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject target acquisition once process shutdown has begun.
|
||||
* Acquisition already inside its transition still finishes; the shutdown
|
||||
* close queued behind that transition retires it.
|
||||
*/
|
||||
beginShutdown(): void {
|
||||
this.#shutdownStarted = true;
|
||||
}
|
||||
|
||||
#targetAcquisitionRefused(
|
||||
operation: "open_binary" | "open_bundle_resources",
|
||||
): Result<never, AnalysisCancelledError> | undefined {
|
||||
if (!this.#shutdownStarted) return undefined;
|
||||
return err(new AnalysisCancelledError(operation));
|
||||
}
|
||||
|
||||
/** Close the active target, if any. */
|
||||
close(
|
||||
options: Pick<ExecutionOptions, "progress"> & {
|
||||
|
||||
Reference in new issue
Block a user