1. How the operating system organizes processes
struct Task_struct {
......
/* Process Status */
volatile long state;
/* point to the kernel stack */
void *stack;
/* For joining the process chain list */
struct List_head tasks;
......
/* The memory area descriptor that points to the process */
struct mm_struct *mm, *active_mm;
........
/* Process ID, each process (thread) has a different PID */
pid_t pid;
/* Thread group ID, the same thread group has the same PID, and the lead thread (the first lightweight process in the group) PID, saved in Tgid, thread group lead thread PID and tgid the same */
pid_t Tgid;
/* For connecting to the PID, Tgid, PGRP, session hash Table */
struct Pid_link Pids[pidtype_max];
........
/* Point to the parent process that created it, and if its parent process does not exist, point to the INIT process */
struct task_struct __rcu *real_parent;
/* points to the current parent process, usually consistent with real_parent */
struct task_struct __rcu *parent;
/* Child process Chain List */
struct List_head children;
/* Sibling Process Chain list */
struct List_head sibling;
/* Thread group lead thread pointer */
struct Task_struct *group_leader;
/* Save hardware context during process switchover (hardware context saved in 2 places: Thread_struct (save most CPU register values, including kernel stack top address and IO permission bit), kernel stack (save Eax,ebx,ecx,edx, etc.) * /
struct THREAD_STRUCT thread;
/* Current directory */
struct Fs_struct *fs;
/* point to the file descriptor, and all open files of the process will be in an array of pointers in this area */
struct Files_struct *files;
........
/* Signal descriptor for tracking shared pending signal queues, shared by all processes belonging to the same thread group That is, the thread of the same threads group this pointer points to the same signal descriptor */
struct signal_struct *signal ;
/* Signal handler function Descriptor */
struct sighand_struct *sighand;
/* sigset_t is a bit array, each signal corresponds to a bit, the maximum number of signals in Linux is 64
* Blocked: Blocked signal mask
* real_blocked: Temporary mask for blocked signals
*/
sigset_t blocked, real_blocked;
sigset_t Saved_sigmask; /* restored if Set_restore_sigmask () was used */
/* Private Suspend signal queue */
struct sigpending pending;
........
}
/* Wq the queue header for a waiting queue */void sleep_on (wait_queue_head_t *wq) {/ * declares a wait queue node */ wait_queue_t wait; /* Initialize the waiting queue node with the current process * /Init_waitqueue_entry (&wait, present); /* Set Current process status to Task_uninterruptible */ current->state = task_uninterruptible; /* Add this waiting queue node representing the current process to the Wq waiting queue * /Add_wait_queue (Wq, &wait); /* Request Scheduler to dispatch, after executing schedule the process will be removed CPU run queue, only wait for Wake up queue will not return to the CPU run queue * /Schedule (); /* Here the process has been waiting for the queue to wake up and move back to the CPU run queue, that is, the waiting condition is true, and the first thing to wake up is to
Wait Queue wq Remove * /Remove_wait_queue (Wq, &wait); }
All processes in the task_running state are placed in the CPU's run queue, which is likely to be in a different CPU running queue.
The system does not have a dedicated list of processes for task_stoped, Exit_zombie, and Exit_dead states, because process access in these states is relatively straightforward and can be accessed through PID and through a list of child processes in a particular parent process.
All task_interruptible and task_uninterruptible are put into the corresponding waiting queue, there are many waiting queues in the system, some are waiting for the termination of the disk operation, some are waiting to release the system resources, some are waiting time through a fixed interval, Each waiting queue has a different wake-up condition, such as waiting for queue 1 to wait for the system to release resource A, while waiting for queue 2 to wait for the system to release resource B. Therefore, the wait queue represents a set of sleep processes, and when a condition is true, the kernel wakes up the process on the waiting queue.
Waiting for a queue is waiting for the system to release resource A, while waiting for all processes in the queue to be able to take possession of this resource A, like the amount of semaphores we have programmed, when the system does not wake up all the processes in this wait queue, but only wakes one. The kernel distinguishes this mutex process from the principle that all of the waiting queue nodes in this wait queue are wait_queue_t with flags set to 1 (default is 0)
2. How the process state is converted (gives the process state transition diagram)
The Linux process states are:
R (task_running), executable state.
S (task_interruptible), an interruptible sleep state.
D (task_uninterruptible), non-disruptive sleep state.
Z (Task_dead-exit_zombie), exit status, process becomes zombie process.
T (task_stopped or task_traced), pause State or trace state.
X (Task_dead-exit_dead), exit status, process is about to be destroyed.
Only processes in that state are likely to run on the CPU. There may be multiple processes in the executable state at the same moment, the task_struct structure of those processes (Process control block)
is placed in the executable queue of the corresponding CPU (a process can only appear in the executable queue of one CPU). The process scheduler chooses from the respective CPU's executable queue
A process runs on that CPU.
Processes that are executing on the CPU are defined as the running state, executable, but not yet scheduled to execute, defined as a ready state, both of which are unified
Task_running status.
The kernel does a process switch operation only when the process is moved from kernel run state to sleep. Processes running in the kernel state cannot be preempted by other processes, and a process cannot change the state of another process. In order to avoid kernel data errors caused by process switching, the kernel disables all interrupts when it executes the critical section code.
Three basic states of the process
Ready status
When a process is assigned to all the necessary resources except the CPU, the process state is called the ready state as long as the processor is available for immediate execution.
Execution (Running) status
When a process has been acquired by a processor, its program is executing on the processing machine, at which point the process state is called the execution state.
Blocking (Blocked) state
A process being executed that is blocked by a processor while waiting for an event to occur cannot be executed. There can be a number of events that cause a process to block, such as waiting for I/O to complete, requesting a buffer not satisfying, waiting for a letter (signal), etc.
(1) Ready → Executes the process in the ready state, and when the process dispatcher assigns it a processor, the process is transformed from the ready state to the execution state.
(2) execution → Ready in the execution of the process during its execution, because a time slice allocated to it has been exhausted and had to give up the processor, so the process from the execution state into a ready state.
(3) execution → blocking the executing process from execution state to blocking state as it waits for an event to occur and cannot continue execution.
(4) blocking → ready to block the process, if its waiting for the event has occurred, then the process from the blocking state into a ready state.
3. How the process is scheduled
static void __sched __schedule (void) {struct task_struct *prev, *next; unsigned long *switch_count; struct RQ *rq; int CPU; Need_resched:/* Disallow kernel preemption */preempt_disable (); CPU = smp_processor_id (); /* Get the scheduling queue for the CPU */RQ = CPU_RQ (CPU); Rcu_note_context_switch (CPU); /* Save current Task */prev = rq->curr; Schedule_debug (prev); if (Sched_feat (Hrtick)) hrtick_clear (RQ); /* * Make sure that signal_pending_state ()->signal_pending () below * can ' t is reordered with __set_current_st Ate (task_interruptible) * done by the caller to avoid, the race with Signal_wake_up (). */Smp_mb__before_spinlock (); RAW_SPIN_LOCK_IRQ (&rq->lock); Switch_count = &prev->nivcsw; /* If the kernel state is not preempted and the kernel preemption is valid, the following conditions are met: 1 The process is in a stopped state 2 the process is not preempted in the kernel state */if (Prev->state & &! (Preempt_count () & preempt_active)) {if (Unlikely (Signal_pending_state (Prev->state, prev)) {prev->state = task_running; } else {Deactivate_task (RQ, Prev, dequeue_sleep); PREV->ON_RQ = 0; /* * If A worker went to sleep, notify and ask Workqueue * whether it wants to wake-a task to Maintain * concurrency. */if (Prev->flags & pf_wq_worker) {struct task_struct *to_wakeup; To_wakeup = wq_worker_sleeping (prev, CPU); if (to_wakeup) try_to_wake_up_local (to_wakeup); }} Switch_count = &prev->nvcsw; } pre_schedule (RQ, prev); if (unlikely (!rq->nr_running)) idle_balance (CPU, RQ); /* Tell the Scheduler that the Prev process is about to be dispatched */Put_prev_task (RQ, prev); /* Pick the next running process */next = Pick_next_task (RQ); /* Clear the Pre tif_need_resched flag */clear_tsk_need_resched (prev); rq->skip_clock_update = 0; /* If Next is inconsistent with the current process, you can schedule the */if(Likely (prev! = next)) {rq->nr_switches++; /* Set the current scheduling process to next*/Rq->curr = next; ++*switch_count; /* Switch Process Context */Context_switch (RQ, Prev, next); /* Unlocks the RQ */* * The context switch has flipped the stack from under US * and restored The local variables which were saved when * This task called schedule () in the past. Prev = = Current * was still correct, but it can be moved to another CPU/RQ. */CPU = SMP_PROCESSOR_ID (); RQ = CPU_RQ (CPU); } else Raw_spin_unlock_irq (&rq->lock); Post_schedule (RQ); Sched_preempt_enable_no_resched (); if (need_resched ()) goto need_resched;}
The process provides two priorities, one is the normal process priority, the second is the real-time priority, the former uses the Scheed_normal scheduling policy, and the latter is optional sched_fifo or SCHED_RR scheduling. At any time, real-time processes are prioritized higher than normal processes, and real-time processes are preempted only by higher-level real-time processes, while real-time processes are scheduled in either FIFO (one-time) or RR (multiple rotation) rules.
First, the scheduling of real-time processes:
Real-time process, only static priority, because the kernel does not adjust its static priority according to factors such as sleep time, the default real-time priority range is 0~99
Unlike normal processes, when the system is scheduled. A process with a high real-time priority is always preceded by a low-priority process, until real-time processes with high real-time priority cannot execute. If there are several real-time processes with the same priority, the system chooses the process in the order in which the process appears on the queue.
The real-time processes of different scheduling strategies are comparable only at the same priority level:
1) for FIFO processes, it means that only the current process is completed before it is executed by another process. This shows quite overbearing.
2) for RR processes, once the time slice is consumed, the process is placed at the end of the queue, and then other processes of the same priority are run, and the process continues to execute if there are no other processes of the same priority level.
For a real-time process, the high-priority process executes first, and he executes until it is impossible to execute, and the process executes with a low priority. Hierarchy is heavily guarded.
Normal process:
Sched_orher: Scheduling based on dynamic priority, its dynamic precedence can be understood as the scheduler calculates weights for each process based on multiple factors.
4. Talk about your view of the operating system process model
The Linux system is an operating system with innate virus immunity and is rarely attacked by viruses. For an open system, at the same time as user-friendly, there is likely to be a security risk.
However, the use of Linux, such as firewall, intrusion detection and security certification tools, timely repair system vulnerabilities, can greatly improve the security of the Linux system, so that hackers can be inorganic.
Deep source Analysis Process Model