A running program's reply never says it has not called (agent/start ...), because the agent's constructor has bound the socket before main
This commit is contained in:
parent
ddf7ca4974
commit
3636f31cba
11
TODO.org
11
TODO.org
@ -1565,11 +1565,12 @@ only by an explicit call. A sentence about the shape of the gate rather than an
|
||||
observed problem: only the daemon sets the variable and it never runs release
|
||||
builds. The fix, if it is ever felt, is a narrower gate.
|
||||
|
||||
** NEXT The daemon's "has not called (agent/start ...)" note is unreachable
|
||||
Decided 2026-09-25: retire the note in the same dead-code sweep.
|
||||
Unreachable, not merely unexercised: the one state it was true of is closed by the
|
||||
constructor. Retiring it is the author's call over a lane that merged days ago, so
|
||||
it is left in place saying a true thing about a state nothing can be in.
|
||||
** DONE The daemon's "has not called (agent/start ...)" note is unreachable
|
||||
CLOSED: [2026-09-25]
|
||||
Retired, with the matching arm of an evaluation's timeout. A running program
|
||||
either links the agent, whose constructor binds the socket before =main=, or
|
||||
links none and has its delivery refused; no reply names =(agent/start ...)= as
|
||||
not yet called.
|
||||
|
||||
** DONE The allocation registry
|
||||
CLOSED: [2026-09-13]
|
||||
|
||||
@ -7024,9 +7024,8 @@ registry now holds.
|
||||
**When it happens.** At the next frame boundary of a running program. A parked program — one whose `main` has
|
||||
finished — drains its ring when that sleep ends, so the store lands at the top of its next run, ahead of `main`; the
|
||||
run's own startup then computes the initialiser again, which is not a wart but the two events `defparameter` has: an
|
||||
evaluation assigns, and a re-run re-initialises. A program that has not called `(agent/start ...)` yet installs at its
|
||||
next `(agent/poll)`, and never if it has none — the reply already says so. A program stopped at a break runs it in the
|
||||
break loop, like any other evaluation.
|
||||
evaluation assigns, and a re-run re-initialises. A program stopped at a break runs it in the break loop, like any other
|
||||
evaluation.
|
||||
|
||||
**A brand-new `def`** gets its initialiser run too. Its storage comes from `flan_dev_global` and nothing in the host's
|
||||
`.init-globals` names it, so before this a new `(def n i64 (count-them))` came up as `calloc`'s zeroes and stayed
|
||||
|
||||
41
lib/dev.ml
41
lib/dev.ml
@ -124,7 +124,7 @@ let await ?(ms = 5000) f =
|
||||
|
||||
(* Whether the program has bound the socket it receives modules on.
|
||||
|
||||
Cheap enough to ask on every reply — one [stat] — and asked rather than
|
||||
Cheap enough to ask before every request — one [stat] — and asked rather than
|
||||
remembered because the answer moves in one direction at a moment this side
|
||||
does not get to see: [agent/start] runs on the program's own thread. *)
|
||||
let agent_bound t = Sys.file_exists t.agent
|
||||
@ -781,7 +781,7 @@ let refusal ~parked reply =
|
||||
refusal; it is the difference between "queued" and "running", which is a
|
||||
difference only the program can close and only at a moment of its choosing.
|
||||
|
||||
Three of them, in the order of how far the module is from being live:
|
||||
Two of them, in the order of how far the module is from being live:
|
||||
|
||||
A PARKED program has finished [main] and is asleep in [flan_merged_park].
|
||||
Its ring is drained whenever that sleep ends — for an expression to run, or
|
||||
@ -796,16 +796,11 @@ let refusal ~parked reply =
|
||||
not per session, because the reader of a *new* park may not be the reader
|
||||
of the last one.
|
||||
|
||||
A RUNNING program that has not bound its agent socket has not called
|
||||
[(agent/start ...)] yet — it may be about to, ahead of a window that is
|
||||
still being created, or it may have no such call at all. Either way the
|
||||
module is in the ring and the ring is drained by [(agent/poll)], so what
|
||||
can honestly be promised is the poll and not a frame: a program with no
|
||||
poll in it never installs this, and saying "at its next frame boundary"
|
||||
would be the reply that made a redefinition look applied when it was not.
|
||||
|
||||
A RUNNING program that has bound it needs no note: the reply already says
|
||||
queued, and the frame boundary is the next one it reaches. *)
|
||||
A RUNNING program needs no note: the reply already says queued, and the
|
||||
frame boundary is the next one it reaches. A running program whose agent
|
||||
socket is not bound is not a third case: the agent package binds it in a
|
||||
constructor, before [main], and a program that does not link the package
|
||||
has nothing to queue a module on, so the delivery is refused instead. *)
|
||||
let install_note t ~parked =
|
||||
if parked then begin
|
||||
let first = not t.park_noted in
|
||||
@ -821,13 +816,6 @@ let install_note t ~parked =
|
||||
else "queued; installs no later than the parked program's next run")
|
||||
]
|
||||
end
|
||||
else if not (agent_bound t) then
|
||||
[ ":note "
|
||||
^ Wire.quote
|
||||
"queued, but the program has not called (agent/start ...) yet, so \
|
||||
this installs when it next reaches an (agent/poll) — and not at \
|
||||
all if it never does"
|
||||
]
|
||||
else []
|
||||
|
||||
(* [pause], when given, is the position of the form to stop at — §9. It rides
|
||||
@ -1253,21 +1241,6 @@ let eval_expr t ~code ~origin ~pause =
|
||||
the program is stopped at an earlier break and runs \
|
||||
nothing until that ends. Take a restart or abort in the \
|
||||
break buffer, and evaluate this again"
|
||||
(* And a third cause, which is the one a session now reaches
|
||||
early enough to hit: the program has not bound its agent
|
||||
socket, so it is still ahead of its own [(agent/start ...)]
|
||||
— inside whatever it does first, a window being created —
|
||||
and asking whether it calls [(agent/poll)] would send the
|
||||
reader to look at a loop it has not got to yet. Said only
|
||||
where it is a fact about *this* program: the socket is
|
||||
missing, which is a stat, not a guess. *)
|
||||
else if not (agent_bound t) then
|
||||
error
|
||||
"the program has not called (agent/start ...) yet, so \
|
||||
nothing has run the expression. It is queued and will run \
|
||||
at the program's first (agent/poll); this reply cannot \
|
||||
carry its value, so evaluate it again once the program is \
|
||||
up"
|
||||
else
|
||||
error
|
||||
"the program did not reach a frame boundary; is it calling \
|
||||
|
||||
@ -7,12 +7,10 @@
|
||||
;;;; hand a module to and no socket to fall back on, so the daemon refuses the
|
||||
;;;; delivery and says which socket it could not reach.
|
||||
;;;;
|
||||
;;;; That is the honest answer for it. The sentence [install_note] keeps for a
|
||||
;;;; running program with no socket — queued, installs at its next
|
||||
;;;; (agent/poll) — was true of a program that *links* the agent and has not
|
||||
;;;; reached its (agent/start ...) yet, because there the ring is reachable
|
||||
;;;; in-process while the socket is not yet bound. The package's constructor
|
||||
;;;; binds before main now, so that window is gone; see TODO.org, "(agent/start) takes no argument, and binds before main".
|
||||
;;;; That is the honest answer for it. A program that *links* the agent has its
|
||||
;;;; socket bound by the package's constructor before main, so a running
|
||||
;;;; program with no socket is always this one; see TODO.org, "(agent/start)
|
||||
;;;; takes no argument, and binds before main".
|
||||
;;;;
|
||||
;;;; So: no (import agent ...) anywhere, and a loop that outlasts the test.
|
||||
(defn step [] i64 7)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user