Stanford Pintos Project1源代码分析&实现思路

0. 引言

本文是对以下博文中Pintos Project1源代码的思路分析,截取了重要的核心函数,以方便读者理解整个的实现思路。

参考源代码: https://blog.csdn.net/denghuang8508/article/details/101357600


1. 第一部分相关

在这里插入图片描述

图1 第一部分相关核心函数调用关系图

1.1 timer_ticks()

timer_ticks (void)
{
   
  enum intr_level old_level = intr_disable ();
  int64_t t = ticks;
  intr_set_level (old_level);
  return t;
}

这里的enum intr_level old_level = intr_disable ()intr_set_level (old_level)两句语句比较重要。简单来说,这两句我们将经常会在代码中看到,这两句语句成对出现,代表这两句语句之间的语句将被保证不会被中断,以维持原子性操作。

背后的原理就是这两句语句实现了:禁用了中断->保存现场->恢复原来中断状态的变化。


除去这两句语句,(就剩了一行)其实timer_ticks也就是一个返回了ticks当前数值的函数。从pintos被启动开始, ticks变量就一直在计时, 代表着操作系统执行单位时间的前进计量。也就是一个用于计时的变量。

1.2 schedule()

static void
schedule (void)
{
   
  struct thread *cur = running_thread ();
  struct thread *next = next_thread_to_run ();
  struct thread *prev = NULL;

  ASSERT (intr_get_level () == INTR_OFF);
  ASSERT (cur->status != THREAD_RUNNING);
  ASSERT (is_thread (next));

  if (cur != next)
    prev = switch_threads (cur, next);
  thread_schedule_tail (prev);
}

schedule先把当前线程丢入就绪队列,切换就绪队列中下一个线程过来在CPU上运行。在切换之前,通过断言保证禁止中断、当前线程不处于运行态。若当前线程和下一个线程不同,则调用switch_thread切换线程,最后调用thread_schedule_tail恢复现场。

1.3 thread_yield()

void
thread_yield (void)
{
   
  struct thread *cur = thread_current ();
  enum intr_level old_level;

  ASSERT (!intr_context ());

  old_level = intr_disable ();
  if (cur != idle_thread)
    list_push_back (&ready_list, &cur->elem);//如果当前线程不是空闲的线程,则把当前线程的元素扔到就绪队列里
  cur->status = THREAD_READY;
  schedule ();
  intr_set_level (old_level);
}

暂时挂起一个线程,等待被唤醒。挂起线程的实现原理:把当前线程扔到就绪队列里, 然后切换下一个线程进入CPU.

1.4 thread_block()

void
thread_block (void)
{
   
  ASSERT (!intr_context ());
  ASSERT (intr_get_level () == INTR_OFF);

  thread_current ()->status = THREAD_BLOCKED;
  schedule ();
}

当前线程设置为阻塞状态,如果没有thread_unblock函数,将不会唤醒该线程。

1.5 timer_sleep()

void
timer_sleep (int64_t ticks) 
{
   
	if(ticks < 0){
   
		return;
	} 
  ASSERT (intr_get_level () == INTR_ON);
  
  enum intr_level old_level = intr_disable();
  struct thread *current_thread = thread_current ();
  current_thread->ticks_blocked = ticks;
  thread_block();
  intr_set_level(old_level);
}

thread_block阻塞该线程。线程结构体成员ticks_blocked代表这个线程睡眠的时间,方便之后调用检测函数blocked_thread_check来判断该线程是否睡眠了足够时间。

1.6 thread_unblock()

void
thread_unblock (struct thread *t)
{
   
  enum intr_level old_level;

  ASSERT (is_thread (t));

  old_level = intr_disable ();
  ASSERT (t->status == THREAD_BLOCKED);
  list_push_back (&ready_list, &t->elem);
  t->status = THREAD_READY;
  intr_set_level (old_level);
}

把阻塞的线程t放入就绪队列中。

1.7 blocked_thread_check()

void
blocked_thread_check (struct thread *t, void *aux UNUSED)
{
   
  if (t->status == THREAD_BLOCKED && t->ticks_blocked > 0)
  {
   
      t->ticks_blocked--;
      if (t->ticks_blocked == 0)
      {
   
          thread_unblock(t);
      }
  }
}

时间检测函数,每次调用该函数将线程的ticks_blocked减1, 如果减到0就调用thread_unblock唤醒这个线程。这样保证了线程有足够的睡眠时间。

1.8 thread_foreach()

void
thread_foreach (thread_action_func *func, void *aux)
{
   
  struct list_elem *e;

  ASSERT (intr_get_level () == INTR_OFF);

  for (e = list_begin (&all_list); e != list_end (&all_list);
       e = list_next (e))
    {
   
      struct thread *t = list_entry (e, struct thread, allelem);
      func (t, aux);
    }
}

顾名思义,就是让每个线程都调用func函数,aux为可选参数。

1.9 timer_interrupt()

static void
timer_interrupt (struct intr_frame *args UNUSED)
{
   
  ticks++;
  thread_tick ();
  thread_foreach(blocked_thread_check,NULL);
}

时间中断处理函数,通过调用thread_foreach对每个线程加入对它睡眠时间的检测函数blocked_thread_check

2. 第二部分相关

在这里插入图片描述

图2 第二部分相关

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值