The following code snippet demonstrates the per-CPU data structure problem, in an SMP system:
int arr[NR_CPUS];
arr[smp_processor_id()] = i;
/* kernel preemption could happen here */
j = arr[smp_processor_id()];
/* i and j are not equal as smp_processor_id() may not be the same */
In this situation, if kernel preemption had happened at the specified point, the task would have been assigned
to some other processor upon re-schedule, in which case smp_processor_id() would have returned a
different value. This situation should be prevented by locking.
FPU mode is another case where the state of the CPU should be protected from preemption. When the kernel
is executing floating point instructions, the FPU state is not saved. If preemption happens here, then upon
reschedule, the FPU state is completely different from what was there before preemption. So, FPU code must
always be locked against kernel preemption.
Locking can be done by disabling preemption for the critical section and re-enabling it afterwards. The Linux
2.6 kernel has provided the following #defines to disable and enable preemption:
preempt_enable() -- decrements the preempt counter
preempt_disable() -- increments the preempt counter
get_cpu() -- calls preempt_disable() followed by a call to smp_processor_id()
put_cpu() -- re-enables preemption
Using these #defines we could rewrite the above code as
int cpu, arr[NR_CPUS];
arr[get_cpu()] = i; /* disable preemption */
j = arr[smp_processor_id()];
/* do some critical stuff here */
put_cpu(); /* re-enable preemption */
Note that preempt_disable() and preempt_enable() calls are nested. That is,
preempt_disable() can be called n number of times, and preemption will only be re-enabled when the
nth preempt_enable() is encountered.
Preemption is implicitly disabled if any spin locks are held. For instance, a call to
spin_lock_irqsave() implicitly prevents preemption by calling preempt_disable(); a call to
spin_unlock_irqrestore() re-enables preemption by calling preempt_enable().
5.3 Inter-process communication
The SLES kernel provides a number of Inter-process communication (IPC) mechanisms that allow processes
to exchange arbitrary amounts of data and synchronize execution. The IPC mechanisms include unnamed
pipes, named pipes (FIFOs), the System V IPC mechanisms (consisting of message queues, semaphores and
shared memory regions), signals, and sockets.
This section describes the general functionality and implementation of each IPC mechanism and focuses on
DAC and object reuse handling.
61