• Mindscape ๐Ÿ”ฅ
    • Playlist ๐ŸŽง
  • Algorithm

    • 1018๋ฒˆ: ์ฒด์ŠคํŒ ๋‹ค์‹œ ์น ํ•˜๊ธฐ
    • 1966๋ฒˆ: ํ”„๋ฆฐํ„ฐ ํ
    • Python ์‹œ๊ฐ„ ์ดˆ๊ณผ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ํŒ
    • C++ std::vector ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ
    • Vim ์‚ฌ์šฉ ๋งค๋‰ด์–ผ
  • Ubuntu

    • ๋ฆฌ๋ˆ…์Šค ์šฐ๋ถ„ํˆฌ GRUB ํฐํŠธ ๋ณ€๊ฒฝ
    • ์šฐ๋ถ„ํˆฌ ์ด๋ฏธ์ง€ ๋น„๋””์˜ค ์ธ๋„ค์ผ(๋ฏธ๋ฆฌ๋ณด๊ธฐ) ์•ˆ ๋ณด์ž„ ๋ฌธ์ œ ํ•ด๊ฒฐ
    • Wine ํ™˜๊ฒฝ์—์„œ ์นด์นด์˜คํ†ก ์‹คํ–‰ ์‹œ explorer.exe ๋œจ์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ๋ฒ•
    • ์šฐ๋ถ„ํˆฌ Wine ์นด์นด์˜คํ†ก ์‚ฌ์ง„ ์ด๋ฏธ์ง€ ์Šคํฌ๋ฆฐ์ƒท ๋ถ™์—ฌ๋„ฃ๊ธฐ
    • Wine ์นด์นด์˜คํ†ก ์ด๋ชจ์ง€ ๊นจ์ง ๋ฌธ์ œ ํ•ด๊ฒฐ
    • Ubuntu ์œˆ๋„์šฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋„๊ธฐ
  • Wellness

    • ์ฐจ์ „์žํ”ผ (Psyllium Husk)
    • ์—‘์ŠคํŠธ๋ผ ๋ฒ„์ง„ ์˜ฌ๋ฆฌ๋ธŒ์œ  (Extra Virgin Olive Oil)
    • ์ž๊ฐ€๋น„๊ฐ•์„ธ์ฒ™ (Nasal Irrigation)
    • QCY HT08 (MeloBuds Pro Plus)
    • ์ฝ˜์„œํƒ€ (Concerta)
    • ์ธ๋ฐ๋†€ (Inderal)
    • ์„คํŠธ๋ž„๋ฆฐ (Sertraline)
    • ๋ฉœ๋ผํ† ๋‹Œ (Melatonin)
    • ์น˜๊ฒฝ๋ถ€ ๋งˆ๋ชจ์ฆ
    • ๋ฐ”๋ฒจ ์Šค์ฟผํŠธ (Barbell Squat)
  • Humanities

    • Nordvik, Russia
    • North Sentinel Island
    • ๋กฑ๊ณ ๋กฑ๊ณ (Rongorongo)
    • ๋ฐ”๋กœํฌ ์Œ์•… (Baroque Music)
  • Design

    • ๊ตฌ๊ธ€์˜ ์•„์ด์ฝ˜ ๋Œ€๊ฐœํŽธ โ€” 6๋…„ ๋งŒ์˜ ์‹ค์ˆ˜ ์ธ์ •
    • ์ œ๋Ÿด๋“œ ์  ํƒ€ โ€” ๋Ÿญ์…”๋ฆฌ ์Šคํฌ์ธ  ์›Œ์น˜์˜ ์ฐฝ์‹œ์ž
    • ๋ฐ”์šฐํ•˜์šฐ์Šค โ€” ํ˜„๋Œ€ ๋””์ž์ธ์˜ ์›์ 
  • Brands

    • NOMOS Glashรผtte
    • Frรฉdรฉrique Constant
    • KZ (Knowledge Zenith)
    • ์—์ŠคํŠธ๋ผ (AESTURA)
    • JINHAO (้‡‘่ฑช)
    • Herman Miller
    • ๋ฐ์Šค์ปค (DESKER)
    • ๋ฌด์‹ ์‚ฌ ์Šคํƒ ๋‹ค๋“œ (Musinsa Standard)
  • Finance

    • ํ˜„๋Œ€์นด๋“œ ZERO โ€” Edition2 vs Edition3 ๋น„๊ต
    • ์‹ ํ•œ์นด๋“œ ์ฒ˜์Œ
    • S&P 500 ETF ํˆฌ์ž ๊ฐ€์ด๋“œ
    • ํŒŒํ‚นํ†ต์žฅ vs CMA ํ†ต์žฅ
    • ๋ฒ„ํฌ์…” ํ•ด์„œ์›จ์ด (Berkshire Hathaway)
    • ๋น„ํŠธ์ฝ”์ธ(Bitcoin)
  • Products

    • ์˜ค๋””์˜ค ์ธํ„ฐํŽ˜์ด์Šค (Audio Interface)
    • ์ฟ ๋ฃจํ† ๊ฐ€ (KURUTOGA)
    • CX31993 DAC ๋™๊ธ€
    • ํด๋ Œ์ง• ๋ฐ€ํฌ (Cleansing Milk)
    • ํ”ผ์ ฏ ํ† ์ด (Fidget Toy)
    • ThinkPad
  • Programming Languages

    • 8.0. Statement Level Control Structures
    • 8. Subprogram
    • 9. Implementing Subprogram
    • 10.1. Abstract Data Types and Encapsulation Constructs
    • 10.2. Support for Object Oriented Programming
    • 11. Concurrency
    • 12. FPL (1)
    • 13. FPL (2)
    • 14. Exception Handling and Event Handling
    • Final Exam

Project 02: xv6 RISC-V Kernel-Level Threads Implementation - wiki

์ž‘์„ฑ 2026. 6. 12.ยท์ˆ˜์ • 2026. 6. 12.

Design

Project Overview

๋ณธ project์˜ ํ•ต์‹ฌ ๋ชฉํ‘œ๋Š” xv6 RISC-V ๊ธฐ๋ฐ˜ ์šด์˜์ฒด์ œ์— kernel-level thread (์ปค๋„ ์ˆ˜์ค€ thread) ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. xv6๋Š” MIT์—์„œ ๊ต์œก ๋ชฉ์ ์œผ๋กœ ์„ค๊ณ„ํ•œ ๊ฐ„๊ฒฐํ•œ UNIX ๊ธฐ๋ฐ˜ OS๋กœ, ๋‹ค์ค‘ ํ”„๋กœ์„ธ์Šค(multiprocessing)๋Š” ์ง€์›ํ•˜์ง€๋งŒ ๋‹ค์ค‘ ์Šค๋ ˆ๋“œ(multithreading)๋Š” ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋ณธ project๋Š” ๊ธฐ์กด xv6์˜ process ๊ด€๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜๋ฉด์„œ, thread์˜ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ(context), ์ž์› ๊ณต์œ  ๋ฐฉ์‹, ๋™๊ธฐํ™” ์‹œ๋‚˜๋ฆฌ์˜ค ๋“ฑ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ์ค‘์ ์„ ๋‘”๋‹ค.

Thread๋Š” process์™€ ๋‹ฌ๋ฆฌ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๊ณต์œ ํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž ์ˆ˜์ค€ stack๊ณผ register๋งŒ ๋…๋ฆฝ์ ์ด๋‹ค. ๋”ฐ๋ผ์„œ xv6์˜ proc ๊ตฌ์กฐ์ฒด๋ฅผ ๊ทธ๋Œ€๋กœ ์žฌํ™œ์šฉํ•˜๋˜, thread ์—ฌ๋ถ€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” flag is_thread๋ฅผ ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ผ clone(), join(), exec(), kill(), sleep(), wakeup() ๋“ฑ์˜ ๋™์ž‘์„ ์ˆ˜์ •ํ•˜์˜€๋‹ค.

Design Principles and Requirements Strategy

1. Address Space Sharing (pagetable)

Thread์˜ ๋ณธ์งˆ์€ ํ•˜๋‚˜์˜ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๊ณต์œ ํ•˜๋Š” ๋‹ค์ค‘ ์‹คํ–‰ ๊ฒฝ๋กœ์ด๋‹ค. ๋”ฐ๋ผ์„œ clone()์œผ๋กœ ์ƒˆ thread๋ฅผ ์ƒ์„ฑํ•  ๋•Œ์—๋Š” fork()์ฒ˜๋Ÿผ ์ƒˆ๋กœ์šด pagetable์„ ๋ณต์‚ฌํ•ด์„œ๋Š” ์•ˆ ๋˜๊ณ , ๊ธฐ์กด process์˜ pagetable์„ ๊ณต์œ ํ•ด์•ผ ํ•œ๋‹ค. ๋‹จ, trapframe๊ณผ context๋Š” thread๋งˆ๋‹ค ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ฐ€์ ธ์•ผ ํ•˜๋ฏ€๋กœ allocproc()์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด proc์„ ํ• ๋‹นํ•œ๋‹ค.

