现在的位置: 首页 > 综合 > 正文

need_sched 一些讨论

2013年12月11日 ⁄ 综合 ⁄ 共 4497字 ⁄ 字号 评论关闭
我想写一个简单的设备驱动, 但对驱动模块的可重入方面不甚了解.

有的书说驱动模块不会被中断, 除非主动地调用schedule()(或是隐式

地调用, 如vmalloc()); 有的书则说即使schedule()被调用, 它也不会

去作进程切换, 因为schedule()不对内核态进程切换.

不知谁对? 望高人指点一二. 谢谢


[Original
]

[Print]
[Top]

Subject
: Re: 设备驱动的可重入问题


Author
: jkl


  
Posted
: 2000-11-29 11:55

  
Length
: 327
byte(s)
[Original
]

[Print]
[Top]

以认为内核态的代码是一种协作式的多线程机制,只有当前线程主动的放弃执行才能引导到新的线程.或者说,当内核有代码不能立即返回到用户代码时,它必须运
行调度过程,将自身挂起,释放对CPU的控制权,当这段线程被唤醒后,代码又从调度过程中返回,它又重新获得CPU控制权,它完成用户指定操作后就可以立
即返回到用户代码中去了.


[Original
]

[Print]
[Top]

Subject
: Re: 设备驱动的可重入问题


Author
: pengchengzou


  
Posted
: 2000-11-29 17:40

  
Length
: 178
byte(s)
[Original
]

[Print]
[Top]
非常感谢JKL的指点. 得寸进尺, 追加一个问题. 如果内核模块不主动放弃CPU,

时钟中断程序是否还会被调用. 是否可以认为在内核模块中中断是被屏蔽调的?

[Original
]

[Print]
[Top]

Subject
: Re: 设备驱动的可重入问题


Author
: difeijing


  
Posted
: 2000-11-29 18:47

  
Length
: 83
byte(s)
[Original
]

[Print]
[Top]
普通情况下,时钟中断仍然会被调用,除非你

显式的关中断.

[Original
]

[Print]
[Top]

Subject
: Re: 设备驱动的可重入问题


Author
: jkl


  
Posted
: 2000-11-29 20:33

  
Length
: 325
byte(s)
[Original
]

[Print]
[Top]

执行操作系统调用时,是不关CPU中断的,时钟中断永远按精确的节拍发生,不管当前CPU是在用户态还是核心态.硬件中断发生时,内核要屏蔽该中断源,当
中断返回时再打开这一号中断,因此同一中断是不会重入的.用户态的硬件中断返回之前要运行调度过程,核心态中断返回时则不运行调度过程,这就是内核过程为
什么不会被抢占的原因.

[Original
]

[Print]
[Top]

Subject
: Re: 设备驱动的可重入问题


Author
: pengchengzou


  
Posted
: 2000-11-30 09:17

  
Length
: 863
byte(s)
[Original
]

[Print]
[Top]
谢谢两位的回答. 得尺进丈一下.

我的理解是, 时钟中断处理函数(do_timer())没有进行实质性的中断服务,

只是设置TIMER_BH, 在Timer Bottom Half 被运行时再作真正的服务.

而Timer Bottom Half 被调用只在这三个时机:

* schedule()

* 系统调用返回

* slow 中断服务返回

我的问题是, 如果系统上运行了两个计算量很大的程序. 它们没有调用任何

系统调用, 那么谁会调用schedule()呢. 是不是一个程序一旦获得CPU, 只要

他不主动放弃 (不调用任何系统调用), 他便不会被调度出去.

我一直以为时钟中断处理函数会作调度工作, 但是看了书和源代码后, 发现

恰恰相反, 是schedule()激活在Timer Bottom Half. 如果真是如此,

Linux的抢占式体现在哪里呢?

我觉得我是哪儿搞错了,很是迷惑. 请大家指点.

多谢.


[Original
]

[Print]
[Top]

Subject
: Re: 设备驱动的可重入问题


Author
: jkl


  
Posted
: 2000-11-30 11:08

  
Length
: 3,927
byte(s)
[Original
]

[Print]
[Top]
看如下的代码应该就清楚了,ret_from_intr是所有硬件中断的返回点.
arch/i386/kernel/entry.S:



ENTRY(system_call)

pushl %eax # save orig_eax

SAVE_ALL

GET_CURRENT(%ebx)

cmpl $(NR_syscalls),%eax

jae badsys

testb $0x20,flags(%ebx) # PF_TRACESYS

