Linux是一款开源的、基于Unix的操作系统。作为世界上最著名的服务器操作系统之一,Linux已经成为了不可或缺的一部分,它在云计算、大数据处理和安全方面发挥着至关重要的作用。在Linux内核中,对于任何一位程序员和系统工程师而言,最基本的就是对Linux源码的理解。本篇文章将深入探究linux 3.10.0源码,帮助大家更好地了解内核的奥秘。
成都创新互联专注于金堂县企业网站建设,响应式网站设计,商城网站制作。金堂县网站建设公司,为金堂县等地区提供建站服务。全流程定制开发,专业设计,全程项目跟踪,成都创新互联专业和态度为您提供的服务
1. 开始我们的探究之旅
我们需要了解的是,Linux 3.10.0是一个稳定版的内核版本。通过获取这个版本的源码,我们可以找到一个名为“Documentation”的文件夹,其中包含了丰富的文档和使用手册。这些文档在大多数情况下是完整的,详细的,说明了源代码的使用和实现方法,以及核心代码的一些关键部分的详细说明。
在文档中,你可以找到大量的信息,包括Linux的基本结构、驱动程序和系统调用、内存管理和进程管理等核心要素,都有详细的说明。不仅如此,还有一些有关开发者文档的信息,例如如何为Linux内核提交一个补丁等等。
2. 探究内核的组成部分
在探究Linux源代码时,我们首先要了解Linux内核的组成部分。补丁是内核开发的重要组成部分。补丁是完整代码的一部分,可以应用于一个代码库的部分,而不会影响库中其他部分的代码。
除了补丁之外,Linux内核还包括若干个子系统,其中最重要的三个子系统是进程管理、内存管理和设备管理。进程管理主要负责Linux操作系统中进程的分配,执行和退出。内存管理负责管理系统内部的内存分配和释放,以及为Linux中各个进程分配内存。设备管理是指对各个设备进行管理,包括块设备、字符设备、网络设备等等。
3. 了解虚拟空间管理类
在Linux内核中,有一个非常重要的类称为vm_area_struct。这个类在虚拟内存管理期间扮演了重要角色,特别是在内存映射、文件交换和共享内存等功能中。每个进程都有一个vm_area_struct列表,Linux内核在启动进程时会为每个进程分配一个虚拟地址空间,该进程的虚拟地址空间将以vm_area_struct列表的形式表示。
在深入了解vm_area_struct之前,我们需要了解一些vm_area_struct中包含的字段。其中一个很重要的字段是start,它表示vm_area的起始地址。另一个很重要的字段是end,它表示vm_area的结束地址。其中,每个vm_area都表示一个可以被映射到其上的虚拟地址范围。
4. 数据结构的实现
现在,我们来进一步了解Linux内核的数据结构。在任何一个操作系统中,数据结构是非常重要的一部分,因为它们决定了数据如何存储和管理。在Linux内核中,有几个非常有代表性的数据结构,例如链表、堆栈、哈希表等等。
链表是最基本的数据结构之一,在Linux内核中被广泛应用。由于Linux最基本的结构是列表结构,所以Linux内核中的许多数据结构都是以链表为基础的。它们通常用于维护内存块、进程、文件系统节点等数据结构。
堆栈是Linux内核中的另一个非常重要的数据结构,可以通过其中的IO栈,对文件和网络操作进行读写操作。在文件系统中,堆栈用于跟踪和查找文件和目录节点,以及创建和修改文件。
哈希表在Linux内核中也非常常见。它们通常用于维护各种资源的关系,例如进程和文件之间的关系,内存映射的对应关系等等。
5.
对于任何一位程序员来说,了解Linux内核源代码的理解是非常必要的。通过阅读源代码和文档,我们可以更好地理解内核的工作原理,加强自己在系统管理、网络安全、云计算和大数据处理等方面的能力。在学习过程中,我们需要学会了解Linux内核的组成部分、虚拟内存管理以及常见的数据结构。掌握这些基本知识,可以帮助我们更好地探索Linux内核的奥秘。
成都网站建设公司-创新互联,建站经验丰富以策略为先导10多年以来专注数字化网站建设,提供企业网站建设,高端网站设计,响应式网站制作,设计师量身打造品牌风格,热线:028-869222201、首先源代码放在linux里的访问源码路径,一般路径都是在根目录下的/usr/src下,其中linux-***代表版本号。
2、其次确定当前系统的版本,hostnamectl可以查看当前系统信息。
3、最后可以看到,每个driver目录都有一个Kcongif目录可支持裁剪。
mutex相关的函数并不是linux kernel实现的,而是glibc实现的,源码位于埋笑nptl目录下。
首先说数据结构:
typedef union
{
struct
{
int __lock;
unsigned int __count;
int __owner;
unsigned int __nusers;
/* KIND must stay at this position in the structure to maintain
binary compatibility. */
int __kind;
int __spins;
} __data;
char __size;
long int __align;
} pthread_mutex_t;
int __lock; 资晌粗源竞争引用计数
int __kind; 锁类型,init 函数中mutexattr 参数传递,该参数可以为NULL,一般为 PTHREAD_MUTEX_NORMAL
结构体其他元素暂时不了解,以后更新。
/*nptl/pthread_mutex_init.c*/
int
__pthread_mutex_init (mutex, mutexattr)
pthread_mutex_t *mutex;
const pthread_mutexattr_t *mutexattr;
{
const struct pthread_mutexattr *imutexattr;
assert (sizeof (pthread_mutex_t) __data.__kind = imutexattr->mutexkind & ~0x;
/* Default values: mutex not used yet. */
// mutex->__count = 0;already done by memset
宴液镇 // mutex->__owner = 0;already done by memset
// mutex->__nusers = 0;already done by memset
// mutex->__spins = 0;already done by memset
return 0;
}
init函数就比较简单了,将mutex结构体清零,设置结构体中__kind属性。
/*nptl/pthread_mutex_lock.c*/
int
__pthread_mutex_lock (mutex)
pthread_mutex_t *mutex;
{
assert (sizeof (mutex->__size) >= sizeof (mutex->__data));
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
{
…
default:
/* Correct code cannot set any other type. */
case PTHREAD_MUTEX_TIMED_NP:
simple:
/* Normal mutex. */
LLL_MUTEX_LOCK (mutex->__data.__lock);
break;
…
}
/* Record the ownership. */
assert (mutex->__data.__owner == 0);
mutex->__data.__owner = id;
#ifndef NO_INCR
++mutex->__data.__nusers;
#endif
return 0;
}
该函数主要是调用LLL_MUTEX_LOCK, 省略部分为根据mutex结构体__kind属性不同值做些处理。
宏定义函数LLL_MUTEX_LOCK最终调用,将结构体mutex的__lock属性作为参数传递进来
#define __lll_mutex_lock(futex) \
((void) ({\
int *__futex = (futex); \
if (atomic_compare_and_exchange_bool_acq (__futex, 1, 0) != 0)\
__lll_lock_wait (__futex);\
}))
atomic_compare_and_exchange_bool_acq (__futex, 1, 0)宏定义为:
#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
({ __typeof (mem) __gmemp = (mem);\
__typeof (*mem) __gnewval = (newval); \
\
*__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; })
这个宏实现的功能是:
如果mem的值等于oldval,则把newval赋值给mem,放回0,否则不做任何处理,返回1.
由此可以看出,当mutex锁限制的资源没有竞争时,__lock 属性被置为1,并返回0,不会调用__lll_lock_wait (__futex); 当存在竞争时,再次调用lock函数,该宏不做任何处理,返回1,调用__lll_lock_wait (__futex);
void
__lll_lock_wait (int *futex)
{
do
{
int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1);
if (oldval != 0)
lll_futex_wait (futex, 2);
}
while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0);
}
atomic_compare_and_exchange_val_acq (futex, 2, 1); 宏定义:
/* The only basic operation needed is compare and exchange. */
#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
({ __typeof (mem) __gmemp = (mem);\
__typeof (*mem) __gret = *__gmemp;\
__typeof (*mem) __gnewval = (newval); \
\
if (__gret == (oldval)) \
*__gmemp = __gnewval; \
__gret; })
这个宏实现的功能是,当mem等于oldval时,将mem置为newval,始终返回mem原始值。
此时,futex等于1,futex将被置为2,并且返回1. 进而调用
lll_futex_wait (futex, 2);
#define lll_futex_timed_wait(ftx, val, timespec)\
({ \
DO_INLINE_SYSCALL(futex, 4, (long) (ftx), FUTEX_WAIT, (int) (val),\
(long) (timespec)); \
_r10 == -1 ? -_retval : _retval;\
})
该宏对于不同的平台架构会用不同的实现,采用汇编语言实现系统调用。不过确定的是调用了Linux kernel的futex系统调用。
futex在linux kernel的实现位于:kernel/futex.c
SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
struct timespec __user *, utime, u32 __user *, uaddr2,
u32, val3)
{
struct timespec ts;
ktime_t t, *tp = NULL;
u32 val2 = 0;
int cmd = op & FUTEX_CMD_MASK;
if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
cmd == FUTEX_WAIT_BITSET ||
cmd == FUTEX_WAIT_REQUEUE_PI)) {
if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
return -EFAULT;
if (!timespec_valid(&ts))
return -EINVAL;
t = timespec_to_ktime(ts);
if (cmd == FUTEX_WAIT)
t = ktime_add_safe(ktime_get(), t);
tp = &t;
}
/*
* requeue parameter in ‘utime’ if cmd == FUTEX_*_REQUEUE_*.
* number of waiters to wake in ‘utime’ if cmd == FUTEX_WAKE_OP.
*/
if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
val2 = (u32) (unsigned long) utime;
return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
}
futex具有六个形参,pthread_mutex_lock最终只关注了前四个。futex函数对参数进行判断和转化之后,直接调用do_futex。
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
u32 __user *uaddr2, u32 val2, u32 val3)
{
int clockrt, ret = -ENOSYS;
int cmd = op & FUTEX_CMD_MASK;
int fshared = 0;
if (!(op & FUTEX_PRIVATE_FLAG))
fshared = 1;
clockrt = op & FUTEX_CLOCK_REALTIME;
if (clockrt && cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI)
return -ENOSYS;
switch (cmd) {
case FUTEX_WAIT:
val3 = FUTEX_BITSET_MATCH_ANY;
case FUTEX_WAIT_BITSET:
ret = futex_wait(uaddr, fshared, val, timeout, val3, clockrt);
break;
…
default:
ret = -ENOSYS;
}
return ret;
}
省略部分为对其他cmd的处理,pthread_mutex_lock函数最终传入的cmd参数为FUTEX_WAIT,所以在此只关注此分之,分析futex_wait函数的实现。
static int futex_wait(u32 __user *uaddr, int fshared,
u32 val, ktime_t *abs_time, u32 bitset, int clockrt)
{
struct hrtimer_sleeper timeout, *to = NULL;
struct restart_block *restart;
struct futex_hash_bucket *hb;
struct futex_q q;
int ret;
… … //delete parameters check and convertion
retry:
/* Prepare to wait on uaddr. */
ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
if (ret)
goto out;
/* queue_me and wait for wakeup, timeout, or a signal. */
futex_wait_queue_me(hb, &q, to);
… … //other handlers
return ret;
}
futex_wait_setup 将线程放进休眠队列中,
futex_wait_queue_me(hb, &q, to);将本线程休眠,等待唤醒。
唤醒后,__lll_lock_wait函数中的while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); 语句将被执行,由于此时futex在pthread_mutex_unlock中置为0,所以atomic_compare_and_exchange_bool_acq (futex, 2, 0)语句将futex置为2,返回0. 退出循环,访问用户控件的临界资源。
/*nptl/pthread_mutex_unlock.c*/
int
internal_function attribute_hidden
__pthread_mutex_unlock_usercnt (mutex, decr)
pthread_mutex_t *mutex;
int decr;
{
switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
{
… …
default:
/* Correct code cannot set any other type. */
case PTHREAD_MUTEX_TIMED_NP:
case PTHREAD_MUTEX_ADAPTIVE_NP:
/* Normal mutex. Nothing special to do. */
break;
}
/* Always reset the owner field. */
mutex->__data.__owner = 0;
if (decr)
/* One less user. */
mutex->__data.__nusers;
/* Unlock. */
lll_mutex_unlock (mutex->__data.__lock);
return 0;
}
省略部分是针对不同的__kind属性值做的一些处理,最终调用 lll_mutex_unlock。
该宏函数最终的定义为:
#define __lll_mutex_unlock(futex)\
((void) ({ \
int *__futex = (futex); \
int __val = atomic_exchange_rel (__futex, 0);\
\
if (__builtin_expect (__val > 1, 0)) \
lll_futex_wake (__futex, 1);\
}))
atomic_exchange_rel (__futex, 0);宏为:
#define atomic_exchange_rel(mem, value) \
(__sync_synchronize (), __sync_lock_test_and_set (mem, value))
实现功能为:将mem设置为value,返回原始mem值。
__builtin_expect (__val > 1, 0) 是编译器优化语句,告诉编译器期望值,也就是大多数情况下__val > 1 ?是0,其逻辑判断依然为if(__val > 1)为真的话执行 lll_futex_wake。
现在分析,在资源没有被竞争的情况下,__futex 为1,那么返回值__val则为1,那么 lll_futex_wake (__futex, 1);不会被执行,不产生系统调用。 当资源产生竞争的情况时,根据对pthread_mutex_lock 函数的分析,__futex为2, __val则为2,执行 lll_futex_wake (__futex, 1); 从而唤醒等在临界资源的线程。
lll_futex_wake (__futex, 1); 最终会调动同一个系统调用,即futex, 只是传递的cmd参数为FUTEX_WAKE。
在linux kernel的futex实现中,调用
static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)
{
struct futex_hash_bucket *hb;
struct futex_q *this, *next;
struct plist_head *head;
union futex_key key = FUTEX_KEY_INIT;
int ret;
if (!bitset)
return -EINVAL;
ret = get_futex_key(uaddr, fshared, &key);
if (unlikely(ret != 0))
goto out;
hb = hash_futex(&key);
spin_lock(&hb->lock);
head = &hb->chain;
plist_for_each_entry_safe(this, next, head, list) {
if (match_futex (&this->key, &key)) {
if (this->pi_state || this->rt_waiter) {
ret = -EINVAL;
break;
}
/* Check if one of the bits is set in both bitsets */
if (!(this->bitset & bitset))
continue;
wake_futex(this);
if (++ret >= nr_wake)
break;
}
}
spin_unlock(&hb->lock);
put_futex_key(fshared, &key);
out:
return ret;
}
该函数遍历在该mutex上休眠的所有线程,调用wake_futex进行唤醒,
static void wake_futex(struct futex_q *q)
{
struct task_struct *p = q->task;
/*
* We set q->lock_ptr = NULL _before_ we wake up the task. If
* a non futex wake up happens on another CPU then the task
* might exit and p would dereference a non existing task
* struct. Prevent this by holding a reference on p across the
* wake up.
*/
get_task_struct(p);
plist_del(&q->list, &q->list.plist);
/*
* The waiting task can free the futex_q as soon as
* q->lock_ptr = NULL is written, without taking any locks. A
* memory barrier is required here to prevent the following
* store to lock_ptr from getting ahead of the plist_del.
*/
p_wmb();
q->lock_ptr = NULL;
wake_up_state(p, TASK_NORMAL);
put_task_struct(p);
}
关于linux 3.10.0源码的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。
创新互联【028-86922220】值得信赖的成都网站建设公司。多年持续为众多企业提供成都网站建设,成都品牌建站设计,成都高端网站制作开发,SEO优化排名推广服务,全网营销让企业网站产生价值。
分享题目:深入探究Linux3.10.0源码,窥探内核的奥秘(linux3.10.0源码)
本文URL:http://www.mswzjz.cn/qtweb/news25/541425.html
攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能