spin_lock on non-preemtive linux kernels - locking

I read that on a system with 1 CPU and non preemtive linux kernel (2.6.x) a spin_lock call is equivalent to an empty call, and thus implemented that way.
I can't understand that: shouldn't it be equivalent to a sleep on a mutex? Even on non-preemtive kernels interrupt handlers may still be executed for example or I might call a function that would put the original thread to sleep. So it's not true that an empty spin_lock call is "safe" as it would be if it was implemented as a mutex.
Is there something I don't get?

If you were to use spin_lock() on a non-preemptive kernel to shield data against an interrupt handler, you'd deadlock (on a single-processor machine).
If the interrupt handler runs while other kernel code holds the lock, it will spin forever, as there is no way for the regular kernel code to resume and release the lock.
Spinlocks can only be used if the lock holder can always run to completion.
The solution for a lock that might be wanted by an interrupt handler is to use spin_lock_irqsave(), which disables interrupts while the spinlock is held. With 1 cpu, no interrupt handler can run, so there will not be a deadlock. On smp, an interrupt handler might start spinning on another cpu, but since the cpu holding the lock can't be interrupted, the lock will eventually be released.

To answer the two parts of your question:
Even on non-preemtive kernels interrupt handlers may still be executed for example ...
spin_lock() isn't supposed to protect against interrupt handlers - only user context kernel code. spin_lock_irqsave() is the interrupt-disabling version, and this isn't a no-op on a non-preemptive uniprocessor.
...or I might call a function that would put the original thread to sleep.
It is not allowed to sleep while holding a spin lock. This is the "Scheduling while atomic" bug. If you want to sleep, you have to use a mutex instead (again - these aren't a no-op on non-preemptive uniprocessor).

Quoted from «Linux Device Drivers», by Jonathan Corbet, Alessandro Rubini and Greg Kroah-Hartman:
If a nonpreemptive uniprocessor system ever went into a spin on a
lock, it would spin forever; no other thread would ever be able to
obtain the CPU to release the lock (because it couldn't yield).
Because of this, spinlock operations on uniprocessor systems without
preemption enabled are optimized to do nothing, with the exception of
the ones that change the IRQ masking status (in Linux, that would be
spin_lock_irqsave()). Because of preemption, even if you never
expect your code to run on an SMP system, you still need to implement
proper locking.
If you're interested in a spinlock that can be taken by code running in interrupt context (hardware or software), you must use a form of spin_lock_* that disables interrupts. Not doing so will deadlock the system as soon as an interrupt arrives while you have entered your critical section.

By definition, if you're using a non-preemptive kernel, you won't be preempted. If you do your own multitasking, that's not the kernel's problem; that's your problem. Interrupt handlers may still be executed, but they won't cause context switches.

Related

Operating System Basics

I am reading process management,and I have a few doubts-
What is meant by an I/o request,for E.g.-A process is executing and
hence it is in running state,it is in waiting state if it is waiting
for the completion of an I/O request.I am not getting by what is meant by an I/O request,Can you
please give an example to elaborate.
Another doubt is -Lets say that a process is executing and suddenly
an interrupt occurs,then the process stops its execution and will be
put in the ready state,is it possible that some other process began
its execution while the interrupt is also being processed?
Regarding the first question:
A simple way to think about it...
Your computer has lots of components. CPU, Hard Drive, network card, sound card, gpu, etc. All those work in parallel and independent of each other. They are also generally slower than the CPU.
This means that whenever a process makes a call that down the line (on the OS side) ends up communicating with an external device, there is no point for the OS to be stuck waiting for the result since the time it takes for that operation to complete is probably an eternity (in the CPU view point of things).
So, the OS fires up whatever communication the process requested (call it IO request), flags the process as waiting for IO, and switches execution to another process so the CPU can do something useful instead of sitting around blocked waiting for the IO request to complete.
When the external device finishes whatever operation was requested, it generates an interrupt, so the OS is informed the work is done, and it can then flag the blocked process as ready again.
This is all a very simplified view of course, but that's the main idea. It allows the CPU to do useful work instead of waiting for IO requests to complete.
Regarding the second question:
It's tricky, even for single CPU machines, and depends on how the OS handles interrupts.
For code simplicity, a simple OS might for example, whenever an interrupt happens process the interrupt in one go, then resume whatever process it decides it's appropriate whenever the interrupt handling is done. So in this case, no other process would run until the interrupt handling is complete.
In practice, things get a bit more complicated for performance and latency reasons.
If you think about an interrupt lifetime as just another task for the CPU (From when the interrupt starts to the point the OS considers that handling complete), you can effectively code the interrupt handling to run in parallel with other things.
Just think of the interrupt as notification for the OS to start another task (that interrupt handling). It grabs whatever context it needs at the point the interrupt started, then keeps processing that task in parallel with other processes.
I/O request generally just means request to do either Input , Output or both. The exact meaning varies depending on your context like HTTP, Networks, Console Ops, or may be some process in the CPU.
A process is waiting for IO: Say for example you were writing a program in C to accept user's name on command line, and then would like to print 'Hello User' back. Your code will go into waiting state until user enters their name and hits Enter. This is a higher level example, but even on a very low level process executing in your computer's processor works on same basic principle
Can Processor work on other processes when current is interrupted and waiting on something? Yes! You better hope it does. Thats what scheduling algorithms and stacks are for. However the real answer depending on what Architecture you are on, does it support parallel or serial processing etc.

Control Flags in Interrupt Routine and NMI [8086]

I know how an interrupt routine is executed in 8086. The thing that isn't clear to me is how different types of interrupts (i.e hardware, software and exception) uses the control flags (Interrupt Flag and Trap Flag) in their execution.
And other thing is what is Non-mask-able Interrupts and its use?
So please help me with this, Thanks.
An interrupt handler doesn't "do" anything with the IF and TF flags. They are cleared so the interrupt handler can do its job properly and safely. You need to understand what those flags do, then it becomes obvious why they are cleared during an interrupt.
When the Interrupt Flag or IF is set, the processor will allow external hardware signals (usually from a Programmable Interrupt Controller or PIC) to trigger interrupts. When it's cleared, hardware interrupt signals are ignored.
(The NMI or Non-Maskable Interrupt is an exception, a special case intended for "emergency-type" or "real-time" events, and it will trigger even if the IF is cleared.)
The Trap Flag or TF is used by debuggers. When the flag is set, the processor will execute exactly one instruction, then trigger an INT 1. A debugger can use this to single-step machine code without having to temporarily modify it (e.g. to temporarily insert an INT 3 instruction), which is not always even possible (e.g. single-stepping code stored in ROM).
Now why are both flags cleared during interrupts?
The IF is cleared because Intel didn't want to impose the restriction that interrupt handlers be reentrant. Reentrant code is code that can be safely suspended at any time, and called again from the top. If you allow interrupts while an interrupt handler is running, it is quite possible for a second interrupt to trigger while in the middle of handling the first one, which would cause the handle to re-enter. Note that software interrupt handlers (like the DOS interrupt handler 21h) typically don't have this concern because they are not called by asynchronous hardware signals; therefore, just about the first thing they do is execute STI to re-enable interrupts.
The situation with TF is very similar but a bit trickier to understand. I don't have experience writing an x86 debugger, so I don't know the ins-and outs. The short version is that the TF is cleared during interrupts to avoid chaos. What follows is a speculative excercise of mine.
First of all, it should be obvious that at least the single-step interrupt (type-1 or INT 1 if you will) MUST clear the flag, otherwise the debugger's single-step handler itself would trigger single-step interrupts or not run at all. Second, let's imagine that the TF is not cleared for every interrupt: if a hardware interrupt triggers while the debugger is trying to use the TF, the interrupt handler itself might be the one triggering the single-step interrupt, instead of the code being debugged. Worse, now the interrupts are suspended (see IF above) and not only are you looking at the wrong code (or thoroughly confused the debugger), but your keyboard doesn't work anymore. (As I said, I'm speculating: I have no idea what happens if IF is cleared but TF is set).
Asynchronous hardware interrupts need to be handled without "bothering" the current running program, that is, they need to execute without the program being aware of them. That includes "not bothering" a single-stepping debugger.

How does the operating system handle its responsibilities while a process is executing?

I had this question in mind from long time and may sound little vacuous. We know that operating system is responsible for handling memory allocation, process management etc. CPU can perform only one task at a time(assuming it to be single core). Suppose an operating system has allocated a CPU cycle to some user initiated process and CPU is executing that. Now where is operating system running? If some other process is using the CPU, then, is operating system not running for that moment? as OS itself must need CPU to run. If in case OS is not running, then who is handling process management, device management etc for that period?
The question is mixing up who's in control of the memory and who's in control of the CPU. The wording “running” is imprecise: on a single CPU, a single task is running at any given time in the sense that the processor is executing its instructions; but many tasks are executing in the sense that their state is stored in memory and their execution can resume at any time.
While a process is executing on the CPU, the kernel is not executing. Its state is saved in memory. The execution of the kernel can resume:
if the process code makes a jump into kernel code — this is called a system call.
if an interrupt occurs.
If the operating system provides preemptive multitasking, it will schedule an interrupt to happen after an interval of time (called a time slice). On a non-preemptive operating system, the process will run forever if it doesn't yield the CPU. See What mechanisms prevent a process from taking over the processor forever? for an explanation of how preemption works.
Tasks such as process management and device management are triggered by some event. If the event is a request by the process, the request will take the form of a system call, which executes kernel code. If the event is triggered from hardware, it will take the form of an interrupt, which executes kernel code.
(Note: in this answer, I use “CPU” and “processor” synonymously, to mean a single execution thread: a single core, or whatever the hardware architecture is.)
The OS kernel does nothing at all until it is entered via an interrupt. It may be entered because of a hardware interrupt that causes a driver to run and the driver chooses to exit via the OS, or a running thread may make a syscall interrupt.
Unless an interrupt occurs, the OS kernel does nothing at all. It does not need to do anything.
Edit:
DMA is, (usually), used for bulk I/O and is handled by a hardware subsystem that handles requests issued by a system call, (software interrupt). When a DMA operation is complete, the DMA hardware raises a hardware interrupt, so running a driver that can further signal the OS of the completion, maybe changing the set of running threads, so DMA is managed by interrupts.
A new process/thread can only be loaded by an existing thread that has issued a system call, (software interrupt), and so new processes are initiated by interrupts.
It's interrupts, all the way down :)
It depends on which type of CPU Scheduling you are using : (in case of single core)
if your process is executing with preemptive scheduling then you can interrupt the process in between for some time duration and you can use the CPU for some other Process or O.S. but in case of Non-Preemptive Scheduling process is not going to yield the CPU before completing there execution.
In case of single Core, if there is a single process then it will execute with given instruction and if there are multiple process then states stored in the PCB. which make process queue and execute one after another, if no interrupts occur.
PCB is responsible for any process management.
when a process initialize it calls to Library function that's System calls and execution of Kernel get invoke if some process get failed during execution or interrupt occur.

Linux Kernel Code Execution Contexts

When a process executing in the user space issues a system call or triggers an exception, it enters into the kernel space and kernel starts executing on behalf of the process. Kernel is said to be executing in the process context. Similarly when an interrupt occurs kernel executes in the interrupt context. I have studied about kernel execution in kernel thread, where kernel processes runs in the background.
My Questions are :
Does the kernel execute in any other contexts?
Suppose a process in the user space never executes a system call or triggers an exception or no interrupt occurs, does the kernel code ever execute ?
The kernel runs periodically, it sets a timer to fire an interrupt at some predefined frequency (100 Hz (Linux 2.4/x86), 1000Hz (early Linux 2.6/x86), 250Hz (newer Linux 2.6/x86)).
The kernel need to do this in order to do preemptive multitasking. OTOH, OSes only doing cooperative multitasking (Windows 3.1, classic Mac OS) needn't do this, and only switch tasks on response to some call from the running task (which could lead to runaway tasks hanging the whole system).
Note that there is some effort to optimize the use of this timer: newer Linux is smarter when there are no runnable tasks, it sets the timer as far in the future as it can, to allow the CPU to sleep longer and deeper, and preserve power (the CONFIG_NOHZ kernel config option). Running powertop will show the number of wakeups per second, which on an idle system can be much lower than the 250 wakeups per second you'd expect of a traditional implementation.
Suppose a process in the user space never executes a system call or triggers an exception or no interrupt occurs, does the kernel code ever execute ?
Assume you have a process p that is running the following code: while(1);. This code will never call into the kernel and won't cause any faults. (It might have set an alarm(3) earlier, causing a signal to be delivered in the future, or it might exceed the setrlimit(2) CPU limit, in which cases the kernel will deliver a signal to the process.)
Or, if another process sends p a signal via kill(2), the kernel will deliver that signal to the process as well.
The signal delivery will either cause a signal handler to run, do nothing (if the signal is ignored or masked), or take the default signal action (which might be nothing or termination).
And, of course, the process execution can be interrupted so the processor can handle interrupts; or a higher-priority process can preempt it.

Which Cortex-M3 interrupts can I use for general purpose work?

I'd have some code that needs to be run as the result of a particular interrupt going off.
I don't want to execute it in the context of the interrupt itself but I also don't want it to execute in thread mode.
I would like to run it at a priority that's lower than the high level interrupt that precipitated its running but also a priority that higher than thread level (and some other interrupts as well).
I think I need to use one of the other interrupt handlers.
Which ones are the best to use and what the best way to invoke them?
At the moment I'm planning on just using the interrupt handlers for some peripherals that I'm not using and invoking them by setting bits directly through the NVIC but I was hoping there's a better, more official way.
Thanks,
ARM Cortex supports a very special kind of exception called PendSV. It seems that you could use this exception exactly to do your work. Virtually all preemptive RTOSes for ARM Cortex use PendSV to implement the context switch.
To make it work, you need to prioritize PendSV low (write 0xFF to the PRI_14 register in the NVIC). You should also prioritize all IRQs above the PendSV (write lower numbers in the respective priority registers in the NVIC). When you are ready to process the whole message, trigger the PendSV from the high-priority ISR:
*((uint32_t volatile *)0xE000ED04) = 0x10000000; // trigger PendSV
The ARM Cortex CPU will then finish your ISR and all other ISRs that possibly were preempted by it, and eventually it will tail-chain to the PendSV exception. This is where your code for parsing the message should be.
Please note that PendSV could be preempted by other ISRs. This is all fine, but you need to obviously remember to protect all shared resources by a critical section of code (briefly disabling and enabling interrupts). In ARM Cortex, you disable interrupts by executing __asm("cpsid i") and you enable interrupts by __asm("cpsie i"). (Most C compilers provide built-in intrinsic functions or macros for this purpose.)
Are you using an RTOS? Generally this type of thing would be handled by having a high priority thread that gets signaled to do some work by the interrupt.
If you're not using an RTOS, you only have a few tasks, and the work being kicked off by the interrupt isn't too resource intensive, it might be simplest having your high priority work done in the context of the interrupt handler. If those conditions don't hold, then implementing what you're talking about would be the start of a basic multitasking OS itself. That can be an interesting project in its own right, but if you're looking to just get work done, you might want to consider a simple RTOS.
Since you mentioned some specifics about the work you're doing, here's an overview of how I've handled a similar problem in the past:
For handling received data over a UART one method that I've used when dealing with a simpler system that doesn't have full support for tasking (ie., the tasks are round-robined i na simple while loop) is to have a shared queue for data that's received from the UART. When a UART interrupt fires, the data is read from the UART's RDR (Receive Data Register) and placed in the queue. The trick to deal with this in such a way that the queue pointers aren't corrupted is to carefully make the queue pointers volatile, and make certain that only the interrupt handler modifies the tail pointer and that only the 'foreground' task that's reading data off the queue modified the head pointer. A high-level overview:
producer (the UART interrupt handler):
read queue.head and queue.tail into locals;
increment the local tail pointer (not the actual queue.tail pointer). Wrap it to the start of the queue buffer if you've incremented past the end of the queue's buffer.
compare local.tail and local.head - if they're equal, the queue is full, and you'll have to do whatever error handing is appropriate.
otherwise you can write the new data to where local.tail points
only now can you set queue.tail == local.tail
return from the interrupt (or handle other UART related tasks, if appropriate, like reading from a transmit queue)
consumer (the foreground 'task')
read queue.head and queue.tail into locals;
if local.head == local.tail the queue is empty; return to let the next task do some work
read the byte pointed to by local.head
increment local.head and wrap it if necessary;
set queue.head = local.head
goto step 1
Make sure that queue.head and queue.tail are volatile (or write these bits in assembly) to make sure there are no sequencing issues.
Now just make sure that your UART received data queue is large enough that it'll hold all the bytes that could be received before the foreground task gets a chance to run. The foreground task needs to pull the data off the queue into it's own buffers to build up the messages to give to the 'message processor' task.
What you are asking for is pretty straightforward on the Cortex-M3. You need to enable the STIR register so you can trigger the low priority ISR with software. When the high-priority ISR gets done with the critical stuff, it just triggers the low priority interrupt and exits. The NVIC will then tail-chain to the low-priority handler, if there is nothing more important going on.
The "more official way" or rather the conventional method is to use a priority based preemptive multi-tasking scheduler and the 'deferred interrupt handler' pattern.
Check your processor documentation. Some processors will interrupt if you write the bit that you normally have to clear inside the interrupt. I am presently using a SiLabs c8051F344 and in the spec sheet section 9.3.1:
"Software can simulate an interrupt by setting any interrupt-pending flag to logic 1. If interrupts are enabled for the flag, an interrupt request will be generated and the CPU will vector to the ISR address associated with the interrupt-pending flag."