https://seung2344.tistory.com/112

 

[์šด์˜์ฒด์ œ]๐Ÿฆ–๊ณต๋ฃก์ฑ…๐Ÿฆ•2์žฅ - ์šด์˜์ฒด์ œ ๊ตฌ์กฐ(2)

https://seung2344.tistory.com/110 [๐Ÿฆ–OS๐Ÿฆ•]2์žฅ. ์šด์˜์ฒด์ œ ๊ตฌ์กฐ(1)์ด ์žฅ์˜ ํ•™์Šต ๋ชฉํ‘œ์šด์˜์ฒด์ œ์—์„œ ์ œ๊ณตํ•˜๋Š” ์„œ๋น„์Šค ํ•™์Šต์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ์ข…๋ฅ˜์— ๋Œ€ํ•ด ํ•™์Šต์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ์‹œ์Šคํ…œ ์ฝœ์„ ์‚ฌ์šฉํ•˜

seung2344.tistory.com

 

  • ์šด์˜์ฒด์ œ์—์„œ ์ œ๊ณตํ•˜๋Š” ์„œ๋น„์Šค ํ•™์Šต
  • ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ์ข…๋ฅ˜์— ๋Œ€ํ•ด ํ•™์Šต
  • ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ์‹œ์Šคํ…œ ์ฝœ์˜ ์ข…๋ฅ˜์— ๋Œ€ํ•ด ํ•™์Šต
  • ๋ง์ปค์™€ ๋กœ๋”์— ๋Œ€ํ•ด ํ•™์Šต
  • ์šด์˜์ฒด์ œ ์„ค๊ณ„๋ฅผ ์œ„ํ•œ ๋ชจ๋†€๋ฆฌ์‹, ๊ณ„์ธตํ™”, ๋งˆ์ดํฌ๋กœ ์ปค๋„, ๋ชจ๋“ˆ ๋ฐ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์ „๋žต์— ๋Œ€ํ•ด ํ•™์Šต
  • ์šด์˜์ฒด์ œ ์„ฑ๋Šฅ์„ ๋ชจ๋‹ˆํ„ฐ๋ง ํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ ํ•™์Šต

์šด์˜์ฒด์ œ ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง์— ๊ด€๋ จํ•œ ๋‚ด์šฉ์€ XV6๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ ์‹ค์Šต์„ ํ†ตํ•ด ์ง„ํ–‰ํ•ด ๋ณผ ์˜ˆ์ •์ด๋‹ค. 

xv6๋Š” MIT์—์„œ ๊ฐœ๋ฐœ๋œ UNIX ๊ธฐ๋ฐ˜์˜ ์šด์˜์ฒด์ œ๋กœ ์ฃผ๋กœ ๊ต์œก ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค. 

brew install qemu
brew install i686-elf-gcc
git clone https://github.com/mit-pdos/xv6-public.git
#Makefile ์ˆ˜์ • ํ•œ ๋‹ค์Œ ์‹คํ–‰
make
make qemu

๋‚˜๋Š” mac m2์นฉ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ์ƒํƒœ์ธ๋ฐ ๋„์ปค๋‚˜ ๋ณ„๋„์˜ vm์„ ๊ตฌ์„ฑํ•˜๊ณ  ๋Œ๋ฆฌ๊ธฐ ์‚ด์ง ๊ท€์ฐฎ์•„์„œ gcc์™€ qemu ์„ค์น˜ํ•ด์„œ ์—๋ฎฌ๋ ˆ์ดํ„ฐ ์œ„์—์„œ ๋Œ์•„๊ฐ€๊ฒŒ๋” Makefile์„ ์ˆ˜์ •ํ•œ ํ›„ ์ง„ํ–‰ํ•˜์˜€๋‹ค. 

๋”๋ณด๊ธฐ

Makefile ์ฝ”๋“œ

OBJS = \
	bio.o \
	console.o \
	exec.o \
	file.o \
	fs.o \
	ide.o \
	ioapic.o \
	kalloc.o \
	kbd.o \
	lapic.o \
	log.o \
	main.o \
	mp.o \
	picirq.o \
	pipe.o \
	proc.o \
	sleeplock.o \
	spinlock.o \
	string.o \
	swtch.o \
	syscall.o \
	sysfile.o \
	sysproc.o \
	trapasm.o \
	trap.o \
	uart.o \
	vectors.o \
	vm.o \

