《Linux内核分析》第五课笔记

孟宁老师的《Linux内核分析》第五课内容与授课大纲上有出入,实际上继续在讲系统调用。前文《Linux内核分析》第四课笔记中已经提前分析了本课的主要内容,这里再做一些补充。

系统调用的代码级跟踪

在课程中,孟宁老师展示了使用gdb来追踪系统调用的步骤,这种方法有些地方跟踪困难。我们可以直接阅读内核源码来了解一个系统调用做了什么。

从system_call到一个具体系统调用的过程已经很清楚,它最终会调用sys_call_table中的对应系统调用服务例程来处理。这些服务例程名称都是sys_XX()。

然而直接搜sys_XX是无法找到函数实现的,因为内核代码做了一个宏定义:

============= include/linux/syscalls.h 244 244 ============ #define SYSCALL_DEFINE(name) asmlinkage long sys_##name

想要找到真正的系统调用实现要搜索SYSCALL_DEFINE和SYSCALL_DEFINE0、SYSCALL_DEFINE1等。例如time系统调用的服务例程为:

================= kernel/time.c 62 72 ======================
SYSCALL_DEFINE1(time, time_t __user *, tloc)
{
    time_t i = get_seconds();

    if (tloc) {
        if (put_user(i,tloc))
            return -EFAULT;
    }
    force_successful_syscall_return();
    return i;
}

系统调用的退出

系统调用的退出和系统从中断和异常中退出的流程基本一致,它们都在同一个文件中,共享了绝大多数代码。这张图说明了中断和异常的退出流程,可以用来理解系统调用的退出。

《Linux内核分析》第五课笔记_第1张图片

中断和异常处理过程中存在内核控制路径的嵌套,而系统调用不存在这一问题。因此系统调用的退出流程集中在resume_userspace分支里。它涉及到重新调度、信号处理和虚拟8086模式等几个方面的主题,这里不再展开。

time系统调用的简单分析

从上面的代码可以看到,time系统调用主要工作是使用get_seconds()获取一个值,然后返回给用户。

================= kernel/time/timekeeping.c 854 857 ==================
unsigned long get_seconds(void)
{
    return xtime.tv_sec;
}

这里直接返回内核全局结构体变量xtime的秒域。xtime是一个timespec结构体,它还有一个精度更高的纳秒域。

================= include/linux/time.h 14 17 ==================
struct timespec {
    __kernel_time_t tv_sec;         /* seconds */
    long        tv_nsec;        /* nanoseconds */
};

我们知道,内核的定时中断是以HZ为频率的,每1/HZ秒才能更新一次时间,这就不可能达到ns的精度。那么这个tv_nsec是如何维护的呢?
这个问题涉及Linux时间管理子系统的工作原理,答案将在下一讲中揭晓。

你可能感兴趣的:(linux,kernel,系统调用)