Every live job is in exactly one job queue at any given moment. In addition, all live jobs are in the `.ps' propdir.
Jobs ready to run: .etc.run queue. 'sleep'ing jobs: .etc.doz queue. 'pause'd jobs: .etc.poz queue. Stopped jobs: .etc.stp queue.
Dead jobs are not actually in any queue (being in a queue
would keep them from ever being garbage-collected), but
their q_this
entry points to `.etc.ded', to make their
status
well-defined.
All other jobs are in a queue associated with the resource for which they are waiting:
Jobs waiting to read from an empty message stream are in its q_in. Jobs waiting to write to a full message stream are in its q_out.
The `.etc.doz' queue for sleeping jobs is sorted by
time waited-for; all other queues rotate chronologically,
with jobs inserted at the prev
end and removed from the
next
end.
A job queue (joq) is a 4-vector with the logical structure:
struct joq { Vm_Obj next; // Next job in queue. Vm_Obj prev; // Prev job in queue. Vm_Obj owner; // Owner of queue. Vm_Obj name; // Queue name: "in" "out" "run" "doz" "poz" "stp" ... };
Jobs are doubly linked into their queue via their
q_next
and q_prev
fields. In an empty queue,
next
and prev
point to the queue itself.
The currently running job is always next
in the run
queue. The run queue can be empty, in which case nothing
much will happen until some external event wakes a job from
some queue -- network I/O unblocking a job waiting on a
message stream, say, or clock timing waking an
`.etc.doz' job.
Go to the first, previous, next, last section, table of contents.