The system · L4 and L3

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:

    OperationNeeds
    open to read, readright-read
    open to write, writeright-write
    create (in a directory), removeright-mutate
    lendthe shell's channel: a job lends nothing
    walknothing 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 readStatus
    attach: fid 0 names /d0 ok
    walk to a0 ok
    open a to write2 not permitted
    open a to read0 ok
    create x in /d2 not permitted
    remove a2 not permitted
    walk ../s4 not a path
    lend fid 0 on2 not permitted
    walk s: it is not under /d1 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 typeThe shell says
    wc /nopeno such file: /nope
    wc /sys/timenot 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
    wcrefused: wc's ask is not connected
    wc /shopping > /countthe 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.