xv6-lab7-thread

Lab: Multithreading

前置知识

阅读xv6 book 第七章

Uthread: switching between threads

实验目的

在本实验中,你需要设计用户级线程切换的上下文

uthread.c 包含了用户级线程切换的代码

uthread_switch.S 是你要是实现的保存和恢复线程上下文代码

实验实现

hints

  • thread_creat()thread_schedule() 中添加你的代码
  • 修改 struct thread 来保存你的上下文
  • 你将会在 thread_schedule() 中调用 thread_switch() --该函数应该在 uthread_switch.S 中实现
  • thread_switch() 只需要保存和还原唤醒线程和被唤醒线程的上下文

实现思路

这里我们主要实现的就是一个 切换上下文 的功能,我们先来看看上下文 是怎么样的。在linux里面,线程和进程在数据结构上是没有区别的,线程就是共享资源的几个进程,这样我们先到xv6的进程里看看进程的数据结构。

/*	proc.c	*/
struct proc {
  struct spinlock lock;
.......
  struct context context;      // swtch() here to run process
.......
};

// Saved registers for kernel context switches.
struct context {
  uint64 ra;	//返回地址
  uint64 sp;	//栈指针

  // callee-saved	//一堆参数
  uint64 s0;	
  uint64 s1;
  uint64 s2;
  uint64 s3;
  uint64 s4;
  uint64 s5;
  uint64 s6;
  uint64 s7;
  uint64 s8;
  uint64 s9;
  uint64 s10;
  uint64 s11;
};

可以关注到有个叫 struct context 的东西,看起来是我们要的上下文,直接把它搬到uthread.c 里面去(似乎没有程序计数器pc?不管了,可能存在下面的某个寄存器里?)

/*	uthread.c	*/

struct context {
  uint64 ra;
  uint64 sp;

  // callee-saved
  uint64 s0;
  uint64 s1;
  uint64 s2;
  uint64 s3;
  uint64 s4;
  uint64 s5;
  uint64 s6;
  uint64 s7;
  uint64 s8;
  uint64 s9;
  uint64 s10;
  uint64 s11;
};
struct thread {
  char       stack[STACK_SIZE]; /* the thread's stack */
  int        state;             /* FREE, RUNNING, RUNNABLE */
  struct context context;
  //save pc of stack? 

};

void 
thread_create(void (*func)())
{
  struct thread *t;

  for (t = all_thread; t < all_thread + MAX_THREAD; t++) {
    if (t->state == FREE) break;
  }
  t->state = RUNNABLE;
  t->context.ra = (uint64)func;//执行完thread_switch()后会返回到这里
  t->context.sp = (uint64)(t->stack + STACK_SIZE);//栈从高地址往低地址增长
  // YOUR CODE HERE
}


void 
thread_schedule(void)
{
......  
  if (current_thread != next_thread) {         /* switch threads?  */
    next_thread->state = RUNNING;
    t = current_thread;
    current_thread = next_thread;
    /* YOUR CODE HERE
     * Invoke thread_switch to switch from t to next_thread:
     * thread_switch(??, ??);
     */
    //保存和恢复上下文
    thread_switch((uint64)(&(t->context)), (uint64)(&(current_thread->context)));
  } else
    next_thread = 0;
}

然后根据计组实验时对xv6指令模糊记忆,去写thread_switch() 的汇编代码

/*	uthread_switch.S	*/	

	.text

	/*
         * save the old thread's registers,
         * restore the new thread's registers.
         */

	.globl thread_switch
thread_switch:
	/* YOUR CODE HERE */
	/* 每个uint64 大小为8个字节,按照偏移量储存然后再载入就行*/
	sd	ra,	0(a0)
	sd	sp,	8(a0)

	sd	s0,		16(a0)
	sd	s1,		24(a0)
	sd	s2,		32(a0)
	sd	s3,		40(a0)
	sd	s4,		48(a0)
	sd	s5,		56(a0)
	sd	s6,		64(a0)
	sd	s7,		72(a0)
	sd	s8,		80(a0)
	sd	s9,		88(a0)
	sd	s10,	96(a0)
	sd	s11,	104(a0)

	ld	ra,	0(a1)
	ld	sp,	8(a1)

	ld	s0,		16(a1)
	ld	s1,		24(a1)
	ld	s2,		32(a1)
	ld	s3,		40(a1)
	ld	s4,		48(a1)
	ld	s5,		56(a1)
	ld	s6,		64(a1)
	ld	s7,		72(a1)
	ld	s8,		80(a1)
	ld	s9,		88(a1)
	ld	s10,	96(a1)
	ld	s11,	104(a1)

	ret    /* return to ra */

剩下两个在linux上使用多线程的实验就不细说了,对锁和条件变量的简单应用

实验结果

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值