Hydra Engine

Scheduling

Interactive work stays snappy while long jobs keep moving.

Ten agents on one daemon only work if a whole-program analysis can't stall a 10 ms decompile, and an agent that sends a hundred requests can't starve one that sends one. Two lanes, per-program locks and deadlines take care of both.

Two lanes

Every request takes a slot in a lane before it takes any lock:

LaneRunsSlots
Quickdecompile, functions, list, open, renameone per CPU (maxQuick)
Longanalyze, import, script, savea quarter of the CPUs, at least 2 (maxLong)

Long work can never take the slots quick queries need. When a lane is full, waiting requests are admitted round-robin by client. The daemon's own background work, such as building an upgraded copy of an old program, takes a long slot only while no client is waiting for one.

Per-program locks

Each program has a fair read/write lock. Queries and contained scripts share it, so readers run in parallel, each with its own pooled decompiler. Edits, analysis, saves and owner scripts hold it alone. Different programs, and different projects, never wait on each other.

Nothing waits forever

Each request has a wait: how many milliseconds it may wait for a slot or a lock (10,000 by default). When that runs out it fails with busy, naming the holder, what it's doing and for how long, and nothing stays queued past the deadline.

python
1s.call("decompile", address="rva:0x1000", wait=30000)

Imports are the exception: by default a queued import waits until it runs or is cancelled, unless you give it a numeric wait.

The import queue

Up to maxImports imports run at once (one per four CPUs, 1 to 4), in any projects. Four large PEs took 64 s in parallel instead of 165 s one after another. The rest wait first come, first served; while one waits it sends progress events with its position and an estimate, and status.imports shows the whole queue.

Cancelling

RequestCancels
{"cmd": "cancel", "target": 17}One of your requests, running or queued.
{"cmd": "cancel", "all": true}All of your connection's requests.
cancel with client/harness labelsOnly that label's requests.
{"cmd": "cancel", "cacheBuild": "all"}Background upgrade-cache builds.

A cancelled script stops at its next monitor.checkCancelled(). A script that never checks its monitor can't be stopped from outside, because it runs inside the daemon's JVM.

Watching it

status shows each lane's running and waiting requests by label, every client's unanswered requests with their latest progress, and the import queue. It's the first thing to look at when something feels slow.

bash
1python $GS status