Skip to content

Commit 0165c3f

Browse files
committed
Turn thread termination resolution into a callback
This allows us later to store an initialised module. For now, it cleans up the scheduler by decreasing the number of responsibilities.
1 parent 8b087e2 commit 0165c3f

File tree

3 files changed

+47
-64
lines changed

3 files changed

+47
-64
lines changed

rt/src/Scheduler.mts

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -110,38 +110,46 @@ export class Scheduler implements SchedulerInterface {
110110
this.__funloop.push(t);
111111
}
112112

113-
/** Create a new thread `t` for the given function to be evaluated and schedule it. */
113+
/** Create a new thread `t` for the given function to be evaluated and schedule it.
114+
*
115+
* NOTE (20-10-2025; SS): A hypothesis about the Javascript event loop:
116+
*
117+
* It would be a more clean design to return the thread identifier of type `LVal`, as we
118+
* do right now, together with a `Promise<LVal>` of the final returned value. But, since
119+
* the Javascript event loop is a LIFO queue, i.e. a stack, this would bury resolving the
120+
* termination of each thread (especially the *main* thread) beneath everything else.
121+
*/
114122
scheduleNewThread(f: () => any,
115123
arg: any,
116124
pc: Level,
117125
block: Level,
118-
tType: ThreadType = ThreadType.Other)
126+
tType: ThreadType = ThreadType.Other,
127+
cb: (LVal) => void = (_) => {})
119128
{
120129
// Create a new process ID at the given level.
121130
const pid = tType === ThreadType.System ? SYSTEM_PROCESS_STRING : uuidv4();
122-
const pidObj = new ProcessID(this.rt_uuid, pid, this.__node);
123-
const newPid = new LVal(pidObj, pc);
131+
const tid = new LVal(new ProcessID(this.rt_uuid, pid, this.__node), pc);
132+
133+
const halt = () => {
134+
this.__currentThread.raiseCurrentThreadPCToBlockingLev();
135+
this.notifyMonitors();
124136

125-
// Epilogue for thread.
126-
const halt = tType === ThreadType.Main ? () => { this.haltMain() }
127-
: () => { this.haltOther() };
137+
const currT = this.__currentThread;
138+
const retVal = new LVal (currT.r0_val, lub(currT.bl, currT.r0_lev), lub(currT.bl, currT.r0_tlev));
139+
140+
delete this.__alive[this.__currentThread.tid.val.toString()];
141+
142+
cb(retVal);
143+
}
128144

129145
// New thread
130-
const t = new Thread
131-
( newPid
132-
, halt
133-
, f
134-
, arg
135-
, pc
136-
, block
137-
, new SandboxStatus.NORMAL()
138-
, this.rtObj
139-
, this );
140-
141-
142-
this.__alive[newPid.val.toString()] = t;
146+
const sStatus = new SandboxStatus.NORMAL();
147+
const t = new Thread(tid, halt, f, arg, pc, block, sStatus, this.rtObj, this);
148+
149+
this.__alive[tid.val.toString()] = t;
143150
this.scheduleThread(t);
144-
return newPid;
151+
152+
return tid as LVal;
145153
}
146154

