淺談task_struct各個字段內容

什麼是進程?什麼是task_struct?

  首先站在用戶的角度來看:進程就是運行中的程序,這是一個比較抽象化的概念。

  站在操作系統的角度來看:進程就是操作系統對進程的描述,這個描述信息就是對進程的具象化描述- - -這個描述信息就是進程,這個描述信息就是pcb(process control block)- - -進程控制塊或者進程描述符。在linux下就是task_struct這個結構體。

  在創建新進程時,Linux就從系統內存中分配一個task_struct結構,並把它的首地址加入 task 數組中,這個 task 數組是系統中的一個向量數組,該數組的長度默認是 512B,該數組的元素是指向task_struct的。

《操作系統精髓與設計原理》這本書中對進程作了如下定義:

  • 一個正在執行中的程序
  • 一個正在計算機上執行的程序實例
  • 能分配給處理器並由處理器處理的實體
  • 一個具有以下特徵的活動單元:1、一組指令序列的執行。2、一個當前狀態和相關的系統資源集合

  那麼 task_struct 中都有什麼內容呢?

  • 標識符:描述本進程的唯一標識符,用於區別其他進程
  • 狀態:任務狀態,退出信號,退出代碼等
  • 優先級:相對於其他進程的優先級
  • 程序計數器:程序中即將被執行的下一條指令的地址
  • 內存指針:包括程序代碼和進程相關數據的指針,還有和其他進程共享的內存塊的指針
  • 上下文數據:進程執行時處理器的寄存器中的數據
  • IO狀態信息:包括顯示的 I/O 請求,分配給進程的 I/O 設備和被進程使用的文件列表。
  • 記賬信息(審計信息):可能包括處理器時間總和,使用的時鐘數總和,時間限制,記賬號等
  • 那麼還有其他的信息如下介紹:

調度數據成員

//進程的狀態,能否執行(-1, 0, >1)
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */

volatile這個關鍵字是保持內存可見性,防止代碼過度優化,就是state變量從內存當中讀取數據,而不是將從寄存器中讀取,這也是爲了保證對操作系統狀態實時訪問的穩定性。

/*	狀態取值
 192  * Task state bitmask. NOTE! These bits are also
 193  * encoded in fs/proc/array.c: get_task_state().
 194  *
 195  * We have two separate sets of flags: task->state
 196  * is about runnability, while task->exit_state are
 197  * about the task exiting. Confusing, but this way
 198  * modifying one set can't modify the other one by
 199  * mistake.
 200  */
#define TASK_RUNNING            0
#define TASK_INTERRUPTIBLE      1
#define TASK_UNINTERRUPTIBLE    2
#define __TASK_STOPPED          4
#define __TASK_TRACED           8
/* in tsk->exit_state */
#define EXIT_ZOMBIE             16
#define EXIT_DEAD               32
/* in tsk->state again */
#define TASK_DEAD               64
#define TASK_WAKEKILL           128
#define TASK_WAKING             256
#define TASK_PARKED             512
#define TASK_STATE_MAX          1024
/* Convenience macros for the sake of set_task_state */
#define TASK_KILLABLE           (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
#define TASK_STOPPED            (TASK_WAKEKILL | __TASK_STOPPED)
#define TASK_TRACED             (TASK_WAKEKILL | __TASK_TRACED)
/* Convenience macros for the sake of wake_up */
#define TASK_NORMAL             (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
#define TASK_ALL                (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED)

//用於自定義調度程序行爲
unsigned int flags; /* per process flags, defined below */

/*Per process flags	進程標誌有以下標誌*/
#define PF_EXITING      0x00000004      /* getting shut down */
#define PF_EXITPIDONE   0x00000008      /* pi exit done on shut down */
#define PF_VCPU         0x00000010      /* I'm a virtual CPU */
#define PF_WQ_WORKER    0x00000020      /* I'm a workqueue worker */
#define PF_FORKNOEXEC   0x00000040      /* forked but didn't exec */
#define PF_MCE_PROCESS  0x00000080      /* process policy on mce errors */
#define PF_SUPERPRIV    0x00000100      /* used super-user privileges */
#define PF_DUMPCORE     0x00000200      /* dumped core */
#define PF_SIGNALED     0x00000400      /* killed by a signal */
#define PF_MEMALLOC     0x00000800      /* Allocating memory */
#define PF_NPROC_EXCEEDED 0x00001000    /* set_user noticed that RLIMIT_NPROC was exceeded */
#define PF_USED_MATH    0x00002000      /* if unset the fpu must be initialized before use */
#define PF_USED_ASYNC   0x00004000      /* used async_schedule*(), used by module init */
#define PF_NOFREEZE     0x00008000      /* this thread should not be frozen */
#define PF_FROZEN       0x00010000      /* frozen for system suspend */
#define PF_FSTRANS      0x00020000      /* inside a filesystem transaction */
#define PF_KSWAPD       0x00040000      /* I am kswapd */
#define PF_MEMALLOC_NOIO 0x00080000     /* Allocating memory without IO involved */
#define PF_LESS_THROTTLE 0x00100000     /* Throttle me less: I clean memory */
#define PF_KTHREAD      0x00200000      /* I am a kernel thread */
#define PF_RANDOMIZE    0x00400000      /* randomize virtual address space */
#define PF_SWAPWRITE    0x00800000      /* Allowed to write to swap */
#define PF_NO_SETAFFINITY 0x04000000    /* Userland is not allowed to meddle with cpus_allowed */
#define PF_MCE_EARLY    0x08000000      /* Early kill for mce process policy */
#define PF_MEMPOLICY    0x10000000      /* Non-default NUMA mempolicy */
#define PF_MUTEX_TESTER 0x20000000      /* Thread belongs to the rt mutex tester */
#define PF_FREEZER_SKIP 0x40000000      /* Freezer should not count it as freezable */
#define PF_SUSPEND_TASK 0x80000000      /* this thread called freeze_processes and should not be frozen */

