xv6 lec13 Sleep & Wake up

https://mit-public-courses-cn-translatio.gitbook.io/mit6-s081/lec13-sleep-and-wakeup-robert/13.1-lock-limitation-during-thread-switching

13.1 线程切换过程中锁的限制

  • XV6中,不允许进程在执行switch函数的过程中,持有任何其他的锁。所以,进程在调用switch函数的过程中,必须要持有p->lock(注,也就是进程对应的proc结构体中的锁),但是同时又不能持有任何其他的锁。

13.2 Sleep&Wakeup 接口

  • 通过Sleep&Wakeup实现工具Coordinantion
  • 由于shell系统调用write,在内核中调用robert重写的uartwrite函数,如果是每次写一个字符到THR寄存器,再等待UART传输完这个字符,这样的方式会很慢,更好的方案是,写一个字符到THR寄存器之后,当前线程就sleep,让出CPU,直到接收到中断
  • LSR是Line Status Register,用于记录UART的状态
  • sleep函数与wakeup函数需要通过一个叫做sleep channel的参数链接
  • 实际情况中的UART设备可以传输更多的字符
  • sleep channel的优点是不用管sleep函数在等待什么事件

13.3 Lost wakeup

  • 因为需要两个线程并发访问共享内存,或者说数据,比如变量done以及UART寄存器,如果不加🔒,必然会导致出错。而在什么地方加🔒,是个值得考量的问题,答案是在while之前加锁,在sleep函数里面释放🔒,并且一定要在sleep里面,就算是sleep前一句都不行,这样还是会发生lost wakeup
  • sleep函数要返回的时候不是会去抢🔒吗,那么其中一个必然抢不到🔒,就不会从sleep中返回?这里或许叫做spurious wakeup,应该是从sleep返回的进程,释放了uart_tx_lock,写了THR之后,在进入sleep,释放uart_tx_lock,这个时候另一个也会从sleep中返回,但是由于tx_done这个时候又是0,那么这另一个进程又会回到sleep,但是还有个问题,在sleep中获取了进程的lock,但是在wakeup的时候也要去获取进程的lock?这中间在哪里释放了p->lock?在sleep函数中中会调用sched,sche又会调用swtch,swtch会返回到scheduler线程,其中会释放p->lock

13.4 如何避免Lost wakeup

  • 为了避免lost wakup,需要做到三件事(这三件事情是为了实现,在释放🔒与进程将自己标记为SLEEPING之间不能留有窗口,如果有窗口,这样中断处理程序中的wakeup才能够看到SLEEPING,不然就会遍历一遍进程数组完全没有看到SLEEPING的进程,就是使用两个🔒):
    • 调用sleep时需要持有condition lock,这样sleep函数才能知道相应的🔒(虽然sleep不需要知道tx_done,但是它需要知道保护这个条件的锁,也就是这里的uart_tx_lock。在调用sleep的时候,锁还被当前线程持有,之后这个锁被传递给了sleep。)
    • sleep函数只有在获取到进程的锁p->lock之后,才能释放condition lock
    • wakeup需要同时持有两个锁才能查看进程。

13.5 Pipe中的sleep和wakeup

  • 介绍了读写pipe场景下的有sleepwakeup组成的Coordination
  • 看阅读材料的semaphore?

13.6 exit系统调用

  • 对于进程的退出,需要处理当前进程的资源的释放,包括被动退出,也就是被kill,和主动退出,也就是exit
  • 进程退出时,进程会释放进程的内存和page table,关闭已经打开的文件,同时我们也知道父进程会从wait系统调用中唤醒,所以exit最终会导致父进程被唤醒。在exit中首先关闭了所有已打开的文件,其他操作在wait中完成
  • exit这里释放了当前目录的inode的引用计数
  • 在这里reparent
  • 这里的wakeup相关的操作是啥意思?在这里需要获取initproc的🔒是因为需要防止lost wakeup吗?
  • 这里的获取p->parent的复制是指什么,以及这里的加锁操作?
  • wakeup函数唤醒父进程,父进程中的wait函数会完成回收进程资源的其他步骤

13.7 wait系统调用

  • 这啥意思,和guard page有啥关系?在创建进程的时候会去重新设置内核线程的内核栈sp
  • 对于wait操作中的一系列加🔒操作,以及重新设置父进程之前,先获取当前进程的父进程?

13.8 kill系统调用

  • kill系统调用只是将目标进程的killed标志位置1
  • 对于SLEEPING状态的进程被kill了,需要立马退出,当然有例外
posted @ 2022-04-08 23:33  抿了抿嘴丶  阅读(226)  评论(0编辑  收藏  举报