미새문지

pintOS - project1(Thread) timer.c 본문

크래프톤 정글/pintOS

pintOS - project1(Thread) timer.c

문미새 2024. 3. 11. 00:26
728x90

timer.c

< macro >

더보기
// 초당 타이머 인터럽트 횟수가 19 초과 1000 미만
#if TIMER_FREQ < 19
#error 8254 timer requires TIMER_FREQ >= 19
#endif
#if TIMER_FREQ > 1000
#error TIMER_FREQ <= 1000 recommended
#endif

< timer_init >

더보기
/*초당 PIT_FREQ를 인터럽트하고 해당 인터럽트를 등록시킨다.
pit = 프로그래밍된 카운트에 도달할 때 출력 신호를 생성하는 카운터*/
void
timer_init (void) {
	/* 8254 입력 주파수를 TIMER_FREQ로 나눈 값을 가장 가까운 값으로 반올림 */
	uint16_t count = (1193180 + TIMER_FREQ / 2) / TIMER_FREQ;
	
	/* outb (pit의 제어워드 레지스터, 설정하려는 제어워드 값) */
	outb (0x43, 0x34);    /* CW: counter 0, LSB then MSB, mode 2, binary. */
	outb (0x40, count & 0xff);
	outb (0x40, count >> 8);

	// 운영체제의 인터럽트 처리 시스템에서 사용되는 함수 호출
	// (인터럽트 벡터 번호, 인터럽트 발생 시 호출 함수, 처리 루틴이나 이름 제공)
	intr_register_ext (0x20, timer_interrupt, "8254 Timer");
}

< timer_calibrate >

더보기
// 짧은 지연을 구현하는데 사용하는 loops_per_tick을 보정한다.
void
timer_calibrate (void) {
	unsigned high_bit, test_bit;

	ASSERT (intr_get_level () == INTR_ON);
	printf ("Calibrating timer...  ");

	// 적절한 loops_per_tick을 2의 제곱형태로 보여준다. << 여전히 timer tick보다 작다.
	loops_per_tick = 1u << 10;
	while (!too_many_loops (loops_per_tick << 1)) {
		loops_per_tick <<= 1;
		ASSERT (loops_per_tick != 0);
	}

	// 다음 8비트의 loops_per_tick을 세분화
	high_bit = loops_per_tick;
	for (test_bit = high_bit >> 1; test_bit != high_bit >> 10; test_bit >>= 1)
		if (!too_many_loops (high_bit | test_bit))
			loops_per_tick |= test_bit;

	printf ("%'"PRIu64" loops/s.\n", (uint64_t) loops_per_tick * TIMER_FREQ);
}

< timer_ticks >

더보기
// OS 부팅 후 타이머 틱 수를 반환한다.
int64_t
timer_ticks (void) {
	enum intr_level old_level = intr_disable (); // 기존 인터럽트 상태를 저장하고 비활성화
	int64_t t = ticks; // t에 ticks를 저장
	intr_set_level (old_level); // 다시 이전 인터럽트 상태를 가져오기
	barrier (); // 메모리 접근 순서를 명확하게 하기 위해 사용
    
	return t;
}

< timer_elapsed >

더보기
// timer_ticks에 의해 반환된 값, 이후 경과한 타이머 틱수를 반환한다.
int64_t
timer_elapsed (int64_t then) {
	return timer_ticks () - then;
}

< timer_sleep >

더보기
// TICKS timer ticks를 대략적으로 실행을 중지한다.
void
timer_sleep (int64_t ticks) {
	int64_t start = timer_ticks (); // 타이머 틱수를 start에 저장
    
	if(ticks <= 0) // 만약 받아온 ticks가 없으면 종료
		return;
	
	ASSERT(intr_get_level() == INTR_ON); // 인터럽트가 꺼져있으면 종료
	
	thread_sleep(ticks+start); // 스레드를 재우기 위해 ticks와 부팅 후 지난 ticks를 더해 매개변수로 전달
}

< timer_interrput >

더보기
// 인터럽트 핸들러
static void
timer_interrupt (struct intr_frame *args UNUSED) {
	// ticks를 증가시키고 틱마다 인터럽트 핸들러를 호출
	ticks++;
	thread_tick ();
	
	thread_wakeup(ticks); // ticks를 전달하여 스레드를 깨운다.

	// mlfqs가 활성화 되있으면 일정한 주기마다 시스템의 평균 부하를 계산한다.
	if (thread_mlfqs == true){
		if(timer_ticks() % TIMER_FREQ == 0)
			update_load_avg();
	}
}

< too_many_loops >

더보기
/* 루프 반복이 ticks보다 오래걸리는지 확인 */
static bool
too_many_loops (unsigned loops) {
	// 타이머가 울릴 때까지 기다린다
	int64_t start = ticks;
	while (ticks == start)
		barrier ();

	// loops만큼 반복 작업 수행
	start = ticks;
	busy_wait (loops);

	// 틱수가 다르면 너무 오래 반복한 것 false 반환, 같으면 true 반환
	barrier ();
	return start != ticks;
}

< busy_wait >

더보기
// 루프를 loops 시간만큼 반복
static void NO_INLINE
busy_wait (int64_t loops) {
	while (loops-- > 0)
		barrier ();
}
728x90