๋ณ€๊ฒฝ ์‚ฌํ•ญ

  • uvmshare() ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์—ฌ, ๋ถ€๋ชจ์˜ user PTE๋ฅผ ์ž์‹ pagetable์— ์ง์ ‘ ๋งคํ•‘ํ•จ.
  • clone()์—์„œ np->pagetable = proc_pagetable(np); ํ›„ uvmshare(np->pagetable, p->pagetable, p->sz); ํ˜ธ์ถœ

2. User Stack Separation

๊ฐ thread๋Š” ๋…๋ฆฝ๋œ ์‚ฌ์šฉ์ž stack์„ ํ•„์š”๋กœ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž ์˜์—ญ์—์„œ thread_create()๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด, sbrk(PGSIZE)๋กœ 1page ๋‹จ์œ„์˜ stack memory๋ฅผ ํ• ๋‹นํ•˜๊ณ , ํ•ด๋‹น ์ฃผ์†Œ๋ฅผ clone()์— ์ธ์ž๋กœ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค. kernel์—์„œ๋Š” trapframe->sp๋ฅผ ํ•ด๋‹น ์ฃผ์†Œ์˜ top(+PGSIZE)๋กœ ์„ค์ •ํ•˜์—ฌ ์‹คํ–‰์„ ๊ฐœ์‹œํ•œ๋‹ค.

๋ณ€๊ฒฝ ์‚ฌํ•ญ

  • thread_create()์—์„œ page-aligned stack์„ ํ™•๋ณด (s = sbrk(PGSIZE)), ์‹คํŒจ ์‹œ -1 ๋ฐ˜ํ™˜
  • clone() ๋‚ด์—์„œ stack ์œ ํšจ์„ฑ ๊ฒ€์ฆ: null ์ฒดํฌ, page-alignment ํ™•์ธ, walkaddr()๋กœ ๋ฌผ๋ฆฌ ์ฃผ์†Œ ๊ฒ€์ฆ

3. Function Pointer-Based Thread Entry Point

xv6์—์„œ๋Š” ์œ ์ € ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ์ง์ ‘ trapframe์— ์„ค์ •ํ•˜์—ฌ ์ง„์ž…์ ์„ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ clone()์—์„œ np->trapframe->epc = (uint64)fcn;์œผ๋กœ fcn์„ ์„ค์ •ํ•˜๊ณ , arg1๊ณผ arg2๋Š” ๊ฐ๊ฐ a0, a1 register์— ์„ธํŒ…ํ•œ๋‹ค. ์ด๋กœ์จ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ thread๋Š” usertrapret() ์ดํ›„ ํ•ด๋‹น ํ•จ์ˆ˜๋กœ jumpํ•˜๊ฒŒ ๋œ๋‹ค.

ํŠน์ด์ 

  • ๋ณธ ๊ณผ์ œ์—์„œ๋Š” fcn == 0x0 ์ธ ๊ฒฝ์šฐ๊ฐ€ ์ •์ƒ์ ์ด๋ฉฐ, ๊ณผ์ œ ๋ช…์„ธ์—์„œ ์ œ๊ณตํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ์ด๋ฅผ ๊ฐ•์ œ์ ์œผ๋กœ ์„ค์ •ํ•ด๋‘์—ˆ์Œ โ†’ ๋ฌดํšจ ์ฃผ์†Œ๊ฐ€ ์•„๋‹˜
  • ๋”ฐ๋ผ์„œ fcn == 0์ผ ๊ฒฝ์šฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋„๋ก ํ•จ

4. Thread Identification (is_thread)

process์™€ thread๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด proc ๊ตฌ์กฐ์ฒด์— is_thread flag๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค. ์ด๋ฅผ ํ†ตํ•ด join(), exec(), kill() ๋“ฑ์—์„œ ์กฐ๊ฑด ๋ถ„๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ ์šฉ ์œ„์น˜

  • clone()์—์„œ๋Š” np->is_thread = 1;
  • fork()์—์„œ๋Š” np->is_thread = 0;๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์ดˆ๊ธฐํ™”

5. Stack Address Reclamation on Exit

thread๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด, ๊ทธ thread๊ฐ€ ์‚ฌ์šฉํ•˜๋˜ stack์€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ, join() ์‹œ ํ•ด๋‹น ์ฃผ์†Œ๋ฅผ user์—๊ฒŒ ๋„˜๊ฒจ sbrk(-PGSIZE)๋กœ memory๋ฅผ ๋ฐ˜๋‚ฉํ•ด์•ผ ํ•œ๋‹ค.

๊ตฌํ˜„ ๋ฐฉ์‹

  • clone() ์‹œ np->ustack = (uint64)stack;์œผ๋กœ ์ €์žฅ
  • join() ์‹œ copyout()์„ ํ†ตํ•ด user stack ์ฃผ์†Œ ์ „๋‹ฌ
  • thread_join()์—์„œ sbrk(-PGSIZE)๋กœ ํšŒ์ˆ˜

6. Remove All Threads on exec()

exec()๋Š” ํ•ด๋‹น process์˜ pagetable์„ ์™„์ „ํžˆ ๋ฎ์–ด์”Œ์šฐ๋Š” ์ž‘์—…์ด๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐ™์€ pagetable์„ ๊ณต์œ ํ•˜๋Š” ๋‹ค๋ฅธ thread๋“ค๋„ ๋ชจ๋‘ ์ œ๊ฑฐํ•˜์ง€ ์•Š์œผ๋ฉด memory corruption์ด ๋ฐœ์ƒํ•œ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ์‹

  • exec() ์ง„์ž… ์‹œ, proc[NPROC]์„ ์ˆœํšŒํ•˜๋ฉฐ pagetable == p->pagetable && p != self์ธ ๋ชจ๋“  proc์— ๋Œ€ํ•ด freeproc() ํ˜ธ์ถœ
  • ์ดํ›„ ์ƒˆ๋กœ์šด pagetable์„ proc_pagetable()๋กœ ์žฌ์ƒ์„ฑํ•˜๊ณ , ELF ๋ฐ”์ด๋„ˆ๋ฆฌ ๋กœ๋“œ ์ˆ˜ํ–‰

7. Terminate All Threads on kill()

RISC-V์—์„œ๋Š” process๋ฅผ ์ฃฝ์ด๊ธฐ ์œ„ํ•ด์„  ๊ทธ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๊ณต์œ ํ•˜๋Š” ๋ชจ๋“  thread๋ฅผ ์ข…๋ฃŒ์‹œ์ผœ์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ kill(pid)๋Š” ๋‹จ์ผ pid๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋˜, ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ํ•ด๋‹น pagetable์„ ๊ณต์œ ํ•˜๋Š” ๋ชจ๋“  proc์„ ์ข…๋ฃŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค.

๋ณ€๊ฒฝ ์‚ฌํ•ญ

  • kill() ๋‚ด๋ถ€์—์„œ target->pagetable์„ ๊ธฐ์ค€์œผ๋กœ, ๊ฐ™์€ pagetable์„ ๊ณต์œ ํ•˜๋Š” ๋ชจ๋“  proc์— ๋Œ€ํ•ด p->killed = 1 ์„ค์ •
  • SLEEPING ์ƒํƒœ์ธ thread๋Š” RUNNABLE๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ sched()์— ์ง„์ž… ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ

8. Separate wait/join

  • ๊ธฐ์กด์˜ wait()๋Š” process๋งŒ ์ˆ˜๊ฑฐํ•ด์•ผ ํ•œ๋‹ค.
  • thread๋Š” join()์„ ํ†ตํ•ด ์ˆ˜๊ฑฐํ•˜๋ฏ€๋กœ wait()์™€๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌํ˜„๋œ๋‹ค.
  • join()์€ proc[NPROC]์„ ์ˆœํšŒํ•˜๋ฉฐ parent == myproc()์ด๊ณ  is_thread == 1์ด๋ฉฐ ZOMBIE ์ƒํƒœ์ธ thread๋ฅผ ์ฐพ์•„ ํšŒ์ˆ˜ํ•œ๋‹ค.

9. Guarantee sleep/wakeup Semantics

thread๊ฐ€ sleep() ์ƒํƒœ์— ๋“ค์–ด๊ฐˆ ๋•Œ, p->lock์„ ๋ฐ˜๋“œ์‹œ ๋จผ์ € ํš๋“ํ•œ ํ›„ sched()๋กœ ๋„˜๊ฒจ์•ผ wakeup()์—์„œ์˜ ๋™๊ธฐํ™” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด ๊ตฌ์กฐ๋Š” ๊ธฐ์กด xv6์—์„œ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋˜๋ฉฐ, thread ํ™˜๊ฒฝ์—์„œ๋„ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค.