147155
/*************************************************************************************************\
@@ -210,32 +218,6 @@ export class Scheduler implements SchedulerInterface {
210218
}
211219
}
212220

213-
/** Epilogue for `main` thread: notify monitors, print and persist the final value */
214-
haltMain () {
215-
this.__currentThread.raiseCurrentThreadPCToBlockingLev()
216-
let retVal = new LVal (this.__currentThread.r0_val,
217-
lub(this.__currentThread.bl, this.__currentThread.r0_lev),
218-
lub(this.__currentThread.bl, this.__currentThread.r0_tlev))
219-
220-
this.notifyMonitors();
221-
222-
delete this.__alive[this.__currentThread.tid.val.toString()];
223-
console.log(">>> Main thread finished with value:", retVal.stringRep());
224-
const persist = argv[TroupeCliArg.Persist];
225-
if (persist) {
226-
this.rtObj.persist(retVal, persist)
227-
console.log("Saved the result value in file", persist)
228-
}
229-
return null;
230-
}
231-
232-
/** Epilogue for non-`main` threads: notify monitors */
233-
haltOther () {
234-
this.notifyMonitors();
235-
// console.log (this.__currentThread.processDebuggingName, this.__currentThread.tid.val.toString(), "done")
236-
delete this.__alive[this.__currentThread.tid.val.toString()];
237-
}
238-
239221
/** Kill thread `t` with the error message `s` sent to its monitors. */
240222
stopThreadWithErrorMessage (t: Thread, errMsg: string) {
241223
this.notifyMonitors(TerminationStatus.ERR, errMsg);

rt/src/builtins/spawn.mts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,13 @@ export function BuiltinSpawn<TBase extends Constructor<UserRuntimeZero>>(Base: T
2121
// console.log ("SPAWN ARGS", larg)
2222
this.runtime.$t.raiseCurrentThreadPC(larg.lev);
2323
let arg = larg.val;
24-
let __sched = this.runtime.__sched
25-
2624

27-
let spawnLocal = (arg) => {
28-
// debug ("scheduled rt_spawn ", arg.fun);
29-
30-
let newPid = __sched.scheduleNewThread(
31-
arg,
32-
__unit, // [arg.env, __unit],
33-
// arg.namespace,
34-
this.runtime.$t.pc,
35-
this.runtime.$t.bl)
36-
return this.runtime.$t.returnImmediateLValue(newPid) ;
25+
const spawnLocal = (func) => {
26+
const tid = this.runtime.__sched.scheduleNewThread(
27+
func, __unit, this.runtime.$t.pc, this.runtime.$t.bl);
28+
return this.runtime.$t.returnImmediateLValue(tid);
3729
}
3830

39-
4031
if (Array.isArray(arg)) {
4132
if (__nodeManager.isLocalNode(arg[0].val)) { // check if we are at the same node or note
4233
// debug ("SAME NODE")
@@ -55,4 +46,4 @@ export function BuiltinSpawn<TBase extends Constructor<UserRuntimeZero>>(Base: T
5546
}
5647
}, "spawn");
5748
}
58-
}
49+
}

rt/src/runtimeMonitored.mts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ async function spawnFromRemote(jsonObj, fromNode) {
133133

134134
const lf = await DS.deserialize(nodeLev, jsonObj);
135135
const f = lf.val;
136-
const newPid =
136+
const tid =
137137
__sched.scheduleNewThread(
138138
f
139139
, __unit //[f.env, __unit]
@@ -145,7 +145,7 @@ async function spawnFromRemote(jsonObj, fromNode) {
145145
// 2018-09-19: AA: because we need to send some info back, we have to invoke
146146
// serialization.
147147

148-
const serObj = serialize(newPid, levels.BOT).data
148+
const serObj = serialize(tid, levels.BOT).data
149149
__sched.resumeLoopAsync();
150150
return serObj;
151151
}
@@ -278,6 +278,7 @@ function rt_ret (arg) {
278278
return $t().returnImmediateLValue(arg);
279279
}
280280

281+
// TODO: Clean up the mess below...
281282
let __sched: Scheduler
282283
let __theMailbox: MailboxProcessor
283284
let __userRuntime: any
@@ -461,15 +462,24 @@ export async function start(f) {
461462

462463
await __userRuntime.linkLibs(f);
463464

465+
const onTerminate = (retVal: LVal) => {
466+
console.log(`>>> Main thread finished with value: ${retVal.stringRep()}`);
467+
if (argv[TroupeCliArg.Persist]) {
468+
this.rtObj.persist(retVal, argv[TroupeCliArg.Persist])
469+
console.log("Saved the result value in file", argv[TroupeCliArg.Persist])
470+
}
471+
};
472+
464473
__sched.scheduleNewThread(
465474
() => f.main({__dataLevel:levels.BOT})
466475
, mainAuthority
467476
, levels.BOT
468477
, levels.BOT
469478
, ThreadType.Main
479+
, onTerminate
470480
);
471481

472482
// ---------------------------------------------------------------------------
473483
// Start code execution
474-
__sched.loop();
484+
__sched.resumeLoopAsync();
475485
}

0 commit comments

Comments
 (0)