范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Linux0。11kernel目录进程管理sched。c详解

  sched.c主要功能是负责进程的调度,其最核心的函数就是 schedule 。除schedule以外, sleep_on和wake_up也是相对重要的函数。 schedulevoid schedule(void)
  schedule函数的基本功能可以分为两大块, 第一块是 检查task中的报警信息和信号 , 第二块则是 进行任务的调度 。
  在第一块中,首先从任务数组的尾部任务开始,检查alarm是否小于当前系统滴答值,如果小于则代表alarm时间已经到期。将进程的signal中的SIGALARM位置1。
  接着就看如果检查进程的信号中如果处理BLOCK位以外还有别的信号,并且如果任务处于可中断状态,则将任务置为就绪状态。 int i,next,c; struct task_struct ** p;  for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)     if (*p) {         if ((*p)->alarm && (*p)->alarm < jiffies) { //如果设置了任务定时的值alarm, 并且已经过期                 (*p)->signal |= (1<<(SIGALRM-1)); //将信号的SIGALARM位置为1                 (*p)->alarm = 0;             }         if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&         (*p)->state==TASK_INTERRUPTIBLE)//如果信号位图中除了被阻塞的信号外还有其他信号, 并且任务处于可中断状态             (*p)->state=TASK_RUNNING; //修改任务的状态为就绪态     }
  第二块的代码就是任务调度的核心代码。
  这里会从任务数组的尾部任务开始进行遍历,从所有任务从选取counter值最大的任务作为下一个运行的任务去执行。 while (1) { 	c = -1; 	next = 0; 	i = NR_TASKS; 	p = &task[NR_TASKS];//从最后一个任务开始 	while (--i) { //遍历所有的task, 取出其中counter最大的task 		if (!*--p) 			continue; 		if ((*p)->state == TASK_RUNNING && (*p)->counter > c)//取出所有任务中counter值最大的任务作为下一个任务 			c = (*p)->counter, next = i; 	} 	if (c) break; 	//如果当前没有RUNNING状态的任务的counter可以大于-1,那么则去更新counter的值,counter = counter/2 + priority 	for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) 		if (*p) 			(*p)->counter = ((*p)->counter >> 1) + 					(*p)->priority;//更新counter值 counter = counter/2 + priority } //切换任务执行next switch_to(next);show_taskvoid show_task(int nr,struct task_struct * p)
  该函数的作用是显示任务序号为nr的进程的pid,进程状态以及内核栈剩余的大小。 int i,j = 4096-sizeof(struct task_struct);  printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state); i=0;
  此时j指向PCB所在内存页的顶部, i指向task_struct结构体的下一个字节。下面这段代码的所用实际就是统计内核栈中空闲大小。
  show_taskwhile (istate = TASK_INTERRUPTIBLE; schedule();sleep_onvoid sleep_on(struct task_struct **p)
  该函数的作用是将当前的task置为 不可中断的等待状态 , 直到被wake_up唤醒再继续执行。入参p是等待任务队列的头指针。通过p指针和tmp变量将等待的任务串在了一起。
  sleep_on示意图
  该函数首先对一些异常情况进行了处理他, 例如p是空指针。或者当前task是任务0。 struct task_struct *tmp;  // 若指针无效,则退出。(指针所指的对象可以是NULL,但指针本身不会为0)。 if (!p) 	return; if (current == &(init_task.task))	// 如果当前任务是任务0,则死机(impossible!)。 	panic ("task[0] trying to sleep");
  接着让当前等待任务的头指针指向当前任务。并将当前任务修改为 不可中断的等待状态 。进行调用schedule函数让操作系统切换其他任务执行。 tmp = *p; *p = current; current->state = TASK_UNINTERRUPTIBLE; schedule();
  当程序从schedule()返回继续执行时,说明任务已经被显式的wake_up,如果此时还有其他进程仍然在等待,那么也一同唤醒。
  因为任务都在等待同样的资源, 那么当资源可用的时候, 就可以唤醒所有等待的任务。 if (tmp)			// 若还存在等待的任务,则也将其置为就绪状态(唤醒)。 	tmp->state = 0;interruptible_sleep_onvoid interruptible_sleep_on (struct task_struct **p)
  该函数与sleep_on类似,但是该函数会将任务的状态修改为 可中断的等待状态 , 而sleep_on则是将任务修改为 不可中断的等待状态 。因此通过interruptible_sleep_on而等待的task是可以被信号唤醒的。 而通过sleep_on而等待的task是 不会被信号唤醒的 ,只能通过wake_up函数唤醒。
  interruptible_sleep_on示意图
  下面这段代码与sleep_on并无太大区别, 只是将进程的状态修改为可中断的等待状态。 	struct task_struct *tmp;  	if (!p) 		return; 	if (current == &(init_task.task)) 		panic ("task[0] trying to sleep"); 	tmp = *p; 	*p = current; repeat: 	current->state = TASK_INTERRUPTIBLE; 	schedule ();
  由于任务是可以被信号唤醒的,因此下面需要判断唤醒的任务是否是等待任务队列的头节点。如果不是则需要等待其他任务。 if (*p && *p != current) { 	(**p).state = 0; 	goto repeat; }
  下面一句代码有误,应该是*p = tmp,让队列头指针指向其余等待任务,否则在当前任务之前插入 等待队列的任务均被抹掉了 *p = NULL; if (tmp) 	tmp->state = 0;wake_upvoid wake_up(struct task_struct **p)
  该函数的作用就是唤醒某一个任务。其用于唤醒p指向的等待队列中的任务。 if (p && *p) { 	(**p).state = 0;		// 置为就绪(可运行)状态。 	*p = NULL; }ticks_to_floppy_onint ticks_to_floppy_on(unsigned int nr)
  该函数指定软盘到正常运转状态所需延迟滴答数(时间)。 floppy_onvoid floppy_on(unsigned int nr)
  该函数等待指定软驱马达启动所需时间。 floppy_offvoid floppy_off(unsigned int nr)
  关闭相应的软驱马达停转定时器3s。 moff_timer[nr]=3*HZ;do_floppy_timervoid do_floppy_timer(void)
  如果马达启动定时到则唤醒进程。 if (mon_timer[i]) { 	if (!--mon_timer[i]) 		wake_up(i+wait_motor);
  如果马达停转定时到期则复位相应马达启动位,并更新数字输出到寄存器。 else if (!moff_timer[i]) { 	current_DOR &= ~mask; 	outb(current_DOR,FD_DOR);add_timeradd_timer(long jiffies, void (*fn)(void)) ```、 该函数的作用是设置定时值和相应的处理函数。  如果定时的值小于0, 那么立即调用处理函数。 ```c if (jiffies <= 0) 	(fn)();
  如果定时的值大于0, 那么首先取timer_list数组中寻找一个位置,将该位置上的滴答数设置为jiffies,将该位置上的fn设置为入参fn。并让next_timer指向它。 for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++) 	if (!p->fn) 		break; if (p >= timer_list + TIME_REQUESTS) 	panic("No more time requests free"); p->fn = fn; p->jiffies = jiffies; p->next = next_timer; next_timer = p;
  下面这段代码的作用是将刚刚插入链表中的timer移动的合适的位置。
  由于next_timer这个链表上的jiffies是一个相对值,即相对于前面一个timer还有多久到期。因此上面步骤的timer也需要进行转换。
  timer移动示意图
  while (p->next && p->next->jiffies < p->jiffies) { 	p->jiffies -= p->next->jiffies;//减去下一个timer的jiffies 	fn = p->fn;//将当前的fn保存给临时变量 	p->fn = p->next->fn;//将当前的fn设置为下一个timer的fn 	p->next->fn = fn;//将下一个timer的fn设置为临时变量fn 	jiffies = p->jiffies;//将jiffies保存给一个临时变量 	p->jiffies = p->next->jiffies;//将当前的jiffies设置为下一个timer的jiffies 	p->next->jiffies = jiffies;//将下一个timer的jiffies设置为当前的jiffies 	p = p->next; 	//这一步骤实际上将p向后挪动到合适的位置, 并把jiffies转化成相对值。 }do_timervoid do_timer(long cpl)
  该函数是时钟中断的处理函数。其在system_call.s中的timer_interrupt函数中被调用。
  参数cpl表示的是当前的特权级, 0表示时钟中断发生时,当前运行在内核态,3表示时钟中断发生时,当前运行在用户态。
  下面的代码根据cpl的值将进程PCB中的utime和stime进行修改。如果cpl为0,则增加stime(supervisor time), 如果cpl为3, 则增加utime。 if (cpl) 	current->utime++; else 	current->stime++;
  下面对定时器的链表进行遍历。 将链表的第一个定时器的滴答数减1。如果滴答数已经等于0, 代表该定时器已经到期,那么需要调用相应的处理程序进行处理。 if (next_timer) { 	next_timer->jiffies--; 	while (next_timer && next_timer->jiffies <= 0) { 		void (*fn)(void); 		 		fn = next_timer->fn; 		next_timer->fn = NULL; 		next_timer = next_timer->next; 		(fn)(); 	} }
  下面代码则是将当前运行的进程的时间片减去1,如果此时进程时间片没有用完,该函数则返回。 如果此时进程时间已经用完,则将时间片设置为0。并且如果此时cpl表明中断发生用户态,那么还将会触发进程的调度。 if ((--current->counter)>0) return; current->counter=0;sys_alarmint sys_alarm(long seconds)
  该函数用于设置 报警值 。
  jiffies是指的是系统开机到目前经历的滴答数。
  current->alarm的单位也是系统滴答数。
  因此(current->alarm - jiffies) /100 就代表就是当前的定时器还剩下多少秒。
  而设置alarm值则需要加上系统当前的滴答数据jiffies, 如下图所示:
  sys_alarm
  sys_getpidint sys_getpid(void)
  该函数用于获取进程的pid。 sys_getppidint sys_getppid(void)
  该函数用于获取父进程的pid。 sys_getuidint sys_getuid(void)
  该函数用于获取用户的uid。 sys_geteuidint sys_geteuid(void)
  该函数用于获取用户的有效id(euid)。 sys_getgidint sys_getgid(void)
  获取组和id号(gid)。 sys_getegidint sys_getegid(void)
  取有效的组id(egid) sys_niceint sys_nice(long increment)
  该函数的作用是降低进程在调度时的优先级。 sched_initvoid sched_init(void)
  该函数的作用是初始化进程调度模块。
  首先在gdt表中设置任务0的tss和ldt值。接着对其他任务的tss和ldt进行初始化。 set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); p = gdt+2+FIRST_TSS_ENTRY; for(i=1;ia=p->b=0; 	p++; 	p->a=p->b=0; 	p++; }
  显式地将任务0的tss加载到寄存器tr中, 显式地将任务0的ldt加载到ldtr中。 ltr(0); lldt(0);
  下面的代码用于初始化8253定时器。通道0,选择工作方式3,二进制计数方式。 outb_p(0x36,0x43);		/* binary, mode 3, LSB/MSB, ch 0 */ outb_p(LATCH & 0xff , 0x40);	/* LSB */ outb(LATCH >> 8 , 0x40);	/* MSB */
  设置时钟中断处理程序的处理函数, 设置系统调用的中断处理函数。 set_intr_gate(0x20,&timer_interrupt); outb(inb_p(0x21)&~0x01,0x21); set_system_gate(0x80,&system_call);

绿美广东丨广东公布首批自然资源林业法治宣传教育基地名单南方财经全媒体记者喻淑琴实习生周可莹傅杨清广州报道3月18日,厚植宪法根基共建绿美广东为主题的法治宣传活动在广州市白云山举办。活动现场公布了首批广东省自然资源林业法治宣传教育基地名国际幸福日9个技巧,找到生活中的幸福感受访专家西南大学心理学部应用心理系教授汤永隆环球时报健康客户端记者高嘉悦3月20日是国际幸福日,国际知名民调机构益普索集团(Ipsos)发布了一份有关全球幸福指数的调查报告,结果显跨国恋情不只现代有,早在古代,唐玄宗就体验把中西合璧了以风流著称的唐玄宗在后官姬妾中,有过洋贵妃。著名的文史专家葛承雍曾堤出,唐玄宗有过一个胡旋女。在新唐书的诸帝公主传中记载寿安公主,曹野那姬所生。在隋唐时代,姬是人们用来称呼年轻貌美古代出公差如何报销呢?现在如果是公派出差吃饭,住宿,交通费都是能报销的。当然,你必须得提供发票或者是消费凭证,那在古代也有发票吗?古人能报销吗?其实在古代官员出行沿途都会遇到许多客栈,这些客栈便是政府专古代灯具鉴赏,没有电的古代,居然都用上了落地灯历史开讲阅读此文前,诚邀您点击一下关注,既方便您进行讨论与分享,又给您带来不一样的参与感,感谢您的支持。引言灯具与家具是两个密不可分的事物,中国古代灯具与家具的关系发展可以分为三个4消息!王晗引冲突,沃特禁赛1场,莫兰德喊话杨鸣,北京攻守蜕变山东惨败给北京之后,只能说他们的内部已经非常混乱了。毕竟攻守两端的人心都散了,而且队内还爆发了冲突。当时王晗一直都在指责刘冠岑,认为他是球队惨败的主要原因。甚至下半场王晗对其破口大缅怀致敬!今天是你的生日你是卫国戍边英雄边境一线你始终是官兵眼中的标杆陈红军今天,是你的生日网友们纷纷缅怀致敬难忘的背影位于西部边境喀喇昆仑山脉褶皱深处的加勒万河谷乱石嶙峋,激流滔滔这里是祖国的西部边陲也当年给拳皇女角色取过的绰号,如今再提总觉得难以启齿游戏厅大多玩家都是中小学的小屁孩,并没有过多的见识和阅历。游戏瘾却看不懂游戏中讲的故事,以及几位可选人物的身份。也正是如此,催生出各种奇葩的绰号。但奇怪的是,无论绰号多么怪异,只要可穿戴设备或迎颠覆性突破!鳄鱼皮压力传感器可100拉伸财联社上海3月20日讯(编辑黄君芝)在过去的几十年里,人们对开发可穿戴或贴片式电子产品产生了巨大的市场需求。开发具有多种感官的电子皮肤对于康复医疗保健假肢机器人等各个领域都是至关重2023年第一个做电商被小二整抑郁的商家简单说一下我这个老实本分的电商商家被小二整抑郁的过程,买家下单购买了产品开了发票,发票随货一起发出,收到后买家反应发票税号有误卖家回应那就等确认收货重新开一份,但是没等到买家确认收被师父抛弃,被女人背叛,如今的欧弟再难回巅峰,他做错了什么?文流水十年闲编辑9号探秘人截至今日,芒果台综艺天天向上已停播五个多月,这段时间很多观众发出质疑这个节目真的凉了吗?对很多人来说,这个节目陪伴了自己14年的青春,尽管因为各种原因陆续
多尔衮当不了皇帝,就当皇帝的后爹爱新觉罗多尔衮。他的身份是叔父摄政王也是皇父摄政王,是有清代举足轻重的中坚人物。今天我们看到的清宫故事大都发生在北京紫禁城里,这跟多尔衮有很大关系。清朝都城本是在沈阳,迁都北京就是勾搭上皇帝的丈母娘后,他被史书除名了文食堂汉景帝刘启汉景帝中元二年(公元前148年),长安未央宫里灯光摇曳。天子刘启,脸色扭曲,阴沉如水,眼眸中迸射出缕缕杀机。因为他刚得到消息花甲之年的曲周侯郦寄,老树开花,又准备娶国庆七天假NBA有哪些精彩比赛国庆小长假来了,这个假期,喜爱篮球的朋友不要错过NBA季前赛,根据赛程整理了一份表格,方便大家选择自己喜欢的球队和方便的时间来看比赛。今年还有2支海外球队参加季前赛,分别是以色列球我国成功实施问天实验舱转位据中国载人航天工程办公室消息北京时间2022年9月30日12时44分,经过约1小时的天地协同,问天实验舱完成转位。转位期间,问天实验舱首先完成相关状态设置,而后与天和核心舱分离,之普京签字接收新领土,美欧声称将实施更多制裁(文姜涛)据俄罗斯媒体报道,9月30日,俄罗斯总统普京在克里姆林宫会见通过全民公投的顿涅茨克卢甘斯克赫尔松州和扎波罗热州四地领导人,并签署关于接纳这四地加入俄罗斯的条约,所有这四个男子因孩子被推倒,竟一脚踹伤7岁男童,冲动的惩罚就是惨遭拘留近日,广东珠海一男子因2岁的女儿被7岁男童推倒,随后直接飞奔向7岁男童,一脚将7岁男童踢飞。男子因孩子被推倒,7岁男童却遭其猛踹一脚,结果冲动后遭拘留7岁男童被踢后直接趴在地上,痛高通骁龙8Gen2将采用全新四丛集架构9月30日消息,据外媒wccftech报道,高通即将在2022年11月中旬发布新一代旗舰移动处理器Snapdragon8Gen2。最新的爆料显示,Snapdragon8Gen2将采加密监管即将来临,哪些代币会被波及?在最新出台的监管规则中,部分加密货币企业将会受到法律的制裁。最近几个月,拜登政府的主要官员发表的声明,监管机构的执法情况,还有许多报道,都表明了美国政府将怎样监管加密货币。美国财政要求儿女两家7口回来过国庆,女儿把我拉黑了,儿媳闹离婚毕淑敏在文章孝心无价中说我相信每一个赤诚忠厚的孩子,都曾在心底向父母许下孝的宏愿,相信来日方长,相信水到渠成,相信必有功成名就衣锦还乡的那一天,可以从容尽孝。可惜人们都忘了,忘了时大长腿美女高清图片(8)假如你是一棵仙人掌,我也愿意忍受所有的疼痛来抱着你。你闻到空气中有烧焦的味道吗?那是我的心在为你燃烧。你知道我为什么会感冒吗?因为见到你就没有抵抗力呀,我爱你。想带你去吃烤紫薯,然黑暗中的掌灯人高尔基的前半生遇见了很多人,在当时的社会背景下,他们大多数都狭隘恶毒,甚至可以为了一点蝇头小利大打出手,可以因为嫉妒或者不满而害人性命。但是外祖母的善良像一颗原始的火种,在高尔基心