[크래프톤 정글 3기] 12/5(화) TIL 🤒

ClassBinu·2023년 12월 5일
0

크래프톤 정글 3기 TIL

목록 보기
52/120

감기 걸려서 병원갔다가 쉬었음.
15:45 입실


Pintos

속았다..
process_exec()에서 파싱하는 게 아니라 내부의 load()에서 파싱하는 거였음.
팀원이 알려줘서 알았음.

어떤지 넘어갈 인수가 없더라.

load()

파일명과 &_if를 인수로 받는다.
&_if는 intr_frame 구조체이다.
메모리에 로드하는 것.

오호.. 이런 식으로 메모리에 프로그램을 로드하는군?

intr_frame은 인터럽트 프레임!
인터럽트도 프레임이 있구나..

인터럽트 프레임은 인터럽트 또는 시스템 호출이 발생했을 때 CPU의 상태를 저장하는 데 사용되는 데이터 구조

문맥 교환에서 PCB, TCB가 사용된다면 인터럽트에서는 인터럽트 프레임이 사용됨.

struct intr_frame {
	/* Pushed by intr_entry in intr-stubs.S.
	   These are the interrupted task's saved registers. */
	struct gp_registers R;
	uint16_t es;
	uint16_t __pad1;
	uint32_t __pad2;
	uint16_t ds;
	uint16_t __pad3;
	uint32_t __pad4;
	/* Pushed by intrNN_stub in intr-stubs.S. */
	uint64_t vec_no; /* Interrupt vector number. */
/* Sometimes pushed by the CPU,
   otherwise for consistency pushed as 0 by intrNN_stub.
   The CPU puts it just under `eip', but we move it here. */
	uint64_t error_code;
/* Pushed by the CPU.
   These are the interrupted task's saved registers. */
	uintptr_t rip;
	uint16_t cs;
	uint16_t __pad5;
	uint32_t __pad6;
	uint64_t eflags;
	uintptr_t rsp;
	uint16_t ss;
	uint16_t __pad7;
	uint32_t __pad8;
} __attribute__((packed))

인터럽트 프레임에 기록되는 정보

	struct intr_frame _if;
    // Dat Segment, Extra Segment, Stack Segment
	_if.ds = _if.es = _if.ss = SEL_UDSEG;
    
    // Code Segment(사용자 모드 코드 세그먼트)
	_if.cs = SEL_UCSEG;
    
    // 프로세서 상태 플래그
	_if.eflags = FLAG_IF | FLAG_MBS

process_cleanup ()

프로세스 자체를 종료하는 게 아님.
문맥 전환을 위해 현재 실행 중인 프로세스를 정리한다고 보는게 더 적절.
정확히 어떤 기능인지는 모르겠음.

process_exec() 함수를 해석해 봄!

int
process_exec (void *f_name) {
	char *file_name = f_name;
	bool success;

	/* We cannot use the intr_frame in the thread structure.
	 * This is because when current thread rescheduled,
	 * it stores the execution information to the member. */
	struct intr_frame _if;
	_if.ds = _if.es = _if.ss = SEL_UDSEG;
	_if.cs = SEL_UCSEG;
	_if.eflags = FLAG_IF | FLAG_MBS;

	/* We first kill the current context */
	process_cleanup ();

	/* And then load the binary */
	success = load (file_name, &_if);

	/* If load failed, quit. */
	palloc_free_page (file_name);
	if (!success)
		return -1;

	/* Start switched process. */
	do_iret (&_if);
	NOT_REACHED ();
}
  1. 새로 로드될 프로세스에 대하여 인터럽트 프레임을 초기화한다.
  2. 현재 실행 중인 프로세스를 안전하게 정리한다.
  3. 인자로 넘어온 프로그램을 메모리에 로드한다.
  4. 실행이 끝나면 해당 프로세스가 할당받은 페이지를 해제한다.
  5. 인터럽프 프레임에 따라 새 프로그램을 실행한다.

인터럽트는 보통 긴급하게 발생한다.
이때 현재 CPU의 상태를 저장하기 위한 자료구조가 필요한데,
이게 인터럽트 프레임이다.

인터럽트 프레임 관련해서 같은 정글러 블로그 정리 잘 되어 있음!
https://stay-present.tistory.com/98


특정 프로그램이 실행되는 게 인터럽트인가?

세그먼트 셀렉터는 세그먼트 레지스터다.