jne tracesys

call *SYMBOL_NAME(sys_call_table)(,%eax,4)

movl %eax,EAX(%esp) # save the return value

ALIGN

.globl ret_from_sys_call

.globl ret_from_intr

ret_from_sys_call:

movl SYMBOL_NAME(bh_mask),%eax

andl SYMBOL_NAME(bh_active),%eax

jne handle_bottom_half

ret_with_reschedule:

cmpl $0,need_resched(%ebx) # need_resched可被pdate_process_times()所置位

jne reschedule


cmpl $0,sigpending(%ebx)

jne signal_return

restore_all:

RESTORE_ALL



ALIGN

signal_return:

sti # we can get here from an interrupt handler

testl $(VM_MASK),EFLAGS(%esp)

movl %esp,%eax

jne v86_signal_return

xorl %edx,%edx

call SYMBOL_NAME(do_signal)

jmp restore_all



ALIGN

v86_signal_return:

call SYMBOL_NAME(save_v86_state)

movl %eax,%esp

xorl %edx,%edx

call SYMBOL_NAME(do_signal)

jmp restore_all



ALIGN

tracesys:

movl $-ENOSYS,EAX(%esp)

call SYMBOL_NAME(syscall_trace)

movl ORIG_EAX(%esp),%eax

cmpl $(NR_syscalls),%eax

jae 1f

call *SYMBOL_NAME(sys_call_table)(,%eax,4)

movl %eax,EAX(%esp) # save the return value

1: call SYMBOL_NAME(syscall_trace)

jmp ret_from_sys_call

badsys:

movl $-ENOSYS,EAX(%esp)

jmp ret_from_sys_call



ALIGN

ret_from_exception:

movl SYMBOL_NAME(bh_mask),%eax

andl SYMBOL_NAME(bh_active),%eax

jne handle_bottom_half

ALIGN



ret_from_intr: # 硬件中断的返回点

GET_CURRENT(%ebx)

movl EFLAGS(%esp),%eax # mix EFLAGS and CS

movb CS(%esp),%al

testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor?

jne ret_with_reschedule # 如果是VM86态或用户态就转ret_with_reschedule

jmp restore_all



ALIGN

handle_bottom_half:

call SYMBOL_NAME(do_bottom_half)

jmp ret_from_intr



ALIGN

reschedule:

call SYMBOL_NAME(schedule) # test

jmp ret_from_sys_call


---------------------------------------

kernel/sched.c:



update_process_times()被Timer Bottom Half所调用



static void update_process_times(unsigned long ticks, unsigned long system)

{

/*

* SMP does this on a per-CPU basis elsewhere

*/

#ifndef __SMP__

struct task_struct * p = current;

unsigned long user = ticks - system;

if (p->pid) {

p->counter -= ticks;

if (p->counter < 0) {

p->counter = 0;

p->need_resched = 1;

}

if (p->priority < DEF_PRIORITY)

kstat.cpu_nice += user;

else

kstat.cpu_user += user;

kstat.cpu_system += system;

}

update_one_process(p, ticks, user, system, 0);

#endif

}


[Original
]

[Print]
[Top]

Subject
: 万分感谢jkl, 这下清楚了. :)


Author
: pengchengzou


  
Posted
: 2000-11-30 12:40

  
Length
: 47
byte(s)
[Original
]

[Print]
[Top]
万分感谢jkl, 这下清楚了. :)

[Original
]

[Print]
[Top]

Subject
: Re: 设备驱动的可重入问题


Author
: bravebird


  
Posted
: 2002-10-10 17:06

  
Length
: 323
byte(s)
[Original
]

[Print]
[Top]
update_process_timers在2.4内核里面应该是在上半部中处理的.

我理解的顺序应该是这样:

时间中断产生->update_process_times(计算各个进程的时间片和优先级,决定是否需要重新调度need_sched ?=1)

->ret_from_intr->ret_with_reschedule->call schedule(如果需要的话);

----
我是一只小小小鸟,想要飞却怎么也飞不高....
[Original
]

[Print]
[Top]

Subject
: Re: 设备驱动的可重入问题


Author
: xunclapton


  
Posted
: 2002-10-10 18:24

  
Length
: 152
byte(s)
[Original
]

[Print]
[Top]
进程不调用系统调用也就是一直运行在用户态,但时钟中断还是会发生,如果这个进程时间片到期,时钟中断会把他的need_schedule置1,这样在返回用户态前被schedule()

抱歉!评论已关闭.