启动大内核锁

5.1.2 启动大内核锁

回到start_kernel557行,lock_kernel(),实际的代码来了,大内核锁。我们在.config文件中配置了CONFIG_LOCK_KERNEL的,所以这个函数是start_kernel中继local_irq_disable之后实际执行到的第二个函数。

 

有关大内核的知识,这里又简单的介绍一下。在早期的Linux内核版本中,大内核锁(big kernel block,也叫全局内核锁或BKL)被广泛使用。在2.0版本中,这个锁是相对粗粒度的自旋锁,确保每次只有一个进程能运行在内核态。2.22.4内核具有极大的灵活性,不再依赖一个单独的自旋锁,而是由许多不同的自旋锁保护大量的内核数据结构。在Linux 2.6版本的内核中,用大内核锁来裸护旧的代码(绝大多数主要是与VFS和几个文件系统相关的函数)。

 

从内核版本2.6.11开始,用一个叫做kernel_sem的信号量来实现大内核锁(在较早的2.6版本中,大内核锁是通过自旋锁来实现的)。但是,大内核锁比简单的信号量要复杂一些。

 

每个进程描述符task_struct都含有lock_depth字段,其就是一个整形变量,这个字段允许同一个进程几次获取大内核锁。因此,对大内核锁两次连续的请求不挂起处理器(相对于普通自旋锁)。如果进程未获的过锁,则这个字段的值为-1;否则,这个字段的值加1,表示已经请求了多少次锁。lock_depth字段对中断处理程序、异常处理程序及可延迟函数获取大内核锁都是至关重要的。如果没有这个字段,那么,在当前进程已经拥有大内核锁的情况下,任何试图获得这个锁的异步函数都可能产生死锁。

 

lock_kernel ()unlock_kernel()内核函数用来获得和释放大内核锁。前一个函数等价于:

    depth = current->lock_depth + 1;

    if (depth == 0)

        down(&kernel_sem);

    current->lock_depth = depth;

 

而后者等价于

    if (--current->lock_depth < 0)

        up(&kernel_sem);

 

注意,lock_kernel()unlock_kernel()函数的if语句不需要原子地执行,因为lock_depth不是全局变量——这是每个CPU在自己当前进程描述符中访问的一个字段。在if语句确本地中断也不会引起竞争条件。即使新内核控制路径调用了lock_kernel(),它在终止前也必须释放大内核锁。

 

对内核同步与互斥机制还不熟悉的同学,请查看博客“同步与互斥的基本原理”。于是乎,后面肯定有会一个unlock_kernel函数跟557行的lock_kernel配对,咱们拭目以待。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内核线程是在Linux内核层面运行的线程,它们与用户空间的线程有所不同。在内核中,我们可以使用互斥进行多个内核线程之间的同步。 下面是一个简单的内核模块示例,它创建了两个内核线程,这两个线程会轮流访问一个共享的计数器,并使用互斥进行同步: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/kthread.h> #include <linux/mutex.h> static struct task_struct *thread1, *thread2; static int counter = 0; static DEFINE_MUTEX(mutex); int thread_func(void *data) { int i; for (i = 0; i < 5; i++) { mutex_lock(&mutex); counter++; printk(KERN_INFO "Counter incremented by %d\n", counter); mutex_unlock(&mutex); msleep(1000); } return 0; } static int __init my_module_init(void) { mutex_init(&mutex); thread1 = kthread_create(thread_func, NULL, "my_thread1"); if (IS_ERR(thread1)) { printk(KERN_INFO "Failed to create thread1\n"); return PTR_ERR(thread1); } wake_up_process(thread1); thread2 = kthread_create(thread_func, NULL, "my_thread2"); if (IS_ERR(thread2)) { printk(KERN_INFO "Failed to create thread2\n"); kthread_stop(thread1); return PTR_ERR(thread2); } wake_up_process(thread2); return 0; } static void __exit my_module_exit(void) { kthread_stop(thread1); kthread_stop(thread2); mutex_destroy(&mutex); } module_init(my_module_init); module_exit(my_module_exit); ``` 在上面的代码中,我们首先定义了一个共享的计数器`counter`,然后创建了两个内核线程`thread1`和`thread2`,这两个线程会轮流访问计数器,并使用互斥`mutex`进行同步。 在线程函数`thread_func`中,我们使用`mutex_lock`函数对互斥进行加操作,然后对计数器进行加1操作,并打印出新的计数器值。在操作完成后,我们使用`mutex_unlock`函数对互斥进行解操作。这样可以保证在任何时刻,只有一个线程可以访问计数器。 在模块的初始化函数`my_module_init`中,我们首先使用`mutex_init`函数对互斥进行初始化。然后创建两个内核线程,并使用`wake_up_process`函数启动它们。在模块的退出函数`my_module_exit`中,我们使用`kthread_stop`函数停止内核线程,并使用`mutex_destroy`函数销毁互斥。 需要注意的是,在内核中,我们可以使用`mutex_lock`和`mutex_unlock`函数对内核互斥进行加和解操作,这些函数与用户空间的`pthread_mutex_lock`和`pthread_mutex_unlock`函数使用方法类似,但是函数名略有不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值