首页 | 资讯动态 | linux基础 | 系统管理 | 网络管理 | 编程开发 | linux数据库 | 服务器技术 | linux相关 | linux认证 | 嵌入式 | 下载中心 | 专题 | linux招聘 | 镜像站
OKLinux中文技术站
·设为首页
·加入收藏
·联系我们
系统管理: 中文环境 系统管理 桌面应用 内核技术 | Linux基础: 基础入门 安装配置 常用命令 经验技巧 软件应用 | Linux数据库: Mysql Postgre Oracle DB2 Sybase other
网络管理: 网络安全 网络应用 Linux服务器 环境配置 黑客安全 | 编程开发: PHP CC++ Python Perl Shell 嵌入式开发 java jsp | PHP技术: PHP基础 PHP技巧 PHP应用 PHP文摘
Linux资讯 Linux招聘 Linux专题 Apache | Linux相关: 硬件相关 Linux解决方案 Linux认证 企业应用 其它Unix | 相关下载: 资料下载 参考手册 开发工具 服务器类 软路由 其它
 技术搜索:
会员中心 注册会员 高级搜索  
  → 当前位置:首页>系统管理>内核技术>正文

小鸟学飞

http://www.oklinux.cn  2006-07-29  来源: oklinux收集整理  邓西村      会员收藏  游客收藏  【 】 
我一直想,应该给自己的第一个帖子起个什么标题好,婉转的小鸟的歌声不期而至,于是就以这个为题吧。这段时间,我一直在学习LINUX内核,却如赵传的歌声那样,我是一只小小鸟,怎么飞也飞不高,期望能和大家一起探讨探讨这内核的奥妙。写这帖子就如同我上交的作业。
     我想从进程的调度开始。以下是从MontaVista Linux预览版本上摘录的schedule(),就从这里开始吧。
代码在kenerl/Sched.c中。该版本采用2.4.XX内核。
/*
* schedule() is the main scheduler function.
*/
asmlinkage void schedule(void)
{
        task_t *prev, *next;
        runqueue_t *rq;
        prio_array_t *array;
        struct list_head *queue;
        int idx;

        if (unlikely(in_interrupt()))
                BUG();

need_resched:
        preempt_disable();
        prev = current;
        rq = this_rq();

        release_kernel_lock(prev, smp_processor_id());
        prepare_arch_schedule(prev);
        prev->sleep_timestamp = jiffies;
        spin_lock_irq(&rq->lock);

        /*
         * if entering from preempt_schedule, off a kernel preemption,
         * go straight to picking the next task.
         */
        if (unlikely(preempt_get_count() & PREEMPT_ACTIVE))
                goto pick_next_task;

        switch (prev->state) {
        case TASK_INTERRUPTIBLE:
                if (unlikely(signal_pending(prev))) {
                        prev->state = TASK_RUNNING;
                        break;
                }
        default:
                deactivate_task(prev, rq);
        case TASK_RUNNING:
                ;
        }
pick_next_task:
        if (unlikely(!rq->nr_running)) {
#if CONFIG_SMP
                load_balance(rq, 1);
                if (rq->nr_running)
                        goto pick_next_task;
#endif
                next = rq->idle;
                rq->expired_timestamp = 0;
                goto switch_tasks;
        }

        array = rq->active;
        if (unlikely(!array->nr_active)) {
                /*
                 * Switch the active and expired arrays.
                 */
                rq->active = rq->expired;
                rq->expired = array;
                array = rq->active;
                rq->expired_timestamp = 0;
        }

        idx = sched_find_first_bit(array->bitmap);
        queue = array->queue + idx;
        next = list_entry(queue->next, task_t, run_list);

switch_tasks:
        prefetch(next);
        clear_tsk_need_resched(prev);

        if (likely(prev != next)) {
                rq->nr_switches++;
                rq->curr = next;
       
                prepare_arch_switch(rq);

                TRACE_SCHEDCHANGE(prev, next);

                prev = context_switch(prev, next);
                barrier();
                rq = this_rq();
                finish_arch_switch(rq);
        } else
                spin_unlock_irq(&rq->lock);
        finish_arch_schedule(prev);

        reacquire_kernel_lock(current);
        preempt_enable_no_resched();
        if (need_resched())
                goto need_resched;
}
该内核虽然说是2.4的,但该schedule()更象是2.6版本的。以下是2.4.31版本的
/*
*  'schedule()' is the scheduler function. It's a very simple and nice
* scheduler: it's not perfect, but certainly works for most things.
*
* The goto is "interesting".
*
*   NOTE!!  Task 0 is the 'idle' task, which gets called when no other
* tasks can run. It can not be killed, and it cannot sleep. The 'state'
* information in task[0] is never used.
*/
asmlinkage void schedule(void)
{
        struct schedule_data * sched_data;
        struct task_struct *prev, *next, *p;
        struct list_head *tmp;
        int this_cpu, c;


        spin_lock_prefetch(&runqueue_lock);

        BUG_ON(!current->active_mm);
need_resched_back:
        prev = current;
        this_cpu = prev->processor;

        if (unlikely(in_interrupt())) {
                printk("Scheduling in interrupt\n");
                BUG();
        }

        release_kernel_lock(prev, this_cpu);

        /*
         * 'sched_data' is protected by the fact that we can run
         * only one process per CPU.
         */
        sched_data = & aligned_data[this_cpu].schedule_data;

        spin_lock_irq(&runqueue_lock);

        /* move an exhausted RR process to be last.. */
        if (unlikely(prev->policy == SCHED_RR))
                if (!prev->counter) {
                        prev->counter = NICE_TO_TICKS(prev->nice);
                        move_last_runqueue(prev);
                }

        switch (prev->state) {
                case TASK_INTERRUPTIBLE:
                        if (signal_pending(prev)) {
                                prev->state = TASK_RUNNING;
                                break;
                        }
                default:
                        del_from_runqueue(prev);
                case TASK_RUNNING:;
        }
        prev->need_resched = 0;

        /*
         * this is the scheduler proper:
         */

repeat_schedule:
        /*
         * Default process to select..
         */
        next = idle_task(this_cpu);
        c = -1000;
        list_for_each(tmp, &runqueue_head) {
                p = list_entry(tmp, struct task_struct, run_list);
                if (can_schedule(p, this_cpu)) {
                        int weight = goodness(p, this_cpu, prev->active_mm);
                        if (weight > c)
                                c = weight, next = p;
                }
        }

        /* Do we need to re-calculate counters? */
        if (unlikely(!c)) {
                struct task_struct *p;

                spin_unlock_irq(&runqueue_lock);
                read_lock(&tasklist_lock);
                for_each_task(p)
                        p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);
                read_unlock(&tasklist_lock);
                spin_lock_irq(&runqueue_lock);
                goto repeat_schedule;
        }

        /*
         * from this point on nothing can prevent us from
         * switching to the next task, save this fact in
         * sched_data.
         */
        sched_data->curr = next;
        task_set_cpu(next, this_cpu);
        spin_unlock_irq(&runqueue_lock);

        if (unlikely(prev == next)) {
                /* We won't go through the normal tail, so do this by hand */
                prev->policy &= ~SCHED_YIELD;
                goto same_process;
        }