# Cross-compiling (e.g., on Mac OS X)
TOOLPREFIX = i686-elf-

# Using native tools (e.g., on X86 Linux)
# TOOLPREFIX = 

# Try to infer the correct TOOLPREFIX if not set
ifndef TOOLPREFIX
TOOLPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
	then echo 'i386-jos-elf-'; \
	elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \
	then echo ''; \
	else echo "***" 1>&2; \
		echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; \
		echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \
		echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \
		echo "*** prefix other than 'i386-jos-elf-', set your TOOLPREFIX" 1>&2; \
		echo "*** environment variable to that prefix and run 'make' again." 1>&2; \
		echo "*** To turn off this error, run 'gmake TOOLPREFIX= ...'." 1>&2; \
		echo "***" 1>&2; exit 1; fi)
endif

# If the makefile can't find QEMU, specify its path here
# QEMU = qemu-system-i386

# Try to infer the correct QEMU
ifndef QEMU
QEMU = $(shell if which qemu > /dev/null; \
	then echo qemu; exit; \
	elif which qemu-system-i386 > /dev/null; \
	then echo qemu-system-i386; exit; \
	elif which qemu-system-x86_64 > /dev/null; \
	then echo qemu-system-x86_64; exit; \
	else \
		qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; \
		if test -x $$qemu; then echo $$qemu; exit; fi; fi; \
		echo "***" 1>&2; \
		echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \
		echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \
		echo "*** or have you tried setting the QEMU variable in Makefile?" 1>&2; \
		echo "***" 1>&2; exit 1)
endif

CC = $(TOOLPREFIX)gcc
AS = $(TOOLPREFIX)gas
LD = $(TOOLPREFIX)ld
OBJCOPY = $(TOOLPREFIX)objcopy
OBJDUMP = $(TOOLPREFIX)objdump
CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -MD -ggdb -fno-omit-frame-pointer
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
ASFLAGS = -gdwarf-2 -Wa,-divide
# FreeBSD ld wants ``elf_i386_fbsd''
LDFLAGS += -m $(shell $(LD) -V | grep elf_i386 2>/dev/null | head -n 1)

# Disable PIE when possible (for Ubuntu 16.10 toolchain)
ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
CFLAGS += -fno-pie -no-pie
endif
ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]nopie'),)
CFLAGS += -fno-pie -nopie
endif

xv6.img: bootblock kernel
	dd if=/dev/zero of=xv6.img count=10000
	dd if=bootblock of=xv6.img conv=notrunc
	dd if=kernel of=xv6.img seek=1 conv=notrunc

xv6memfs.img: bootblock kernelmemfs
	dd if=/dev/zero of=xv6memfs.img count=10000
	dd if=bootblock of=xv6memfs.img conv=notrunc
	dd if=kernelmemfs of=xv6memfs.img seek=1 conv=notrunc

