110 likes | 228 Views
The Structuring of Systems Using Upcalls. Paper by David D. Clark Presentation by Emerson Murphy-Hill. Objectives. Build Swift operating system Develop and describe layered OS methodology that is: Supportive of highly interactive, parallel execution Based on layered network protocols
E N D
The Structuring of Systems Using Upcalls Paper by David D. Clark Presentation by Emerson Murphy-Hill
Objectives • Build Swift operating system • Develop and describe layered OS methodology that is: • Supportive of highly interactive, parallel execution • Based on layered network protocols • Coherent and easily readable • Simple, short, and efficient
Synchronized process calls (IPC) Processes Slow! Interprocess (intermodule?) Communication Fast! Multitask modules (layers) Subroutine Calls Interprocess Communication Tasks General Architecture Standard Layers (Dijkstra) Swift
Layers / Multitask Modules • Each layer is an encapsulated module: • Private state • Accessible only through subroutine calls • A layer “depends on” the layer below • A layer is a coherent piece of functionality • Layer “instance of” multitask module (analogously – object instance of class)
Call Direction • Typically down through layers (example: send data) • Can be upcall (example: more data?), but: • Do nice testing properties remain? • What are the semantics of the relationship of a lower to an upper layer? • What about recursion?
display-start(): local-port = transport-open(display-receive) end display-receive(char) : //write char to display end Display Layer transport-open(receive-handler): local-port = net-open (transport-receive) transport-handler-array (local-port)=receive-handler return(localport) end transport-get-port(packet): //upcalled by interruptlayer extract port from packet return(port) end transport-receive(packet,port): //upcalled by net-layer handler=transport-handler-array(port) validate packet header for,each char in packet do handler(char) end Transport Layer net-open(receive-handler): port=generate-uid() task-id = create-task( net-receive( port, receive-handler)) net-task-array(port)=task-ld return(port) end net-receive(port,handler): handler=net-handler-array(port) do forever remove packet from port queue handler(packet,port) block() end end net-dispatch(): //upcalled by interrupt handler read packet from device restart device port = transport-get-port(packet) put packet on per port queue task-id = net-task-array(port) wakeup-task(task-ld) end Net Layer transport_handler_array[p] = {display-receive} net_task_array[p] = {net-receive(p,transport_receive)}
display-start(): local-port = transport-open(display-receive) end display-receive(char) : //write char to display end transport-open(receive-handler): local-port = net-open (transport-receive) transport-handler-array (local-port)=receive-handler return(localport) end transport-get-port(packet): //upcalled by interruptlayer extract port from packet return(port) end transport-receive(packet,port): //upcalled by net-layer handler=transport-handler-array(port) validate packet header for,each char in packet do handler(char) end net-open(receive-handler): port=generate-uid() task-id = create-task( net-receive( port, receive-handler)) net-task-array(port)=task-ld return(port) end net-receive(port,handler): handler=net-handler-array(port)? do forever remove packet from port queue handler(packet,port) block() end end net-dispatch(): //upcalled by interrupt handler read packet from device restart device port = transport-get-port(packet) put packet on per port queue task-id = net-task-array(port) wakeup-task(task-ld) end transport_handler_array[p] = {display-receive} net_task_array[p] = {net-receive(p,transport_receive)}
Advantages of Methodology • Generally, layers have low-coupling • Uses subroutine calls: • Substantially cheaper than IPC / RPC (no context switching or message queue management) • Preserves traditional programming semantics • Fast! • No need to implement communication protocol • Best suited towards interactive and network-based systems
Encountered Problems • Local upcall failure. Control propagation through: • Partitioning/recover data • Destroy task stripe • Indirect recursive calls corrupt state. Solutions: • Completely reevaluate state on return (expensive/clumsy) • Prohibit recursive downcall while doing upcall (runtime only) • Locking problems • Solution: queue work on recursive lock conflict (not implemented) • Not easy to impose locking discipline
Other Features • Task Scheduling • Dynamic priority based on deadline • Deadline promotion • Address Space Management • Compile/runtime checking for pointers, etc • Garbage collection
Conclusion • Layers with upcalls are suitable for “a large class of programming problems” – if you have good programmers! • Layers implemented as: • processes are bad • multitask modules are good (fast and simple)