#ifdef CONFIG_SMP
        /*
         * maintain the per-process 'last schedule' value.
         * (this has to be recalculated even if we reschedule to
         * the same process) Currently this is only used on SMP,
         * and it's approximate, so we do not have to maintain
         * it while holding the runqueue spinlock.
         */
        sched_data->last_schedule = get_cycles();

        /*
         * We drop the scheduler lock early (it's a global spinlock),
         * thus we have to lock the previous process from getting
         * rescheduled during switch_to().
         */

#endif /* CONFIG_SMP */

        kstat.context_swtch++;
        /*
         * there are 3 processes which are affected by a context switch:
         *
         * prev == .... ==> (last => next)
         *
         * It's the 'much more previous' 'prev' that is on next's stack,
         * but prev is set to (the just run) 'last' process by switch_to().
         * This might sound slightly confusing but makes tons of sense.
         */
        prepare_to_switch();
        {
                struct mm_struct *mm = next->mm;
                struct mm_struct *oldmm = prev->active_mm;
                if (!mm) {
                        BUG_ON(next->active_mm);
                        next->active_mm = oldmm;
                        atomic_inc(&oldmm->mm_count);
                        enter_lazy_tlb(oldmm, next, this_cpu);
                } else {
                        BUG_ON(next->active_mm != mm);
                        switch_mm(oldmm, mm, next, this_cpu);
                }

                if (!prev->mm) {
                        prev->active_mm = NULL;
                        mmdrop(oldmm);
                }
        }

        /*
         * This just switches the register state and the
         * stack.
         */
        switch_to(prev, next, prev);
        __schedule_tail(prev);

same_process:
        reacquire_kernel_lock(current);
        if (current->need_resched)
                goto need_resched_back;
        return;
}

上一篇:linux内核防synflood   下一篇:Linux 2.6内核中新的锁机制--RCU


收藏于收藏夹】 【评论】 【推荐】 【打印】 【关闭
相关文档
·linux内核防synflood
·Linux 2.6内核中新的锁机制--RCU
·FC4 下编译Linux内核+perfctr
·Linux 2.6 内核的嵌入式系统应用
·linux内核源码目录结构
·Debian/Ubuntu Linux下内核编程者必备的几件法宝
·Linux:让内存不再泄漏
·Linux 内核解读入门
·最新Linux内核:更好的Wi-Fi和文件系统
·Linux密码的破解
·升级Linux内核奋斗记
·Linux内核ARP的设计实现概述 ZT
·Linux内核源代码位于/usr/src/linux目录中概述
·Linux内核主要五个子系统详解
·KGDB源码级的内核调试
·linux 内核版本号
发表评论
密码: 匿名评论
评论内容:

(不超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规)
 
  最新文档
·Linux系统下内核定时器的用法
·学习园地:Linux系统内核中判断大小的
·系统编译:如何给Make命令来传递参数
·Linux 2.6内核中sysfs文件系统简单概述
·Fedora 8 Linux系统的内核配置注意事项
·升级Linux内核的一般步骤方法
·Linux发行版知识普及:三个版本的CPUID
·编译安装Virtualbox驱动模块
· Linux系统的内核解读入门
·新手学堂 Linux系统的内核解读入门
·Linux系统内核中网络参数的意义及其应
·走向Linux系统高手之路 内核编译过程解
  阅读排行
· 深入理解LINUX内核中文版下载地址
·基于S3C44B0微处理器的uClinux内核引导
·Kernel command using Linux system ca
·Linux 2.6内核如何武装Fedora Core 2
·Process priority and control on AIX
·Linux操作系统的内核编译内幕详解
·推荐:Linux用户态与内核态的交互
·通过振动向Linux ThinkPad传输信息
·Linux操作系统源代码详细分析(二)
·Linux系统内核接收以太帧的处理程序
·Linux and symmetric multiprocessing
·主流嵌入式Linux系统下GUI解决方案
·揭秘Linux内核调试器之内幕
·用命令行加挂Linux的文件系统简介
·Linux内核和核心OS组件的测试与分析
网摘收藏: