3. SMP system initialization
Init_Task After completing the key data structure initialization, the SMP_init () is called to initialize the SMP system before the hardware is initialized. SMP_INIT () calls SMP_BOOT_CPUS (), SMP_BOOT_CPUS () calls each CPU once a DO_BOOT_CPU (), completes the initialization of SMP other CPUs.
/ * Extract from [Arch / I386 / kernel / SmpBoot.c] do_boot_cpu () * /
IF (fork_by_hand () <0) / * do_fork (clone_vm | clone_pid) Creates a new process, with INIT_TASK, with 0 PID * /
PANIC ("Failed for CPU% D", CPU);
IDLE = init_task.prev_task; / * In the list of processes, the new process is always located on the left chain of init_task. * /
IF (! idle)
PANIC ("NO Idle Process for CPU% D", CPU);
IDLE-> Processor = CPU;
IDLE-> CPUS_Runnable = 1 << CPU; / * Run on the specified CPU * /
Map_cpu_to_boot_apicid (CPU, APICID);
Idle-> thread.eip = (unsigned long) start_secondary; / * Startup address that is scheduled to the post * /
Del_from_runqueue (idle); / * iDLE process does not pass ready queue dispatch * /
Unhash_process (idle);
INIT_TASKS [CPU] = iDLE; / * All IDLE processes can be accessed through init_tasks [] array * /
This process is scheduled to time, and then execute start_secondary (), eventually calls CPU_IDLE (), becoming the IDLE process.
Seven. Some problems in Linux 2.4 scheduling system
Process time
2.4 The process default time sheet in the kernel is calculated according to the following formula:
/ * Extreme [kernel / SCHED.C] * /
#if hz <200
#define tick_scale (x) ((x) >> 2)
#LIF HZ <400
#define tick_scale (x) ((x) >> 1)
#ELIF HZ <800
#define tick_scale (x) (x)
#ELIF HZ <1600
#define tick_scale (x) ((x) << 1)
#ELSE
#define tick_scale (x) ((x) << 2)
#ENDIF
#define nice_to_ticks (nice) (Tick_Scale (20- (nice)) 1)
......
Schedule ()
{
......
P-> counter = (p-> counter >> 1) nice_to_tics (p-> nice);
......
}
As mentioned above, the clock interrupt will continue to perform the operation of the currently running non-IDLE process to reduce the remaining value of 1, until the counter in all ready queues is reduced to 0, just in schedule () for each process (including Sleeping process) Use the above formula to perform the update of the time slice. Among them, Hz is 100 in [include / ASM-I386 / param.h], and counter typically 0, NICE defaults to 0 (Nice is selected between -20 to 19), so I386 COUNTER The default value is 6, that is, about 60ms (clock interrupt approximately every 10ms). At the same time, for the process of sleep, it participates in the calculated counter non-0, so its Counter is accumulated, constitutes a number of quadrograms counter = Counter / 2 K, 1 Because the value of the cand selection algorithm accounts for a significant weight (see "Ready Process Selection Algorithm"), this method of laminating the dormant process is more than the Timmer of Linux tends to prioritize the number of sleep, that is, IO Process of IO-BOUND. Linux designers are originally desirable to improve the response speed of the interactive process, so that the terminal user, but the IO intensive process is not necessarily an interactive process, such as database operations need to be read and write disk, which is often in sleep. The dynamic priority is usually higher, but this application does not need a user interaction, so it affects the response of the true interactive action. The length of the time film is also very affected by the system performance. If it is too short, the process switch will be too frequent, the overhead is very large; if it is too long, the system response will be too slow, and Linux's strategy is that the system response is not too slow to make the time film as soon as possible. 2. The kernel cannot be preemptive From the above analysis we can see that schedule () is the only entry for process switching, and its runtime is very special. Once control enters the core state, there is no way to interrupt it unless you give up the CPU. One of the most typical examples is the core thread if a dead cycle (as long as the schedule ()) is not called, the system will lose response, and the various interrupts (including clock interrupts) are still in response, but not scheduling Other processes (including core processes) have no chance to run. The following is the code that is broken back: / * Announcement from [Arch / I386 / ENTRY.S] * / Entry (RET_FROM_INTR) Get_current (% EBX) # Saves the Current pointer to the EBX register RET_FROM_EXCEPTION: MOVL EFLAGS (% ESP),% EAX # Take the VM_Mask bit in EFLAGS to determine if it is in VM86 mode MOVB CS (% ESP),% Al # take CS low two judgments in user state Testl $ (VM_MASK | 3),% EAX JNE RET_FROM_SYS_CALL # If in the VM86 mode or in a user state, return from the RET_FROM_SYS_CALL entry, otherwise it will return directly. JMP Restore_all This is the only place that may call Schedule () at this time (see "scheduler working opportunity", but the normal core thread does not belong to any required state, it can respond to interrupt, but cannot cause dispatch. One of this feature is that the high priority process cannot interrupt the low priority process that is executing the system call (or interrupt service) in the nuclear, which is fatal for real-time systems, but simplifies the core code. Many places in the kernel use this feature, you can access shared data without excessive protection, without worrying about the disturb of other processes.