Design Key Summary

ElementImplementation Strategy Summary
Address Spaceuvmshare()๋กœ parent์˜ pagetable ๊ณต์œ 
User Stacksbrk(PGSIZE)๋กœ ํ™•๋ณด, clone()์— ์ „๋‹ฌํ•˜์—ฌ trapframe->sp ์„ค์ •
Function Pointer Entrytrapframe->epc = fcn
Argument Passinga0 = arg1, a1 = arg2
TCB Separationallocproc() โ†’ ๋…๋ฆฝ๋œ trapframe/context
Thread Identificationis_thread == 1
exec Cleanup๋™์ผ pagetable ๊ณต์œ ํ•˜๋Š” proc ์ „๋ถ€ freeproc()
join Collectioncopyout()์œผ๋กœ stack ์ฃผ์†Œ ์œ ์ €์—๊ฒŒ ์ „๋‹ฌ
kill() Extension๊ฐ™์€ pagetable ๊ฐ€์ง„ ๋ชจ๋“  proc์— ๋Œ€ํ•ด killed = 1 ์„ค์ •
Synchronizationsleep() ์ „ p->lock ํ™•๋ณด, sched() ์ดํ›„ wakeup ๊ฐ€๋Šฅ ๋ณด์žฅ

์ด๋Ÿฌํ•œ ์ผ๊ด€๋œ ์„ค๊ณ„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ, xv6 ์œ„์— ์•ˆ์ „ํ•˜๊ณ  ๊ฐ€๋ฒผ์šด kernel thread ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ์œผ๋ฉฐ, ์ด๋Š” ๊ณผ์ œ ๋ช…์„ธ์—์„œ ์ œ๊ณตํ•œ thread_test.c์˜ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•จ์œผ๋กœ์จ ๊ทธ ๊ธฐ๋Šฅ์  ์™„์„ฑ๋„๋ฅผ ์ž…์ฆํ•˜์˜€๋‹ค.

Implementation

Overall Structure Overview

์ด๋ฒˆ project๋Š” xv6์˜ kernel๊ณผ ์‚ฌ์šฉ์ž ์˜์—ญ ์–‘์ชฝ์— ๊ฑธ์ณ thread ์‹œ์Šคํ…œ ์ „๋ฐ˜์„ ์•„์šฐ๋ฅด๋Š” ๊ตฌํ˜„ ๋ณ€๊ฒฝ์„ ํ•„์š”๋กœ ํ•œ๋‹ค. ๊ตฌํ˜„์€ ํฌ๊ฒŒ ์•„๋ž˜ 4๊ฐ€์ง€ layer๋กœ ๋‚˜๋‰œ๋‹ค.

  • ์‹œ์Šคํ…œ ์ฝœ ์ธํ„ฐํŽ˜์ด์Šค (sysproc.c)
  • kernel ๋‚ด๋ถ€ ๊ธฐ๋Šฅ (proc.c)
  • ์‚ฌ์šฉ์ž ์ˆ˜์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (user/thread.c, thread.h)
  • ๋นŒ๋“œ ์‹œ์Šคํ…œ ๋ฐ ์‹คํ–‰ ํŒŒ์ผ ๊ตฌ์„ฑ (Makefile ๋ณ€๊ฒฝ)

๊ฐ ์˜์—ญ์— ๋Œ€ํ•ด ์„ธ๋ถ€ ๊ตฌํ˜„๊ณผ ํ•ต์‹ฌ ๋ณ€๊ฒฝ ํฌ์ธํŠธ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์„ค๋ช…ํ•  ๊ฒƒ์ด๋‹ค.

1. System Call Implementation (kernel/sysproc.c)

sys_clone()

uint64 sys_clone(void)
{
  uint64 f, a1, a2, s;
  argaddr(0, &f);
  argaddr(1, &a1);
  argaddr(2, &a2);
  argaddr(3, &s);
  return clone((void (*)(void*, void*))f, (void*)a1, (void*)a2, (void*)s);
}
  • argaddr()๋Š” ๋ฐ˜ํ™˜ํ˜•์ด void์ด๋ฏ€๋กœ, argraw() ๊ฐ’์„ ๊ฐ„์ ‘์ ์œผ๋กœ ์ฐธ์กฐํ•˜์—ฌ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • ์ธ์ž์˜ ์ˆœ์„œ์™€ ์˜๋ฏธ๋Š” clone(void(*fcn)(void*,void*), void*, void*, void*)์™€ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋„๋ก ์ „๋‹ฌ๋œ๋‹ค.
  • ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ์ฃผ์†Œ(fcn)๋„ user space ๊ฐ’์ด๋ฏ€๋กœ uint64๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

sys_join()

uint64 sys_join(void)
{
  uint64 p;
  argaddr(0, &p);
  return join((void**)p);
}
  • join()์€ (void**) ํ˜•ํƒœ๋กœ user stack address๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค.
  • void **stack ํ˜•ํƒœ๋ฅผ uint64๋กœ ๋ฐ›๋˜, ์ปค๋„ ๋‚ด๋ถ€์—์„œ๋Š” type casting์œผ๋กœ ๋ณต์›ํ•œ๋‹ค.

2. Kernel Internal Functions (kernel/proc.c)

clone()

  • allocproc()์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด TCB๋ฅผ ํ• ๋‹นํ•œ๋‹ค.
  • uvmshare()๋กœ ๋ถ€๋ชจ์™€ ๋™์ผํ•œ pagetable์„ ๊ณต์œ ํ•œ๋‹ค.
  • trapframe์€ ๋ถ€๋ชจ์˜ ๊ฒƒ์„ ๋ณต์‚ฌํ•˜๊ณ , epc/sp/a0/a1 ๋“ฑ์€ ์ธ์ž๋กœ ์ฃผ์–ด์ง„ ๊ฐ’์„ ๋ฐ˜์˜ํ•ด ์„ค์ •ํ•œ๋‹ค.
  • ofile[]๊ณผ cwd๋Š” filedup(), idup()์„ ํ†ตํ•ด ๋ณต์‚ฌํ•œ๋‹ค.
  • RUNNABLE๋กœ ์ „ํ™˜๋˜๋ฉด scheduler์— ์˜ํ•ด ์‹คํ–‰๋œ๋‹ค.
np->trapframe->epc = (uint64)fcn;
np->trapframe->sp  = (uint64)stack + PGSIZE;
np->trapframe->a0  = (uint64)arg1;
np->trapframe->a1  = (uint64)arg2;
  • np->ustack = (uint64)stack;์€ join์—์„œ stack ์ฃผ์†Œ๋ฅผ ์œ ์ €์— ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ๋”ฐ๋กœ ์ €์žฅํ•˜๋Š” ๊ฐ’์ด๋‹ค.

join()

  • proc[] ๋ฐฐ์—ด ์ „์ฒด๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ, parent == myproc()์ด๋ฉด์„œ is_thread == 1์ธ ์ž์‹๋งŒ ํ™•์ธํ•œ๋‹ค.
  • state == ZOMBIE์ธ thread๋ฅผ ๋ฐœ๊ฒฌํ•˜๋ฉด freeproc()์œผ๋กœ ํšŒ์ˆ˜ํ•˜๊ณ , ๊ทธ thread์˜ ustack ๊ฐ’์„ copyout()์„ ํ†ตํ•ด ์œ ์ €์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.
  • ์ˆ˜๊ฑฐํ•  thread๊ฐ€ ์—†์œผ๋ฉด sleep ์ƒํƒœ๋กœ ๋Œ€๊ธฐํ•œ๋‹ค.

exec()

for(struct proc *q = proc; q < &proc[NPROC]; q++) {
  if(q != p && q->pagetable == p->pagetable) {
    acquire(&q->lock);
    freeproc(q);
    release(&q->lock);
  }
}
  • exec์„ ํ˜ธ์ถœํ•œ ํ˜„์žฌ thread๋ฅผ ์ œ์™ธํ•œ, ๊ฐ™์€ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๊ณต์œ ํ•˜๋Š” thread๋ฅผ ๋ชจ๋‘ ์ œ๊ฑฐํ•œ๋‹ค.
  • ์ด ๋™์ž‘์€ ์ƒˆ๋กœ์šด pagetable์„ ์„ธํŒ…ํ•˜๊ธฐ ์ „์— ๋ฐ˜๋“œ์‹œ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•œ๋‹ค.

kill()

