kernel/time/posix-timers.c

Source file repositories/reference/linux-study-clean/kernel/time/posix-timers.c

File Facts

System
Linux kernel
Corpus path
kernel/time/posix-timers.c
Extension
.c
Size
44896 bytes
Lines
1583
Domain
Core OS
Bucket
Scheduler, Processes, Timers, Sync, And Syscalls
Inferred role
Core OS: syscall or user/kernel boundary
Status
core implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
		struct sigevent __user *, timer_event_spec,
		timer_t __user *, created_timer_id)
{
	if (timer_event_spec) {
		sigevent_t event;

		if (copy_from_user(&event, timer_event_spec, sizeof (event)))
			return -EFAULT;
		return do_timer_create(which_clock, &event, created_timer_id);
	}
	return do_timer_create(which_clock, NULL, created_timer_id);
}

#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock,
		       struct compat_sigevent __user *, timer_event_spec,
		       timer_t __user *, created_timer_id)
{
	if (timer_event_spec) {
		sigevent_t event;

		if (get_compat_sigevent(&event, timer_event_spec))
			return -EFAULT;
		return do_timer_create(which_clock, &event, created_timer_id);
	}
	return do_timer_create(which_clock, NULL, created_timer_id);
}
#endif

static struct k_itimer *lock_timer(timer_t timer_id)
{
	struct k_itimer *timr;

	/*
	 * timer_t could be any type >= int and we want to make sure any
	 * @timer_id outside positive int range fails lookup.
	 */
	if ((unsigned long long)timer_id > INT_MAX)
		return NULL;

	/*
	 * The hash lookup and the timers are RCU protected.
	 *
	 * Timers are added to the hash in invalid state where
	 * timr::it_signal is marked invalid. timer::it_signal is only set
	 * after the rest of the initialization succeeded.
	 *
	 * Timer destruction happens in steps:
	 *  1) Set timr::it_signal marked invalid with timr::it_lock held
	 *  2) Release timr::it_lock
	 *  3) Remove from the hash under hash_lock
	 *  4) Put the reference count.
	 *
	 * The reference count might not drop to zero if timr::sigq is
	 * queued. In that case the signal delivery or flush will put the
	 * last reference count.
	 *
	 * When the reference count reaches zero, the timer is scheduled
	 * for RCU removal after the grace period.
	 *
	 * Holding rcu_read_lock() across the lookup ensures that
	 * the timer cannot be freed.
	 *
	 * The lookup validates locklessly that timr::it_signal ==
	 * current::it_signal and timr::it_id == @timer_id. timr::it_id
	 * can't change, but timr::it_signal can become invalid during
	 * destruction, which makes the locked check fail.
	 */
	guard(rcu)();
	timr = posix_timer_by_id(timer_id);
	if (timr) {
		spin_lock_irq(&timr->it_lock);
		/*
		 * Validate under timr::it_lock that timr::it_signal is
		 * still valid. Pairs with #1 above.
		 */
		if (timr->it_signal == current->signal)
			return timr;
		spin_unlock_irq(&timr->it_lock);
	}
	return NULL;
}

static ktime_t common_hrtimer_remaining(struct k_itimer *timr, ktime_t now)
{
	struct hrtimer *timer = &timr->it.real.timer;

	return __hrtimer_expires_remaining_adjusted(timer, now);
}

Annotation

Implementation Notes