linux进程调度 - 组织进程
来源:互联网 发布:淘宝文案策划待遇 编辑:程序博客网 时间:2024/05/20 09:07
1. 进程的运行状态
进程的运行状态有下面这么几种:
进程被创建后,会被设置各种运行状态,然后会被不同方式进行处理,分下面两种情况
1.1 可运行进程处置方式
TASK_RUNNING状态的进程会被挂入一个运行队列的链表中,然后被调度程序来选择合适的时机进行调度运行,这个运行队列链表是runqueues,会在以后的文章中介绍
1.2 不运行进程处置方式
当要把其他状态的进程分组时,不同的状态要求不同的处理,对于处于暂停、僵死、死亡状态的进程没有专门的链表来组织它们,对于处于TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE状态的进程会把它们加入不同的等待队列中,等待合适的条件来把他们转化为TASK_RUNNING状态并加入运行队列,然后被调度执行。
2. 进程等待队列
等待队列在内核中有很多用途,比如在中断处理、进程同步及定时等,等待队列由双向链表实现,每个等待队列都有一个等待队列头(wait queue head),数据结构如下所示:
typedef struct __wait_queue_head wait_queue_head_t;struct __wait_queue_head { spinlock_t lock; struct list_head task_list;-----------等待队列链表头,队列元素都加入此list};
每个等待队列头中后期都会加入进程,这些进程由**队列元素**wait_queue_t来包装。
typedef struct __wait_queue wait_queue_t;struct __wait_queue { unsigned int flags;---------------区分互斥进程(1)和非互斥进程(0) void *private;----------------一般是task_struct wait_queue_func_t func;----------------唤醒此队列元素的函数 struct list_head task_list;-----------list};
一般来说互斥进程会加入到队尾,非互斥进程在队列头
2.1 初始化等待队列头
定义的每个队列元素,都会加入一个已经初始化好的等待队列头中,初始化wait_queue_head_t的宏定义为DECLARE_WAIT_QUEUE_HEAD(name),如下所示:
#define DECLARE_WAIT_QUEUE_HEAD(name) \ wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \ .lock = __SPIN_LOCK_UNLOCKED(name.lock), \ .task_list = { &(name).task_list, &(name).task_list } }
2.2 初始化队列元素
初始化一个wait_queue_t的宏定义为#define DECLARE_WAITQUEUE(name, tsk),第二个参数是进程描述符,如下所示:
#define DECLARE_WAITQUEUE(name, tsk) \ wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)#define __WAITQUEUE_INITIALIZER(name, tsk) { \ .private = tsk, \ .func = default_wake_function, \ .task_list = { NULL, NULL } }
另外还有一些函数能初始化wait_queue_t,如下所示:
static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p){ q->flags = 0; q->private = p; q->func = default_wake_function;----------------内核默认的一个唤醒函数}static inline voidinit_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func){-------------------------------------------------------和进程无关的队列元素 q->flags = 0; q->private = NULL; q->func = func;}
当然也可以自定义函数来初始化wait_queue_t
3. 把进程加入等待队列
等待队列头和队列元素初始化后,就可以把前者加入后者中了,相应会有多个函数能做这项任务
- 非互斥进程调用的函数
(kernel/sched/wait.c : wait.h)
extern void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);上面的函数最后会调用函数__add_wait_queuestatic inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new){ list_add(&new->task_list, &head->task_list);}
- 互斥进程调用的函数:
(kernel/sched/wait.c : wait.h)
extern void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);上面的函数最后会调用函数__add_wait_queue_tailstatic inline void __add_wait_queue_tail(wait_queue_head_t *head, wait_queue_t *new){ list_add_tail(&new->task_list, &head->task_list);}
4. 唤醒等待队列中的进程
唤醒等待队列中的元素有一些宏定义:
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)#define wake_up_nr(x, nr) __wake_up(x, TASK_NORMAL, nr, NULL)#define wake_up_all(x) __wake_up(x, TASK_NORMAL, 0, NULL)#define wake_up_locked(x) __wake_up_locked((x), TASK_NORMAL, 1)#define wake_up_all_locked(x) __wake_up_locked((x), TASK_NORMAL, 0)#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)#define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)#define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)#define wake_up_interruptible_sync(x) __wake_up_sync((x), TASK_INTERRUPTIBLE, 1)
最终调用到函数__wake_up -> __wake_up_common
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, int wake_flags, void *key){ wait_queue_t *curr, *next; list_for_each_entry_safe(curr, next, &q->task_list, task_list) { unsigned flags = curr->flags; if (curr->func(curr, mode, wake_flags, key) && (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) break; }}
遍历链表中的每项队列元素,执行其func函数,默认的一个唤醒函数是default_wake_function
int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags, void *key){ return try_to_wake_up(curr->private, mode, wake_flags);}
change log
- linux进程调度 - 组织进程
- 进程调度之--进程的组织
- linux 进程与进程调度
- Linux 进程调度工具
- linux进程调度解析
- linux进程调度策略
- Linux 进程调度原理
- linux进程调度政策
- Linux进程调度时机
- Linux 进程调度机制
- Linux 进程调度原理
- linux进程调度方法
- Linux 进程调度原理
- linux 进程调度
- Linux 进程调度分析
- Linux 进程调度原理
- linux进程调度关键词
- linux进程调度浅析
- Android学习 (十六) 用HttpURLConnection方法发送一个HTTP请求
- Java 实例
- c++的随机数
- Error:No signature of method: java.lang.Integer.call() is applicable for arg
- 动态规划——看似dp的贪心问题最大乘积(蓝桥杯试题集)
- linux进程调度 - 组织进程
- Android Material Design兼容库控件使用(一)
- 网络爬虫学习笔记——GET方法下几种常用情况
- 新增非空约束字段在不同版本中的演进
- *[Lintcode]k Sum II
- DatabaseTest
- 死循环-内存溢出
- python中的闭包与装饰器
- 第十一周项目1——二叉树算法验证(2)二叉树构造算法验证