for (p = proc; p < &proc[NPROC]; p++) {
  if (p->pagetable == target->pagetable) {
    p->killed = 1;
    if (p->state == SLEEPING)
      p->state = RUNNABLE;
  }
}
  • ๋‹จ์ผ pid๊ฐ€ ์•„๋‹Œ ๋™์ผ ์ฃผ์†Œ ๊ณต๊ฐ„(pagetable)์„ ๊ณต์œ ํ•˜๋Š” ๋ชจ๋“  proc์— ๋Œ€ํ•ด killed = 1 ์„ค์ •
  • ์ด๋Š” multi-thread ํ™˜๊ฒฝ์—์„œ ์˜ฌ๋ฐ”๋ฅธ kill semantics๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค.

fork()

  • ๊ธฐ์กด๊ณผ ๊ฑฐ์˜ ๋™์ผํ•˜๋‚˜, is_thread = 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ์™„์ „ํ•œ process ๋ณต์ œ๊ฐ€ ๋˜๋„๋ก ํ•œ๋‹ค.
  • thread๊ฐ€ ์•„๋‹Œ process๋Š” ๋ฐ˜๋“œ์‹œ ๋…๋ฆฝ์ ์ธ ์ฃผ์†Œ ๊ณต๊ฐ„์„ ๊ฐ€์ง„๋‹ค.

3. User-Level Library (user/thread.c, user/thread.h)

thread_create()

void *s = sbrk(PGSIZE);
if (s == (void*)-1 || (uint64)s % PGSIZE) return -1;
return clone(f, a1, a2, s);
  • Stack์€ ๋ฐ˜๋“œ์‹œ 4KB ๋‹จ์œ„๋กœ page-aligned ๋˜์–ด์•ผ ํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด clone์ด ์‹คํŒจํ•œ๋‹ค.
  • stack ํ• ๋‹น์€ ๋™์ ์ด๋ฉฐ, ์œ ์ €๊ฐ€ ์ง์ ‘ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜์ง€ ์•Š์•„๋„ ๋‚ด๋ถ€์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.

thread_join()

void *s = 0;
int pid = join(&s);
if (pid > 0 && s) sbrk(-PGSIZE);
return pid;
  • join์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ข…๋ฃŒ๋œ thread์˜ stack ์ฃผ์†Œ๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๋ฉด, ์ด๋ฅผ sbrk(-PGSIZE)๋กœ ๋ฐ˜๋‚ฉํ•˜์—ฌ memory leak์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

thread.h

int thread_create(void (*fcn)(void*, void*), void *arg1, void *arg2);
int thread_join(void);
  • ์‚ฌ์šฉ์ž ๋ ˆ๋ฒจ API๋Š” ๊ธฐ์กด pthread ์Šคํƒ€์ผ์„ ๋ชจ๋ฐฉํ•˜์—ฌ ์ตœ์†Œํ•œ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  • ์‹ค์ œ ์‹œ์Šคํ…œ ์ฝœ์€ ๋‚ด๋ถ€์ ์œผ๋กœ clone/join์„ ํ˜ธ์ถœํ•œ๋‹ค.

4. Build Configuration Changes (Makefile.user)

$U/_thread_test: $U/thread_test.o $U/thread.o $(ULIB)
$U/_thread_fcn:  $U/thread_fcn.o  $(ULIB)
  • ๋ณ„๋„๋กœ thread.o๋ฅผ ๋งํฌ์— ํฌํ•จํ•ด์•ผ thread ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์—ฐ๊ฒฐ๋œ๋‹ค.
entry("clone");
entry("join");
  • user/usys.pl ๋˜๋Š” equivalent ํŒŒ์ผ์—์„œ system call table์— clone๊ณผ join์„ ๋ช…์‹œ์ ์œผ๋กœ ์ถ”๊ฐ€ํ•ด์•ผ user code์—์„œ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•˜๋‹ค.

Summary: Overall Flow

Implementation TargetRole Summary
clone()์ƒˆ๋กœ์šด TCB(proc), ๊ณต์œ ๋œ ์ฃผ์†Œ ๊ณต๊ฐ„, ๋…๋ฆฝ๋œ trapframe ์ƒ์„ฑ
join()์ข…๋ฃŒ๋œ thread ํšŒ์ˆ˜ ๋ฐ stack ์ฃผ์†Œ ๋ฐ˜ํ™˜
exec()๊ธฐ์กด thread ์ •๋ฆฌ ํ›„ ์ƒˆ๋กœ์šด ์ฃผ์†Œ ๊ณต๊ฐ„ ๋กœ๋”ฉ
kill()thread ํฌํ•จ ๋ชจ๋“  ์‹คํ–‰ ์ปจํ…์ŠคํŠธ ์ข…๋ฃŒ
thread_create()์Šคํƒ ํ• ๋‹น + clone ์‹œ์Šคํ…œ ์ฝœ ๋ž˜ํ•‘
thread_join()join ํ˜ธ์ถœ ํ›„ ์Šคํƒ ๋ฐ˜๋‚ฉ

์ด๋กœ์จ xv6 ๋‚ด์— ๊ฒฝ๋Ÿ‰ํ™”๋œ multithreading ํ™˜๊ฒฝ์ด ๊ตฌ์ถ•๋˜๋ฉฐ, fork์™€ exec์˜ ๊ธฐ์กด ์˜๋ฏธ๋ฅผ ์นจํ•ดํ•˜์ง€ ์•Š์œผ๋ฉด์„œ๋„ thread ๊ธฐ๋ฐ˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์™€ ์ž์› ๊ณต์œ ๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

Results

๊ฐ test์—์„œ ์ˆ˜์—…์—์„œ ์ œ๊ณต๋œ ์ถœ๋ ฅ ์˜ˆ์‹œ์™€ ์‹ค์ œ ์‹คํ–‰ ๊ฒฐ๊ณผ์˜ ์ฐจ์ด๋ฅผ ๋น„๊ตํ•˜๊ณ , ๊ทธ ์ฐจ์ด๊ฐ€ ๋ฐœ์ƒํ•œ ์›์ธ์„ ๋ถ„์„ํ•˜๋ฉฐ, ๊ฒฐ๊ณผ๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ํƒ€๋‹นํ•œ์ง€๋ฅผ ์„ค๋ช…ํ•œ๋‹ค. ์•„๋ž˜๋Š” user/thread_test.c ์‹คํ–‰ ๊ฒฐ๊ณผ์ด๋‹ค. ์ด 6๊ฐœ์˜ test๋ฅผ ๋ชจ๋‘ ํ†ต๊ณผํ•˜์˜€์œผ๋ฉฐ, ๊ฐ๊ฐ์˜ test๋Š” ํŠน์ • thread ๊ธฐ๋Šฅ์˜ ์ •์ƒ ์ž‘๋™ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•œ๋‹ค.

TEST#1: Thread Creation and Global Variable Sharing

Comparison

  • ์˜ˆ์‹œ ์ถœ๋ ฅ์—์„œ๋Š” thread 1, 2, 3์ด ๋จผ์ € ์‹คํ–‰๋˜๊ณ  ์ข…๋ฃŒ๋œ ๋’ค, thread 0์ด ๋งˆ์ง€๋ง‰์— ์‹คํ–‰๋œ๋‹ค.
  • ์‹ค์ œ ๊ฒฐ๊ณผ์—์„œ๋Š” thread 0์ด ๊ฐ€์žฅ ๋จผ์ € ์‹คํ–‰์„ ์‹œ์ž‘ํ•˜๊ณ , ๊ทธ ๋’ค๋กœ 1~4๋ฒˆ thread๊ฐ€ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.

Analysis

  • thread 0์ด ๋จผ์ € ์‹คํ–‰๋˜๋Š” ๊ฒƒ์€ ์Šค์ผ€์ค„๋ง ๋ฐฉ์‹์˜ ์ฐจ์ด์— ๋”ฐ๋ฅธ ๊ฒƒ์ด๋‹ค.
  • ๊ฐ thread์˜ ์‹คํ–‰ ์ˆœ์„œ์™€ ์ข…๋ฃŒ ์‹œ์ ์€ ์˜ˆ์‹œ์™€ ๋‹ค๋ฅด์ง€๋งŒ, ์ „์—ญ ๋ณ€์ˆ˜์˜ ์ˆ˜์ • ๋ฐ main thread์—์„œ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๋Š” ํ๋ฆ„์€ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€๋œ๋‹ค.

Conclusion

  • ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋ฌธ์ œ๊ฐ€ ์—†์œผ๋ฉฐ, xv6์˜ round-robin scheduler์— ๋”ฐ๋ผ ์‹คํ–‰ ์ˆœ์„œ๋Š” ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ถœ๋ ฅ ์ˆœ์„œ์˜ ์ฐจ์ด๋Š” ํ—ˆ์šฉ๋˜๋Š” ๊ฒƒ์œผ๋กœ ๋ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค.

TEST#2: Argument Passing and Independent Execution

