tcThreadManager

Thread management for JavaScript running inside the Total Control (TC) environment.

This module exposes two thread wrappers — TCThread (backed by pooled Java platform threads)
and TCThreadVirtual (backed by JDK 21+ virtual threads) — plus a set of manager utilities
to coordinate thread lifecycle, cooperative pause/resume, interruption on timeout, and global
concurrency policy ("serialized" vs "unsafe-parallel").

Why this module exists

Rhino/RingoJS style engines frequently execute JS on a single-host thread and are not re‑entrant.
Running JS callbacks concurrently from multiple Java threads can corrupt interpreter state or
produce hard‑to‑debug races. This module provides:

  • A global JS lock to serialize entry into JS frames when policy is "serialized"
  • A thread registry with synchronized access to support lookups, counting, and cleanup
  • Cooperative controls (pause/resume/stop) that work with yield points inside user code
  • Stable waiting semantics via TCWait with immediate/finite timeout handling
  • Re‑runnable executor that can be shut down and automatically re‑created as needed

Public Surface

  • Classes: TCThread, TCThreadVirtual
  • Managers: stopAllThreads, pauseAllThreads, resumeAllThreads,
    listThreadStatus, shutdownExecutor
  • Waiting & lookup: TCWait, getAllThreadNames, getThreadByName,
    getThreadsByName, threadCount, threadCountByPrefix
  • Diagnostics & policy: setDebug, getDebug, setGlobalConcurrency,
    getGlobalConcurrency

Quick Start

var {
  TCThread, TCThreadVirtual, TCWait,
  pauseAllThreads, resumeAllThreads, stopAllThreads,
  setGlobalConcurrency, getGlobalConcurrency
} = require("sigma/tcThreadManager");

// Pooled thread
var t = new TCThread("job1", () => delay(200));
t.start();
print("job1 finished?", TCWait(t, 1000));

// Virtual thread
var v = new TCThreadVirtual("vjob", () => delay(150));
v.start();
print("vjob finished?", v.await(500));

setGlobalConcurrency("serialized");

Classes

TCThread
TCThreadVirtual

(inner) TCWait(name, timeOutopt) → {boolean}

Wait for a thread to complete with optional timeout. Supports thread object or name.

Example
// Example: wait by object
var t = new TCThread("w1", () => delay(80));
    t.start();
    print(TCWait(t, 500));

// Example: wait by name (most recent with same name)
var a = new TCThread("sameN", () => delay(200));
var b = new TCThread("sameN", () => delay(50));
a.start();
delay(10);
b.start();
print(TCWait("sameN", 500));

// Example: immediate timeout (<=0)
var longT = new TCThread("long", () => delay(2000));
longT.start();
print(TCWait(longT, 0)); // false
Parameters:
TCThread | TCThreadVirtual | string name

Thread object or logical name (most recent)

number timeOut <optional>

Milliseconds timeout (<=0 means immediate timeout)

Returns:
boolean

true if finished without interruption, else false

(inner) getAllThreadNames() → {Array.<string>}

Get names of all currently registered threads.

Example
// Example: list names
print(getAllThreadNames().join(", "));
Returns:
Array.<string>

(inner) getDebug() → {boolean}

Return whether debug logging is enabled.

Example
// Example: query debug flag
print("debug enabled?", getDebug());
Returns:
boolean

(inner) getGlobalConcurrency() → {"serialized"|"unsafe-parallel"}

Get current global concurrency policy.

Example
// Example: print policy
print("Policy:", getGlobalConcurrency());
Returns:
"serialized" | "unsafe-parallel"

(inner) getThreadByName(name) → {TCThread|TCThreadVirtual|undefined}

Get the most recently started thread with a given name.

Example
// Example: fetch by name
var t = new TCThread("lookupJob", () => delay(50));
t.start();
var found = getThreadByName("lookupJob");
Parameters:
string name
Returns:
TCThread | TCThreadVirtual | undefined

(inner) getThreadsByName(name) → {Array.<(TCThread|TCThreadVirtual)>}

Get all threads (of any age) that match a given name.

Example
// Example: duplicate names
var a=new TCThread("dup",()=>delay(20)),
    b=new TCThread("dup",()=>delay(20));
a.start();
b.start();
print(getThreadsByName("dup").length>=2);
Parameters:
string name
Returns:
Array.<(TCThread|TCThreadVirtual)>

(inner) listThreadStatus()

Print a snapshot of all registered threads.

Example
// Example: list current threads for debugging
listThreadStatus();

(inner) pauseAllThreads()

Pause all registered threads (cooperative).

Example
pauseAllThreads();

(inner) resumeAllThreads()

Resume all registered threads.

Example
resumeAllThreads();

(inner) setDebug(v)

Enable/disable non‑fatal debug logs.

Example
// Example: enable logs while diagnosing a failure
setDebug(true); // ... run ...
setDebug(false);
Parameters:
boolean v

(inner) setGlobalConcurrency(mode)

Switch the global JS concurrency policy.

  • serialized: all JS callbacks are serialized via a global lock
  • unsafe-parallel (default): JS callbacks are invoked concurrently at your own risk
Example
// Example: enable parallel callbacks (expert only)
setGlobalConcurrency("unsafe-parallel");
// ... do parallel-safe work ...
setGlobalConcurrency("serialized");
Parameters:
"serialized" | "unsafe-parallel" mode

(inner) shutdownExecutor()

Shutdown the shared ExecutorService and proactively stop registered virtual threads.
Destructive for pooled threads; future TCThread#start will recreate the pool.

Example
// Example: destructive shutdown (tests/teardown)
shutdownExecutor();

(inner) stopAllThreads(optionsopt)

Stop all registered threads and guarantee registry cleanup.

Example
// Example: stop everything quickly
stopAllThreads({ timeout: 300, step: 25 });
// or
stopAllThreads();
Parameters:
Object options <optional>

Milliseconds window (default 1000/50)

Properties
number timeout <optional>
number step <optional>

(inner) threadCount() → {number}

Total number of registered threads.

Example
// Example: count after starting two threads
var t1=new TCThread("c1",()=>delay(30)),
    t2=new TCThread("c2",()=>delay(30));
t1.start();
t2.start();
print(threadCount()>=2);
Returns:
number

(inner) threadCountByPrefix(prefix) → {number}

Count threads whose names start with a given prefix.

Example
// Example: count by prefix
var x1=new TCThread("job_x_1",()=>delay(30)),
    x2=new TCThread("job_x_2",()=>delay(30));
x1.start();
x2.start();
print(threadCountByPrefix("job_x_")===2);
Parameters:
string prefix
Returns:
number