[커널 18차] 67주차
2022.09.03 22:24
lowres timer 진행.
추석연휴 휴식
git : https://github.com/iamroot18/5.10/commit/441edf6ccc4b22fe3cccf9606ae30444f1317b1d
diff --git a/arch/arm64/include/asm/preempt.h b/arch/arm64/include/asm/preempt.h
index e83f0982b99c..658a198a17a9 100644
--- a/arch/arm64/include/asm/preempt.h
+++ b/arch/arm64/include/asm/preempt.h
@@ -7,6 +7,10 @@
#define PREEMPT_NEED_RESCHED BIT(32)
#define PREEMPT_ENABLED (PREEMPT_NEED_RESCHED)
+/*
+ * IAMROOT, 2022.09.03:
+ * - preempt count를 가져온다.
+ */
static inline int preempt_count(void)
{
return READ_ONCE(current_thread_info()->preempt.count);
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 4ade2757d06d..aac88978ccb7 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -949,6 +949,16 @@ static void arch_timer_configure_evtstream(void)
* - evt_stream_div = arch_timer_rate / 2000
* arch_timer_rate = 19.2M이라고 했을대
* evt_stream_div = 19200000 / 2000 = 9600
+ * - ex) x us마다 evt 발생.
+ * 1us 마다
+ * arch_timerr_rate / 1000_000
+ * 10us 마다
+ * arch_timerr_rate / 100_000
+ * 100us 마다
+ * arch_timerr_rate / 10_000
+ * 1000us 마다
+ * arch_timerr_rate / 1_000
+ *
*/
evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ / 2;
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 1f22a30c0963..7fbf8a85c90a 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -515,6 +515,10 @@ DECLARE_STATIC_KEY_FALSE(force_irqthreads_key);
enum
{
HI_SOFTIRQ=0,
+/*
+ * IAMROOT, 2022.09.03:
+ * - softirq bottom half
+ */
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 5d85ffb15800..4810e7d317f1 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -108,16 +108,60 @@ static inline u64 get_jiffies_64(void)
* good compiler would generate better code (and a really good compiler
* wouldn't care). Gcc is currently neither.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - return true가 되는 상황.
+ *
+ * i) A, B둘다 값이 작을때.
+ *
+ * signed long
+ * B A |
+ * --------------|-----------
+ *
+ *
+ * ii) A, B둘다 값이 클때(signed long값 over가 안됬을때)
+ *
+ * signed long
+ * | B A
+ * --------------|-----------
+ *
+ * iii) A가 unsigned log값을 over flow
+ *
+ * signed long
+ * A | B
+ * --------------|-----------
+ */
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)((b) - (a)) < 0))
+
+/*
+ * IAMROOT, 2022.09.03:
+ * -
+ * A B
+ * time ----------->
+ * return true.
+ *
+ * - if (a < b)
+ * return true;
+ * return false;
+ */
#define time_before(a,b) time_after(b,a)
+/*
+ * IAMROOT, 2022.09.03:
+ * - a가 b시각 이후이거나 같으면 true.
+ */
#define time_after_eq(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)((a) - (b)) >= 0))
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - a가 b시각 이전이거나 같으면 true.
+ */
#define time_before_eq(a,b) time_after_eq(b,a)
/*
diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
index cc9f393e2a70..47f9167a04af 100644
--- a/include/linux/sched/isolation.h
+++ b/include/linux/sched/isolation.h
@@ -17,6 +17,11 @@ enum hk_flags {
HK_FLAG_KTHREAD = (1 << 8),
};
+/*
+ * IAMROOT, 2022.09.03:
+ * - ex) kernel param : nohz_full=4-7
+ * 4~7번 cpu를 nohz_full로 사용할수 있게 한다.
+ */
#ifdef CONFIG_CPU_ISOLATION
DECLARE_STATIC_KEY_FALSE(housekeeping_overridden);
extern int housekeeping_any_cpu(enum hk_flags flags);
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index f56d89e358c5..3f1e1ac65fb8 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -291,6 +291,10 @@ static inline void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock)
#endif
+/*
+ * IAMROOT, 2022.09.03:
+ * - irq disable후 spin lock수행.
+ */
#define raw_spin_lock_irq(lock) _raw_spin_lock_irq(lock)
#define raw_spin_lock_bh(lock) _raw_spin_lock_bh(lock)
#define raw_spin_unlock(lock) _raw_spin_unlock(lock)
diff --git a/include/linux/timer.h b/include/linux/timer.h
index fda13c9d1256..d25907404a50 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -16,6 +16,13 @@ struct timer_list {
struct hlist_node entry;
unsigned long expires;
void (*function)(struct timer_list *);
+/*
+ * IAMROOT, 2022.09.03:
+ * - TIMER_BASEMASK 참고.
+ * cpu id(TIMER_CPUMASK. 18bits)와 같이 field를 사용한다.
+ * ex)
+ * timer->flags = flags | raw_smp_processor_id();
+ */
u32 flags;
#ifdef CONFIG_LOCKDEP
@@ -61,6 +68,33 @@ struct timer_list {
* should be placed on a particular CPU, then add_timer_on() has to be
* used.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * @TIMER_DEFERRABLE: 지연 가능한 타이머는 시스템이 사용 중일 때 정상적으로
+ * 작동하지만 CPU를 서비스하기 위해 유휴 상태에서 벗어나게 하지는 않습니다.
+ * 대신, CPU가 나중에 지연되지 않는 타이머로 깨어날 때 타이머가 서비스됩니다.
+ *
+ * @TIMER_IRQSAFE: irqsafe 타이머는 IRQ가 비활성화된 상태에서 실행되며, 예를 들어
+ * del_timer_sync()를 호출하여 IRQ 처리기에서 실행 중인 인스턴스가 완료될 때까지
+ * 기다리는 것이 안전합니다.
+ *
+ * Note: irq 비활성화된 콜백 실행은 작업 대기열 잠금 문제의 특별한 경우입니다.
+ * 인터럽트가 비활성화된 상태에서 무작위 쓰레기를 실행하기 위한 것이 아닙니다.
+ * 학대가 모니터링됩니다!
+ *
+ * @TIMER_PINNED: 고정된 타이머는 타이머 배치 휴리스틱(예: NOHZ)의 영향을 받지
+ * 않으며 타이머가 대기열에 추가된 CPU에서 항상 만료됩니다.
+ *
+ * Note: 타이머를 대기열에 넣으면 한 CPU에서 다른 CPU로 타이머를 마이그레이션할
+ * 수 있으므로 고정된 타이머가 처음에 선택한 CPU에 유지된다는 보장은 없습니다.
+ * enqueue 기능이 mod_timer() 또는 add_timer()를 통해 호출되는 CPU로 이동합니다.
+ * 타이머를 특정 CPU에 배치해야 하는 경우 add_timer_on()을 사용해야 합니다.
+ *
+ * - field
+ * | 10bits | 4bits | 18bits |
+ * | timer idx | flags | cpu id |
+ */
#define TIMER_CPUMASK 0x0003FFFF
#define TIMER_MIGRATING 0x00040000
#define TIMER_BASEMASK (TIMER_CPUMASK | TIMER_MIGRATING)
@@ -73,6 +107,10 @@ struct timer_list {
#define TIMER_TRACE_FLAGMASK (TIMER_MIGRATING | TIMER_DEFERRABLE | TIMER_PINNED | TIMER_IRQSAFE)
+/*
+ * IAMROOT, 2022.09.03:
+ * - compile time시 timer 초기화.
+ */
#define __TIMER_INITIALIZER(_function, _flags) { \
.entry = { .next = TIMER_ENTRY_STATIC }, \
.function = (_function), \
@@ -81,6 +119,11 @@ struct timer_list {
__FILE__ ":" __stringify(__LINE__)) \
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - compile time시 timer 초기화.
+ * - runtime시는 timer_setup
+ */
#define DEFINE_TIMER(_name, _function) \
struct timer_list _name = \
__TIMER_INITIALIZER(_function, 0)
@@ -122,6 +165,10 @@ static inline void init_timer_on_stack_key(struct timer_list *timer,
#_timer, &__key); \
} while (0)
#else
+/*
+ * IAMROOT, 2022.09.03:
+ * - @_timer를 초기화한다.
+ */
#define __init_timer(_timer, _fn, _flags) \
init_timer_key((_timer), (_fn), (_flags), NULL, NULL)
#define __init_timer_on_stack(_timer, _fn, _flags) \
@@ -138,6 +185,11 @@ static inline void init_timer_on_stack_key(struct timer_list *timer,
* or timer_setup(). For timers on the stack, timer_setup_on_stack() must
* be used and must be balanced with a call to destroy_timer_on_stack().
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - runtime시 timer초기화.
+ * 실제 timer 등록은 add_timer를 수행해야한다.
+ */
#define timer_setup(timer, callback, flags) \
__init_timer((timer), (callback), (flags))
@@ -163,6 +215,13 @@ static inline void destroy_timer_on_stack(struct timer_list *timer) { }
*
* return value: 1 if the timer is pending, 0 if not.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * @return value 1 if the timer is pending, 0 if not.
+ * - @timer가 wheel에 등록이 되있는지 안되있는지 확인한다.
+ * - list의 pprev가 있다면 등록이 되있다는 의미.
+ * 없다면 expire가 됬거나 등록이 안 됬다는 의미.
+ */
static inline int timer_pending(const struct timer_list * timer)
{
return !hlist_unhashed_lockless(&timer->entry);
@@ -178,6 +237,10 @@ extern int timer_reduce(struct timer_list *timer, unsigned long expires);
* The jiffies value which is added to now, when there is no timer
* in the timer wheel:
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - 2^30 - 1
+ */
#define NEXT_TIMER_MAX_DELTA ((1UL << 30) - 1)
extern void add_timer(struct timer_list *timer);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index f21714ea3db8..6f176718435c 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1003,20 +1003,49 @@ void resched_cpu(int cpu)
* selecting an idle CPU will add more delays to the timers than intended
* (as that CPU's timer base may not be uptodate wrt jiffies etc).
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papgo
+ * semi idle 상태의 경우 유휴 CPU에서 타이머를 마이그레이션하기 위해 가장 가까운
+ * 사용 중인 CPU를 사용합니다. 절전에 좋습니다.
+ *
+ * 우리는 완전히 idle 상태인 시스템에 대해 유사한 최적화를 수행하지 않습니다.
+ * idle CPU를 선택하면 타이머에 의도한 것보다 더 많은 지연이 추가되기
+ * 때문입니다(해당 CPU의 타이머 기반이 wrt jiffies 등으로 업데이트되지 않을 수
+ * 있음).
+ *
+ * - busy cpu를 찾는다.
+ */
int get_nohz_timer_target(void)
{
int i, cpu = smp_processor_id(), default_cpu = -1;
struct sched_domain *sd;
const struct cpumask *hk_mask;
+/*
+ * IAMROOT, 2022.09.03:
+ * - housekeeping이 가능한 cpu인지 확인(동작해도 되는 cpu인지 확인)
+ */
if (housekeeping_cpu(cpu, HK_FLAG_TIMER)) {
+/*
+ * IAMROOT, 2022.09.03:
+ * - busy이면 return.
+ */
if (!idle_cpu(cpu))
return cpu;
+/*
+ * IAMROOT, 2022.09.03:
+ * - 현재 cpu가 idle이면 idle이 아닌것을 찾으러간다.
+ */
default_cpu = cpu;
}
hk_mask = housekeeping_cpumask(HK_FLAG_TIMER);
+/*
+ * IAMROOT, 2022.09.03:
+ * - 가장 가까운 domain. 인접한 cpu에서 busy cpu를 찾아온다.
+ */
rcu_read_lock();
for_each_domain(cpu, sd) {
for_each_cpu_and(i, sched_domain_span(sd), hk_mask) {
@@ -1030,6 +1059,11 @@ int get_nohz_timer_target(void)
}
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - idle이 아닌걸 못 찾고, 현재 cpu가 housekeeping이 아니였다면 hosekeeping중에
+ * any cpu로 고른다.
+ */
if (default_cpu == -1)
default_cpu = housekeeping_any_cpu(HK_FLAG_TIMER);
cpu = default_cpu;
@@ -1086,6 +1120,14 @@ static bool wake_up_full_nohz_cpu(int cpu)
* caller's responsibility to deal with the lost wakeup, for example,
* by hooking into the CPU_DEAD notifier like timers and hrtimers do.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 지정된 CPU를 깨우십시오. CPU가 오프라인 상태가 되면 호출자의 책임은 타이머
+ * 및 hrtimers와 같이 CPU_DEAD 알리미에 연결하는 것과 같이 손실된 웨이크업을
+ * 처리하는 것입니다.
+ * -
+ */
void wake_up_nohz_cpu(int cpu)
{
if (!wake_up_full_nohz_cpu(cpu))
@@ -6990,6 +7032,12 @@ int task_prio(const struct task_struct *p)
*
* Return: 1 if the CPU is currently idle. 0 otherwise.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * @return 1 idle
+ * 0 run
+ * - 현재 idle인지 아닌지 판별한다.
+ */
int idle_cpu(int cpu)
{
struct rq *rq = cpu_rq(cpu);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 3d3e5793e117..8c5291801ce8 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1736,6 +1736,10 @@ queue_balance_callback(struct rq *rq,
* The domain tree of any CPU may only be accessed from within
* preempt-disabled sections.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - tree 구조로 되있다. sched domain 위로 올라간다.
+ */
#define for_each_domain(cpu, __sd) \
for (__sd = rcu_dereference_check_sched_domain(cpu_rq(cpu)->sd); \
__sd; __sd = __sd->parent)
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 322b65d45676..a12dbf8ca8bd 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -683,6 +683,10 @@ inline void raise_softirq_irqoff(unsigned int nr)
wakeup_softirqd();
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - @nr번의 softirq 처리요청.
+ */
void raise_softirq(unsigned int nr)
{
unsigned long flags;
@@ -699,6 +703,10 @@ void __raise_softirq_irqoff(unsigned int nr)
or_softirq_pending(1UL << nr);
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - softirq @nr에 대한 @action함수를 등록한다.
+ */
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 643d412ac623..2d7dfe856c66 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -1153,6 +1153,11 @@ static inline bool fastpath_timer_check(struct task_struct *tsk)
static void handle_posix_cpu_timers(struct task_struct *tsk);
#ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - posix timer 초기화.(application timer)
+ */
static void posix_cpu_timers_work(struct callback_head *work)
{
handle_posix_cpu_timers(current);
@@ -1162,6 +1167,11 @@ static void posix_cpu_timers_work(struct callback_head *work)
* Initialize posix CPU timers task work in init task. Out of line to
* keep the callback static and to avoid header recursion hell.
*/
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - posix timer 초기화.(application timer)
+ */
void __init posix_cputimers_init_work(void)
{
init_task_work(¤t->posix_cputimers_work.work,
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 3a68f23b6786..142e2cbee7ab 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -157,6 +157,21 @@ EXPORT_SYMBOL(jiffies_64);
#define LVL_CLK_DIV (1UL << LVL_CLK_SHIFT)
#define LVL_CLK_MASK (LVL_CLK_DIV - 1)
#define LVL_SHIFT(n) ((n) * LVL_CLK_SHIFT)
+
+/*
+ * IAMROOT, 2022.09.03:
+ * ex) 1000hz 기준.
+ * n LVL_SHIFT(n) LVL_GRAN(n)
+ * 0 0 * 3 = 0 1 << 0 = 1
+ * 1 1 * 3 = 3 1 << 3 = 8
+ * 2 2 * 3 = 6 1 << 6 = 64
+ * 3 3 * 3 = 9 1 << 9 = 512
+ * 4 4 * 3 = 12 1 << 12 = 4096
+ * 5 5 * 3 = 15 1 << 15 = 32768
+ * 6 6 * 3 = 18 1 << 18 = 262144
+ * 7 7 * 3 = 21 1 << 21 = 2097152
+ * 8 8 * 3 = 24 1 << 24 = 16777216
+ */
#define LVL_GRAN(n) (1UL << LVL_SHIFT(n))
/*
@@ -164,6 +179,24 @@ EXPORT_SYMBOL(jiffies_64);
* time. We start from the last possible delta of the previous level
* so that we can later add an extra LVL_GRAN(n) to n (see calc_index()).
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 대기열에 넣을 때 버킷을 선택하기 위한 각 레벨의 시간 시작 값입니다. 이전
+ * 레벨의 마지막 가능한 델타에서 시작하여 나중에 LVL_GRAN(n)을 n에 추가할 수
+ * 있습니다(calc_index() 참조).
+ *
+ * n (((n) - 1) * LVL_CLK_SHIFT) LEVL_START(n)
+ * 1 0 0b111111 << 0
+ * 2 3 0b111111 << 3
+ * 3 6 0b111111 << 6
+ * 4 9 0b111111 << 9
+ * 5 12 0b111111 << 12
+ * 6 15 0b111111 << 15
+ * 7 18 0b111111 << 18
+ * 8 21 0b111111 << 21
+ *
+ */
#define LVL_START(n) ((LVL_SIZE - 1) << (((n) - 1) * LVL_CLK_SHIFT))
/* Size of each clock level */
@@ -187,11 +220,23 @@ EXPORT_SYMBOL(jiffies_64);
* The resulting wheel size. If NOHZ is configured we allocate two
* wheels so we have a separate storage for the deferrable timers.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - LVL_DEPTH == 9
+ * 2^6 * 9 = 576
+ *
+ * - LVL_DEPTH == 8
+ * 2^6 * 8 = 512
+ */
#define WHEEL_SIZE (LVL_SIZE * LVL_DEPTH)
#ifdef CONFIG_NO_HZ_COMMON
# define NR_BASES 2
# define BASE_STD 0
+/*
+ * IAMROOT, 2022.09.03:
+ * - NOHZ용 (deffered 가능한).
+ */
# define BASE_DEF 1
#else
# define NR_BASES 1
@@ -478,12 +523,19 @@ unsigned long round_jiffies_up_relative(unsigned long j)
}
EXPORT_SYMBOL_GPL(round_jiffies_up_relative);
-
+/*
+ * IAMROOT, 2022.09.03:
+ * - flags로부터 timer가 위치한 vector idx를 가져온다.
+ */
static inline unsigned int timer_get_idx(struct timer_list *timer)
{
return (timer->flags & TIMER_ARRAYMASK) >> TIMER_ARRAYSHIFT;
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - flags에 timer vector @idx를 set한다.
+ */
static inline void timer_set_idx(struct timer_list *timer, unsigned int idx)
{
timer->flags = (timer->flags & ~TIMER_ARRAYMASK) |
@@ -494,6 +546,71 @@ static inline void timer_set_idx(struct timer_list *timer, unsigned int idx)
* Helper function to calculate the array index for a given expiry
* time.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - Git blame
+ *
+ * timers: Use only bucket expiry for base->next_expiry value
+ *
+ * The bucket expiry time is the effective expriy time of timers and is
+ * greater than or equal to the requested timer expiry time. This is due
+ * to the guarantee that timers never expire early and the reduced expiry
+ * granularity in the secondary wheel levels.
+ *
+ * When a timer is enqueued, trigger_dyntick_cpu() checks whether the
+ * timer is the new first timer. This check compares next_expiry with
+ * the requested timer expiry value and not with the effective expiry
+ * value of the bucket into which the timer was queued.
+ *
+ * Storing the requested timer expiry value in base->next_expiry can lead
+ * to base->clk going backwards if the requested timer expiry value is
+ * smaller than base->clk. Commit 30c66fc30ee7 ("timer: Prevent base->clk
+ * from moving backward") worked around this by preventing the store when
+ * timer->expiry is before base->clk, but did not fix the underlying
+ * problem.
+ *
+ * Use the expiry value of the bucket into which the timer is queued to
+ * do the new first timer check. This fixes the base->clk going backward
+ * problem.
+ *
+ * The workaround of commit 30c66fc30ee7 ("timer: Prevent base->clk from
+ * moving backward") in trigger_dyntick_cpu() is not longer necessary as the
+ * timers bucket expiry is guaranteed to be greater than or equal base->clk.
+ *
+ * - papago
+ * timers: base->next_expiry 값에 대해 버킷 만료만 사용합니다.
+ *
+ * 버킷 만료 시간은 타이머의 유효 만료 시간이며 요청된 타이머 만료 시간보다
+ * 크거나 같습니다. 이는 타이머가 일찍 만료되지 않는다는 보장과 보조 휠 레벨의
+ * 만료 세분성 감소 때문입니다.
+ *
+ * 타이머가 대기열에 추가되면 trigger_dyntick_cpu()는 타이머가 새로운 첫 번째
+ * 타이머인지 확인합니다. 이 검사는 next_expiry를 요청된 타이머 만료 값과
+ * 비교하며 타이머가 대기열에 포함된 버킷의 유효 만료 값과 비교하지 않습니다.
+ *
+ * 요청된 타이머 만료 값을 base->next_expiry에 저장하면 요청된 타이머 만료 값이
+ * base->clk보다 작은 경우 base->clk가 뒤로 이동할 수 있습니다. 커밋
+ * 30c66fc30ee7("타이머: 기본->clk가 뒤로 이동하는 것을 방지")은 timer->expire가
+ * 기본->clk 이전일 때 저장소를 방지하여 이 문제를 해결했지만 근본적인 문제는
+ * 수정하지 않았습니다.
+ *
+ * 타이머가 대기 중인 버킷의 만료 값을 사용하여 새로운 첫 번째 타이머 확인을
+ * 수행합니다. 이것은 base->clk가 거꾸로 가는 문제를 수정합니다.
+ *
+ * trigger_dyntick_cpu()의 커밋 30c66fc30ee7("타이머: 기본->clk가 뒤로 이동하는
+ * 것을 방지")의 해결 방법은 타이머 버킷 만료가 base->clk보다 크거나 같도록
+ * 보장되므로 더 이상 필요하지 않습니다.
+ *
+ * @bucket_expiry LVL_GRAN(lvl) 단위로 올림.
+ * ex) exipres = 0x43dd, lvl = 2일때 return, bucket_expiry
+ * expires_new = (0x43dd + LVL_GRAN(2)) >> LVL_SHIFT(2)
+ * = (0x43dd + 0x40) >> 6 = 0x441d >> 6
+ * = 0x110
+ * bucket_expiry = 0x110 << 6
+ * = 0x4400 = 17408
+ * return = LVL_OFFS(2) + (0x110 & 0x3f)
+ * = 0x80 + 0x10 = 0x90
+ */
static inline unsigned calc_index(unsigned long expires, unsigned lvl,
unsigned long *bucket_expiry)
{
@@ -511,12 +628,30 @@ static inline unsigned calc_index(unsigned long expires, unsigned lvl,
return LVL_OFFS(lvl) + (expires & LVL_MASK);
}
+/*
+ * IAMROOT, 2022.09.03:
+ * @clk base->clk
+ * wheel idx를 구한다.
+ *
+ * ex) clk = 2, expires = 67
+ * delta = 65 -> calc_index(expires, 1, bucket_expiry) 호출
+ *
+ * expires_new = (67 + 8) >> 3 = 9
+ * bucket_expiry = 9 << 3 = 72
+ * return = 64 + (9 & 0x3f) = 73
+ *
+ * bucket_expiry = 72, idx = 73
+ */
static int calc_wheel_index(unsigned long expires, unsigned long clk,
unsigned long *bucket_expiry)
{
unsigned long delta = expires - clk;
unsigned int idx;
+/*
+ * IAMROOT, 2022.09.03:
+ * - delta가 들어갈 idx를 찾는다.
+ */
if (delta < LVL_START(1)) {
idx = calc_index(expires, 0, bucket_expiry);
} else if (delta < LVL_START(2)) {
@@ -532,11 +667,24 @@ static int calc_wheel_index(unsigned long expires, unsigned long clk,
} else if (delta < LVL_START(7)) {
idx = calc_index(expires, 6, bucket_expiry);
} else if (LVL_DEPTH > 8 && delta < LVL_START(8)) {
+/*
+ * IAMROOT, 2022.09.03:
+ * - LVL_DEPTH가 9가 존재하면 lvl 7까지.(0 ~ 7)
+ * LVL_DEPTH가 8까지라면 lvl 6까지만한다. (0 ~ 6)
+ */
idx = calc_index(expires, 7, bucket_expiry);
} else if ((long) delta < 0) {
+/*
+ * IAMROOT, 2022.09.03:
+ * - delta가 -면 lvl 0로 본다.
+ */
idx = clk & LVL_MASK;
*bucket_expiry = clk;
} else {
+/*
+ * IAMROOT, 2022.09.03:
+ * - delta가 너무 큰상황. 마지막 값으로 fixup 한후 idx를 재계산한다.
+ */
/*
* Force expire obscene large timeouts to expire at the
* capacity limit of the wheel.
@@ -549,6 +697,13 @@ static int calc_wheel_index(unsigned long expires, unsigned long clk,
return idx;
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - @base->cpu가 nohz로 동작중일때 깨운다.
+ * 1. 일반 timer인 경우 idle 상태면 깨운다.
+ * 2. defferable일경우 nohz full일 경우에만 깨운다.
+ * nohz idle 상태일경우엔 그냥 빠져올것이다.
+ */
static void
trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer)
{
@@ -559,6 +714,11 @@ trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer)
* TODO: This wants some optimizing similar to the code below, but we
* will do that when we switch from push to pull for deferrable timers.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - deffered로 등록한 timer인 경우 deffer를 하지만, cpu가 nohz full인 상태라면
+ * cpu를 wakeup.
+ */
if (timer->flags & TIMER_DEFERRABLE) {
if (tick_nohz_full_cpu(base->cpu))
wake_up_nohz_cpu(base->cpu);
@@ -570,6 +730,14 @@ trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer)
* timer is not deferrable. If the other CPU is on the way to idle
* then it can't set base->is_idle as we hold the base lock:
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * -papago
+ * 베이스가 idle 상태이고 타이머를 연기할 수 없는 경우 원격 CPU를 IPI해야 할 수도
+ * 있습니다. 다른 CPU가 유휴 상태가 되면 기본 잠금을 유지하므로 base->is_idle을
+ * 설정할 수 없습니다.
+ * - base->is_idle : base쪽 timer tick이 꺼져있다는뜻.
+ */
if (base->is_idle)
wake_up_nohz_cpu(base->cpu);
}
@@ -579,6 +747,11 @@ trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer)
* the bitmap, store the index in the timer flags then wake up
* the target CPU if needed.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - timer를 idx에 add한다. cpu가 idle인 상태인경우 next_expiry가
+ * 갱신되는 상황에서 필요에 따라 cpu를 깨운다.
+ */
static void enqueue_timer(struct timer_base *base, struct timer_list *timer,
unsigned int idx, unsigned long bucket_expiry)
{
@@ -594,6 +767,13 @@ static void enqueue_timer(struct timer_base *base, struct timer_list *timer,
* effective expiry time of the timer is required here
* (bucket_expiry) instead of timer->expires.
*/
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - bucket_expire가 timer_base보다 먼저라면 bucket_expiry로 갱신한다.
+ * - 기존에 있었던 next timer보다 새로 추가되는 timer의 bucket_expiry가
+ * 빠르면 bucket_expiry로 갱신하라는것이다.
+ */
if (time_before(bucket_expiry, base->next_expiry)) {
/*
* Set the next expiry time and kick the CPU so it
@@ -606,6 +786,10 @@ static void enqueue_timer(struct timer_base *base, struct timer_list *timer,
}
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - idx를 산출해서 enqueue 한다.
+ */
static void internal_add_timer(struct timer_base *base, struct timer_list *timer)
{
unsigned long bucket_expiry;
@@ -788,6 +972,10 @@ static inline void debug_assert_init(struct timer_list *timer)
debug_timer_assert_init(timer);
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - @timer를 초기화한다. 초기화시 함수를 실행한 cpu id를 flags에 기록한다.
+ */
static void do_init_timer(struct timer_list *timer,
void (*func)(struct timer_list *),
unsigned int flags,
@@ -813,6 +1001,10 @@ static void do_init_timer(struct timer_list *timer,
* init_timer_key() must be done to a timer prior calling *any* of the
* other timer functions.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - @timer를 초기화한다.
+ */
void init_timer_key(struct timer_list *timer,
void (*func)(struct timer_list *), unsigned int flags,
const char *name, struct lock_class_key *key)
@@ -822,6 +1014,10 @@ void init_timer_key(struct timer_list *timer,
}
EXPORT_SYMBOL(init_timer_key);
+/*
+ * IAMROOT, 2022.09.03:
+ * - 0timer를 detach 한다.
+ */
static inline void detach_timer(struct timer_list *timer, bool clear_pending)
{
struct hlist_node *entry = &timer->entry;
@@ -834,14 +1030,27 @@ static inline void detach_timer(struct timer_list *timer, bool clear_pending)
entry->next = LIST_POISON2;
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - @timer를 @base로부터 분리를 시도한다.
+ */
static int detach_if_pending(struct timer_list *timer, struct timer_base *base,
bool clear_pending)
{
unsigned idx = timer_get_idx(timer);
+/*
+ * IAMROOT, 2022.09.03:
+ * - 이미 분리 되있다. 아무것도 안한다.
+ */
if (!timer_pending(timer))
return 0;
+/*
+ * IAMROOT, 2022.09.03:
+ * - @idx vector에 timer가 1개만 등록되있다면. pending_map을 clear한다.
+ * 최종적으로 한개를 분리해내면 idx에서 아무것도 없어지기 때문이다.
+ */
if (hlist_is_singular_node(&timer->entry, base->vectors + idx)) {
__clear_bit(idx, base->pending_map);
base->next_expiry_recalc = true;
@@ -851,6 +1060,10 @@ static int detach_if_pending(struct timer_list *timer, struct timer_base *base,
return 1;
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - @cpu에 해당하는 timer_base를 가져온다.
+ */
static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu)
{
struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_STD], cpu);
@@ -859,11 +1072,19 @@ static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu)
* If the timer is deferrable and NO_HZ_COMMON is set then we need
* to use the deferrable base.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - nohz enable이면서 deffered로 등록한 timer라면 nohz용 timer_base를 가져온다.
+ */
if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && (tflags & TIMER_DEFERRABLE))
base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu);
return base;
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - 현재 cpu의 timer base를 가져온다.
+ */
static inline struct timer_base *get_timer_this_cpu_base(u32 tflags)
{
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
@@ -877,22 +1098,49 @@ static inline struct timer_base *get_timer_this_cpu_base(u32 tflags)
return base;
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - @tflags의 cpu로 timer_base를 가져온다.
+ */
static inline struct timer_base *get_timer_base(u32 tflags)
{
return get_timer_cpu_base(tflags, tflags & TIMER_CPUMASK);
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - 1. busy cpu에서 timer base 얻어오기.
+ * 2. 현재 cpu로 timer base 얻어오기.
+ */
static inline struct timer_base *
get_target_base(struct timer_base *base, unsigned tflags)
{
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
+/*
+ * IAMROOT, 2022.09.03:
+ * - migration이 가능하고, pinned를 해야된다는 flag가 없다면 busy cpu에서
+ * timer_base를 가져온다.
+ *
+ */
if (static_branch_likely(&timers_migration_enabled) &&
!(tflags & TIMER_PINNED))
return get_timer_cpu_base(tflags, get_nohz_timer_target());
#endif
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - pinned요청이거나, migration을 못한다면 현재 cpu의 timer_base를 가져온다.
+ */
return get_timer_this_cpu_base(tflags);
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - @base를 현재 시간 기준으로 udpate한다.
+ *
+ * - 기본적으로 @base->clk을 현재 시간으로 update를 한다.
+ * 만약 next_expiry가 현재 과거(ex. nohz)라면 base->clk으로 update한다.
+ */
static inline void forward_timer_base(struct timer_base *base)
{
unsigned long jnow = READ_ONCE(jiffies);
@@ -902,6 +1150,10 @@ static inline void forward_timer_base(struct timer_base *base)
* Also while executing timers, base->clk is 1 offset ahead
* of jiffies to avoid endless requeuing to current jiffies.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - 이미 timer start 시간이 지낫으면 return.
+ */
if ((long)(jnow - base->clk) < 1)
return;
@@ -909,11 +1161,47 @@ static inline void forward_timer_base(struct timer_base *base)
* If the next expiry value is > jiffies, then we fast forward to
* jiffies otherwise we forward to the next expiry value.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - next_expiry가 현재시간 이후라면 현재시간을 base->clk에 등록.
+ * 그게 아니면 clk를 next_expiry로 등록.
+ */
if (time_after(base->next_expiry, jnow)) {
+/*
+ * IAMROOT, 2022.09.03:
+ * - 매 tick마다 갱신된다.(normal case)
+ * now
+ * -----------------|-----------|-------
+ * | next
+ * update base->clk
+ */
base->clk = jnow;
} else {
+/*
+ * IAMROOT, 2022.09.03:
+ * - error 처리.
+ * - timer가 이미 지낫으면 return.
+ * - next_expiry가 base->clk이전 warn후 return.
+ * now
+ * |
+ * ---------|-------|--------|----------
+ * next base->clk
+ */
if (WARN_ON_ONCE(time_before(base->next_expiry, base->clk)))
return;
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - nohz로 인해서 발생하는 상황.
+ * - base->clk <--> now사이에 sleep timer가 tick이 들어오지 않아서
+ * 갱신이 안됬을때.
+ * now
+ * |
+ * --------|------------|---------|---
+ * base->clk next
+ * |
+ * update base->clk
+ */
base->clk = base->next_expiry;
}
}
@@ -930,6 +1218,10 @@ static inline void forward_timer_base(struct timer_base *base)
* When a timer is migrating then the TIMER_MIGRATING flag is set and we need
* to wait until the migration is done.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - @flags에 등록된 cpu의 timer base를 가져온다.
+ */
static struct timer_base *lock_timer_base(struct timer_list *timer,
unsigned long *flags)
__acquires(timer->base->lock)
@@ -945,8 +1237,23 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
*/
tf = READ_ONCE(timer->flags);
+/*
+ * IAMROOT, 2022.09.03:
+ * - migrating 자체가 매우빠르기 때문에 for문으로 migrating이
+ * 풀릴때까지 적당히 기다린다.
+ * - migrating이 끝나면 기본적으로 cpu가 바뀐다.
+ */
if (!(tf & TIMER_MIGRATING)) {
+/*
+ * IAMROOT, 2022.09.03:
+ * - @timer의 flag(tf)에 timer를 생성한 cpu nr이 등록되있어, 해당
+ * cpu의 timer_base를 가져온다.
+ */
base = get_timer_base(tf);
+/*
+ * IAMROOT, 2022.09.03:
+ * - tf가 같지 않으면 경쟁상황. loop를 계속돈다.
+ */
raw_spin_lock_irqsave(&base->lock, *flags);
if (timer->flags == tf)
return base;
@@ -960,6 +1267,10 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
#define MOD_TIMER_REDUCE 0x02
#define MOD_TIMER_NOTPENDING 0x04
+/*
+ * IAMROOT, 2022.09.03:
+ * - timer를 추가하거나 expired를 변경한다.
+ */
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires, unsigned int options)
{
@@ -975,16 +1286,45 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
* the timer is re-modified to have the same timeout or ends up in the
* same array bucket then just return:
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 이것은 네트워킹 코드에 의해 트리거되는 일반적인 최적화입니다. 타이머가 동일한
+ * 시간 초과를 갖도록 다시 수정되거나 동일한 어레이 버킷에서 끝나는 경우 다음을
+ * 반환합니다.
+ * - pending중인 timer이면서 option이
+ * MOD_TIMER_PENDING_ONLY (mod_timer_pending())
+ * MOD_TIMER_REDUCE (timer_reduce()),
+ * 0 (mod_timer())
+ * 경우 if문 동작.
+ *
+ * - 즉 add_timer()가 아닌 경우
+ */
if (!(options & MOD_TIMER_NOTPENDING) && timer_pending(timer)) {
/*
* The downside of this optimization is that it can result in
* larger granularity than you would get from adding a new
* timer with this expiry.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 이 최적화의 단점은 이 만료로 새 타이머를 추가하는 것보다 더 큰 세분성을
+ * 초래할 수 있다는 것입니다.
+ */
long diff = timer->expires - expires;
+/*
+ * IAMROOT, 2022.09.03:
+ * - 갱신하는 expires시간이 기존과 같다면 아무것도 할필요없을것이다.
+ */
if (!diff)
return 1;
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - reduce일때 expire 시간을 더 증가시키는 경우는 무시한다.
+ */
if (options & MOD_TIMER_REDUCE && diff <= 0)
return 1;
@@ -994,9 +1334,22 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
* just update the expiry time and avoid the whole
* dequeue/enqueue dance.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 여기에서 타이머 베이스를 잠그고 버킷 인덱스를 계산합니다. 타이머가
+ * 동일한 버킷에서 끝나면 만료 시간을 업데이트하고 전체 대기열에서
+ * 빼기/대기하기 댄스를 방지합니다.
+ *
+ * - lock을 건다.
+ */
base = lock_timer_base(timer, &flags);
forward_timer_base(base);
+/*
+ * IAMROOT, 2022.09.03:
+ * - reduce일때, @expires값이 기존보다 감소되지 않았으면 무시.
+ */
if (timer_pending(timer) && (options & MOD_TIMER_REDUCE) &&
time_before_eq(timer->expires, expires)) {
ret = 1;
@@ -1011,6 +1364,14 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
* timer. If it matches set the expiry to the new value so a
* subsequent call will exit in the expires check above.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 보류 중인 타이머의 배열 인덱스를 검색하고 비교합니다. 일치하는 경우 만료를
+ * 새 값으로 설정하여 위의 만료 확인에서 후속 호출이 종료되도록 합니다.
+ * - idx가 변한게 없는경우, expires만 재갱신한다.
+ * reduce인 경우 전진만 허용한다.
+ */
if (idx == timer_get_idx(timer)) {
if (!(options & MOD_TIMER_REDUCE))
timer->expires = expires;
@@ -1020,16 +1381,34 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
goto out_unlock;
}
} else {
+/*
+ * IAMROOT, 2022.09.03:
+ * - @timer의 cpu에 해당하는 timer base를 가져오고 update한다.
+ */
base = lock_timer_base(timer, &flags);
forward_timer_base(base);
}
ret = detach_if_pending(timer, base, false);
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - mod_timer_pending()으로 pending중인 timer에 한해서 수정 요청이 왔는데
+ * 이미 timer가 없는 상황. 종료한다.
+ */
if (!ret && (options & MOD_TIMER_PENDING_ONLY))
goto out_unlock;
new_base = get_target_base(base, timer->flags);
+/*
+ * IAMROOT, 2022.09.03:
+ * - timer에서 사용하는 cpu와 변경되었는지 확인한다.
+ * - ex) cpu0에서 timer0를 add_timer했다고 가정.
+ * cpu0 -> add_timer(). timer0가 cpu0번으로 등록
+ * cpu1 -> mod_timer(timer0).
+ * 이런 상황일 경우 base != new_base가 된다.
+ */
if (base != new_base) {
/*
* We are trying to schedule the timer on the new base.
@@ -1038,6 +1417,18 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
* handler yet has not finished. This also guarantees that the
* timer is serialized wrt itself.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * new base에서 타이머를 예약하려고 합니다.,
+ * 그러나 타이머가 실행되는 동안에는 타이머의 기반을 변경할 수 없습니다.
+ * 그렇지 않으면 del_timer_sync()가 타이머의 핸들러가 아직 완료되지 않았음을
+ * 감지할 수 없습니다. 이것은 또한 타이머가 자체적으로 직렬화됨을 보장합니다.
+ *
+ * - running_timer : expired 되서 동작중인 timer.
+ * - running_timer와 현재 timer가 다를경우, 즉 동작중인 timer가 아닐경우.
+ * new_base로 base를 갱신하고 timer의 cpu를 갱신된 new_base로 고친후 update.
+ */
if (likely(base->running_timer != timer)) {
/* See the comment in lock_timer_base() */
timer->flags |= TIMER_MIGRATING;
@@ -1060,6 +1451,16 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
* enqueue_timer() is required. Otherwise we need to (re)calculate
* the wheel index via internal_add_timer().
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 'idx'가 위에서 계산되었고 기본 시간이 'idx' 계산과 기본 전환 사이에 진행되지
+ * 않은 경우 enqueue_timer()만 필요합니다. 그렇지 않으면 internal_add_timer()를
+ * 통해 휠 인덱스를 (재)계산해야 합니다.
+ *
+ * - 기존 timer가 존재하여 이미 idx를 알아온 경우 즉시. enqueue.
+ * 새로 들어온 timer인 경우 idx가 없으므로 idx를 새로 산출해서 enqueue한다.
+ */
if (idx != UINT_MAX && clk == base->clk)
enqueue_timer(base, timer, idx, bucket_expiry);
else
@@ -1081,6 +1482,10 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
*
* It is useful for unserialized use of timers.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - timer가 pending중일때, expires를 변경한다.
+ */
int mod_timer_pending(struct timer_list *timer, unsigned long expires)
{
return __mod_timer(timer, expires, MOD_TIMER_PENDING_ONLY);
@@ -1107,6 +1512,25 @@ EXPORT_SYMBOL(mod_timer_pending);
* (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
* active timer returns 1.)
*/
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * mod_timer()는 활성 타이머의 만료 필드를 업데이트하는 더 효율적인
+ * 방법입니다(타이머가 비활성화된 경우 활성화됨)
+ *
+ * mod_timer(timer, expires)는 다음과 같습니다.
+ *
+ * del_timer(timer); timer->expires = expires; add_timer(timer);
+ *
+ * 동일한 타이머의 직렬화되지 않은 동시 사용자가 여러 명 있는 경우
+ * add_timer()가 이미 실행 중인 타이머를 수정할 수 없으므로
+ * mod_timer()가 시간 초과를 수정하는 유일한 안전한 방법입니다.
+ *
+ * 함수는 보류 중인 타이머를 수정했는지 여부를 반환합니다.
+ * (즉, 비활성 타이머의 mod_timer()는 0을 반환하고 활성 타이머의
+ * mod_timer()는 1을 반환합니다.)
+ */
int mod_timer(struct timer_list *timer, unsigned long expires)
{
return __mod_timer(timer, expires, 0);
@@ -1122,6 +1546,10 @@ EXPORT_SYMBOL(mod_timer);
* modify a running timer if that would reduce the expiration time (it will
* start a timer that isn't running).
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - timer가 pending중일때, expired를 줄인다.
+ */
int timer_reduce(struct timer_list *timer, unsigned long expires)
{
return __mod_timer(timer, expires, MOD_TIMER_REDUCE);
@@ -1142,6 +1570,10 @@ EXPORT_SYMBOL(timer_reduce);
* Timers with an ->expires field in the past will be executed in the next
* timer tick.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - @timer 등록.
+ */
void add_timer(struct timer_list *timer)
{
BUG_ON(timer_pending(timer));
@@ -1199,6 +1631,10 @@ EXPORT_SYMBOL_GPL(add_timer_on);
* (ie. del_timer() of an inactive timer returns 0, del_timer() of an
* active timer returns 1.)
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - @timer가 pending중이라면 detach.
+ */
int del_timer(struct timer_list *timer)
{
struct timer_base *base;
@@ -1224,6 +1660,12 @@ EXPORT_SYMBOL(del_timer);
* This function tries to deactivate a timer. Upon successful (ret >= 0)
* exit the timer is not queued and the handler is not running on any CPU.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * @return -1. running중인 timer라면 삭제를 못한다는것.
+ * 1. 삭제 성공.
+ * 0. 이미 expire되서 없다.
+ */
int try_to_del_timer_sync(struct timer_list *timer)
{
struct timer_base *base;
@@ -1244,16 +1686,30 @@ int try_to_del_timer_sync(struct timer_list *timer)
EXPORT_SYMBOL(try_to_del_timer_sync);
#ifdef CONFIG_PREEMPT_RT
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - spinlock을 사용한다.
+ */
static __init void timer_base_init_expiry_lock(struct timer_base *base)
{
spin_lock_init(&base->expiry_lock);
}
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - spin_lock
+ */
static inline void timer_base_lock_expiry(struct timer_base *base)
{
spin_lock(&base->expiry_lock);
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - spin_unlock
+ */
static inline void timer_base_unlock_expiry(struct timer_base *base)
{
spin_unlock(&base->expiry_lock);
@@ -1266,10 +1722,26 @@ static inline void timer_base_unlock_expiry(struct timer_base *base)
* timer callback to finish. Drop expiry_lock and reacquire it. That allows
* the waiter to acquire the lock and make progress.
*/
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * del_timer_wait_running()의 대응물.
+ *
+ * base->expiry_lock에 대한 웨이터가 있는 경우 타이머 콜백이 완료되기를 기다리고
+ * 있는 것입니다. expiry_lock을 삭제하고 다시 획득하십시오. 그러면 웨이터가
+ * 잠금을 획득하고 진행할 수 있습니다.
+ * -
+ */
static void timer_sync_wait_running(struct timer_base *base)
{
if (atomic_read(&base->timer_waiters)) {
raw_spin_unlock_irq(&base->lock);
+/*
+ * IAMROOT, 2022.09.03:
+ * - del_timer_wait_running()에서 del wait를 하고 있는경우 deadlock풀어서
+ * callback이 끝난걸 알려 delete가 가능하게 풀어준다.
+ */
spin_unlock(&base->expiry_lock);
spin_lock(&base->expiry_lock);
raw_spin_lock_irq(&base->lock);
@@ -1286,6 +1758,18 @@ static void timer_sync_wait_running(struct timer_base *base)
* delete a timer preempted the softirq thread running the timer callback
* function.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 이 함수는 타이머 콜백 함수가 실행 중이기 때문에 타이머의 빠른 경로 삭제가
+ * 실패한 경우 PREEMPT_RT 커널에서 호출됩니다.
+ *
+ * 이것은 원격 CPU의 softirq 스레드가 선점된 경우 우선 순위 반전을 방지하고
+ * 타이머를 삭제하려는 작업이 타이머 콜백 기능을 실행하는 softirq 스레드를
+ * 선점할 때 생명 잠금을 방지합니다.
+ * - timer가 irqsafe가 아니라면 timer_waiters에 등록하고 deadlock을 걸어
+ * callback이 끝날떄까지 기다린다.
+ */
static void del_timer_wait_running(struct timer_list *timer)
{
u32 tf;
@@ -1303,6 +1787,11 @@ static void del_timer_wait_running(struct timer_list *timer)
* causes another wait loop.
*/
atomic_inc(&base->timer_waiters);
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - timer_sync_wait_running()의 spin_unlock을 deadlock을 걸어 기다린다.
+ */
spin_lock_bh(&base->expiry_lock);
atomic_dec(&base->timer_waiters);
spin_unlock_bh(&base->expiry_lock);
@@ -1353,6 +1842,13 @@ static inline void del_timer_wait_running(struct timer_list *timer) { }
*
* The function returns whether it has deactivated a pending timer or not.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - @timer를 삭제한다.
+ * 1. pending중인 경우. 삭제후 return 0.
+ * 2. expire된 경우 별거 안하고 return 1.
+ * 3. running중인 경우 deadlock을 걸어 callback이 끝날때까지 wait.
+ */
int del_timer_sync(struct timer_list *timer)
{
int ret;
@@ -1385,6 +1881,12 @@ int del_timer_sync(struct timer_list *timer)
do {
ret = try_to_del_timer_sync(timer);
+/*
+ * IAMROOT, 2022.09.03:
+ * - running중인 timer를 삭제하라는 요청이 왔다.
+ * irqsave가 없는 timer인 경우 callback이 완료 될때까지
+ * deadlock으로 기다리고, 그렇지 않을 경우 cpu_relax를 한번한후 while.
+ */
if (unlikely(ret < 0)) {
del_timer_wait_running(timer);
cpu_relax();
@@ -1396,6 +1898,10 @@ int del_timer_sync(struct timer_list *timer)
EXPORT_SYMBOL(del_timer_sync);
#endif
+/*
+ * IAMROOT, 2022.09.03:
+ * - @fn callback 수행.
+ */
static void call_timer_fn(struct timer_list *timer,
void (*fn)(struct timer_list *),
unsigned long baseclk)
@@ -1427,6 +1933,11 @@ static void call_timer_fn(struct timer_list *timer,
lock_map_release(&lockdep_map);
+/*
+ * IAMROOT, 2022.09.03:
+ * - @fn 안에서 preempt_enable/disable을 증감 하면 count가 증감하게된다.
+ * 이러면안된다.
+ */
if (count != preempt_count()) {
WARN_ONCE(1, "timer: %pS preempt leak: %08x -> %08x\n",
fn, count, preempt_count());
@@ -1436,10 +1947,21 @@ static void call_timer_fn(struct timer_list *timer,
* callback kept a lock held, bad luck, but not worse
* than the BUG() we had.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 선점 횟수를 복원합니다. 그것은 우리에게 생존하고 정보를 추출할 적절한 기회를
+ * 제공합니다. 콜백이 잠금을 유지했다면 운이 나빴지만 BUG()보다 나쁘지는
+ * 않았습니다.
+ */
preempt_count_set(count);
}
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - @head에 있는 timer에 등록된 callback function을 호출한다.
+ */
static void expire_timers(struct timer_base *base, struct hlist_head *head)
{
/*
@@ -1447,12 +1969,24 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head)
* incremented directly before expire_timers was called. But expiry
* is related to the old base->clk value.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - papago
+ * 이 값은 추적에만 필요합니다. base->clk는 expire_timers가 호출되기 직전에
+ * 증분되었습니다. 그러나 만료는 이전 base->clk 값과 관련이 있습니다.
+ */
unsigned long baseclk = base->clk - 1;
while (!hlist_empty(head)) {
struct timer_list *timer;
void (*fn)(struct timer_list *);
+/*
+ * IAMROOT, 2022.09.03:
+ * - 1. timer를 한개빼고
+ * 2. running에 넣은후
+ * 3. callback 함수 호출.
+ */
timer = hlist_entry(head->first, struct timer_list, entry);
base->running_timer = timer;
@@ -1460,12 +1994,21 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head)
fn = timer->function;
+/*
+ * IAMROOT, 2022.09.03:
+ * - timer가 irq safe라는 일반 spinlock, 그렇지 않은 경우 irq spinlock수행.
+ * - irq에 영향이 없는 timer인경우.
+ */
if (timer->flags & TIMER_IRQSAFE) {
raw_spin_unlock(&base->lock);
call_timer_fn(timer, fn, baseclk);
raw_spin_lock(&base->lock);
base->running_timer = NULL;
} else {
+/*
+ * IAMROOT, 2022.09.03:
+ * - irq에 영향이 있는경우,
+ */
raw_spin_unlock_irq(&base->lock);
call_timer_fn(timer, fn, baseclk);
raw_spin_lock_irq(&base->lock);
@@ -1475,6 +2018,11 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head)
}
}
+/*
+ * IAMROOT, 2022.09.03:
+ * lvl 0..LVL_DEPTH 까지 순회하며 expired된 timer들을 heads에 옮기며 가장 높은
+ * level을 기록한다.
+ */
static int collect_expired_timers(struct timer_base *base,
struct hlist_head *heads)
{
@@ -1483,6 +2031,17 @@ static int collect_expired_timers(struct timer_base *base,
int i, levels = 0;
unsigned int idx;
+/*
+ * IAMROOT, 2022.09.03:
+ *
+ * lvl 0..LVL_DEPTH 까지 순회하며 expired된 timer들을 heads에 옮기며 가져온
+ * 레벨 개수를 return 한다.
+ *
+ * level 0 -> timer0, timer1, timer2 -> heads[0]에 통째로 넣어진다.
+ * level 1 -> timer3, timer4, -> heads[1]에 통째로 넣어진다.
+ * level 2 -> NULL -> 여기서 중단되고 return level2
+ * level 3 -> timer5.
+ */
for (i = 0; i < LVL_DEPTH; i++) {
idx = (clk & LVL_MASK) + i * LVL_SIZE;
@@ -1492,6 +2051,11 @@ static int collect_expired_timers(struct timer_base *base,
levels++;
}
/* Is it time to look at the next level? */
+
+/*
+ * IAMROOT, 2022.09.03:
+ * - 중간이 비면 그만한다.
+ */
if (clk & LVL_CLK_MASK)
break;
/* Shift clock for the next level granularity */
@@ -1523,6 +2087,10 @@ static int next_pending_bucket(struct timer_base *base, unsigned offset,
* Search the first expiring timer in the various clock levels. Caller must
* hold base->lock.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - TODO
+ */
static unsigned long __next_timer_interrupt(struct timer_base *base)
{
unsigned long clk, next, adj;
@@ -1711,17 +2279,34 @@ void timer_clear_idle(void)
* __run_timers - run all expired timers (if any) on this CPU.
* @base: the timer vector to be processed.
*/
+
+/*
+ * IAMROOT, 2022.09.03:
+ * -
+ */
static inline void __run_timers(struct timer_base *base)
{
struct hlist_head heads[LVL_DEPTH];
int levels;
+/*
+ * IAMROOT, 2022.09.03:
+ * - 만료시각이 아직 안됬다. return.
+ */
if (time_before(jiffies, base->next_expiry))
return;
timer_base_lock_expiry(base);
raw_spin_lock_irq(&base->lock);
+/*
+ * IAMROOT, 2022.09.03:
+ *
+ * time ---------|--------------|-------------------------|--------
+ * base->clk base->next_expiry jiffies
+ * ---------------------------------------->
+ * 이 사이에 있는 timer들을 expire 시킨다.
+ */
while (time_after_eq(jiffies, base->clk) &&
time_after_eq(jiffies, base->next_expiry)) {
levels = collect_expired_timers(base, heads);
@@ -1734,6 +2319,10 @@ static inline void __run_timers(struct timer_base *base)
base->clk++;
base->next_expiry = __next_timer_interrupt(base);
+/*
+ * IAMROOT, 2022.09.03:
+ * - 가져온 timer들을 역순으로 expire 시킨다.
+ */
while (levels--)
expire_timers(base, heads + levels);
}
@@ -1744,6 +2333,10 @@ static inline void __run_timers(struct timer_base *base)
/*
* This function runs timers and the timer-tq in bottom half context.
*/
+/*
+ * IAMROOT, 2022.09.03:
+ * - TIMER_SOFTIRQ 발생시 동작하는 함수.
+ */
static __latent_entropy void run_timer_softirq(struct softirq_action *h)
{
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
@@ -1998,6 +2591,10 @@ int timers_dead_cpu(unsigned int cpu)
#endif /* CONFIG_HOTPLUG_CPU */
+/*
+ * IAMROOT, 2022.09.03:
+ * - @cpu의 lowres timer 자료구조를 초기화한다.
+ */
static void __init init_timer_cpu(int cpu)
{
struct timer_base *base;
@@ -2007,12 +2604,20 @@ static void __init init_timer_cpu(int cpu)
base = per_cpu_ptr(&timer_bases[i], cpu);
base->cpu = cpu;
raw_spin_lock_init(&base->lock);
+/*
+ * IAMROOT, 2022.09.03:
+ * - 현재 clock을 저장해놓는다.
+ */
base->clk = jiffies;
base->next_expiry = base->clk + NEXT_TIMER_MAX_DELTA;
timer_base_init_expiry_lock(base);
}
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - 전체 cpu의 lowres timer 자료구조를 초기화한다.
+ */
static void __init init_timer_cpus(void)
{
int cpu;
@@ -2021,6 +2626,13 @@ static void __init init_timer_cpus(void)
init_timer_cpu(cpu);
}
+/*
+ * IAMROOT, 2022.09.03:
+ * - 1. 전체 cpu lowres timer 자료구조 초기화.
+ * 2. posix timer 초기화.
+ * 3. TIMER_SOFTIRQ callback 함수 등록.
+ * (raise_softirq)
+ */
void __init init_timers(void)
{
init_timer_cpus();
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 629 |
248 | [커널 19차] 103 주차 | Min | 2024.04.28 | 23 |
247 | [커널 20차] 48주차 | 무한질주 | 2024.04.25 | 32 |
246 | [커널 19차] 102 주차 | Min | 2024.04.20 | 43 |
245 | [커널 19차] 101 주차 | Min | 2024.04.13 | 64 |
244 | [커널 19차] 100 주차 | Min | 2024.04.13 | 18 |
243 | [커널 19차] 99 주차 | Min | 2024.03.30 | 82 |
242 | [커널 19차] 98 주차 | Min | 2024.03.23 | 57 |
241 | [커널 19차] 97 주차 | Min | 2024.03.16 | 50 |
240 | [커널 19차] 96 주차 | Min | 2024.03.14 | 32 |
239 | [커널 19차] 95 주차 [2] | Min | 2024.03.03 | 111 |
238 | [커널 20차] 32주차 | brw | 2023.12.16 | 388 |
237 | [커널 20차] 29주차 | brw | 2023.11.27 | 163 |
236 | [커널 20차] 27주차 | brw | 2023.11.21 | 86 |
235 | [커널 20차] 26주차 | brw | 2023.11.21 | 49 |
234 | [커널 20차] 28주차 | 이민찬 | 2023.11.19 | 65 |
233 | [커널 20차] 25주차 | 이민찬 | 2023.10.30 | 120 |
232 | [커널 20차] 24주차 | 이민찬 | 2023.10.22 | 793 |
231 | [커널 20차] 23주차 | 이민찬 | 2023.10.14 | 81 |
230 | [커널 20차] 22주차 | 이민찬 | 2023.10.08 | 76 |
229 | [커널 20차] 21주차 | 이민찬 | 2023.09.23 | 116 |
.