This is a good chance to look into timer mechanism ofkernel timer.
/** * alarmtimer_fired - Handles alarm hrtimer being fired. * @timer: pointer to hrtimer being run * * When a alarm timer fires, this runs through the timerqueue to * see which alarms expired, and runs those. If there are more alarm * timers queued for the future, we set the hrtimer to fire when * when the next future alarm timer expires. */ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) { struct alarm_base *base = container_of(timer, struct alarm_base, timer); struct timerqueue_node *next; unsigned long flags; ktime_t now; int ret = HRTIMER_NORESTART; int restart = ALARMTIMER_NORESTART; spin_lock_irqsave(&base->lock, flags); now = base->gettime(); while ((next = timerqueue_getnext(&base->timerqueue))) { struct alarm *alarm; ktime_t expired = next->expires; if (expired.tv64 > now.tv64) break; alarm = container_of(next, struct alarm, node); timerqueue_del(&base->timerqueue, &alarm->node); alarm->state &= ~ALARMTIMER_STATE_ENQUEUED; alarm->state |= ALARMTIMER_STATE_CALLBACK; spin_unlock_irqrestore(&base->lock, flags); if (alarm->function) restart = alarm->function(alarm, now); spin_lock_irqsave(&base->lock, flags); alarm->state &= ~ALARMTIMER_STATE_CALLBACK; if (restart != ALARMTIMER_NORESTART) { timerqueue_add(&base->timerqueue, &alarm->node); alarm->state |= ALARMTIMER_STATE_ENQUEUED; } } if (next) { hrtimer_set_expires(&base->timer, next->expires); ret = HRTIMER_RESTART; } spin_unlock_irqrestore(&base->lock, flags); return ret; }. |
This is a good chance to look into timer mechanism ofkernel timer.
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rv = 0; unsigned long flags; <snip> case ANDROID_ALARM_SET_OLD: case ANDROID_ALARM_SET_AND_WAIT_OLD: if (get_user(new_alarm_time.tv_sec, (int __user *)arg)) { rv = -EFAULT; goto err1; } new_alarm_time.tv_nsec = 0; goto from_old_alarm_set; case ANDROID_ALARM_SET_AND_WAIT(0): case ANDROID_ALARM_SET(0): if (copy_from_user(&new_alarm_time, (void __user *)arg, sizeof(new_alarm_time))) { rv = -EFAULT; goto err1; } from_old_alarm_set: spin_lock_irqsave(&alarm_slock, flags); pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type, new_alarm_time.tv_sec, new_alarm_time.tv_nsec); alarm_enabled |= alarm_type_mask; devalarm_start(&alarms[alarm_type], timespec_to_ktime(new_alarm_time)); spin_unlock_irqrestore(&alarm_slock, flags); if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0) && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD) break; /* fall though */ case ANDROID_ALARM_WAIT: |
static const struct file_operations alarm_fops = { .owner = THIS_MODULE, .unlocked_ioctl = alarm_ioctl, .open = alarm_open, .release = alarm_release, }; |
This driver is accessible thru “/dev/alarm”.
static struct miscdevice alarm_device = { .minor = MISC_DYNAMIC_MINOR, .name = "alarm", .fops = &alarm_fops, }; |
[ 1248.598756 04-23 15:18:45.380] [<c00bccd4>] (alarmtimer_fired+0x144/0x15c) from [<c00970ac>] (__run_hrtimer+0x98/0x304) [ 1248.609786 04-23 15:18:45.380] [<c00970ac>] (__run_hrtimer+0x98/0x304) from [<c0097fb0>] (hrtimer_interrupt+0x134/0x2f0) [ 1248.620908 04-23 15:18:45.380] [<c0097fb0>] (hrtimer_interrupt+0x134/0x2f0) from [<c0028e84>] (tegra_cputimer_interrupt+0x4c/0x54) [ 1248.632924 04-23 15:18:45.380] [<c0028e84>] (tegra_cputimer_interrupt+0x4c/0x54) from [<c00e9450>] (handle_irq_event_percpu+0x78/0x2d8) [ 1248.645365 04-23 15:18:45.380] [<c00e9450>] (handle_irq_event_percpu+0x78/0x2d8) from [<c00e96f4>] (handle_irq_event+0x44/0x64) [ 1248.657087 04-23 15:18:45.380] [<c00e96f4>] (handle_irq_event+0x44/0x64) from [<c00ec480>] (handle_fasteoi_irq+0xc4/0x16c) [ 1248.668375 04-23 15:18:45.380] [<c00ec480>] (handle_fasteoi_irq+0xc4/0x16c) from [<c00e8c6c>] (generic_handle_irq+0x30/0x44) [ 1248.679844 04-23 15:18:45.380] [<c00e8c6c>] (generic_handle_irq+0x30/0x44) from [<c000f074>] (handle_IRQ+0x54/0xb4) [ 1248.690514 04-23 15:18:45.380] [<c000f074>] (handle_IRQ+0x54/0xb4) from [<c00084cc>] (gic_handle_irq+0x2c/0x60) [ 1248.700859 04-23 15:18:45.380] [<c00084cc>] (gic_handle_irq+0x2c/0x60) from [<c081d804>] (__irq_svc+0x44/0x78) |
static void __run_hrtimer(struct hrtimer *timer, ktime_t *now) { struct hrtimer_clock_base *base = timer->base; struct hrtimer_cpu_base *cpu_base = base->cpu_base; enum hrtimer_restart (*fn)(struct hrtimer *); int restart; WARN_ON(!irqs_disabled()); debug_deactivate(timer); __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0); timer_stats_account_hrtimer(timer); fn = timer->function; // alarmtimer_fired is called thru this callback function. <snip> |
'Core BSP 분석 > 리눅스 커널 핵심 분석' 카테고리의 다른 글
copy_mm()함수 (0) | 2023.05.05 |
---|---|
커널 에러 로그(1) (0) | 2023.05.05 |
바인더가 깨질 때의 콜 스택 (0) | 2023.05.05 |
아이노드 오퍼레이션 - ext4 파일 시스템 (0) | 2023.05.05 |
덴트리를 통해 시스템 콜 파일 패스 알아내기 (0) | 2023.05.05 |