System call semantics and kernel design
- System call behavior affects kernel data structures
- The relationships between semantics and data structures are fascinating, important, and broadly applicable (e.g. to APIs); OS issues make these relationships clear
Process communication
- Many system calls involve process interactions
- How does a behave with respect to
fork
? - Some system calls refer to shared resources, such as files; processes may interact there
- How does a behave with respect to
- Consider these interactions when designing a system call
Example: getppid
, exit
, waitpid
getppid
returns the parent process ID- Unless the parent process has exited, in which case it returns 1
exit(S)
sets a process’s exit status and marks the process as non-runnablewaitpid(pid, status, options)
blocks until a child process exits, then returns that process’s ID and sets*status
to its exit statuspid == 0
matches any child process- If no matching child process exists, returns
E_CHILD
- If no matching child process has exited and
options == W_NOHANG
, returnsE_AGAIN
- Otherwise, blocks until a matching child process has exited
- It is only possible to wait for a child process once
- A process ID is not reused until
waitpid
has returned the status
Questions
- What bookkeeping structures are required to support these semantics?
- What performance (e.g., computational complexity) ensues from different bookkeeping structures?
- What synchronization is required to access those bookkeeping structures?
- Often a tradeoff between bookkeeping and computational complexity
- Many points on the tradeoff are valid!
- Don’t overbuild!!
Motivating questions
- Support
getppid
/exit
/waitpid
with little additional state - …with efficient operations in terms of computational complexity
- …with minimal storage needs for exited processes
Example: fork
return value
- Consider two possible
fork
semantics - If
fork
successfully creates a new process, then the new process ID…- Is any currently-unused process ID
- Is the smallest available currently-unused process ID
- Consequences?
Example: File-related system calls
-
fd = open(path, oflag, [mode])
-
close(fd)
-
read(fd, buf, siz)
-
write(fd, buf, siz)
-
lseek(fd, off)
-
dup2(oldfd, newfd)
-
[rfd, wfd] = pipe()
-
Console, pipe, disk files all support
read
andwrite
!
Specific and general questions
-
How extensible should the file interface be?
-
Where should this extensibility be implemented?
- In
read
andwrite
? - Somewhere else?
- In
-
Where is the file position stored?
-
Bookkeeping structures?
-
Performance?
-
Synchronization?