unsigned int policy; //該進程的調度策略

調度策略有:
SCHED_OTHER 0 非實時進程,基於優先權的輪轉法(round robin)。
SCHED_FIFO 1 實時進程,用先進先出算法。
SCHED_RR 2 實時進程,用基於優先權的輪轉法。

進程標識符

pid_t pid; //進程標識符
pid_t tgid; //線程組標識符

tgid是用於表示線程組的標識符,它等於主線程的id,主線程的id也就是這個進程的id。

表示進程間親屬關係的成員

struct task_struct __rcu *real_parent; /* real parent process */
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
struct list_head children;      /* list of my children */
struct list_head sibling;       /* linkage in my parent's children list */
struct task_struct *group_leader;       /* threadgroup leader */

real_parent 指向其父進程,如果父進程不存在,則指向1號 init 進程;
parent 是父進程,是接受SIGCHLD信號的,也就是回收子進程資源的進程;
children 鏈表中都是它的子進程;
sibling 把當前鏈表插入兄弟鏈表中
group_leader 指向線程組的首位。

進程地址空間

struct mm_struct *mm, *active_mm;

struct mm_struct *mm, *active_mm;
#ifdef CONFIG_COMPAT_BRK
        unsigned brk_randomized:1;
#endif
#if defined(SPLIT_RSS_COUNTING)
        struct task_rss_stat    rss_stat;

mm 指向進程所擁有的內存描述符;
active_mm指向進程運行時所使用的內存描述符;
對於普通進程而言,這兩個指針的值相同;
對於內核線程而言,它們不擁有任何內存描述符,所以它們的mm總爲NULL,當內核線程運行時,它的active_mm初始化爲前一個active_mm的值。

信號處理

/* signal handlers */
         struct signal_struct *signal;
         struct sighand_struct *sighand;
 
         sigset_t blocked, real_blocked;
         sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
         struct sigpending pending;
 
         unsigned long sas_ss_sp;
         size_t sas_ss_size;
         int (*notifier)(void *priv);
         void *notifier_data;
         sigset_t *notifier_mask;

signal 指向信號描述符
sighand 指向信號處理程序描述符
blocked 表示被阻塞信號的掩碼
real_blocked 表示臨時掩碼
pending 中存放未決信號(未被處理的信號)
sas_ss_sp 是信號處理程序備用堆棧的地址
sas_ss_size 表示堆棧的大小
設備驅動程序常用notifier指向的函數來阻塞進程的某些信號。(notifier_data是可能用到的數據,notifier_mask是信號的位掩碼)

ptrace系統調用

gdb調試中底層就是使用 ptrace 來完成的。

unsigned int ptrace; //追蹤

/*
* ptraced is the list of tasks this task is using ptrace on.
* This includes both natural children and PTRACE_ATTACH targets.
* p->ptrace_entry is p's link on the p->parent->ptraced list.
*/
struct list_head ptraced;
struct list_head ptrace_entry;
unsigned long ptrace_message;
siginfo_t *last_siginfo; /* For ptrace use.  */
#ifdef CONFIG_HAVE_HW_BREAKPOINT
        atomic_t ptrace_bp_refcnt;
#endif

其他數據成員

fpu_counter包含使用FPU的連續上下文切換的數量。

(1) unsigned char fpu_counter;

進程描述符使用計數,被置爲2時,表示進程描述符正在被使用而且其相應的進程處於活動狀態。

(2) atomic_t usage;

用於表示獲取大內核鎖的次數,如果進程未獲得過鎖,則置爲-1。

(3) int lock_depth; /* BKL lock depth */

用於管理資源分配以及釋放的自旋鎖。

(4) /* Protection of (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed,
mempolicy */
spinlock_t alloc_lock;

用於調度器統計進程的運行信息。

(5)
#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
struct sched_info sched_info;
#endif

命名空間

(6)/* namespaces */
struct nsproxy *nsproxy;

死鎖檢測

(7)#ifdef CONFIG_DEBUG_MUTEXES
/* mutex deadlock detection */
struct mutex_waiter *blocked_on;
#endif

內存回收

(8)struct reclaim_state *reclaim_state;

I/O調度器所使用的信息

(9)struct io_context *io_context;

存放塊設備I/O數據流量信息

(10)struct backing_dev_info *backing_dev_info;


PS:本文是基於CentOS Linux release 7.3.1611版本。task_struct中還有很多其他信息,本文沒有講到,可以自行查看。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章