Phase F: kicadOpenFile runs on a dispatch context — the awaited-ccall class retired for the open (fcsTotal 1800→100/load)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Td4ujboGuAw26jvbDQzehj
This commit is contained in:
parent
d185f5c1d2
commit
747bf5ecf4
4 changed files with 84 additions and 1 deletions
|
|
@ -1 +1 @@
|
||||||
15
|
16
|
||||||
|
|
|
||||||
|
|
@ -1241,6 +1241,32 @@ upstream-divergence decision) remove the population. Until then the ring is
|
||||||
the correct containment: bounded at 32, over-capacity silent at the flip, and
|
the correct containment: bounded at 32, over-capacity silent at the flip, and
|
||||||
the eager path stands ready for any flow that does complete-and-release.
|
the eager path stands ready for any flow that does complete-and-release.
|
||||||
|
|
||||||
|
### The awaited-ccall entry class RETIRED for the open path (2026-08-09)
|
||||||
|
|
||||||
|
`kicadOpenFile` — the last production member of the overlapped-wake class the
|
||||||
|
D-on beacon sweep named — no longer parks the main stack. The body is
|
||||||
|
unchanged; `kicadOpenFileStart` runs it on a DISPATCH CONTEXT (every wait
|
||||||
|
inside the load becomes a context park through the registry) and resolves an
|
||||||
|
"open" wait token on completion; the shim conditionally rewraps
|
||||||
|
`Module.kicadOpenFile` to return the token's plain JS promise, so the shell's
|
||||||
|
`await` and the busy gate are byte-compatible (older per-app binaries without
|
||||||
|
the starter keep the legacy suspending export). The F0 early-resolve retention
|
||||||
|
covers the fast-error path by construction.
|
||||||
|
|
||||||
|
**Gates: collab-load-fuzz + mailbox-ordering (the staged parked-open levers)
|
||||||
|
green — with ZERO `overlapped-wake`/`hot-main-swap-out` beacons where they
|
||||||
|
always fired; suite 139/1; battery 395/1; repro oracle 3/3 warm loads PASS
|
||||||
|
with `rootHotTotal=0`, `fiberStackParks=0` — and `fcsTotal` COLLAPSED from
|
||||||
|
~1800–5000 per load to 97–235.** The load no longer round-trips fiber swaps
|
||||||
|
through main-stack in-place parks; that order-of-magnitude drop is the
|
||||||
|
measured shape of "the main stack is the scheduler and nothing else".
|
||||||
|
|
||||||
|
Remaining members of the class: the standalone per-app binaries (eeschema.js
|
||||||
|
etc., rebuilt rarely — conversion rides their next rebuild via the same
|
||||||
|
starter pattern) and the wx TEST HARNESS pages' direct `ccall` buttons
|
||||||
|
(harness-only; the interlock and shim capture/restore stay until those are
|
||||||
|
routed or retired).
|
||||||
|
|
||||||
### Prod-provider smoke (2026-08-08) — done, with one pre-existing red bisected
|
### Prod-provider smoke (2026-08-08) — done, with one pre-existing red bisected
|
||||||
|
|
||||||
Against the live web stack (playwright-web config, reference backend :3060):
|
Against the live web stack (playwright-web config, reference backend :3060):
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,23 @@ if (typeof Asyncify !== "undefined" && !globalThis.__wxSchedulerInstalled) {
|
||||||
if (this.mutatorsWrapped > 0)
|
if (this.mutatorsWrapped > 0)
|
||||||
console.log("[wx-scheduler] embind lane: wrapped " + this.mutatorsWrapped + " mutator(s)");
|
console.log("[wx-scheduler] embind lane: wrapped " + this.mutatorsWrapped + " mutator(s)");
|
||||||
},
|
},
|
||||||
|
// Phase F (doc 22 §10, the awaited-ccall entry class): when the binary
|
||||||
|
// carries kicadOpenFileStart, the open body runs on a DISPATCH CONTEXT
|
||||||
|
// and the await surface becomes a plain JS promise over the wait token —
|
||||||
|
// the main stack never parks in place during a load. Conditional: older
|
||||||
|
// binaries without the starter keep the legacy suspending export.
|
||||||
|
_wrapOpenFile: function () {
|
||||||
|
var self = this;
|
||||||
|
var start = Module["kicadOpenFileStart"];
|
||||||
|
if (typeof start !== "function" || typeof Module["kicadOpenFile"] !== "function") return;
|
||||||
|
Module["kicadOpenFile"] = function (path) {
|
||||||
|
var token = start(path);
|
||||||
|
// waitPromise consumes early-resolved entries (the fast-error path),
|
||||||
|
// so a job that finished before this await still resolves correctly.
|
||||||
|
return self.waitPromise(token).then(function (r) { return !!r; });
|
||||||
|
};
|
||||||
|
console.log("[wx-scheduler] open lane: kicadOpenFile routed through the dispatch context");
|
||||||
|
},
|
||||||
_armMutatorPump: function () {
|
_armMutatorPump: function () {
|
||||||
if (this._mutatorPumpArmed) return;
|
if (this._mutatorPumpArmed) return;
|
||||||
this._mutatorPumpArmed = true;
|
this._mutatorPumpArmed = true;
|
||||||
|
|
@ -763,11 +780,13 @@ if (typeof Asyncify !== "undefined" && !globalThis.__wxSchedulerInstalled) {
|
||||||
if (typeof Module !== "undefined") {
|
if (typeof Module !== "undefined") {
|
||||||
if (Module["calledRun"]) {
|
if (Module["calledRun"]) {
|
||||||
AsyncifyScheduler._wrapMutators();
|
AsyncifyScheduler._wrapMutators();
|
||||||
|
AsyncifyScheduler._wrapOpenFile();
|
||||||
} else {
|
} else {
|
||||||
var __wxSchedPrevInit = Module["onRuntimeInitialized"];
|
var __wxSchedPrevInit = Module["onRuntimeInitialized"];
|
||||||
Module["onRuntimeInitialized"] = function () {
|
Module["onRuntimeInitialized"] = function () {
|
||||||
if (typeof __wxSchedPrevInit === "function") __wxSchedPrevInit();
|
if (typeof __wxSchedPrevInit === "function") __wxSchedPrevInit();
|
||||||
AsyncifyScheduler._wrapMutators();
|
AsyncifyScheduler._wrapMutators();
|
||||||
|
AsyncifyScheduler._wrapOpenFile();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#include <emscripten/bind.h>
|
#include <emscripten/bind.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <wx/app.h>
|
#include <wx/app.h>
|
||||||
|
|
@ -164,6 +165,42 @@ static bool kicadOpenFile( std::string path )
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Phase F (docs/features/async/22 §10, the awaited-ccall entry class): the
|
||||||
|
// open body above, driven from a DISPATCH CONTEXT instead of the main stack.
|
||||||
|
// Run there, every wait inside the load parks the context through the
|
||||||
|
// registry — the main stack never parks in place, which is the last
|
||||||
|
// production member of the overlapped-wake class the D-on beacon sweep named.
|
||||||
|
// The shim wraps Module.kicadOpenFile over this starter when it exists: the
|
||||||
|
// wrapper returns the wait token's promise, so the shell's `await` semantics
|
||||||
|
// (and the busy gate) are unchanged. Early failures resolve before the
|
||||||
|
// wrapper awaits — covered by the wait registry's early-resolve retention.
|
||||||
|
extern "C" void wxWasmRunOnDispatchContext( void ( *fn )( void* ), void* arg );
|
||||||
|
extern "C" int wxWasmBeginWait( const char* aKind );
|
||||||
|
extern "C" void wxWasmResolveWait( int aToken, int aResult );
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct OPEN_JOB
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
int token;
|
||||||
|
};
|
||||||
|
|
||||||
|
void kicadOpenFileJob( void* aArg )
|
||||||
|
{
|
||||||
|
std::unique_ptr<OPEN_JOB> job( static_cast<OPEN_JOB*>( aArg ) );
|
||||||
|
const bool ok = kicadOpenFile( job->path );
|
||||||
|
wxWasmResolveWait( job->token, ok ? 1 : 0 );
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
static int kicadOpenFileStart( std::string path )
|
||||||
|
{
|
||||||
|
const int token = wxWasmBeginWait( "open" );
|
||||||
|
wxWasmRunOnDispatchContext( &kicadOpenFileJob, new OPEN_JOB{ std::move( path ), token } );
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
// JS-pollable open-in-flight probe (open_gate.h): the web shell defers the
|
// JS-pollable open-in-flight probe (open_gate.h): the web shell defers the
|
||||||
// collab/presence attach until the open chain has truly completed.
|
// collab/presence attach until the open chain has truly completed.
|
||||||
static bool kicadOpenFileBusy()
|
static bool kicadOpenFileBusy()
|
||||||
|
|
@ -573,6 +610,7 @@ EMSCRIPTEN_BINDINGS(kicad_editor) {
|
||||||
function("kicadCollabFiberBusy", &kicadCollabFiberBusyProbe);
|
function("kicadCollabFiberBusy", &kicadCollabFiberBusyProbe);
|
||||||
// Programmatic file open (preferred over UI automation from the web app).
|
// Programmatic file open (preferred over UI automation from the web app).
|
||||||
function("kicadOpenFile", &kicadOpenFile);
|
function("kicadOpenFile", &kicadOpenFile);
|
||||||
|
function("kicadOpenFileStart", &kicadOpenFileStart);
|
||||||
function("kicadOpenFileBusy", &kicadOpenFileBusy);
|
function("kicadOpenFileBusy", &kicadOpenFileBusy);
|
||||||
function("kicadTestSetOpenPark", &kicadTestSetOpenPark);
|
function("kicadTestSetOpenPark", &kicadTestSetOpenPark);
|
||||||
function("kicadTestArmTimerPark", &kicadTestArmTimerPark);
|
function("kicadTestArmTimerPark", &kicadTestArmTimerPark);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue