# linux 任务状态定义
Date: 2019-06-29


# 结构定义：

       Linux  task\_struct 结构中 涉及进程状态的属性有三个，其中进程对应的状态分为两类， 一类是运行中状态， 另一类是进程退出状态。 

```
struct task_struct {
...
	/* -1 unrunnable, 0 runnable, >0 stopped: */
	volatile long			state;
	int				exit_state;
        unsigned int			flags;
...
}
```

* * *

# 状态说明：

| TASK\_RUNNING | 等待运行状态 |
| --- | --- |
| TASK\_INTERRUPTIBLE | 可中断睡眠状态 |
| TASK\_UNINTERRUPTIBLE | 不可中断睡眠状态 |
| TASK\_STOPPED | 停止状态（收到 SIGSTOP、SIGTTIN、SIGTSTP 、 SIG.TTOU信号后状态） |
| TASK\_TRACED | 被调试状态 |
| TASK\_KILLABLE | 新可中断睡眠状态 |
| TASK\_PARKED | kthread\_park使用的特殊状态 |
| TASK\_NEW | 创建任务临时状态 |
| TASK\_DEAD | 任务退出状态 |
| TASK\_WAKING | 被唤醒状态 |
| TASK\_IDLE | 任务空闲状态 |

```

/*
 * 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.
 */

/* Used in tsk->state: */
#define TASK_RUNNING			0x0000
#define TASK_INTERRUPTIBLE		0x0001
#define TASK_UNINTERRUPTIBLE		0x0002
#define __TASK_STOPPED			0x0004
#define __TASK_TRACED			0x0008
/* Used in tsk->exit_state: */
#define EXIT_DEAD			0x0010
#define EXIT_ZOMBIE			0x0020
#define EXIT_TRACE			(EXIT_ZOMBIE | EXIT_DEAD)
/* Used in tsk->state again: */
#define TASK_PARKED			0x0040
#define TASK_DEAD			0x0080
#define TASK_WAKEKILL			0x0100
#define TASK_WAKING			0x0200
#define TASK_NOLOAD			0x0400
#define TASK_NEW			0x0800
#define TASK_STATE_MAX			0x1000

/* Convenience macros for the sake of set_current_state: */
#define TASK_KILLABLE			(TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
#define TASK_STOPPED			(TASK_WAKEKILL | __TASK_STOPPED)
#define TASK_TRACED			(TASK_WAKEKILL | __TASK_TRACED)

#define TASK_IDLE			(TASK_UNINTERRUPTIBLE | TASK_NOLOAD)

/* Convenience macros for the sake of wake_up(): */
#define TASK_NORMAL			(TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)

/* get_task_state(): */
#define TASK_REPORT			(TASK_RUNNING | TASK_INTERRUPTIBLE | \
					 TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \
					 __TASK_TRACED | EXIT_DEAD | EXIT_ZOMBIE | \
					 TASK_PARKED)
```

* * *

# 相关代码：

    下面通过内核代码，看下任务状态转换的一个大致过程。

* * *