bootblock: bootasm.S bootmain.c
	$(CC) $(CFLAGS) -fno-pic -O -nostdinc -I. -c bootmain.c
	$(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c bootasm.S
	$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o
	$(OBJDUMP) -S bootblock.o > bootblock.asm
	$(OBJCOPY) -S -O binary -j .text bootblock.o bootblock
	./sign.pl bootblock

entryother: entryother.S
	$(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c entryother.S
	$(LD) $(LDFLAGS) -N -e start -Ttext 0x7000 -o bootblockother.o entryother.o
	$(OBJCOPY) -S -O binary -j .text bootblockother.o entryother
	$(OBJDUMP) -S bootblockother.o > entryother.asm

initcode: initcode.S
	$(CC) $(CFLAGS) -nostdinc -I. -c initcode.S
	$(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o
	$(OBJCOPY) -S -O binary initcode.out initcode
	$(OBJDUMP) -S initcode.o > initcode.asm

kernel: $(OBJS) entry.o entryother initcode kernel.ld
	$(LD) $(LDFLAGS) -T kernel.ld -o kernel entry.o $(OBJS) -b binary initcode entryother
	$(OBJDUMP) -S kernel > kernel.asm
	$(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym

# kernelmemfs is a copy of kernel that maintains the
# disk image in memory instead of writing to a disk.
# This is not so useful for testing persistent storage or
# exploring disk buffering implementations, but it is
# great for testing the kernel on real hardware without
# needing a scratch disk.
MEMFSOBJS = $(filter-out ide.o,$(OBJS)) memide.o
kernelmemfs: $(MEMFSOBJS) entry.o entryother initcode kernel.ld fs.img
	$(LD) $(LDFLAGS) -T kernel.ld -o kernelmemfs entry.o $(MEMFSOBJS) -b binary initcode entryother fs.img
	$(OBJDUMP) -S kernelmemfs > kernelmemfs.asm
	$(OBJDUMP) -t kernelmemfs | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernelmemfs.sym

tags: $(OBJS) entryother.S _init
	etags *.S *.c

vectors.S: vectors.pl
	./vectors.pl > vectors.S

ULIB = ulib.o usys.o printf.o umalloc.o

_%: %.o $(ULIB)
	$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^
	$(OBJDUMP) -S $@ > $*.asm
	$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym

_forktest: forktest.o $(ULIB)
	# forktest has less library code linked in - needs to be small
	# in order to be able to max out the proc table.
	$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o _forktest forktest.o ulib.o usys.o
	$(OBJDUMP) -S _forktest > forktest.asm

mkfs: mkfs.c fs.h
	gcc -o mkfs mkfs.c

# Prevent deletion of intermediate files, e.g. cat.o, after first build, so
# that disk image changes after first build are persistent until clean.  More
# details:
# http://www.gnu.org/software/make/manual/html_node/Chained-Rules.html
.PRECIOUS: %.o

UPROGS = \
	_cat \
	_echo \
	_forktest \
	_grep \
	_init \
	_kill \
	_ln \
	_ls \
	_mkdir \
	_rm \
	_sh \
	_stressfs \
	_usertests \
	_wc \
	_zombie \


fs.img: mkfs README $(UPROGS)
	./mkfs fs.img README $(UPROGS)

-include *.d

clean: 
	rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
	*.o *.d *.asm *.sym vectors.S bootblock entryother \
	initcode initcode.out kernel xv6.img fs.img kernelmemfs \
	xv6memfs.img mkfs .gdbinit \
	$(UPROGS)

# make a printout
FILES = $(shell grep -v '^\#' runoff.list)
PRINT = runoff.list runoff.spec README toc.hdr toc.ftr $(FILES)

xv6.pdf: $(PRINT)
	./runoff
	ls -l xv6.pdf

print: xv6.pdf

# run in emulators

bochs: fs.img xv6.img
	if [ ! -e .bochsrc ]; then ln -s dot-bochsrc .bochsrc; fi
	bochs -q

# try to generate a unique GDB port
GDBPORT = $(shell expr `id -u` % 5000 + 25000)
# QEMU's gdb stub command line changed in 0.11
QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \
	then echo "-gdb tcp::$(GDBPORT)"; \
	else echo "-s -p $(GDBPORT)"; fi)
ifndef CPUS
CPUS := 2
endif
QEMUOPTS = -drive file=fs.img,index=1,media=disk,format=raw -drive file=xv6.img,index=0,media=disk,format=raw -smp $(CPUS) -m 512 $(QEMUEXTRA)

qemu: fs.img xv6.img
	$(QEMU) -serial mon:stdio $(QEMUOPTS)

qemu-memfs: xv6memfs.img
	$(QEMU) -drive file=xv6memfs.img,index=0,media=disk,format=raw -smp $(CPUS) -m 256

qemu-nox: fs.img xv6.img
	$(QEMU) -nographic $(QEMUOPTS)

.gdbinit: .gdbinit.tmpl
	sed "s/localhost:1234/localhost:$(GDBPORT)/" < $^ > $@

qemu-gdb: fs.img xv6.img .gdbinit
	@echo "*** Now run 'gdb'." 1>&2
	$(QEMU) -serial mon:stdio $(QEMUOPTS) -S $(QEMUGDB)

qemu-nox-gdb: fs.img xv6.img .gdbinit
	@echo "*** Now run 'gdb'." 1>&2
	$(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB)

# CUT HERE
# prepare dist for students
# after running make dist, probably want to
# rename it to rev0 or rev1 or so on and then
# check in that version.

EXTRA = \
	mkfs.c ulib.c user.h cat.c echo.c forktest.c grep.c kill.c \
	ln.c ls.c mkdir.c rm.c stressfs.c usertests.c wc.c zombie.c \
	printf.c umalloc.c \
	README dot-bochsrc *.pl toc.* runoff runoff1 runoff.list \
	.gdbinit.tmpl gdbutil \

dist:
	rm -rf dist
	mkdir dist
	for i in $(FILES); \
	do \
		grep -v PAGEBREAK $$i >dist/$$i; \
	done
	sed '/CUT HERE/,$$d' Makefile >dist/Makefile
	echo >dist/runoff.spec
	cp $(EXTRA) dist

dist-test:
	rm -rf dist
	make dist
	rm -rf dist-test
	mkdir dist-test
	cp dist/* dist-test
	cd dist-test; $(MAKE) print
	cd dist-test; $(MAKE) bochs || true
	cd dist-test; $(MAKE) qemu

# update this rule (change rev#) when it is time to
# make a new revision.
tar:
	rm -rf /tmp/xv6
	mkdir -p /tmp/xv6
	cp dist/* dist/.gdbinit.tmpl /tmp/xv6
	(cd /tmp; tar cf - xv6) | gzip >xv6-rev10.tar.gz  # the next one will be 10 (9/17)

.PHONY: dist-test dist

xv6์—์„œ ์‹œ์Šคํ…œ ์ฝœ๊ณผ ๊ด€๋ จ๋œ ์‹ค์Šต์„ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํŒŒ์•…ํ•ด๋‘์–ด์•ผ ํ•  ํŒŒ์ผ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • user.h : xv6์˜ ์‹œ์Šคํ…œ ์ฝœ ์ •์˜ํ•˜๋Š” ํ—ค๋” ํŒŒ์ผ
  • usys.S : xv6์˜ ์‹œ์Šคํ…œ ์ฝœ ๋ฆฌ์ŠคํŠธ
  • defs.h : ๋ฐ์ดํ„ฐ ํƒ€์ž…, ๋งคํฌ๋กœ, ์ƒ์ˆ˜, ํ•จ์ˆ˜ ์ •์˜๋ฅผ ๊ฐ–๋Š” ํ—ค๋” ํŒŒ์ผ
  • syscall.h : ์‹œ์Šคํ…œ ์ฝœ ๋ฒˆํ˜ธ๋ฅผ ๋งคํ•‘ํ•˜๋Š” ํ—คใ„ทใ„ฑ๋” ํŒŒ์ผ. ์ƒˆ๋กœ์šด ์‹œ์Šคํ…œ ์ฝœ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋ฒˆํ˜ธ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•จ
  • syscall.c : ์‹œ์Šคํ…œ ์ฝœ ์ธ์ˆ˜๋ฅผ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๋Š” ํ•จ์ˆ˜ ๋ฐ ์‹ค์ œ ์‹œ์Šคํ…œ ์ฝœ ๊ตฌํ˜„์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ
  • sysproc.c : ํ”„๋กœ์„ธ์Šค ๊ด€๋ จ ์‹œ์Šคํ…œ ํ˜ธ์ถœ ๊ตฌํ˜„. fork(), exec(), wait(), exit() ์™€ ๊ฐ™์€ ์‹œ์Šคํ…œ ํ˜ธ์ถœ์˜ ์‹ค์ œ ๋กœ์ง์ด ์žˆ์Œ. ์ƒˆ๋กœ์šด ํ”„๋กœ์„ธ์Šค ๊ด€๋ จ ์‹œ์Šคํ…œ ํ˜ธ์ถœ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ์—ฌ๊ธฐ์— ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•จ
  • proc.h : ํ”„๋กœ์„ธ์Šค์— ๋Œ€ํ•œ ๊ตฌ์กฐ์ฒด์ธ struct proc์˜ ์ •์˜๊ฐ€ ํฌํ•จ๋œ ํ—ค๋” ํŒŒ์ผ. ํ”„๋กœ์„ธ์Šค์˜ ์ƒํƒœ, PID(ํ”„๋กœ์„ธ์Šค ID), ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค, ์Šคํƒ ํฌ์ธํ„ฐ ๋“ฑ ํ”„๋กœ์„ธ์Šค์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋จ
  • proc.c : ํ”„๋กœ์„ธ์Šค ๊ฐ„์˜ ์Šค์ผ€์ค„๋ง ๋ฐ ์ปจํ…์ŠคํŠธ ์ „ํ™˜์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๊ตฌํ˜„๋œ ํŒŒ์ผ.

์„ฑ๋Šฅ ๊ด€์ฐฐ ๋ฐ ์กฐ์ •

์‹œ์Šคํ…œ์˜ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„  ๋ณ‘๋ชฉ ์ง€์ ์„ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ํ•„์ˆ˜์ ์ด๋‹ค. ์ด๋Ÿฌํ•œ ๋ณ‘๋ชฉ ์ง€์ ์„ ๋ฐœ๊ฒฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” counter์™€ tracing ๋‘ ๊ฐ€์ง€ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋Œ€ํ‘œ์ ์ด๋‹ค.

  • Counter : ํ˜ธ์ถœ๋œ ์‹œ์Šคํ…œ ์ฝœ ํšŸ์ˆ˜ ๋˜๋Š” ๋„คํŠธ์›Œํฌ ์žฅ์น˜ ๋˜๋Š” ๋””์Šคํฌ์— ์ˆ˜ํ–‰๋œ ์ž‘์—… ์ˆ˜์™€ ๊ฐ™์€ ์‹œ์Šคํ…œ ํ™œ๋™์„ ์ถ”์  
  • Tracing : ์‹œ์Šคํ…œ ์ฝœ๊ณผ ๊ด€๋ จ๋œ ๋‹จ๊ณ„์™€ ๊ฐ™์€ ํŠน์ • ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘

getforkcount ์‹ค์Šต

fork๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ, ๊ณผ์—ฐ ๊ด€๋ จ ์‹œ์Šคํ…œ ์ฝœ์ด ์ •ํ™•ํžˆ ๋ฐœ์ƒํ•˜๋Š” ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๊ทธ ์ˆ˜๋ฅผ ์„ธ๋Š” ๊ฐ„๋‹จํ•œ ์‹œ์Šคํ…œ ์ฝœ์ด๋‹ค. ์‹œ์Šคํ…œ ์ฝœ์„ ์ถ”๊ฐ€ํ•˜๋Š” ์ „์ฒด์ ์ธ ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. ์ „์—ญ ๋ณ€์ˆ˜ ์„ ์–ธ: sysproc.c ํ˜น์€proc.c์— ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธ
  2. ์‹œ์Šคํ…œ ์ฝœ ํ•จ์ˆ˜ ๊ตฌํ˜„: ์‹œ์Šคํ…œ ์ฝœ์— ๋Œ€ํ•œ ๋™์ž‘์„ ์ •์˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ sysproc.c์— ์ž‘์„ฑ
  3. ์‹œ์Šคํ…œ ์ฝœ ๋ฒˆํ˜ธ ํ• ๋‹น: syscall.h์— ์ƒˆ๋กœ์šด ์‹œ์Šคํ…œ ์ฝœ ๋ฒˆํ˜ธ๋ฅผ ํ• ๋‹น
  4. ์‹œ์Šคํ…œ ์ฝœ ํ…Œ์ด๋ธ” ๋“ฑ๋ก: syscall.c ํŒŒ์ผ์— ์‹œ์Šคํ…œ ์ฝœ ํ…Œ์ด๋ธ”์— ์ƒˆ๋กœ์šด ์‹œ์Šคํ…œ ์ฝœ์„ ๋“ฑ๋ก
  5. ์œ ์ € ์ธํ„ฐํŽ˜์ด์Šค ์ถ”๊ฐ€: usys.S ํŒŒ์ผ์— ์‹œ์Šคํ…œ ์ฝœ์„ ์œ ์ € ๊ณต๊ฐ„์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ ์–ธ
  6. ์œ ์ € ํ”„๋กœ๊ทธ๋žจ ์ถ”๊ฐ€ : user.h ํŒŒ์ผ์— ์œ ์ € ๊ณต๊ฐ„์—์„œ ์‚ฌ์šฉํ•  ํ•จ์ˆ˜์˜ ์„ ์–ธ๋ถ€ ์ž‘์„ฑ

(user.h๋Š” ํ•จ์ˆ˜์˜ ํ”„๋กœํ†  ํƒ€์ž…์ด๋ฉฐ, ์‹ค์ œ๋กœ๋Š” usys.S์—์„œ ์‹œ์Šคํ…œ์ฝœ๊ณผ ์ปค๋„์˜ ์—ฐ๊ฒฐ์ด ์ด๋ฃจ์–ด์ง„๋‹ค.)

// sysproc.c์— ์ „์—ญ ๋ณ€์ˆ˜ ์„ค์ • ํ›„, sys_fork ํ•จ์ˆ˜์— ๋กœ์ง ์ถ”๊ฐ€ 
// fork_count ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ ์ถ”๊ฐ€
int fork_count = 0;
int
sys_fork(void)
{
  fork_count++;
  return fork();
}
int
sys_getforkcount(void)
{
    return fork_count; 
}


// syscall.h์— ์‹œ์Šคํ…œ ์ฝœ ์ถ”๊ฐ€
#define SYS_getforkcount  23


// syscall.c์—์„œ ์‹œ์Šคํ…œ ์ฝœ ํ…Œ์ด๋ธ”์— ๋“ฑ๋ก
extern int sys_getforkcount(void);
...
[SYS_getforkcount] sys_getforkcount,


//usys.S์— ps ์‹œ์Šคํ…œ ์ฝœ ์ •์˜
SYSCALL(getforkcount)


// user.h์— ์ถ”๊ฐ€. ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ์˜ ์‚ฌ์šฉ์„ ์œ„ํ•จ
int getforkcount(void);


//getforkcount.c์—์„œ ์‹œ์Šคํ…œ ์ฝœ ํ˜ธ์ถœ
#include "types.h"
#include "user.h"

int
main(void)
{
    int count = getforkcount();
    printf(1,"Initial fork count: %d\n", count);

    // fork ํ˜ธ์ถœ
    if (fork() == 0) {
        // ์ž์‹ ํ”„๋กœ์„ธ์Šค์—์„œ๋Š” exit๋งŒ ์ˆ˜ํ–‰
        exit();
    }
    wait();  // ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ

    count = getforkcount();
    printf(1,"Fork count after fork: %d\n", count);

    exit();
}


//Makefile์— ps ์ถ”๊ฐ€
UPROGS = \
	...
	_getforkcount	\
	

EXTRA = \
	mkfs.c ... getforkcount.c\

fork ๋ฐœ์ƒ ์‹œ์— counter๊ฐ€ ๋™์ž‘ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด์— ์ด๋ฏธ ์ž‘์„ฑ๋˜์–ด ์žˆ๋Š” fork ์‹œ์Šคํ…œ ์ฝœ ๋กœ์ง์— count๊ฐ’์„ ๋Š˜๋ฆฌ๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•˜์˜€๋‹ค. 

getforkcount์—๋Š” fork๋ฅผ 1ํšŒ ์ˆ˜ํ–‰ํ•˜๊ฒŒ๋” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋‘” ์ƒํƒœ์ด๋‹ค. getforkcount ๋ช…๋ น์–ด ์‚ฌ์šฉ์„ ํ†ตํ•ด forkcount ์ˆ˜๊ฐ€ 1 ์ฆ๊ฐ€ ๋จ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, xv6์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” forktest ์ดํ›„ ๋‹ค์‹œ ์‹œ์Šคํ…œ ์ฝœ ํ˜ธ์ถœ ์‹œ forkcount ์ˆ˜๊ฐ€ ๋” ์ฆ๊ฐ€ํ•œ ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 


trace ์‹ค์Šต

์‹œ์Šคํ…œ ์ฝœ์ด ๋ฐœ์ƒํ•˜๋ฉด ์–ด๋–ค ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ…Œ์Šคํฌ๋ฅผ ํ• ๋‹น๋ฐ›์•„ ์‹œ์Šคํ…œ ์ฝœ์„ ํ˜ธ์ถœํ–ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์Šคํ…œ ์ฝœ์ด๋‹ค. ์‹œ์Šคํ…œ ์ฝœ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋Œ€๋žต์ ์ธ ๊ณผ์ •์€ counter ์‹ค์Šต๊ณผ ๋™์ผํ•˜๊ฒŒ ์ง„ํ–‰๋œ๋‹ค.

// sysproc.c์— ์ „์—ญ ๋ณ€์ˆ˜ ์„ค์ •
// trace ๊ธฐ๋Šฅ์„ ์ œ์–ดํ•˜๋Š” ์‹œ์Šคํ…œ ์ฝœ ์ถ”๊ฐ€
extern int tracing_enabled; // 0: tracing ๋น„ํ™œ์„ฑํ™”, 1: tracing ํ™œ์„ฑํ™”
int
sys_trace(void)
{
    int enable;
    if(argint(0, &enable) < 0)
        return -1;
    tracing_enabled = enable;
    return 0;
}


// syscall.h์— ์‹œ์Šคํ…œ ์ฝœ ์ถ”๊ฐ€
#define SYS_trace  24


// syscall.c์—์„œ ์‹œ์Šคํ…œ ์ฝœ ํ…Œ์ด๋ธ”์— ๋“ฑ๋ก
// syscall์„ ์ˆ˜์ •ํ•˜์—ฌ ์‹œ์Šคํ…œ ์ฝœ ๋ฐœ์ƒ ์‹œ, ์ฝ˜์†”์— ์ถœ๋ ฅํ•˜๊ฒŒ๋” ์ˆ˜์ •
int tracing_enabled = 0;  
extern int sys_trace(void);
...
[SYS_getforkcount] sys_trace,

void
syscall(void)
{
  int num;
  struct proc *curproc = myproc();

  num = curproc->tf->eax;
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
    if(tracing_enabled) {  // tracing์ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ
      cprintf("   pname : %s   pid : %d   syscall : %d\n", curproc->name, curproc->pid, num);
    }
    curproc->tf->eax = syscalls[num]();
  } else {
    cprintf("%d %s: unknown sys call %d\n",
            curproc->pid, curproc->name, num);
    curproc->tf->eax = -1;
  }
}


//usys.S์— ์‹œ์Šคํ…œ ์ฝœ ์ •์˜
SYSCALL(trace)


// user.h์— ์ถ”๊ฐ€. ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ์˜ ์‚ฌ์šฉ์„ ์œ„ํ•จ
int trace(int enable);


//trace.c
#include "types.h"
#include "user.h"

int
main(int argc, char *argv[])
{
    if(argc != 2) {
        printf(2, "Usage: trace [0|1]\n");
        exit();
    }

    int enable = atoi(argv[1]);
    if(enable != 0 && enable != 1) {
        printf(2, "Invalid argument. Use 0 to disable or 1 to enable tracing.\n");
        exit();
    }

    // ์‹œ์Šคํ…œ ์ฝœ์„ ํ†ตํ•ด tracing ํ™œ์„ฑํ™” ๋˜๋Š” ๋น„ํ™œ์„ฑํ™”
    trace(enable);

    if(enable)
        printf(1, "Tracing enabled\n");
    else
        printf(1, "Tracing disabled\n");

    exit();
}



//Makefile์— ps ์ถ”๊ฐ€
UPROGS = \
	...
	_trace \
	

EXTRA = \
	mkfs.c ... trace.c\

์‹œ์Šคํ…œ ์ฝœ์ด ๋™์ž‘ํ•  ๋•Œ๋งˆ๋‹ค ์–ด๋–ค ํ”„๋กœ์„ธ์Šค๊ฐ€ ์–ด๋–ค ์ž‘์—…์„ ํ•˜๋Š”์ง€ ์•Œ๊ธฐ ์œ„ํ•ด์„œ ๊ธฐ์กด์— ์ž‘์„ฑ๋˜์–ด์žˆ๋Š” syscall ํ•จ์ˆ˜๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์‹ค์Šต์„ ์ง„ํ–‰ํ•˜์˜€๋‹ค. trace 1 ์ž…๋ ฅ์„ ํ†ตํ•ด tracing์„ ์‹œ์ž‘ํ•˜๊ณ  trace 0์„ ํ†ตํ•ด tracing์„ ์ข…๋ฃŒํ•˜๊ฒŒ ๋œ๋‹ค.

์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. 70๋ฒˆ ํ”„๋กœ์„ธ์Šค๊ฐ€ trace๋ฅผ ์œ„ํ•œ ์ž‘์—…์„ ์œ„ํ•ด ํ• ๋‹น๋˜์–ด ์‹œ์Šคํ…œ ์ฝœ์„ ํ˜ธ์ถœ ์ค‘์ด๋ฉฐ trace ์‹œ์ž‘ ์‹œ Tracing enabled๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด write ์‹œ์Šคํ…œ ์ฝœ(16๋ฒˆ)์„ ํ˜ธ์ถœ ํ•˜์˜€์œผ๋ฉฐ ์ถœ๋ ฅ์ด ๋๋‚˜์ž exit ์‹œ์Šคํ…œ ์ฝœ(2๋ฒˆ)์„ ํ˜ธ์ถœํ•˜์—ฌ ์ข…๋ฃŒํ•˜๊ณ  ์‰˜์„ ์œ„ํ•œ 2๋ฒˆ ํ”„๋กœ์„ธ์Šค์—๊ฒŒ ์ œ์–ด๋ฅผ ๋„˜๊ฒผ๋‹ค. 2๋ฒˆ ํ”„๋กœ์„ธ์Šค๋Š” ๊ณต๋ฐฑ๊ณผ $ ๋ฌธ๊ตฌ ์ถœ๋ ฅ์„ ์œ„ํ•ด 16๋ฒˆ ์‹œ์Šคํ…œ ์ฝœ์„ ํ˜ธ์ถœํ•œ ํ›„ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ฐ’์„ ์ž…๋ ฅ๋ฐ›๊ธฐ ์œ„ํ•ด read ์‹œ์Šคํ…œ ์ฝœ(5๋ฒˆ)์„ ํ˜ธ์ถœํ•˜์˜€๋‹ค.

 

์ดํ›„ getforkcount ์‹œ์Šคํ…œ ์ฝœ์„ ๋ถˆ๋Ÿฌ๋ณด์•˜๋‹ค. ์ž‘์„ฑํ•œ ๊ธ€์ž๋ฅผ ์ฝ์–ด๋“ค์ด๊ธฐ ์œ„ํ•ด 5๋ฒˆ ์‹œ์Šคํ…œ ์ฝœ์ด ๊ธ€์ž์ˆ˜ ๋งŒํผ ํ˜ธ์ถœ๋˜์—ˆ์œผ๋ฉฐ, ์ดํ›„ fork ์‹œ์Šคํ…œ ์ฝœ(1๋ฒˆ)์„ ํ˜ธ์ถœํ•˜์—ฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋“ค์–ด๊ฐ€(3๋ฒˆ) ์ž์‹ ํ”„๋กœ์„ธ์Šค(71๋ฒˆ ํ”„๋กœ์„ธ์Šค)์—๊ฒŒ ์ œ์–ด๋ฅผ ๋„˜๊ฒผ๋‹ค. 71๋ฒˆ ํ”„๋กœ์„ธ์Šค๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹น๋ฐ›๊ณ (12๋ฒˆ) ํ™œ์„ฑํ™” ์ƒํƒœ(7๋ฒˆ)๋กœ ๋“ค์–ด๊ฐ”๋‹ค. ๊ทธ ํ›„ getforkcount ์‹œ์Šคํ…œ ์ฝœ(23๋ฒˆ)์„ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด write ์‹œ์Šคํ…œ ์ฝœ์„ ๋ฐ˜๋ณตํ•˜์˜€๋‹ค. 

 

ํ•ด๋‹น ์‹ค์Šต์„ ํ†ตํ•ด ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹œ์Šคํ…œ ์ฝœ์„ ํ˜ธ์ถœํ•˜๋Š” ์•„์ฃผ ๋Œ€๋žต์ ์ธ ๊ณผ์ •์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ  ์˜ˆ์ƒ๋Œ€๋กœ ๋™์ž‘ํ•จ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.