Communicating with Input and Output Devices
Polling
What is it?
CPU requests and then waits for data from a device. Constantly checking to see if the data has arrived.
Drawbacks:
– high overhead costly (i/o device slow response time)
– if low probability of movement then wasted work
– difficult to know when to poll
– transfer time – only one word transferred at a time
– does not allow multi tasking (if you are constantly checking)
When is it okay?
– You know when to ask roughly (CPU has no idea how to make a good prediction)
– Or you don’t have to ask very often (you don’t care)
– When asking has very low overhead.
Solution:
Allow CPU and IO controller to work in parallel
Either should be able to access memory
Either should be able to signal the other.
Programmed Input/Output (PIO)
CPU uses PIO to transfer data between the CPU and IO controllers. PIO is initiated by the CPU
Direct Memory Access (DMA)
Controller can access main memory directly, initiated by I/O controller
Interrupts
– Controller can signal the CPU, initiated by the I/O controller
When the CPU is notified by way of an interrupt and then executes the correct Interrupt Service Routine (ISR), would you say this would be a dynamic or static call? Dynamic
Does the compiler know which interrupt will occur? It doesn’t
How would you suggest the execution of the ISR be implemented?
Jump tables
Using PIO, DMA, and Interrupts
PIO makes a request to read data
Controller gets data from device
Controller uses DMA to write data to memory Controller interrupts by signaling CPU
CPU accesses memory
Examples with different expectations
Cell phone incoming network traffic. Mouse in a video game.
Mouse watching a fullscreen movie.
Benefits of using DMA and Interrupts
After the CPU requests to read data, it can continue doing something else. Unlike polling, it doesn’t have to keep checking and waiting for data to become available.
Code example:
Problem:
What happens if there is a large amount of latency loading correct data into buf. The sum will be calculated by reading incorrect values (whatever was on the stack), resulting in incorrect result.
Why does this happen, how does diskRead
complete before the data is stored in memory?
The job of diskRead is just to make the request to read data (i.e. PIO). The actually reading of data and storing in memory is not the job of the CPU but the I/O controller (i.e DMA)
What needs to happen in order to get expected
behavior?
Code is currently written synchronously – has asynchronous behavior – needs synchronization added.
What is an Event? What is an Event Handler? How can they be used to address asynchronous behavior in a program?
Asynchronous execution – steps dependent on asynchronous behaviour (event handler) will only be allowed to continue once the event is complete (Event fired – call event handler)
Event – notification that asynchronous behavior is complete
Handler – is registered with a specific event – a function that will execute after async task is complete (fired)
Steps to fixing the problem
1.
2.
3. Implement event handler, callback function (i.e.
compute sum)
4. Include event handler as an argument to the function with async behavior (ie. disk read call)
Determine where there is asynchronous behavior (i.e. not
sequential)
Separate the blocks of code
When does computeSum run?
ComputeSum does not run until the interrupt occurs
What is wrong with the solution above?
It still does not complete the task of computing the sum and displaying it to the screen
Fix
Add the print statement to computeSum
But what if we wanted to do something else other than print? How do we make our solution more general?
Add a callback function for sum
What is the problem with this approach?
Callback hell – Cascading set of callbacks, everything in the program is waiting for an event to trigger, but no work can get done. This brings us right back to where we started!
What do we do now?
We abstract asynchrony by using threads See you all in 2B
You don’t know when the interrupt will occur so you can’t
assume that the buffer has the data