Files for jobs
A job can be lent part of the disk's tree for as long as it runs (sysk 031). The shell lends, the file server enforces, the kernel connects the two only while the job runs, and the build checks that no job can stall the server. You type wc /notes/shopping; wc reads that one file, and nothing else.
A lend, step by step
Step through wc /notes/shopping. Blue boxes are tasks, purple the job, green the kernel.
sysk> echo (milk eggs) > /notes/shopping sysk> wc /notes/shopping (wc (bytes 12) (lines 1)) job ended
A service: two pool streams with a fixed server
The jobs clause declares the service; one task serves it. That makes two more pool channels, streams of 576 bytes: files-ask, a job's requests, and files-reply, its replies. Their other ends are the server's.
(task fsd (heap 32768) (tx disk-ask) (rx disk-answer) (rx fs-ask) (tx fs-reply) (serves files)) (jobs (programs producer filter consumer greeter talker wc (follow (quiet 5000))) (slots 4 (heap 4096)) (channels (j0 (bytes 8) (depth 2)) (j1 (bytes 8)) (out (bytes 64) (depth 2))) (service files (bytes 576)))
(serves files) hands the server a Service, a capability like Jobs, which keeps where its holder is in the protocol: no lease, the requests' end given, both ends given. When a job that binds the service starts, the kernel marks it fresh: a new kind of alt source. The server opens a lease (service-open gives the receiving end of the requests, service-reply the sending end of the replies), serves it, and once the requests have ended, service-close ends the replies.
One lifetime argument makes the kernel's part small. A job ends only when its tasks have finished, and the client finishes only once it has received the replies to their end, which service-close sends. So by the time the next job-start empties the pool's channels, the server holds no end of them. The contracts carry it: close-rx needs a stream's end received, and only service-close gives it.
The job check counts the server
A service's channels have one end outside the job, as the shell's out does: its requests a receiver (the server), its replies a sender. A job may bind them only to the parameters of a program that was checked as the service's client (below), and both or neither. Reasons 3 and 5 of the check say so. To the check's waits rule, a wait for the service is never held up, as a wait for the launcher's output is not: what makes that true is the client check at build time.
Checked when the catalogue is built: a well-behaved client
Every program that could be bound to a service is judged, when the system is built, together with a server that answers each request, until the requests end, and then ends its replies. The rule of the deadlock check judges the two as it judges any system. wc asks, then reads the reply, every time, so it passes; it and follow ask through one function, files-ask in prg/files-client.sysp. A program that sends four requests before it reads any reply could leave the server holding a reply it cannot send while the program waits to send again, and the build stops:
tests/manifest/service-greedy.sysk: the catalogue: `greedy`, as a client of service `files`, could get stuck: greedy waits for room on p0; the service waits for room on p1
The real server does what the reference server does, or less: it may take its time. It serves the shell and the job together with alt, and while a reply to the job is unread it reads none of the job's requests, but goes on serving the shell. A job that stopped reading would stall itself, not the server.
What a job can reach
What a job attaches to is the node the shell lent, with the rights the shell lent it, no more than the shell's. Paths only go down (no ..), so nothing above the lent node can be named. Every fid carries rights, and each operation needs its own:
| Operation | Needs |
|---|---|
| open to read, read | right-read |
| open to write, write | right-write |
| create (in a directory), remove | right-mutate |
| lend | the shell's channel: a job lends nothing |
| walk | nothing more: the new fid has the rights of the one it came from |
The test system tests/fsd/lend.sysk runs a launcher that makes /d/a and a sibling /s, then three jobs. A probe lent /d to read tries each operation; wc is lent /d/a; the probe again, lent nothing. Each line is one job's:
The probe, lent /d to read | Status |
|---|---|
attach: fid 0 names /d | 0 ok |
walk to a | 0 ok |
open a to write | 2 not permitted |
open a to read | 0 ok |
create x in /d | 2 not permitted |
remove a | 2 not permitted |
walk ../s | 4 not a path |
| lend fid 0 on | 2 not permitted |
walk s: it is not under /d | 1 no such name |
(probe 0 0 2 0 2 2 4 2 1)
(wc (bytes 8) (lines 2))
(probe 2) ; lent nothing: the attach is not permitted
When a job's requests end, the server forgets what it lent, frees the job's fids, and drops any file the job was writing and never closed: only the shell's own requests survive a job.
In the shell
A path as a program's only argument lends it, to read: (wc /notes/shopping), or through sugar wc /notes/shopping. The program's service parameters are bound to the service of the tree the path is in, the rest wired as a pipe of one. Since sysk 058 there are two services, fsd's files and netd's talk, and a program is the client of any service of its message size, not of one by name: the namespace says which server serves jobs, (/ 4 (jobs 3 4)) … (/net 7 (jobs 5 6)), so wc /net/eth/addr binds talk-ask and talk-reply, and wc /notes/shopping binds files-ask and files-reply. An address in place of the path dials a conversation and lends its data (The network). The shell lends after the job check passes and before the job starts, so a refused job never leaves a lend behind. The refusals come in the command's terms:
| You type | The shell says |
|---|---|
wc /nope | no such file: /nope |
wc /sys/time | not permitted: /sys/time: the kernel's tree serves no jobs, so it lends nothing |
wc /net/eth/addr | (wc (bytes 86) (lines 1)): netd lends it, as fsd would |
wc | refused: wc's ask is not connected |
wc /shopping > /count | the counts, and the job's end, into /count |
Not yet: lending to write from the shell's syntax, but for a dialed conversation (the servers already honour every right); a job that binds two services at once. A job can follow a file as it grows: a read of its may wait for a change (Reads that wait, sysk 033), as follow's do.