Comparison

  • ์˜ˆ์‹œ์—์„œ๋Š” ๊ฐ thread๊ฐ€ ์ „๋‹ฌ๋ฐ›์€ iter ๊ฐ’์„ ์ •ํ™•ํžˆ ์ถœ๋ ฅํ•œ๋‹ค.
  • ์‹ค์ œ ๊ฒฐ๊ณผ์—์„œ๋„ iter ๊ฐ’์ด 0๋ถ€ํ„ฐ 4000๊นŒ์ง€ ์ •ํ™•ํžˆ ์ถœ๋ ฅ๋œ๋‹ค.

Conclusion

  • ์ถœ๋ ฅ ํ˜•์‹๊ณผ ์ˆœ์„œ๊ฐ€ ๋ชจ๋‘ ์ผ์น˜ํ•˜๋ฉฐ, ๊ธฐ๋Šฅ์ ์œผ๋กœ๋„ ์™„๋ฒฝํžˆ ๊ตฌํ˜„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„์˜ ์„ค๋ช… ์—†์ด ํ†ต๊ณผ๋กœ ํŒ๋‹จ๋œ๋‹ค.

TEST#3: Address Space Isolation After Fork

Comparison

  • ์˜ˆ์‹œ์—์„œ๋Š” ๊ฐ thread๊ฐ€ forkํ•œ ์ž์‹ process์—์„œ "start" ๋ฐ "end" ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.
  • ์‹ค์ œ ๊ฒฐ๊ณผ์—์„œ๋„ ๋™์ผํ•œ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

Conclusion

  • ์ „์ฒด ๊ตฌ์กฐ์™€ ํ๋ฆ„์ด ๋™์ผํ•˜๋ฉฐ, ์ฃผ์†Œ ๊ณต๊ฐ„ ์ถฉ๋Œ ์—†์ด fork ์ดํ›„ ์ž์‹ thread๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋ถ„๋ฆฌ๋œ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‹คํ–‰๋˜์—ˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ถ€๋ชจ thread๊ฐ€ ์ž์‹ ์˜ ์ž์‹ thread๋ฅผ ์‹คํ–‰์‹œ์ผœ ๋ณ‘๋ ฌ์ ์œผ๋กœ ์ฒ˜๋ฆฌ
  • ๋ชจ๋“  ์ž์‹๊ณผ ๋ถ€๋ชจ thread๊ฐ€ ์ •์ƒ ์ข…๋ฃŒ
  • ๊ฒฐ๊ณผ: nested thread ์ƒ์„ฑ ๋ฐ ์‹คํ–‰ ์ •์ƒ ์ฒ˜๋ฆฌ

TEST#4: sbrk and Memory Allocation Boundary Protection

Comparison

  • ์˜ˆ์‹œ์—์„œ๋Š” addr n at break = 0x... ํ˜•ํƒœ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.
  • ์‹ค์ œ ๊ฒฐ๊ณผ์—์„œ๋Š” ์—ฌ๋Ÿฌ thread๊ฐ€ ์ ‘๊ทผํ•˜๋ฉด์„œ usertrap ๋ฐ scause 0xf ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

Analysis

  • ์˜ˆ์‹œ๋Š” user program์ด ์ง์ ‘ ํ• ๋‹น ์ฃผ์†Œ๋ฅผ ์ถœ๋ ฅํ•œ ๋ฐ˜๋ฉด, ์‹ค์ œ ๊ตฌํ˜„์—์„œ๋Š” ์ปค๋„ ์ˆ˜์ค€์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ณดํ˜ธ ๊ธฐ์ž‘์ด ๋™์ž‘ํ•˜์—ฌ trap์ด ๋ฐœ์ƒํ–ˆ๋‹ค.
  • ์ด๋Š” thread๊ฐ€ ํ• ๋‹นํ•˜์ง€ ์•Š์€ page์— ์ ‘๊ทผํ–ˆ์„ ๋•Œ ๋ณดํ˜ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€๋ฅผ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•œ ํ…Œ์ŠคํŠธ์ด๋ฉฐ, ์˜ˆ์ƒ๋œ ๋™์ž‘์ด๋‹ค.

Conclusion

  • ์˜คํžˆ๋ ค trap์ด ๋ฐœ์ƒํ•จ์œผ๋กœ์จ ๋ณดํ˜ธ๋˜์ง€ ์•Š์€ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•จ์„ ์ฆ๋ช…ํ•˜์˜€๊ณ , ์ด๋Š” test์˜ ์˜๋„์™€ ๋ถ€ํ•ฉํ•˜๋ฏ€๋กœ ํ†ต๊ณผ๋กœ ๊ฐ„์ฃผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • thread 0์—์„œ sbrk()๋กœ ๋ฉ”๋ชจ๋ฆฌ ํ™•์žฅ
  • ๊ฐ thread๋Š” ๊ณต์œ ๋œ ์ฃผ์†Œ ๊ณต๊ฐ„์— ๋Œ€ํ•œ ์ ‘๊ทผ ์‹œ๋„
  • ์—ฌ๋Ÿฌ thread์—์„œ ์ ‘๊ทผ ์˜ค๋ฅ˜(scause 0xf) ๋ฐœ์ƒ โ†’ ์˜ˆ์ƒ๋œ ํ–‰๋™
  • ๊ฒฐ๊ณผ: ์ฃผ์†Œ ๊ณต๊ฐ„ ๊ณต์œ ์™€ memory boundary test ์„ฑ๊ณต

TEST#5: Shared PID and Kill Behavior

Comparison

  • ์˜ˆ์‹œ์—์„œ๋Š” thread 2๋งŒ ์กฐ๊ธฐ ์ข…๋ฃŒ๋œ๋‹ค.
  • ์‹ค์ œ ๊ฒฐ๊ณผ์—์„œ๋Š” ๋ชจ๋“  thread๊ฐ€ ๋™์ผํ•œ pid๋กœ ์‹œ์ž‘ํ•˜๊ณ , thread 0์˜ ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€๋งŒ ๋ช…์‹œ์ ์œผ๋กœ ์ถœ๋ ฅ๋œ๋‹ค.

Analysis

  • ๋ชจ๋“  thread๊ฐ€ ๋™์ผํ•œ pid๋ฅผ ๊ณต์œ ํ•˜๋Š” ์ ์€ ์˜ˆ์ƒ๋œ ๊ฒฐ๊ณผ์ด๋ฉฐ, thread 2์˜ ์ข…๋ฃŒ ๋กœ๊ทธ ๋ˆ„๋ฝ์€ scheduling timing ์ฐจ์ด์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค.
  • join ์ดํ›„ main์ด ์ข…๋ฃŒ๋˜์—ˆ์œผ๋ฏ€๋กœ ๋‚˜๋จธ์ง€ thread๋“ค๋„ ํ•จ๊ป˜ ์ข…๋ฃŒ๋œ ๊ฒƒ์ด๋‹ค.

Conclusion

  • kill ๊ด€๋ จ ๋™์ž‘์€ ์ œ๋Œ€๋กœ ๋ฐ˜์˜๋˜์—ˆ๊ณ , ๋ชจ๋“  thread๊ฐ€ ๋™์ผํ•œ process์˜ ์ผ๋ถ€๋กœ ์ •์ƒ ์ข…๋ฃŒ๋˜์—ˆ์œผ๋ฏ€๋กœ ๊ธฐ๋Šฅ ๊ตฌํ˜„์— ๋ฌธ์ œ๋Š” ์—†๋‹ค.
  • ๋ชจ๋“  thread๊ฐ€ ๋™์ผํ•œ PID(29)๋กœ ์ถœ๋ ฅ๋จ
  • ์ด๋Š” thread๊ฐ€ ๋…๋ฆฝ์ ์ธ process๊ฐ€ ์•„๋‹˜์„ ์ฆ๋ช…
  • ๊ฒฐ๊ณผ: ๋ชจ๋“  thread๋Š” ๋™์ผํ•œ process ๋‚ด์—์„œ ์‹คํ–‰๋จ

TEST#6: exec and Thread Termination Behavior

Comparison

  • ์˜ˆ์‹œ์—์„œ๋Š” exec ์ดํ›„ "thread exec test 0" ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.
  • ์‹ค์ œ ๊ฒฐ๊ณผ์—์„œ๋Š” ์ผ๋ถ€ thread๊ฐ€ ๋จผ์ € trap์„ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์ดํ›„ ๋™์ผํ•œ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

Analysis

  • exec์ด ํ˜ธ์ถœ๋˜๋ฉด ์ฃผ์†Œ ๊ณต๊ฐ„์ด ์ƒˆ๋กœ์šด program image๋กœ ๋Œ€์ฒด๋˜๋ฉฐ, ๊ธฐ์กด์˜ ๋ชจ๋“  thread๋Š” ์ข…๋ฃŒ๋œ๋‹ค.
  • ๊ทธ์— ๋”ฐ๋ผ ์ ‘๊ทผ ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ณต๊ฐ„์— ์žˆ๋˜ thread๋“ค์ด trap์„ ๋ฐœ์ƒ์‹œํ‚จ ๋’ค, ์ƒˆ๋กœ ์‹คํ–‰๋œ image๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋œ ๊ฒƒ์ด๋‹ค.

