0
votes

I have the following "pretend" implementation of a semaphore's wait() operation. Assume a single core, single processor environement:

wait () { 
 Disable interrupts
 sem->value--
 if (sem->value < 0) {
 save_state (current) ; //"Manually" save the context of the current running process
 State[current] = Blocked; //Block it
 Queue current to block queue;
 current = Select from the ready queue; //Select another process to run
 State[current] = Running; //Put the retrieved process in the running state
 restore_state (current); //"Manually" restore the context of the new process
 }
 Enable interrupts
}

The implementation is to test our knowledge on disabling interrupts to protect the critical section. One of the questions is to determine whether the new process that is selected from the ready queue in wait() runs while interrupts are disabled or after they are enabled.

I'm struggling with the answer as I see it in two ways.

  • (Obvious answer): The process is allowed to run while interrupts are disabled since clearly this is what the code is intended to do. But I have my doubts...
  • When interrupts are disabled the kernel is not aware of any changes made to the running state/blocked state. The register and other resource allocations can only be done after interrupts have been enabled.

Any tips would be greatly appreciated.

1

1 Answers

0
votes

If a process/thread is able to run with interrupts disabled, then that process/thread is able to prevent the operating system from interrupting it, and therefore able to hog all CPU time, and can therefore be an unstoppable malicious denial of service attack.

For some CPUs under some conditions (e.g. 80x86 with IOPL set to 3) it is possible for an OS to allow a process/thread to disable IRQs, and is possible to let a process/thread run with IRQs disabled but without the ability to enable/disable IRQs (e.g. disable IRQs in the kernel just before returning to user-space); but because they're security disasters very few operating systems will allow either.

However; semaphores also involve interaction with the scheduler (blocking a task until it can acquire the semaphore, and unblocking a task when it can acquire the semaphore), and the scheduler (its "ready to run" queues, processs/thread states, etc) and the ability to access the full process/thread's state (e.g. special "kernel only" registers, like whichever register controls which virtual address space is currently selected) are also typically only accessible from kernel's code (and not allowed to be accessed from user-space, by a process/thread).

In other words; it's reasonable (ignoring bizarre and unlikely cases) to assume that over 50% of the code in your wait() function can not be implemented in user-space and must be implemented in the kernel; and therefore it's reasonable to assume that your wait() function is intended to be implemented in the kernel (and not intended to be implemented in user-space, by a process or thread).