감기 걸려서 병원갔다가 쉬었음.
15:45 입실
속았다..
process_exec()에서 파싱하는 게 아니라 내부의 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
프로세스 자체를 종료하는 게 아님.
문맥 전환을 위해 현재 실행 중인 프로세스를 정리한다고 보는게 더 적절.
정확히 어떤 기능인지는 모르겠음.
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 ();
}
인터럽트는 보통 긴급하게 발생한다.
이때 현재 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을 시작점으로 해서
마치 새로운 문자열의 토큰을 분리하는 것처럼 작동되게 됨.
왜 이렇게 해야 하는지는 모르겠음.
그냥 아예 처음부터 문자열의 시작 주소를 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() 내용 대충 살펴보고 기존 프로그램 파일에서 옵션 파싱하는 것까지는 얼추 이해함.