Conclusion

  • ๋ชจ๋“  trap์€ exec์— ๋”ฐ๋ฅธ ์˜๋„๋œ ๋ถ€์ž‘์šฉ์ด๋ฉฐ, exec ์ดํ›„ program์ด ์ •์ƒ ์‹คํ–‰๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ฌ๋ฐ”๋ฅธ ๋™์ž‘์œผ๋กœ ํŒ๋‹จ๋œ๋‹ค.
  • thread 0์ด exec()์„ ํ˜ธ์ถœํ•˜์—ฌ ์ƒˆ๋กœ์šด ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ๋ณ€ํ™˜
  • ๋‹ค๋ฅธ thread๋“ค์€ ์˜ˆ์ƒ๋Œ€๋กœ ๋น„์ •์ƒ ์ข…๋ฃŒ (scause 0x2 / 0xd)
  • exec() ์ดํ›„ ์ƒˆ๋กœ์šด ํ”„๋กœ๊ทธ๋žจ์ด ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋จ์„ ํ™•์ธ
  • ๊ฒฐ๊ณผ: exec ์ดํ›„ ์ „์ฒด process context ๊ต์ฒด ์„ฑ๊ณต

Final Conclusion

  • ์ด 6๊ฐœ์˜ ํ…Œ์ŠคํŠธ ๋ชจ๋‘ ํ†ต๊ณผ
  • xv6์— ์ปค๋„ ์ˆ˜์ค€์˜ thread๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ๋„์ž… ๋ฐ ๊ฒ€์ฆ ์™„๋ฃŒ
  • ์ฃผ์š” ๊ธฐ๋Šฅ(์ƒ์„ฑ, ์ข…๋ฃŒ, ๋ฉ”๋ชจ๋ฆฌ ๊ณต์œ , PID ์ผ์น˜, exec ์ฒ˜๋ฆฌ ๋“ฑ) ์ „๋ฐ˜์ ์œผ๋กœ ๊ธฐ๋Œ€ ๋™์ž‘ ์ˆ˜ํ–‰
  • ์ˆ˜์—…์—์„œ ์ œ๊ณต๋œ ์˜ˆ์‹œ ์ถœ๋ ฅ๊ณผ ์‹คํ–‰ ์ˆœ์„œ ๋˜๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ์ผ๋ถ€ ๋‹ค๋ฅด์ง€๋งŒ, ์ด๋Š” xv6์˜ scheduler ํŠน์„ฑ์ƒ ์ž์—ฐ์Šค๋Ÿฌ์šด ์ฐจ์ด์ด๋‹ค.
  • ๋ชจ๋“  test์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์€ ์ •ํ™•ํžˆ ๊ตฌํ˜„๋˜์—ˆ์œผ๋ฉฐ, trap ๋ฐœ์ƒ ๋˜ํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ณดํ˜ธ ๊ธฐ๋ฒ•์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ–ˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค.
  • ๋”ฐ๋ผ์„œ "All tests passed" ๋ผ๋Š” ์ถœ๋ ฅ์€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ํƒ€๋‹นํ•˜๊ณ , ๋ชจ๋“  ์š”๊ตฌ ์กฐ๊ฑด์„ ์ถฉ์กฑํ–ˆ๋‹ค๊ณ  ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.

Troubleshooting

thread ๊ตฌํ˜„์€ ์ „ํ†ต์ ์ธ process์™€ ๋‹ฌ๋ฆฌ ์ฃผ์†Œ ๊ณต๊ฐ„ ๊ณต์œ , ์ปจํ…์ŠคํŠธ ๋ถ„๋ฆฌ, ์ž์› ํšŒ์ˆ˜ ํƒ€์ด๋ฐ ๋“ฑ ๋‹ค์ธต์ ์ธ ๋ฌธ์ œ๋ฅผ ์ˆ˜๋ฐ˜ํ•œ๋‹ค. ๋ณธ project ์ง„ํ–‰ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ–ˆ๋˜ ๋Œ€ํ‘œ์ ์ธ ๋ฌธ์ œ ์‚ฌ๋ก€๋“ค๊ณผ, ๊ทธ์— ๋Œ€ํ•œ ์›์ธ ๋ถ„์„ ๋ฐ ํ•ด๊ฒฐ ๊ณผ์ •์„ ๊ธฐ์ˆ ํ•˜๋„๋ก ํ•œ๋‹ค.

1. clone() Infinite Thread Creation โ†’ PID Explosion

Issue

  • thread_create()๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœ๋˜๋ฉฐ clone()์ด ์‹คํŒจํ–ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๊ณ„์†ํ•ด์„œ pid๊ฐ€ ์ฆ๊ฐ€
  • pid๊ฐ€ 64๋ฅผ ์ดˆ๊ณผํ•˜๋ฉฐ ์‹œ์Šคํ…œ์ด ๋น„์ •์ƒ ์ƒํƒœ์— ์ง„์ž…
  • usertrap(): unexpected scause ๋˜๋Š” kerneltrap()์ด ๋‹ค์ˆ˜ ๋ฐœ์ƒ

Cause

  • thread_create()์—์„œ sbrk(PGSIZE)๋กœ stack์„ ์š”์ฒญํ–ˆ์œผ๋‚˜ ์‹คํŒจํ•œ ๊ฒฝ์šฐ, ๊ทธ stack ์ฃผ์†Œ๊ฐ€ (void*)-1์ด ๋จ
  • ์ด ์ƒํƒœ๋กœ๋„ clone()์ด ํ˜ธ์ถœ๋˜๋ฉด, ์ปค๋„ ๋‚ด stack validation์—์„œ ์‹คํŒจํ•˜์—ฌ -1์„ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ, ์‚ฌ์šฉ์ž ์ฝ”๋“œ๋Š” ์ด๋ฅผ ๋ฌด์‹œํ•จ
  • ๊ทธ ๊ฒฐ๊ณผ join์ด ๋ถˆ๊ฐ€๋Šฅํ•œ zombie thread๊ฐ€ ๊ณ„์† ์ƒ์„ฑ๋˜์–ด proc[]์„ ์†Œ์ง„ํ•จ

Solution

  • thread_create()์—์„œ stack์ด ํ• ๋‹น ์‹คํŒจํ–ˆ๊ฑฐ๋‚˜ page alignment๊ฐ€ ๋งž์ง€ ์•Š์œผ๋ฉด ์ฆ‰์‹œ ์‹คํŒจ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋ณ€๊ฒฝ
void *s = sbrk(PGSIZE);
if (s == (void*)-1 || (uint64)s % PGSIZE) return -1;
  • clone() ๋‚ด๋ถ€์—์„œ๋„ stack์ด NULL์ด๊ฑฐ๋‚˜ ๋ฒ”์œ„ ๋ฐ–์ธ ๊ฒฝ์šฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ฐ•ํ™”
if (!stack || (uint64)stack < PGSIZE || ... ) return -1;

2. Error on fcn == 0 โ†’ Test Failure

Issue

  • clone() ๋‚ด์—์„œ if (!fcn) return -1; ์กฐ๊ฑด์„ ์„ค์ •ํ•œ ํ›„, ๋ชจ๋“  thread ์ƒ์„ฑ์ด ์‹คํŒจ
  • thread_test์—์„œ Thread 0 start์กฐ์ฐจ ์ถœ๋ ฅ๋˜์ง€ ์•Š์Œ

Cause

  • ์ˆ˜์—…์—์„œ ์ œ๊ณตํ•œ test code์—์„œ thread_basic() ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๊ฐ€ ์‹ค์ œ๋กœ 0x0์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ์Œ
  • ์ด๋Š” xv6์˜ linker ๋ฐ loader ์„ค์ • ์ƒ ์ผ๋ถ€ ํ•จ์ˆ˜๊ฐ€ .text ์„ธ๊ทธ๋จผํŠธ์˜ ์‹œ์ž‘ ์ฃผ์†Œ์ธ 0x0์— ๋ฐฐ์น˜๋˜๊ธฐ ๋•Œ๋ฌธ
  • xv6 riscv ํ™˜๊ฒฝ์—์„œ๋Š” epc = 0์ด trap ์—†์ด ์œ ํšจํ•˜๊ฒŒ ์‹คํ–‰๋˜์–ด์•ผ ํ•˜๋ฉฐ, 0x0 ์ฃผ์†Œ๋Š” ์ •์ƒ์ ์ธ ์‹คํ–‰ ์ง„์ž…์ ์ž„

