process
Processes are also called tasks in linux.
For user space, a process is an instance of program execution.A process can be compared to a human individual: there is only one parent process and there can be multiple child processes; there are more or less valid lives; it takes on certain functions or tasks; it has different states, and there is only one state at any time; and it will eventually die out.
For the kernel space, the purpose of the process is to reasonably allocate the entities of the system resources.Each process will use the kernel to get its own CPU, memory, and other system resources to perform tasks.
1. Process Descriptor
Since a process is an instance of a program execution, in addition to program instructions, it contains a large number of resources and has a separate virtual address space.In order to better manage processes, the kernel must have a clear understanding of each process's current state and what it does.Thus, there is the concept of a process descriptor.In Linux, a process is described using the task_struct structure.
Process descriptors are task_struct type structures that contain all process-related information.
ubuntu system code location (Linux version 4.15): /usr/src/linux-headers-4.15.0-72/include/linux/sched.h
linux online code location: https://elixir.bootlin.com/linux/v5.5.2/source/include/linux/sched.h
Since the task_struct structure is very large and complex, the main structures are listed here:
struct task_struct { //Process Running State /* -1 unrunnable, 0 runnable, >0 stopped: */ volatile long state; //end //Kernel State Stack void *stack; //end //Process Status Information /* Per task flags (PF_*), defined further below: */ unsigned int flags; //end //Process priority information int prio;//Dynamic Priority int static_prio;//Static priority, can be modified directly with nice int normal_prio;//Static Priority and Scheduling Policy unsigned int rt_priority;//Real-time priority //end //Process memory information struct mm_struct *mm; struct mm_struct *active_mm; /* Per-thread vma caching: */ struct vmacache vmacache; #ifdef SPLIT_RSS_COUNTING struct task_rss_stat rss_stat; #endif //end //Process Exit Status int exit_state; int exit_code; int exit_signal; /* The signal sent when the parent dies: */ int pdeath_signal; //end //Atomic Access Marker unsigned long atomic_flags; /* Flags requiring atomic access. */ //end //Process Identifier pid_t pid; pid_t tgid; //end //The relatives of a process /* * Pointers to the (original) parent process, youngest child, younger sibling, * older sibling, respectively. (p->father can be replaced with * p->real_parent->pid) */ /* Real parent process: */ struct task_struct __rcu *real_parent; //Real parent process /* Recipient of SIGCHLD, wait4() reports: */ struct task_struct __rcu *parent; //Formally, the parent process is usually real_parent. /* * Children/sibling form the list of natural children: */ struct list_head children; struct list_head sibling; struct task_struct *group_leader; //end //Time Statistics u64 utime; u64 stime; #ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME u64 utimescaled; u64 stimescaled; #endif u64 gtime; struct prev_cputime prev_cputime; #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN struct vtime vtime; #endif #ifdef CONFIG_NO_HZ_FULL atomic_t tick_dep_mask; #endif /* Context switch counts: */ unsigned long nvcsw; unsigned long nivcsw; /* Monotonic time in nsecs: */ u64 start_time; /* Boot based time in nsecs: */ u64 real_start_time; /* MM fault and swap info: this can arguably be seen as either mm-specific or thread-specific: */ unsigned long min_flt; unsigned long maj_flt; #ifdef CONFIG_POSIX_TIMERS struct task_cputime cputime_expires; struct list_head cpu_timers[3]; #endif //end //Process name, up to 15 characters /* * executable name, excluding path. * * - normally initialized setup_new_exec() * - access it with [gs]et_task_comm() * - lock it with task_lock() */ char comm[TASK_COMM_LEN]; //end /* Filesystem information: */ struct fs_struct *fs; /* Open file information: */ struct files_struct *files; /* Namespaces: */ struct nsproxy *nsproxy; /* Signal handlers: */ struct signal_struct *signal; struct sighand_struct *sighand; sigset_t blocked; sigset_t real_blocked; /* Restored if set_restore_sigmask() was used: */ sigset_t saved_sigmask; struct sigpending pending; unsigned long sas_ss_sp; size_t sas_ss_size; unsigned int sas_ss_flags; /* Protection against (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed, mempolicy: */ spinlock_t alloc_lock; /* * WARNING: on x86, 'thread_struct' contains a variable-sized * structure. It *MUST* be at the end of 'task_struct'. * * Do not put anything below here! */ };
Process name
/* Task command name length: */ #define TASK_COMM_LEN 16 /* * executable name, excluding path. * * - normally initialized setup_new_exec() * - access it with [gs]et_task_comm() * - lock it with task_lock() */ char comm[TASK_COMM_LEN];
comm is the process name and is no longer than 15 characters in length.
Process Running State
/* -1 unrunnable, 0 runnable, >0 stopped: */ volatile long state;
/* * Task state bitmask. NOTE! These bits are also * encoded in fs/proc/array.c: get_task_state(). * * We have two separate sets of flags: task->state * is about runnability, while task->exit_state are * about the task exiting. Confusing, but this way * modifying one set can't modify the other one by * mistake. */ #define TASK_RUNNING 0x0000 //Runnable state, either running or ready to run #define TASK_INTERRUPTIBLE 0x0001 //Interruptible wait state #define TASK_UNINTERRUPTIBLE 0x0002 //Uninterruptible wait state #Define u TASK_STOPPED 0x0004 //pause state #Define u TASK_TRACED 0x0008 //Tracking status /* in tsk->exit_state */ #define EXIT_DEAD 0x0010 //Process Death Status #define EXIT_ZOMBIE 0x0020//Process Dead State #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD) /* in tsk->state again */ #define TASK_DEAD 0x0040 // Abnormal death during process death -->EXIT_ZOMBIE; Normal death -->EXIT_DEAD #define TASK_WAKEKILL 0x0080 //Process to wake up and kill #define TASK_WAKING 0x0100 //Wake-up process #define TASK_PARKED 0x0200 // #define TASK_NOLOAD 0x0400 #define TASK_NEW 0x0800 #define TASK_STATE_MAX 0x1000
Process Identifier
//Process Identifier pid_t pid; pid_t tgid;
Is the easy-to-understand pid and tgid.
PID is the process id, fork creates a unique pid.
TGID is the thread group id, and all processes in the same thread group have the same TGID; the TGID of the thread group leader is the same as its PID; and if a process does not use a thread, its TGID and PID are the same.
Process Kinship
/* * Pointers to the (original) parent process, youngest child, younger sibling, * older sibling, respectively. (p->father can be replaced with * p->real_parent->pid) */ /* Real parent process: */ struct task_struct __rcu *real_parent; /* Recipient of SIGCHLD, wait4() reports: */ struct task_struct __rcu *parent; /* * Children/sibling form the list of natural children: */ struct list_head children; struct list_head sibling; struct task_struct *group_leader;
Where real_parent is a pointer to the parent process and is the fork's own process; parent is the formal parent process and is the trace's own process.Typically, parent is real_parent.Upon exit, report wait4() to parent.