From: http://hi.baidu.com/yangyingchao/blog/item/af66b9d4e522940ca18bb705.html
1. Related Data Structure
struct thread_info { struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ __u32 flags; /* low level flags */ __u32 status; /* thread synchronous flags */ __u32 cpu; /* current CPU */ int preempt_count; /* 0 => preemptable, <0 => BUG */ mm_segment_t addr_limit; struct restart_block restart_block; void __user *sysenter_return; #ifdef CONFIG_X86_32 unsigned long previous_esp; /* ESP of the previous stack in case of nested (IRQ) stacks */ __u8 supervisor_stack[0]; #endif int uaccess_err; }; /* how to get the thread information struct from C */ static inline struct thread_info *current_thread_info(void) { return (struct thread_info *) (current_stack_pointer & ~(THREAD_SIZE - 1)); } #define preempt_count() (current_thread_info()->preempt_count) |
2 The following content is transferred from: kernel preemption
Unlike most other UNIX variants and most other operating systems, Linux fully supports kernel preemption.
In a kernel that does not support kernel preemption, the kernel code can be executed until it is completed. That is to say, the Scheduler cannot reschedule a kernel-level task while it is being executed. All tasks in the kernel are scheduled in a collaborative manner and cannot be preemptible.
In the kernel version 2.6, the kernel introduces the preemption capability. Now, as long as rescheduling is secure, the kernel can seize the tasks being executed at any time.
So when is rescheduling secure? As long as no lock is held, the kernel can be preemptible. The lock is a flag of a non-preemptible region. Because the kernel supports SMP, if no lock is held, the code being executed can be re-imported, that is, it can be preemptible.
The first change to support kernel preemption is the introduction of the preempt_count (thread_info.preempt_count) counter in thread_info of each process. The initial value of the counter is 0. When the lock is used, the value is 1. When the lock is released, the value is reduced by 1. When the value is 0, the kernel can be preemptible. When the kernel space is returned from the interrupt, the kernel checks the flag and preempt_count values. If tif_need_resched is set in the flag and the value of preempt_count is 0, this indicates that a more important task needs to be executed and can be safely preemptible, the scheduler will schedule (preemptible the current process ). If the value of preempt_count is not 0, the current task holds a lock, so preemption is insecure. In this case, the current execution process is directly returned from the interrupt as usual. If all the locks held by the current process are released, the preemptcount value is 0 again. The code for releasing the lock checks whether need_resched is set. If yes, the scheduler will be called. Some kernel code must allow or disable kernel preemption.
If the process in the kernel is blocked, or it explicitly calls schedule (), kernel preemption also occurs. This form of kernel code is always supported, because no additional logic is required to ensure that the kernel can be safely preemptible. If the Code explicitly calls schedule (), it should be clear that it can be safely preemptible.
Kernel preemption occurs in:
Before the "Slave interrupt handler" is being executed and the kernel space is returned
The kernel code is once again preemptible
If a task in the kernel explicitly calls schedule ()
If the task in the kernel is blocked (this also causes schedule () to be called ())
Note:
In current-> threadinfo. Flags, tif_need_resched is 1, indicating that the current process needs to execute schedule () to release CPU control.
Current-> threadinfo. preemptcount is not 0, indicating that the current process cannot release CPU control (cannot be preemptible) when holding the lock)
When the kernel state is returned to the user State, check whether scheduling is performed. Scheduling depends on two conditions:
1. If the preempt_count value is 02. If the rescheduled value is set to preempt_count, the system checks whether the value is 0. That is to say, there are four conditions that may not be able to be scheduled. 1. preempt_disable () # define preempt_disable ()\
Do {\
Inc_preempt_count ();\
Barrier ();\
} While (0) # define inc_preempt_count () add_preempt_count (1) will be released in preempt_enable 2. add_preempt_count (hardirq_offset) is called in irq_enter (). It records the number of times the hardware is interrupted (count) and is released in irq_exit. _ local_bh_disable (unsigned long) _ builtin_return_address (0); static inline void _ local_bh_disable (unsigned long IP) called in do_softirq)
{
Add_preempt_count (softirq_offset );
Barrier ();
} 4. General switch, first.