Solution

  • clone() ๋‚ด fcn null-check ์กฐ๊ฑด์„ ์™„์ „ํžˆ ์ œ๊ฑฐ
  • ๋Œ€์‹  walkaddr()๋ฅผ ํ†ตํ•ด ํ•ด๋‹น address๊ฐ€ ์œ ์ € ์˜์—ญ์— ์กด์žฌํ•˜๋Š” ์œ ํšจํ•œ physical page๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š”์ง€๋งŒ ํ™•์ธ
if ((uint64)fcn >= MAXVA || !walkaddr(p->pagetable, (uint64)fcn)) return -1;

3. join Unable to Collect Thread (Infinite Wait)

Issue

  • join()์„ ํ˜ธ์ถœํ–ˆ์œผ๋‚˜ Thread X join failed๊ฐ€ ์ถœ๋ ฅ๋˜๋ฉฐ ํ…Œ์ŠคํŠธ ์‹คํŒจ
  • thread๋Š” ์ข…๋ฃŒ๋˜์—ˆ์œผ๋‚˜ ์ปค๋„์ด ํ•ด๋‹น ์ƒํƒœ๋ฅผ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•จ

Cause

  • thread ์ข…๋ฃŒ ์‹œ state == ZOMBIE๊ฐ€ ๋˜์—ˆ์ง€๋งŒ, join()์—์„œ ์ ‘๊ทผ ์‹œ np->lock์„ ํš๋“ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜, ์ด๋ฏธ freeproc() ์ดํ›„ lock์„ ํ•ด์ œํ•œ ๋’ค ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๋ ค ํ•ด race condition์ด ๋ฐœ์ƒ
  • ๋˜๋Š” p->lock๊ณผ wait_lock์„ ๋™์‹œ์— ์‚ฌ์šฉํ•˜๋ฉด์„œ deadlock์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

Solution

  • join() ๋‚ด์—์„œ ๋ฐ˜๋“œ์‹œ np->lock์„ ํš๋“ํ•œ ๋’ค state๋ฅผ ํ™•์ธ
  • freeproc()๋„ ๋ฐ˜๋“œ์‹œ np->lock์„ ๋ณด์œ ํ•œ ์ƒํƒœ์—์„œ ํ˜ธ์ถœํ•˜๊ณ , ํ•ด์ œ๋Š” ์ดํ›„์— ์ˆ˜ํ–‰
  • sleep์€ ๋ฐ˜๋“œ์‹œ p->lock ์—†์ด wait_lock๋งŒ ๋ณด์œ ํ•œ ์ƒํƒœ์—์„œ๋งŒ ํ˜ธ์ถœํ•ด์•ผ ํ•จ

4. Other Threads usertrap on exec() โ†’ panic