#define SEL_NULL 0x00 / Null selector. /
#define SEL_KCSEG 0x08 / Kernel code selector. /
#define SEL_KDSEG 0x10 / Kernel data selector. /
#define SEL_UDSEG 0x1B / User data selector. /
#define SEL_UCSEG 0x23 / User code selector. /
#define SEL_TSS 0x28 / Task-state segment. /
#define SEL_CNT 8 / Number of segments.

0x08과 같은 숫자는 글로벌 디스크립터 테이블(Global Descriptor Table, GDT)에서 커널 코드 세그먼트(Kernel Code Segment)를 지정하는 데 사용

세그먼트의 역할: SEL_UCSEG 0x23는 사용자 모드의 코드 세그먼트에 대한 일반적인 속성(권한, 세그먼트 타입 등)을 정의


프로그램과 옵션 분리하기

gitbook에서처럼 strtok_r을 쓴다.

	char *token;
	char *next_ptr;
	char **argv = malloc(sizeof(char*) * 10);
	int argc = 0;

	token = strtok_r(file_name, " ", &next_ptr);
	while (token != NULL && argc < 10) {
		argv[argc++] = token;
		token = strtok_r(NULL, " ", &next_ptr);
	}

문자를 나눈 단위를 토큰이라고 한다. 그래서 openAI에서 과금 단위로 토큰을 썼나?
여튼 이 토큰은 원래 값에서 앞에서부터 공백으로 구분된 토큰을 하나씩 떼어낸다.

storok_r은 next_prt을 넘겨줘야 한다.
한번 토큰화가 된 후에 다음에 시작할 위치를 알려줌.

그래서 처음 호출할 때는 문자열을 넘겨주지만,
그 다음 부터는 NULL을 넘기고 next_ptr을 시작점으로 해서
마치 새로운 문자열의 토큰을 분리하는 것처럼 작동되게 됨.

strtok_r는 다음과 같이 사용한다.

  1. 첫 호출시에는 전체 문자열을 넘겨서 토큰화를 시작한다.
  2. 이후 호출 시에는 문자열을 NULL로 넘기고, next_ptr에 직전 strtok_r이 저장한 next_ptr을 넘긴다.

왜 이렇게 해야 하는지는 모르겠음.
그냥 아예 처음부터 문자열의 시작 주소를 next_ptr로 넘기면 안 되나?
이런 이유 때문이라고 한다.

함수의 내부 로직과의 충돌: strtok_r 함수는 내부적으로 현재 분석 위치를 추적하고 관리합니다. 첫 번째 호출에서 전체 문자열을 받으면, 함수는 내부적으로 다음 토큰의 시작 위치를 next_ptr에 저장합니다. 만약 next_ptr에 이미 문자열의 시작 주소가 저장되어 있으면, 함수의 내부 상태 관리와 충돌할 수 있으며, 이는 예상치 못한 결과를 초래할 수 있습니다.

상태 관리의 복잡성: strtok_r는 호출 간의 상태를 next_ptr를 통해 관리합니다. 이 상태는 함수가 자체적으로 계산하고 업데이트합니다. 사용자가 직접 next_ptr에 문자열의 시작 주소를 설정하면, 함수가 기대하는 상태 관리 방식이 깨지게 되어, 함수가 제대로 동작하지 않을 수 있습니다.

함수 사용의 명확성 저하: strtok_r의 사용 방식은 명확하고 일관된 패턴을 따릅니다. 첫 번째 호출에서 전체 문자열을 넘기고, 이후 호출에서는 NULL을 사용하는 것이 이 패턴입니다. 이것은 사용자에게 함수의 사용 방식을 명확하게 전달하는 데 도움이 됩니다. 사용자가 next_ptr를 직접 관리하면 함수 사용의 명확성이 저하됩니다.

함수의 재진입성 보장: strtok_r은 재진입 가능한 함수로 설계되었습니다. 이는 동일한 문자열에 대해 여러 스레드나 재귀 호출에서 안전하게 사용될 수 있음을 의미합니다. 사용자가 next_ptr를 직접 관리하면, 이러한 재진입 가능성이 손상될 수 있습니다.

결론적으로, strtok_r 함수는 특정한 방식으로 사용되도록 설계되었으며, 이를 변경하여 사용하면 함수의 기대되는 동작과 안정성이 보장되지 않을 수 있습니다. 따라서, 함수를 문서화된 대로 올바르게 사용하는 것이 중요합니다.


몸이 안 좋아서 22:00에 마감.. 좀 쉬어야지..
process_exec(), load() 내용 대충 살펴보고 기존 프로그램 파일에서 옵션 파싱하는 것까지는 얼추 이해함.

0개의 댓글