Plan 9 System Calls
The sys
package, when compiled for Plan 9, contained an interface to the
Plan 9 system calls. This list is more or less complete.
Summary
Overall, this documentation will not attempt to summarize the full behavior of the system calls, but will instead attempt to highlight where system calls diverge from the libc interfaces, which are documented in section 2 of the system manpages.
Unlike the Posixy systems, Plan 9 does return -1 directly from the kernel,
and for error checking, the result of the errstr
system call must be
inspected, just like when writing C.
The most notable divergence is that short zero terminated strings strings such
as file names are wrapped up as a byte[:]
, but are generally converted to
strings on the stack before being passed to the kernel. Long buffers that are
exposed to C as a char* buf, size_t len
pair are exposed to Myrddin code as
simply accepting a byte[:].
Exported Symbols
pkg sys =
type scno = int64 /* syscall */
type pid = int32 /* process id */
type fdopt = int32 /* fd options */
type fd = int32 /* fd */
type rflags = int32 /* rfork flags */
type tos = struct
prof : prof
cyclefreq : uint64
kcycles : int64
pcycles : int64
pid : pid
clock : uint32
;;
type prof = struct
pp : byte# /* plink */
next : byte# /* plink */
last : byte# /* plink */
first : byte# /* plink */
pid : pid /* plink */
what : uint32 /* plink */
;;
const Maxerr : size = 128
const Ordonly : fdopt = 0
const Owronly : fdopt = 1
const Ordwr : fdopt = 2
const Oexec : fdopt = 3
const Otrunc : fdopt = 16
const Ocexec : fdopt = 32
const Orclose : fdopt = 64
const Oexcl : fdopt = 0x1000
const Qtdir : int = 0x80
const Qtappend : int = 0x40
const Qtexcl : int = 0x20
const Qtmount : int = 0x10
const Qtauth : int = 0x08
const Qttmp : int = 0x04
const Qtfile : int = 0x00
const Dmdir : int = 0x8000000
const Dmappend : int = 0x4000000
const Dmexcl : int = 0x2000000
const Dmmount : int = 0x1000000
const Dmauth : int = 0x0800000
const Dmtmp : int = 0x0400000
const Dmread : int = 0x4
const Dmwrite : int = 0x2
const Dmexec : int = 0x1
const Rfnameg : rflags = 1 << 0
const Rfenvg : rflags = 1 << 1
const Rffdg : rflags = 1 << 2
const Rfnoteg : rflags = 1 << 3
const Rfproc : rflags = 1 << 4
const Rfmem : rflags = 1 << 5
const Rfnowait : rflags = 1 << 6
const Rfcnameg : rflags = 1 << 10
const Rfcenvg : rflags = 1 << 11
const Rfcfdg : rflags = 1 << 12
const Rfrend : rflags = 1 << 13
const Rfnomnt : rflags = 1 << 14
const Syssysr1 : scno = 0
const Sys_errstr : scno = 1
const Sysbind : scno = 2
const Syschdir : scno = 3
const Sysclose : scno = 4
const Sysdup : scno = 5
const Sysalarm : scno = 6
const Sysexec : scno = 7
const Sysexits : scno = 8
const Sys_fsession : scno = 9
const Sysfauth : scno = 10
const Sys_fstat : scno = 11
const Syssegbrk : scno = 12
const Sys_mount : scno = 13
const Sysopen : scno = 14
const Sys_read : scno = 15
const Sysoseek : scno = 16
const Syssleep : scno = 17
const Sys_stat : scno = 18
const Sysrfork : scno = 19
const Sys_write : scno = 20
const Syspipe : scno = 21
const Syscreate : scno = 22
const Sysfd2path : scno = 23
const Sysbrk_ : scno = 24
const Sysremove : scno = 25
const Sys_wstat : scno = 26
const Sys_fwstat : scno = 27
const Sysnotify : scno = 28
const Sysnoted : scno = 29
const Syssegattach : scno = 30
const Syssegdetach : scno = 31
const Syssegfree : scno = 32
const Syssegflush : scno = 33
const Sysrendezvous : scno = 34
const Sysunmount : scno = 35
const Sys_wait : scno = 36
const Syssemacquire : scno = 37
const Syssemrelease : scno = 38
const Sysseek : scno = 39
const Sysfversion : scno = 40
const Syserrstr : scno = 41
const Sysstat : scno = 42
const Sysfstat : scno = 43
const Syswstat : scno = 44
const Sysfwstat : scno = 45
const Sysmount : scno = 46
const Sysawait : scno = 47
const Syspread : scno = 50
const Syspwrite : scno = 51
const Systsemacquire : scno = 52
const Sys_nsec : scno = 53
const sysr1 : (-> int64)
const bind : (nm : byte[:], old : byte[:] -> int64)
const chdir : (dir : byte[:] -> int64)
const close : (fd : fd -> int64)
const dup : (old : fd, new : fd -> fd)
const alarm : (msec : uint32 -> int64)
const exits : (msg : byte[:] -> int64)
const fauth : (fd : fd, name : byte[:] -> int64)
const segbrk : (saddr : void#, addr : void# -> int64)
const open : (path : byte[:], opt : fdopt -> fd)
const sleep : (msec : uint32 -> int64)
const rfork : (rflags : rflags -> pid)
const pipe : (fds : fd[2]# -> int64)
const create : (path : byte[:], opt : fdopt, perm : int -> fd)
const fd2path : (fd : fd, path : byte[:] -> int64)
const remove : (path : byte[:] -> int64)
const notify : (fn : (a : void#, c : char# -> int64) -> int64)
const noted : (v : int32 -> int64)
const segattach : (attr : int32, class : byte[:], va : void#, len : uint32 -> int64)
const segdetach : (va : void# -> int64)
const segfree : (va : byte#, len : size -> int64)
const segflush : (va : void#, len : uint32 -> int64)
const unmount : (name : byte[:], old : byte[:] -> int64)
const errstr : (buf : byte[:] -> int64)
const stat : (name : byte[:], edir : byte[:] -> int64)
const fstat : (fd : fd, edir : byte[:] -> int64)
const wstat : (name : byte[:], edir : byte[:] -> int64)
const fwstat : (fd : byte[:], edir : byte[:] -> int64)
const seek : (fd : fd, len : off, ty : int64 -> off)
const mount : (fd : fd, afd : fd, old : byte[:], flag : int32, aname : byte[:] -> int64)
const await : (buf : byte[:] -> int64)
const pread : (fd : fd, buf : byte[:], off : off -> size)
const pwrite : (fd : fd, buf : byte[:], off : off -> size)
const exec : (bin : byte[:], args : byte[:][:] -> int64)
const brk_ : (endp : byte# -> int64)
const nsec : (-> uint64)
extern const alloca : (sz : size -> byte#)
extern var tosptr : tos#
extern var curbrk : byte#
;;
/* asm stub from syscall.s */
extern const syscall : (scno : scno, args : ... -> int64)
/* asm stubs from util+plan9.s */
extern const cstring : (str : byte[:] -> byte#)
extern const alloca : (sz : size -> byte#)
/*
ABI mismatch: Plan 9 aligns all arguments individually to
8 bytes, Myrddin uses natural alignment (min(sizeof(t), 16).
Cast to a 64 bit type to paper over this.
*/
generic a = {a : @t; -> a castto(uint64)}
generic s = {a : @t; -> a castto(int64)}
generic p = {a : @t; -> a castto(byte#)}
const sysr1 = {; -> syscall(Syssysr1)}
const bind = {name, old; -> syscall(Sysbind, cstring(name), cstring(old))}
const chdir = {dir; -> syscall(Syschdir, cstring(dir)) }
const close = {fd; -> syscall(Sysclose, a(fd))}
const dup = {ofd, nfd; -> syscall(Sysdup, a(ofd), a(nfd)) castto(fd)}
const alarm = {msec; -> syscall(Sysalarm, a(msec))}
const exits = {msg; -> syscall(Sysexits, cstring(msg))}
const fauth = {fd, aname; -> syscall(Sysfauth, a(fd), cstring(aname))}
const segbrk = {saddr, addr; -> syscall(Syssegbrk, a(saddr), a(addr))}
const open = {path, opt; -> syscall(Sysopen, cstring(path), a(opt)) castto(fd)}
const sleep = {msec; -> syscall(Syssleep, a(msec))}
const rfork = {rflags; -> syscall(Sysrfork, a(rflags)) castto(pid)}
const pipe = {fds; -> syscall(Syspipe, a(fds))}
const create = {path, mode, perm; -> syscall(Syscreate, cstring(path), a(mode), a(perm)) castto(fd)}
const fd2path = {fd, buf; -> syscall(Sysfd2path, a(fd), p(buf), a(buf.len))}
const remove = {path; -> syscall(Sysremove, cstring(path))}
const notify = {fn; -> syscall(Sysnotify, fn)} /* FIXME: this is likely to break when we do closures... */
const noted = {v; -> syscall(Sysnoted, a(v))}
const segattach = {attr, class, va, len; -> syscall(Syssegattach, a(attr), cstring(class), a(va), a(len))}
const segdetach = {va; -> syscall(Syssegdetach, a(va))}
const segfree = {va, len; -> syscall(Syssegfree, a(va), a(len))}
const segflush = {va, len; -> syscall(Syssegfree, a(va), a(len))}
const unmount = {name, old; -> syscall(Sysunmount, cstring(name), cstring(old))}
const errstr = {buf; -> syscall(Syserrstr, p(buf), a(buf.len))}
const stat = {name, edir; -> syscall(Sysstat, cstring(name), p(edir), a(edir.len))}
const fstat = {fd, edir; -> syscall(Sysstat, a(fd), p(edir), a(edir.len))}
const wstat = {name, edir; -> syscall(Syswstat, cstring(name), p(edir), a(edir.len))}
const fwstat = {fd, edir; -> syscall(Sysfwstat, a(fd), p(edir), a(edir.len))}
const mount = {fd, afd, old, flag, aname; -> syscall(Sysmount, a(fd), a(afd), cstring(old), a(flag), cstring(aname))}
const pread = {fd, buf, off; -> syscall(Syspread, a(fd), p(buf), a(buf.len), off) castto(size)}
const pwrite = {fd, buf, off; -> syscall(Syspwrite, a(fd), p(buf), a(buf.len), s(off)) castto(size)}
const await = {buf; -> syscall(Sysawait, p(buf), a(buf.len))}
const brk_ = {endp; -> syscall(Sysbrk_, p(endp))}
const nsec = {; -> syscall(Sys_nsec) castto(uint64)}
const seek = {fd, n, ty
var ret : off
syscall(Sysseek, a(&ret), a(fd), a(n), a(ty))
-> ret
}
const exec = {bin, args
var p, cargs, i
/* we need an array of C strings. */
p = alloca((args.len + 1)*sizeof(byte#))
cargs = (a(p) castto(byte##))[:args.len + 1]
for i = 0; i < args.len; i++
cargs[i] = cstring(args[i])
;;
cargs[args.len] = 0 castto(byte#)
-> syscall(Sysexec, cstring(bin), a(cargs))
}