CS4411
Practicum in Operating Systems

Project 2: Preemptive Multitasking (FAQ)

Missed Interrupts

I have measuered the time interval between invocations of the clock handler and it's more than the value of PERIOD defined in clock.h. What's going on?

A clock interrupt is only raised when it's "safe" to do so. When the clock timer goes off, indicating a clock interrupt should be raised, a check is made to make sure the currently running thread is executing safe code, which is not part of an NT-supplied library. Since we have no control over what a thread might do in a library, it's risky to interrupt it. For instance, a thread could be interrupted in the middle of a printf(), when it's holding an NT lock. The context-switch might start another thread which also calls printf(), cannot get the lock, and blocks, causing a deadlock.

Preemption and Performance

Why does PortOS run more slowly when preemption is turned on?

Getting user-level threads preemption to work correctly in Windows NT requires some extra kernel threads to trigger clock interrupts and make the interrupt handler run and exit cleanly, which compete for CPU time with the NT kernel thread running the minithreads. Basically, the design of timers in NT makes an efficient implementation difficult.

No Runnable Threads

What do I do if no thread is available to run on a context switch (i.e. all threads are blocked)?

This situation could arise if all the threads in the system are blocked on semaphores or waiting for alarms. The clock interrupt mechanism we have given you assumes that there is always a thread running, ready to take the interrupt. This means that you have to create an "idle thread", which is ready to run if all the other threads are blocked, but does nothing (i.e. runs a function which loops infinitely, or yields infinitely). The idle thread should only run if all other threads are blocked, so it should not go on run queue with all the normal threads, and should never block!

Run-Time Check Failure

I see an error message that reads:

Run-Time Check Failure #2 - Stack around the variable 'name' was corrupted

Is my preemption code broken?

There was a bug in the version of Project 2 that we first released. We've fixed the bug and released a new version on CMS. If you've already gone through the process of merging your code, then you just need to use the new interrupts.c.

Alarms

I put the alarms on the running queue when they fire. What now?

Alarms are callback functions. They are not minithreads, and are called directly from the interrupt handler. They do not create threads, are not threads, and do not go on the run queue.

What is the unit for the delay parameter of register/deregister?

Milliseconds.

What do we use register/deregister for?

User applications will use these functions to schedule callbacks. The deregister function should allow user-level code to request that an alarm registration be cancelled. It should not fire on deregistration.

Semaphores

What is minithread_unlock_and_stop for?

You will need this atomic function for the implementation of semaphores (specifically clearing a lock and stopping a thread in one, indivisible action).

Can I use semaphores within the interrupt handler?

No. This will likely lead to buggy, race-condition-filled code.

Consider what happens if the idle thread takes an interrupt and blocks on a semaphore_P. You may not have other threads to schedule, and so the idle thread would be rescheduled, allowing it into access the critical section anyway.

Scheduling

If I'm in level 0, and I dequeue from level 2, what do I do?

Schedule the thread as if it came from level 0. When it comes time to age (on thread preemption), there are two policies: unconditionally age (e.g. decrease priority of the thread no matter what), or set the priority to the lower priority of (current priority, level + 1).
Powered by Firmant