zoukankan      html  css  js  c++  java
  • 20169219《linux内核原理与分析》第七周作业

    网易云课堂学习

    把write系统调用加入到MenuOS里面

    我在试验过程中在MenuOS里加入了time、time-asm、write和write-asm命令。以time和time-asm为例,
    步骤如下

    • 更新menu代码到最新版
    • 在main函数中增加MenuConfig
    • 增加对应的Time函数和TimeAsm函数
    • make rootfs

    实验结果如图所示

    然后使用gdb跟踪分析write系统调用函数。write对应的系统调用函数是sys_write

    分析system_call的执行过程

    首先看系统调用的初始化,在start_kernel里面有trap_init,也就是中断初始化的一个函数,trap_init里面有set_system_trap_gate(SYSCALL_VECTOR,&system_call)&system_call就是系统调用的入口。代码中一旦出现init 0x80的指令,立即就会跳转到system_call的位置,即ENTRY(system_call).
    看一下ENTRY(system_call)的代码

    490ENTRY(system_call)
    491	RING0_INT_FRAME			# can't unwind into user space anyway
    492	ASM_CLAC
    493	pushl_cfi %eax			# save orig_eax
    494	SAVE_ALL
    495	GET_THREAD_INFO(%ebp)
    496					# system call tracing in operation / emulation
    497	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
    498	jnz syscall_trace_entry
    499	cmpl $(NR_syscalls), %eax
    500	jae syscall_badsys
    501syscall_call:
    502	call *sys_call_table(,%eax,4)
    503syscall_after_call:
    504	movl %eax,PT_EAX(%esp)		# store the return value
    505syscall_exit:
    506	LOCKDEP_SYS_EXIT
    507	DISABLE_INTERRUPTS(CLBR_ANY)	# make sure we don't miss an interrupt
    508					# setting need_resched or sigpending
    509					# between sampling and the iret
    510	TRACE_IRQS_OFF
    511	movl TI_flags(%ebp), %ecx
    512	testl $_TIF_ALLWORK_MASK, %ecx	# current->work
    513	jne syscall_exit_work
    514
    515restore_all:
    516	TRACE_IRQS_IRET
    

    关于汇编跳转指令的说明
    JNS表示如果符号位没有被置位则跳转。
    JAE表示如果超过或等于(>=)则跳转。
    JNE表示如果不相等(<>)则跳转。
    先判断是否符合跳转条件,再执行后面相应指令。

    system_call的中断处理过程如下:

      1. SAVE_ALL保护现场。保护的是发生中断处,进程下一条指令的地址,还包括标志寄存器的内容。
    • 2)通过call *sys_call_table(,%eax,4)调用系统调用表,传递系统调用号,调用相应函数。
    • 3)syscall_after_call: movl %eax,PT_EAX(%esp)保存返回值。
    • 4)检测是否处理syscall_exit_work,如果不处理的话恢复现场。
    • 5)返回用户态。

    Linux内核设计与实现

    第9章内核同步介绍

    (1)多个执行线程同时访问和操作数据,就有可能发生各线程之间相互覆盖共享数据的情况,造成共享数据处于不一致状态。并发访问共享数据是造成系统不稳定的一类隐患,而且这种错误一般难以跟踪和调试。在使用共享内存的应用程序中,程序员必须特别留意保护共享资源,防止共享资源并发访问,内核也不例外。

    (2)临界区是访问和操作共享数据的代码段。
    (3)避免并发和防止竞争条件称为同步。

    (4)原子操作在操作执行结束前不可被打断。
    (5)可以通过加锁来保护临界区资源。

    • 内核中可能造成并发的原因:
    • 中断——中断几乎可以在任何时刻异步发生,也就可以随时打断当前正在执行的代码。
    • 软中断和tasklet——内核能在任何时刻唤醒或调度软中断和tasklet,打断当前正在执行的代码。
    • 内核抢占——因为内核具有抢占性,所以内核中的任务可能会被另一任务抢占。

    (6)尽管释放锁的顺序和死锁无关,但最好还是以获得锁的相反顺序来释放锁。

    第10章内核同步方法

    原子操作:

    内核提供了两组原子操作接口,一组针对整数进行操作,另一组针对单独的位进行操作。
    针对整数的原子操作只能对atomic_t类型的数据进行处理。
    原子性与顺序性:原子性确保指令执行期间不被打断,要么全部执行,要么根本不执行。顺序性确保即使两条或多条指令同时出现在独立的执行线程中,他们依然保持本该的执行顺序。顺序性通过屏障指令来实施。

    自旋锁:

    自旋锁只能被一个可执行线程持有。如果一个线程试图争用自旋锁,他就会处于忙循环——旋转——等待锁重新可用中一直自旋,浪费处理器时间。
    所以自旋锁不应被长时间占有。这正是使用自旋锁的初衷:在短期内进行轻量级加锁。
    处理锁争用的其他方式:让请求线程睡眠,直到锁重新可用时唤醒他。
    中断处理程序中使用自旋锁时要在获取锁之前禁止本地中断,否则中断处理程序会打断正持有锁的内核代码。
    下半部可以抢占进程上下文中的代码,所以下半部和进程上下文共享数据时,要保护进程上下文中的共享数据。

    信号量

    信号量是一种睡眠锁,他比自旋锁提供了更好的处理器利用率,因为没有把时间花费在忙等待上。
    在占用信号量的同时不能占用自旋锁。
    锁被持有时间长时用信号量,被持有时间短时用自旋锁。
    信号量包括互斥信号量和计数信号量。计数信号量在一个时刻至多有count个持有者。
    互斥体是相对于信号量更简单的睡眠锁。

    自旋锁与信号量的比较

    需求 建议的加锁方法
    低开销加锁 优先使用自旋锁
    短期锁定 优先使用自旋锁
    长期加锁 优先使用互斥体
    中断上下文中加锁 使用自旋锁
    持有锁需要睡眠 使用互斥体

    自旋锁方法列表

    方法 描述
    spin_lock() 获取指定的自旋锁
    spin_lock_irq() 禁止本地中断并获得指定的锁
    spin_lock_irqsave() 保存本地中断的当前状态,禁止本地中断,并获取指定的锁
    spin_unlock() 释放指定的锁
    spin_unlock_irq() 释放指定的锁,并激活本地中断
    spin_unlock_irqrestore() 释放指定的锁,并让本地中断恢复到以前状态
    spin_lock_init() 动态初始化指定的spinlock_t
    spin_trylock() 试图获取指定的锁,如果未获取,则返回非0
    spin_is_locked() 如果指定的锁当前正在被获取,则返回非0,否则返回0

    信号量方法列表

    方法 描述
    sema_init(struct semaphore *,int) 以指定的计数值初始化动态创建的信号量
    init_MUTEX(struct semaphore *) 以计数值1初始化动态创建的信号量
    init_MUTEX_LOCKED(struct semaphore *) 以计数值0初始化动态创建的信号量
    down_interruptible(struct semaphore *) 以试图获得指定的信号量,如果信号量已被争用,则进入可中断睡眠状态
    down (struct semaphore *) 以试图获得指定的信号量,如果信号量已被争用,则进入不可中断睡眠状态
    down_trylock (struct semaphore *) 以试图获得指定的信号量,如果信号量已被争用,则立刻返回非0值
    up (struct semaphore *) 以释放指定的信号量,如果睡眠队列不空,则唤醒其中一个任务

    出现的问题

    (1)实验楼的实验环境不稳定,总是出现错误
    (2)加入自己写的系统调用的时候,在write函数后面没写(int argc,char *argv[])这句,出现错误,经查询了解到这两个就是用于接受参数和记录参数信息的。

  • 相关阅读:
    jsp文件中charset和pageEncoding的区别
    如果jsp表单元素的值为空,如何避免null出现在页面上?
    C# 未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序。
    正则表达式
    事件委托与键盘事件
    事件对象的兼容性
    作用域解析题
    事件冒泡与事件铺获的解析
    浏览器内核
    js中级总结
  • 原文地址:https://www.cnblogs.com/weihua2616/p/6033473.html
Copyright © 2011-2022 走看看