-     **TASK\_RUNNING， TASK\_INTERRUPTIBLE**

           以 [poll\_schedule\_timeout](https://elixir.bootlin.com/linux/v5.2-rc6/ident/poll_schedule_timeout)    函数为例

           文件： [/](https://elixir.bootlin.com/linux/v5.2-rc6/source)[fs](https://elixir.bootlin.com/linux/v5.2-rc6/source/fs)/[select.c](https://elixir.bootlin.com/linux/v5.2-rc6/source/fs/select.c)：

           poll\_schedule\_timeout 运行->睡眠->唤醒运行等待时间片， 任务状态变化为TASK\_RUNNING->TASK\_INTERRUPTIBLE->TASK\_RUNNING

#### 具体过程：（select为例）

- 等待队列初始化： select 函数调用 do\_select,  do\_select 通过poll\_initwait将当前进程放入等待队列:

[poll\_initwait->](https://elixir.bootlin.com/linux/v5.2-rc6/ident/poll_initwait) [init\_poll\_funcptr](https://elixir.bootlin.com/linux/v5.2-rc6/ident/init_poll_funcptr) ->[\_\_pollwait](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__pollwait)  ->  [add\_wait\_queue](https://elixir.bootlin.com/linux/v5.2-rc6/ident/add_wait_queue)  \->[\_\_add\_wait\_queue](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__add_wait_queue)  ->   [list\_add](https://elixir.bootlin.com/linux/v5.2-rc6/ident/list_add)  ->[\_\_list\_add](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__list_add)

          poll\_initwait current也就是当前进程 放入 pwq\->polling\_task \= [current](https://elixir.bootlin.com/linux/v5.2-rc6/ident/current);

-  轮询监听I/O当前状态并进行处理： 通过vfs对具体的I/O进程了封装，同时将等待队列pt 传送给底层驱动等待队列。

[vfs\_poll](https://elixir.bootlin.com/linux/v5.2-rc6/ident/vfs_poll) \-> file\->f\_op\->[poll](https://elixir.bootlin.com/linux/v5.2-rc6/ident/poll)(file, [pt](https://elixir.bootlin.com/linux/v5.2-rc6/ident/pt))

-  如果当前监听的I/O没有事件发生：进程睡眠

[poll\_schedule\_timeout](https://elixir.bootlin.com/linux/v5.2-rc6/ident/poll_schedule_timeout) -> [set\_current\_state(](https://elixir.bootlin.com/linux/v5.2-rc6/ident/set_current_state)[TASK\_INTERRUPTIBLE）](https://elixir.bootlin.com/linux/v5.2-rc6/ident/TASK_INTERRUPTIBLE)  

- 如果这时候等待的是个鼠标事件，事件发生时唤醒队列的进程。 

[mousedev\_notify\_readers](https://elixir.bootlin.com/linux/v5.2-rc6/ident/mousedev_notify_readers)\->[wake\_up\_interruptible](https://elixir.bootlin.com/linux/v5.2-rc6/ident/wake_up_interruptible)  
[mousedev\_write](https://elixir.bootlin.com/linux/v5.2-rc6/ident/mousedev_write)\->[wake\_up\_interruptible](https://elixir.bootlin.com/linux/v5.2-rc6/ident/wake_up_interruptible)

- 唤醒队列的进程，设置状态为TASK\_RUNNING

[\_\_set\_current\_state](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__set_current_state)([TASK\_RUNNING](https://elixir.bootlin.com/linux/v5.2-rc6/ident/TASK_RUNNING));

* * *

- ###  **TASK\_RUNNING， TASK\_UNINTERRUPTIBLE**
    

  以 [mutex\_lock\_slowpath](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__mutex_lock_slowpath)  ，[mutex\_unlock\_slowpath](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__mutex_unlock_slowpath)

  函数为例

           文件：[/](https://elixir.bootlin.com/linux/v5.2-rc6/source)[kernel](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel)/[locking](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel/locking)/[mutex.c](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel/locking/mutex.c)

           mutex\_lock 分为三个阶段（fastpath，midpath，slowpath），其中slowpath会被放置到wait\_queue睡眠并等待被唤醒，被阻塞为TASK\_UNINTERRUPTIBLE。 

#### 具体过程：（mutex\_lock/unlock为例）

-    mutex\_lock 不满足 fast\_path和midpath 调用 slow\_path方式， 增加等待任务到等待队列

[mutex\_lock](https://elixir.bootlin.com/linux/v5.2-rc6/ident/mutex_lock)  ->[\_\_mutex\_lock\_slowpath](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__mutex_lock_slowpath) \->[\_\_mutex\_lock](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__mutex_lock) ->

\_\_[mutex\_lock\_common](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__mutex_lock_common)  ->[\_\_mutex\_add\_waiter](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__mutex_add_waiter)

-  mutex slow\_path设置等待任务当前进程将任务状态设置为TASK\_UNINTERRUPTIBLE

        -> [set\_current\_state](https://elixir.bootlin.com/linux/v5.2-rc6/ident/set_current_state)

-  mutex\_unlock\_slowpath释放锁资源，唤醒进程

[mutex\_unlock](https://elixir.bootlin.com/linux/v5.2-rc6/ident/mutex_unlock)\->[\_\_mutex\_unlock\_slowpath](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__mutex_unlock_slowpath)   ->[wake\_q\_add](https://elixir.bootlin.com/linux/v5.2-rc6/ident/wake_q_add) \->[wake\_up\_q](https://elixir.bootlin.com/linux/v5.2-rc6/ident/wake_up_q)(&[wake\_q](https://elixir.bootlin.com/linux/v5.2-rc6/ident/wake_q));

-  mutex\_lock 通过trylock检查是否获取锁，通过后将进程状态设置为
    
    [\_\_mutex\_trylock](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__mutex_trylock)\->[\_\_set\_current\_state](https://elixir.bootlin.com/linux/v5.2-rc6/ident/__set_current_state)([TASK\_RUNNING](https://elixir.bootlin.com/linux/v5.2-rc6/ident/TASK_RUNNING));
    

* * *

- ### **\_\_TASK\_STOPPED, \_TASK\_STOPPED**
    
    暂停状态， 收到SIGSTOP,SIGTTIN,SIGTSTP SIGTTOU,进入该状态。不带下划线的宏增加了， TASK\_WAKEKILL属性 内核只有在do\_signal\_stop设置了**TASK\_STOPPED**
    

         [do\_signal\_stop](https://elixir.bootlin.com/linux/v5.2-rc6/ident/do_signal_stop)   -> [set\_special\_state](https://elixir.bootlin.com/linux/v5.2-rc6/ident/set_special_state)([TASK\_STOPPED](https://elixir.bootlin.com/linux/v5.2-rc6/ident/TASK_STOPPED));          （[/](https://elixir.bootlin.com/linux/v5.2-rc6/source)[kernel](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel)/[signal.c](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel/signal.c)）

* * *

- ### **\_\_TASK\_TRACED，TASK\_TRACED**
    

跟踪状态：进程被调试后进入该状态，不带下划线的宏增加了， TASK\_WAKEKILL属性

[ptrace\_stop](https://elixir.bootlin.com/linux/v5.2-rc6/ident/ptrace_stop)\->[set\_special\_state](https://elixir.bootlin.com/linux/v5.2-rc6/ident/set_special_state)([TASK\_TRACED](https://elixir.bootlin.com/linux/v5.2-rc6/ident/TASK_TRACED));

* * *

- ### **TASK\_PARKED**
    

        这个状态主要是[kthread\_park](https://elixir.bootlin.com/linux/v5.2-rc6/ident/kthread_park) 和 [kthread\_unpark](https://elixir.bootlin.com/linux/v5.2-rc6/ident/kthread_unpark)    函数使用。 主要为了解决cpu hotplug问题。 

* * *

- ### **TASK\_DEAD**
    

进程退出状态[do\_exit](https://elixir.bootlin.com/linux/v5.2-rc6/ident/do_exit) ->[do\_task\_dead](https://elixir.bootlin.com/linux/v5.2-rc6/ident/do_task_dead)     设置该状态。

* * *

- ### ****TASK\_WAKEKILL，**TASK\_KILLABLE**
    

用于接收到致命信号唤醒进程， 实现了一种可以被中断的新的睡眠状态

* * *

- ### **TASK\_WAKING**
    

这个状态就是就成睡眠是唤醒函数中使用， 具体调用链如下， 标识任务已经被唤醒。

[wake\_up\_process](https://elixir.bootlin.com/linux/v5.2-rc6/ident/wake_up_process)\-> [try\_to\_wake\_up](https://elixir.bootlin.com/linux/v5.2-rc6/ident/try_to_wake_up)

* * *

- ### **TASK\_IDLE， TASK\_NOLOAD**
    

Workqueue机制中再创建内核线程时，线程进入sleep状态,任务状态设置为TASK\_IDLE  （= TASK\_UNINTERRUPTIBLE | TASK\_NOLOAD）

[create\_worker](https://elixir.bootlin.com/linux/v5.2-rc6/ident/create_worker)\-> [worker\_thread](https://elixir.bootlin.com/linux/v5.2-rc6/ident/worker_thread)

[文件：/](https://elixir.bootlin.com/linux/v5.2-rc6/source)[kernel](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel)/[workqueue.c](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel/workqueue.c)

* * *

- ### **TASK\_NEW**
    

涉及系统调用fork， clone 以及生成内核线程 kernel\_thread 任务创建时， 通过sched\_fork 会设置当前任务为 TASK\_NEW， 创建完成后通过

[wake\_up\_new\_task](https://elixir.bootlin.com/linux/v5.2-rc6/ident/wake_up_new_task) 设置未TASK\_RUNNING

          文件： [/](https://elixir.bootlin.com/linux/v5.2-rc6/source)[kernel](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel)/[fork.c,](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel/fork.c)     [/](https://elixir.bootlin.com/linux/v5.2-rc6/source)[kernel](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel)/[sched](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel/sched)/[core.c](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel/sched/core.c)

          fork系统调用

[SYSCALL\_DEFINE0](https://elixir.bootlin.com/linux/v5.2-rc6/ident/SYSCALL_DEFINE0)([fork](https://elixir.bootlin.com/linux/v5.2-rc6/ident/fork)) ->[\_do\_fork](https://elixir.bootlin.com/linux/v5.2-rc6/ident/_do_fork) ->[copy\_process](https://elixir.bootlin.com/linux/v5.2-rc6/ident/copy_process) \->[sched\_fork](https://elixir.bootlin.com/linux/v5.2-rc6/ident/sched_fork)  ， [wake\_up\_new\_task](https://elixir.bootlin.com/linux/v5.2-rc6/ident/wake_up_new_task) 

* * *

- ### **TASK\_NORMAL**
    

         为wake\_up系列函数设置的宏 

          TASK\_NORMAL=([TASK\_INTERRUPTIBLE](https://elixir.bootlin.com/linux/v5.2-rc6/ident/TASK_INTERRUPTIBLE) | [TASK\_UNINTERRUPTIBLE](https://elixir.bootlin.com/linux/v5.2-rc6/ident/TASK_UNINTERRUPTIBLE))

          [wake\_up\_process](https://elixir.bootlin.com/linux/v5.2-rc6/ident/wake_up_process)   ->[try\_to\_wake\_up](https://elixir.bootlin.com/linux/v5.2-rc6/ident/try_to_wake_up)     

           [/](https://elixir.bootlin.com/linux/v5.2-rc6/source)[kernel](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel)/[sched](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel/sched)/[core.c](https://elixir.bootlin.com/linux/v5.2-rc6/source/kernel/sched/core.c)

          其中try\_to\_wake\_up 判断进程的state是否是 TASK\_NORMAL的状态， 及睡眠状态， 非睡眠状态不需要唤醒。 也就是只有TASK\_NORMAL包含的这两个状态才执行  [try\_to\_wake\_up](https://elixir.bootlin.com/linux/v5.2-rc6/ident/try_to_wake_up)  相关操作。 

* * *

- ### **TASK\_REPORT**
    

         主要应用于\*[get\_task\_state](https://elixir.bootlin.com/linux/v5.2-rc6/ident/get_task_state)函数显示任务状态

         [文件：/](https://elixir.bootlin.com/linux/v5.2-rc6/source)[fs](https://elixir.bootlin.com/linux/v5.2-rc6/source/fs)/[proc](https://elixir.bootlin.com/linux/v5.2-rc6/source/fs/proc)/[array.c](https://elixir.bootlin.com/linux/v5.2-rc6/source/fs/proc/array.c)     

```
/*
 * The task state array is a strange "bitmap" of
 * reasons to sleep. Thus "running" is zero, and
 * you can test for combinations of others with
 * simple bit tests.
 */
static const char * const task_state_array[] = {

	/* states in TASK_REPORT: */
	"R (running)",		/* 0x00 */
	"S (sleeping)",		/* 0x01 */
	"D (disk sleep)",	/* 0x02 */
	"T (stopped)",		/* 0x04 */
	"t (tracing stop)",	/* 0x08 */
	"X (dead)",		/* 0x10 */
	"Z (zombie)",		/* 0x20 */
	"P (parked)",		/* 0x40 */

	/* states beyond TASK_REPORT: */
	"I (idle)",		/* 0x80 */
};

static inline const char *get_task_state(struct task_struct *tsk)
{
	BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) != ARRAY_SIZE(task_state_array));
	return task_state_array[task_state_index(tsk)];
}
```

   可以看到 get\_task\_state 函数显示了大多数任务的状态， 与ps man 命令中的状态对比， 多了一个 P (parked)状态， 也就是上面说得解决cpu hotplug 问题引入的状态描述。

```
man ps
PROCESS STATE CODES
       Here are the different values that the s, stat and state output specifiers
       (header "STAT" or "S") will display to describe the state of a process:

               D    uninterruptible sleep (usually IO)
               R    running or runnable (on run queue)
               S    interruptible sleep (waiting for an event to complete)
               T    stopped by job control signal
               t    stopped by debugger during the tracing
               W    paging (not valid since the 2.6.xx kernel)
               X    dead (should never be seen)
               Z    defunct ("zombie") process, terminated but not reaped by its
                    parent
```

    任务结构详细介绍可以参考极客时间刘超《趣谈Linux操作系统》 12-14章节。 

# 参考

[What is the “Waiting Channel” of a process?](https://askubuntu.com/questions/19442/what-is-the-waiting-channel-of-a-process)

[do\_select()函数分析，理解select(),poll(),poll\_wait()函数的关系](https://blog.csdn.net/lgq1010/article/details/12285211)

[select()/poll() 的内核实现](http://janfan.cn/chinese/2015/01/05/select-poll-impl-inside-the-kernel.html)

[Documentation/mutex-design.txt](https://lwn.net/Articles/602393/)

[TASK\_KILLABLE：Linux 中的新进程状态](https://www.ibm.com/developerworks/cn/linux/l-task-killable/index.html)

[Linux 进程中 Stop, Park, Freeze](http://kernel.meizu.com/linux-process-stop.html)

[kthread: Implement park/unpark facility](https://lwn.net/Articles/500338/)

[Linux CPU core的电源管理(5)\_cpu control及cpu hotplug](http://www.wowotech.net/pm_subsystem/cpu_hotplug.html)

[Documentation for CPU hotplug support](https://lwn.net/Articles/159561/)

[CPU hotplug in the Kernel](https://www.kernel.org/doc/html/latest/core-api/cpu_hotplug.html?highlight=cpu%20hotplug)

[\[tip:sched/core\] sched: Add TASK\_WAKING](https://lore.kernel.org/patchwork/patch/170913/)

[进程调度API之wake\_up\_process](https://blog.csdn.net/tiantao2012/article/details/78872831)

