Placeholder Image

字幕表 動画を再生する

  • When a user-mode program wants to read a typed character it executes a ReadKey() SVC.

  • The binary representation of the SVC has an illegal value in the opcode field, so the

  • CPU hardware causes an exception, which starts executing the illegal opcode handler in the

  • OS.

  • The OS handler recognizes the illegal opcode value as being an SVC and uses the low-order

  • bits of the SVC instruction to determine which sub-handler to call.

  • Here's our first draft for the ReadKey sub-handler, this time written in C.

  • The handler starts by looking at the process table entry for the current process to determine

  • which keyboard buffer holds the characters for the process.

  • Let's assume for the moment the buffer is *not* empty and skip to the last line,

  • which reads the character from the buffer and uses it to replace the saved value for

  • the user's R0 in the array holding the saved register values.

  • When the handler exits, the OS will reload the saved registers and resume execution of

  • the user-mode program with the just-read character in R0.

  • Now let's figure what to do when the keyboard buffer is empty.

  • The code shown here simply loops until the buffer is no longer empty.

  • The theory is that eventually the user will type a character, causing an interrupt,

  • which will run the keyboard interrupt handler discussed in the previous section, which will

  • store a new character into the buffer.

  • This all sounds good until we remember that the SVC handler is running with the supervisor

  • bit (PC[31]) set to 1, disabling interrupts.

  • Oops!

  • Since the keyboard interrupt will never happen, the while loop shown here is actually an infinite

  • loop.

  • So if the user-mode program tries to read a character from an empty buffer, the system

  • will appear to hang, not responding to any external inputs since interrupts are disabled.

  • Time to reach for the power switch :) We'll fix the looping problem by adding code

  • to subtract 4 from the saved value of the XP register before returning.

  • How does this fix the problem?

  • Recall that when the SVC illegal instruction exception happened, the CPU stored the PC+4

  • value of the illegal instruction in the user's XP register.

  • When the handler exits, the OS will resume execution of the user-mode program by reloading

  • the registers and then executing a JMP(XP), which would normally then execute the instruction

  • *following* the SVC instruction.

  • By subtracting 4 from the saved XP value, it will be the SVC itself that gets re-executed.

  • That, of course, means we'll go through the same set of steps again, repeating the cycle

  • until the keyboard buffer is no longer empty.

  • It's just a more complicated loop!

  • But with a crucial difference: one of the instructions - the ReadKey() SVC - is executed

  • in user-mode with PC[31] = 0.

  • So during that cycle, if there's a pending interrupt from the keyboard, the device interrupt

  • will supersede the execution of the ReadKey() and the keyboard buffer will be filled.

  • When the keyboard interrupt handler finishes, the ReadKey() SVC will be executed again,

  • this time finding that the buffer is no longer empty.

  • Yah!

  • So this version of the handler actually works, with one small caveat.

  • If the buffer is empty, the user-mode program will continually re-execute the complicated

  • user-mode/kernel-mode loop until the timer interrupt eventually transfers control to

  • the next process.

  • This seems pretty inefficient.

  • Once we've checked and found the buffer empty, it would be better to give other processes

  • a chance to run before we try again.

  • This problem is easy to fix!

  • We'll just add a call to Scheduler() right after arranging for the ReadKey() SVC to be

  • re-executed.

  • The call to Scheduler() suspends execution of the current process and arranges for the

  • next process to run when the handler exits.

  • Eventually the round-robin scheduling will come back to the current process and the ReadKey()

  • SVC will try again.

  • With this simple one-line fix the system will spend much less time wasting cycles checking

  • the empty buffer and instead use those cycles to run other, hopefully more productive, processes.

  • The cost is a small delay in restarting the program after a character is typed,

  • but typically the time slices for each process are small enough that one round of process

  • execution happens more quickly than the time between two typed characters, so the extra

  • delay isn't noticeable.

  • So now we have some insights into one of the traditional arguments against timesharing.

  • The argument goes as follows.

  • Suppose we have 10 processes, each of which takes 1 second to complete its computation.

  • Without timesharing, the first process would be done after 1 second, the second after 2

  • seconds, and so on.

  • With timesharing using, say, a 1/10 second time slice, all the processes will complete

  • sometime after 10 seconds since there's a little extra time needed for

  • the hundred or so process switches that would happen before completion.

  • So in a timesharing system the time-to-completion for *all* processes is as long the worst-case

  • completion time without time sharing!

  • So why bother with timesharing?

  • We saw one answer to this question earlier in this slide.

  • If a process can't make productive use of its time slice, it can donate those cycles

  • to completion of some other task.

  • So in a system where most processes are waiting for some sort of I/O, timesharing is actually

  • a great way of spending cycles where they'll do the most good.

  • If you open the Task Manager or Activity Monitor on the system you're using now, you'll see

  • there are hundreds of processes, almost all of which are in some sort of I/O wait.

  • So timesharing does extract a cost when running compute-intensive computations, but in an

  • actual system where there's a mix of I/O and compute tasks, time sharing is the way to

  • go.

  • We can actually go one step further to ensure we don't run processes waiting for an I/O

  • event that hasn't yet happened.

  • We'll add a status field to the process state indicating whether the process is ACTIVE (e.g.,

  • status is 0) or WAITING (e.g., status is non-zero).

  • We'll use different non-zero values to indicate what event the process is waiting for.

  • Then we'll change the Scheduler() to only run ACTIVE processes.

  • To see how this works, it's easiest to use a concrete example.

  • The UNIX OS has two kernel subroutines, sleep() and wakeup(), both of which require a non-zero

  • argument.

  • The argument will be used as the value of the status field.

  • Let's see this in action.

  • When the ReadKey() SVC detects the buffer is empty, it calls sleep() with an argument

  • that uniquely identifies the I/O event it's waiting for, in this case the arrival of a

  • character in a particular buffer.

  • sleep() sets the process status to this unique identifier, then calls Scheduler().

  • Scheduler() has been modified to skip over processes with a non-zero status, not giving

  • them a chance to run.

  • Meanwhile, a keyboard interrupt will cause the interrupt handler to add a character to

  • the keyboard buffer and call wakeup() to signal any process waiting on that buffer.

  • Watch what happens when the kbdnum in the interrupt handler matches the kbdnum in the

  • ReadKey() handler.

  • wakeup() loops through all processes, looking for ones that are waiting for this particular

  • I/O event.

  • When it finds one, it sets the status for the process to zero, marking it as ACTIVE.

  • The zero status will cause the process to run again next time the Scheduler() reaches

  • it in its round-robin search for things to do.

  • The effect is that once a process goes to sleep() WAITING for an event, it's not considered

  • for execution again until the event occurs and wakeup() marks the process as ACTIVE.

  • Pretty neat!

  • Another elegant fix to ensure that no CPU cycles are wasted on useless activity.

  • I can remember how impressed I was when I first saw this many years ago in a (very)

  • early version of the UNIX code :)

When a user-mode program wants to read a typed character it executes a ReadKey() SVC.

字幕と単語

ワンタップで英和辞典検索 単語をクリックすると、意味が表示されます

B1 中級

18.2.2 入出力用SVC (18.2.2 SVCs for Input/Output)

  • 1 0
    林宜悉 に公開 2021 年 01 月 14 日
動画の中の単語