Issue

  • exec() ํ…Œ์ŠคํŠธ(TEST#6) ์ˆ˜ํ–‰ ์‹œ, ๋‹ค๋ฅธ thread๋“ค์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ log ์ถœ๋ ฅ
usertrap(): unexpected scause 0x2 pid=36 sepc=0x1000 stval=0xdeadbeef
  • ์ดํ›„ ์ปค๋„ panic ๋˜๋Š” stack overflow ๋ฐœ์ƒ

Cause

  • exec()์€ ํ˜ธ์ถœ thread์˜ pagetable์„ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ๊ฒƒ์œผ๋กœ ๊ต์ฒดํ•˜๋Š” ์ž‘์—…์ด๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ™์€ pagetable์„ ๊ณต์œ ํ•˜๋Š” ๋‹ค๋ฅธ thread๋“ค์ด ์•„์ง ์‚ด์•„ ์žˆ๊ณ , ํ•ด๋‹น ์ฃผ์†Œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ช…๋ น์–ด๋ฅผ fetchํ•˜๋ ค๊ณ  ํ•˜๋ฉด invalid memory trap์ด ๋ฐœ์ƒ
  • ํŠนํžˆ, ์ด๋ฏธ ์†Œ๋ฉธ๋œ ํ•จ์ˆ˜ ์ฃผ์†Œ(fcn)๋กœ ์ ํ”„ํ•˜๋Š” ๋„์ค‘ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ

Solution

  • exec() ํ˜ธ์ถœ ์‹œ ํ˜„์žฌ thread๋ฅผ ์ œ์™ธํ•œ ๋™์ผ pagetable์˜ thread๋ฅผ freeproc()์œผ๋กœ ์ œ๊ฑฐ
for(struct proc *q = proc; q < &proc[NPROC]; q++) {
  if(q != p && q->pagetable == p->pagetable) {
    acquire(&q->lock);
    freeproc(q);
    release(&q->lock);
  }
}
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ, exec()๋Š” ํ•ด๋‹น process๋ฅผ thread ๋‹จ์œ„๊ฐ€ ์•„๋‹Œ "์ฃผ์†Œ ๊ณต๊ฐ„ ๋‹จ์œ„"๋กœ ์™„์ „ํžˆ ์žฌ์‹œ์ž‘ํ•˜๋Š” ํ•จ์ˆ˜๋กœ ๋ณด์•„์•ผ ํ•œ๋‹ค.

5. Only Some Threads Terminated on kill(pid) โ†’ zombie leak

Issue

  • kill(main_pid) ํ˜ธ์ถœ ์‹œ ์ผ๋ถ€ thread๋Š” ์—ฌ์ „ํžˆ ๋Œ๊ณ  ์žˆ์œผ๋ฉฐ, join()๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Œ
  • TEST#5์—์„œ thread ์ค‘ ํ•˜๋‚˜๋งŒ ์ข…๋ฃŒํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋ฌดํ•œ ๋ฃจํ”„์— ๋น ์ง

Cause

  • ๊ธฐ์กด kill() ๊ตฌํ˜„์€ pid์™€ ์ผ์น˜ํ•˜๋Š” ๋‹จ์ผ process๋งŒ ์ข…๋ฃŒ ์ฒ˜๋ฆฌํ•จ
  • ๊ทธ๋Ÿฌ๋‚˜ thread ๊ตฌ์กฐ์—์„œ๋Š” ํ•˜๋‚˜์˜ ์ฃผ์†Œ ๊ณต๊ฐ„์— ์—ฌ๋Ÿฌ thread๊ฐ€ ์กด์žฌํ•˜๋ฉฐ, ๊ฐœ๋ณ„ pid๋งŒ ์ข…๋ฃŒํ•ด์„  ํšจ๊ณผ๊ฐ€ ์—†์Œ

Solution

  • kill() ๊ตฌํ˜„์„ ํ™•์žฅํ•˜์—ฌ ๋™์ผํ•œ pagetable์„ ๊ณต์œ ํ•˜๋Š” ๋ชจ๋“  proc์— ๋Œ€ํ•ด killed = 1 ์„ค์ •
  • SLEEPING ์ƒํƒœ์ผ ๊ฒฝ์šฐ, ๊ฐ•์ œ๋กœ RUNNABLE๋กœ ๋งŒ๋“ค์–ด sched()์— ์ง„์ž…ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ
for (p = proc; p < &proc[NPROC]; p++) {
  if (p->pagetable == target->pagetable) {
    p->killed = 1;
    if (p->state == SLEEPING)
      p->state = RUNNABLE;
  }
}

6. Stack Memory Leak after thread_join()

Issue

  • thread ์ˆ˜๊ฑฐ ์ดํ›„์—๋„ sbrk()๋œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํšŒ์ˆ˜๋˜์ง€ ์•Š์•„, sbrk(0) ๊ฐ’์ด ๊ณ„์† ์ฆ๊ฐ€
  • long-running process์—์„œ memory exhaustion ๋ฐœ์ƒ

Cause

  • join()์ด stack ์ฃผ์†Œ๋ฅผ ์œ ์ €์—๊ฒŒ ๋„˜๊ฒจ์คฌ์ง€๋งŒ, ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฅผ ๋ฐ˜๋‚ฉํ•˜์ง€ ์•Š์Œ
  • thread_join()์€ join()์„ ํ˜ธ์ถœ๋งŒ ํ•˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ ํšŒ์ˆ˜๋Š” ํ•˜์ง€ ์•Š์Œ

Solution

  • ์‚ฌ์šฉ์ž ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ˆ˜์ค€์—์„œ thread_join() ๋‚ด๋ถ€์—์„œ ์ง์ ‘ sbrk(-PGSIZE) ํ˜ธ์ถœ
  • stack ์ฃผ์†Œ๊ฐ€ 0์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ ํ•ด์ œ
if (pid > 0 && s) sbrk(-PGSIZE);

7. sleep/wakeup Deadlock

Issues

  • join()์—์„œ sleep(p, &wait_lock) ์ดํ›„ ๊นจ์–ด๋‚˜์ง€ ์•Š๊ฑฐ๋‚˜, wakeup ์ดํ›„์—๋„ ์ƒํƒœ๊ฐ€ ๋ณต๊ตฌ๋˜์ง€ ์•Š์Œ
  • Debugging ์‹œ sched() ์ง„์ž… ํ›„ ๋‹ค์‹œ ๋Œ์•„์˜ค์ง€ ์•Š๊ฑฐ๋‚˜ panic: unlock ๋ฐœ์ƒ

Cause

  • sleep()์€ ๋‚ด๋ถ€์ ์œผ๋กœ p->lock์„ ์š”๊ตฌํ•˜๋ฉฐ, ์™ธ๋ถ€์—์„œ ์ด๋ฏธ p->lock์„ ํš๋“ํ•œ ์ƒํƒœ๋กœ ๋“ค์–ด์˜ค๋ฉด ์ค‘๋ณต lock์œผ๋กœ crash
  • ๋˜๋Š” wakeup()๊ณผ sleep() ์‚ฌ์ด์˜ window์—์„œ race condition์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

Solution

  • sleep() ํ˜ธ์ถœ ์ „ ๋ฐ˜๋“œ์‹œ p->lock์ด ํš๋“๋˜์–ด ์žˆ์ง€ ์•Š๋„๋ก ์„ค๊ณ„
  • sleep() ๋‚ด๋ถ€์—์„œ p->lock์„ ํš๋“ํ•˜๋ฉฐ, ์™ธ๋ถ€์—์„œ๋Š” wait_lock๋งŒ ๋ณด์œ ํ•ด์•ผ ํ•จ
acquire(&p->lock);
release(&wait_lock);
...
sched();
...
release(&p->lock);
acquire(&wait_lock);
  • wakeup()์€ lock ์—†์ด ์ž‘๋™ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ณ„๋„๋กœ p->lock์„ ๊ฐ thread๋งˆ๋‹ค ํš๋“ํ•˜๊ณ  ์ƒํƒœ๋ฅผ ๋ฐ”๊ฟ”์คŒ

Summary: Major Issues List

Issue Code AreaCauseSolution Summary
thread_createsbrk ์‹คํŒจ ๋˜๋Š” misalignment์‹คํŒจ ์‹œ ๋ฐ”๋กœ return
clonefcn == 0 ์ฃผ์†Œ ๊ฑฐ๋ถ€fcn null-check ์ œ๊ฑฐ, walkaddr๋งŒ์œผ๋กœ ์œ ํšจ์„ฑ ํ™•์ธ
joinlock ๋ณดํ˜ธ ๋ฏธํกlock ์ˆœ์„œ ๋ฐ freeproc() ๋‚ด๋ถ€ ๋™๊ธฐํ™” ๋ณด๊ฐ•
exec๋‹ค๋ฅธ thread๊ฐ€ trap ๋ฐœ์ƒ๋™์ผ pagetable ๊ณต์œ  thread ์ „๋ถ€ ์ œ๊ฑฐ
kill์ผ๋ถ€ thread๋งŒ ์ข…๋ฃŒ๋จpagetable ๊ธฐ์ค€ ์ „์ฒด killed ์ฒ˜๋ฆฌ
thread_joinstack ํšŒ์ˆ˜ ๋ˆ„๋ฝ๋‚ด๋ถ€์—์„œ sbrk(-PGSIZE) ํ˜ธ์ถœ ์ถ”๊ฐ€
sleep/wakeupdeadlock ๋˜๋Š” race conditionlock ์ˆœ์„œ ๋ฐ wakeup ์‹œ์  ์กฐ์ •

์ด์™€ ๊ฐ™์€ ๋ฐ˜๋ณต์  debugging๊ณผ ์ฝ”๋“œ ๊ฐœ์„ ์„ ํ†ตํ•ด, xv6์— ์•ˆ์ •์ ์ด๊ณ  ์ •ํ™•ํ•œ kernel ์ˆ˜์ค€ thread ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

Additional Content

Reference Notes for Thread Implementation in xv6 RISC-V

  • ๋ณธ project๋Š” xv6 RISC-V ๋ฒ„์ „์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋ฉฐ, x86 ๊ธฐ๋ฐ˜ ๊ตฌํ˜„ ์˜ˆ์ œ๋“ค๊ณผ๋Š” ๊ตฌ์กฐ์ ์œผ๋กœ ๋‹ค๋ฅด๋‹ค.

    • ํŠนํžˆ ptable[]์ด ์กด์žฌํ•˜์ง€ ์•Š๊ณ , proc[NPROC] ๋ฐฐ์—ด๊ณผ spinlock์œผ๋กœ๋งŒ ๋™๊ธฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
    • ๋”ฐ๋ผ์„œ x86์˜ switchuvm(), loaduvm() ๋“ฑ์˜ ๋™์ž‘ ๋ฐฉ์‹๊ณผ ๋‹ฌ๋ฆฌ, RISC-V์—์„œ๋Š” walk() ๋ฐ pagetable_t์— ์ง์ ‘ ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ์‹์ด ํ•„์š”ํ–ˆ๋‹ค.
  • xv6์˜ trapframe, context, scheduler ๋“ฑ์€ thread-safeํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, thread๋งˆ๋‹ค ๋ฐ˜๋“œ์‹œ ๋…๋ฆฝ๋œ trapframe, context, ustack์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

  • uvmshare()๋Š” ๊ธฐ์กด uvmcopy()๋ฅผ ๋ณ€ํ˜•ํ•˜์—ฌ ๊ตฌํ˜„ํ•œ ํ•จ์ˆ˜๋กœ, PTE_U ๋น„ํŠธ๊ฐ€ ์„ค์ •๋œ ์‚ฌ์šฉ์ž ์˜์—ญ page์— ๋Œ€ํ•ด์„œ๋งŒ ๊ณต์œ (reference mapping)ํ•˜๋„๋ก ์„ค๊ณ„ํ•˜์˜€๋‹ค.

    • ์ด๋Š” read-only ์„ธ๊ทธ๋จผํŠธ์— ๋Œ€ํ•ด์„œ๋„ ๋ฌธ์ œ๊ฐ€ ์—†์œผ๋ฉฐ, exec์ด๋‚˜ fork์™€๋Š” ๋‹ค๋ฅธ ๋™์ž‘์„ ๋ณด์žฅํ•œ๋‹ค.
  • thread_fcn.c, thread_test.c๋Š” ๊ณผ์ œ ๋ช…์„ธ์—์„œ ์ œ๊ณตํ•œ ์ฑ„์  ๊ธฐ์ค€ ํŒŒ์ผ์ด๋‹ค.

    • ์ด ํŒŒ์ผ์˜ ๊ตฌ์กฐ๋‚˜ fcn = 0x0 ํ˜•ํƒœ์˜ ํ˜ธ์ถœ ๋ฐฉ์‹์€ ์ •์ƒ ๋™์ž‘์ด๋ฉฐ, panic ์œ ๋ฐœ ์š”์†Œ๊ฐ€ ์•„๋‹ˆ๋‹ค.
  • ๋ชจ๋“  thread ๊ตฌํ˜„์€ xv6์˜ ๊ธฐ์กด ๊ธฐ๋Šฅ๊ณผ ์™„์ „ํžˆ ํ˜ธํ™˜๋˜์–ด์•ผ ํ•˜๋ฉฐ, ํŠนํžˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ system call๋“ค๊ณผ ์—ฐ๋™ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค.

    • fork(), exec(), exit(), wait(), kill(), sleep(), pipe()

Additional Useful References

https://github.com/mit-pdos/xv6-riscv
https://pdos.csail.mit.edu/6.828/2022/xv6/book-riscv-rev3.pdf

์‹ค์Šต ์ค‘ ์ฐธ๊ณ ํ•œ StackOverflow thread:

  • https://stackoverflow.com/questions/78141535/threading-using-jmp-buf-array-in-c-test-in-xv6 (x86 ์ค‘์‹ฌ์ด๋ฏ€๋กœ ๊ตฌ์กฐ๋Š” ์ฐธ์กฐ์šฉ)

์ด์ƒ์œผ๋กœ ๋ณธ project์˜ ๊ธฐ์ˆ ์  ๋ฐฐ๊ฒฝ๊ณผ ์—ฐ๊ด€๋œ ๋ชจ๋“  ํ•ต์‹ฌ ์š”์†Œ๋“ค์„ ํฌํ•จํ•˜์˜€๋‹ค.

์ตœ๊ทผ ์ˆ˜์ •: 26. 6. 12. ์˜คํ›„ 3:28
Contributors: kmbzn, Claude Sonnet 4.6

BUILT WITH

CloudflareNode.jsGitHubGitVue.jsJavaScriptVSCodenpm

All trademarks and logos are property of their respective owners.
ยฉ 2026 kmbzn ยท MIT License