# timekeeping: 갱신 중인 시계를 일관되게 읽기

v6.6 / kernel/time/timekeeping.c

커널의 현재 시각은 기준 시각과 그 뒤에 흐른 시간으로 계산할 수 있습니다. 그런데 두 값을 읽는 사이 다른 CPU가 기준을 갱신하면 서로 다른 세대의 값을 섞을 수 있습니다. ktime_get은 sequence counter를 확인해 충돌했을 때 다시 읽습니다.

## ktime_get

```c

ktime_t ktime_get(void)
{
	struct timekeeper *tk = &tk_core.timekeeper;
	unsigned int seq;
	ktime_t base;
	u64 nsecs;

	WARN_ON(timekeeping_suspended);

	do {
		seq = read_seqcount_begin(&tk_core.seq);
		base = tk->tkr_mono.base;
		nsecs = timekeeping_get_ns(&tk->tkr_mono);

	} while (read_seqcount_retry(&tk_core.seq, seq));

	return ktime_add_ns(base, nsecs);
}

```

### 836행

```c

ktime_t ktime_get(void)

```

monotonic 시각을 ktime_t 형태로 반환합니다. wall clock 날짜를 문자열로 만드는 함수가 아닙니다.

### 838행

```c

	struct timekeeper *tk = &tk_core.timekeeper;

```

공통 timekeeper의 주소를 구합니다. 기준 시각과 clocksource 읽기 정보가 연결된 관리 구조체입니다.

### 839행

```c

	unsigned int seq;

```

읽기 시작 시점의 sequence 번호를 저장할 변수입니다.

### 840행

```c

	ktime_t base;

```

기준 monotonic 시각을 보관합니다.

### 841행

```c

	u64 nsecs;

```

기준 이후 추가된 나노초 수를 보관합니다.

### 843행

```c

	WARN_ON(timekeeping_suspended);

```

timekeeping이 suspend된 상태에서 일반 읽기를 시도하는지 경고합니다. 정상 시계 갱신 상태가 아닐 수 있다는 검사입니다.

### 845행

```c

	do {

```

읽기 결과가 갱신과 충돌했으면 전체를 반복할 블록을 시작합니다.

### 846행

```c

		seq = read_seqcount_begin(&tk_core.seq);

```

쓰기 진행 여부를 고려하여 시작 sequence 값을 읽습니다. 이후 검사에서 이 값과 현재 상태를 비교합니다.

### 847행

```c

		base = tk->tkr_mono.base;

```

현재 monotonic 기준 시각을 복사합니다.

### 848행

```c

		nsecs = timekeeping_get_ns(&tk->tkr_mono);

```

동일한 읽기 기준의 clocksource 정보로 추가 경과 나노초를 계산합니다.

### 850행

```c

	} while (read_seqcount_retry(&tk_core.seq, seq));

```

읽는 동안 writer가 상태를 갱신했다면 방금 읽은 조합을 버리고 do 블록을 다시 실행합니다.

### 852행

```c

	return ktime_add_ns(base, nsecs);

```

일관된 base와 nsecs를 더해 현재 monotonic 시각을 반환합니다.

