From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A377E3A7F73 for ; Tue, 24 Feb 2026 16:37:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771951061; cv=none; b=WmyKHSUNPtolWU4O/W+4R0GnEmFolE1K/FgXhampove9EcGFJ8EJ4QIRCCJaBcUonAKqsePxL3MAJVX8xebwer18EWZKQJznznHPDzAMxSEZc/pPHF+9lYUQGNOHG75swfxlsJd11fVWPFxRDs5xKP5JwwwuTn/KAtbpSTNaN6c= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771951061; c=relaxed/simple; bh=rMMuECiwN5OCAX2ML+MIBWLXX/8zsL2y08Z5WD9oE+g=; h=Date:Message-ID:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=AUeDLmDxraVvZEL8iaBiND3PpnBPUtsWzCGVR8F1QkVtg/i9eurbB6xApX05TPoVZEcyc7Qwyu1VsvTbnFlP5j/1YjfDPlKjYrTgHdf3fUNAbNQC2Js4YJepz4QhHbD6MjMQydPmnur/0UjjTL84eAG1JezCFGibIABHfIFs+o0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Pe4l8Adm; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Pe4l8Adm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 21479C116D0; Tue, 24 Feb 2026 16:37:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1771951061; bh=rMMuECiwN5OCAX2ML+MIBWLXX/8zsL2y08Z5WD9oE+g=; h=Date:From:To:Cc:Subject:References:From; b=Pe4l8AdmxP2j96S9dHiZAaSALa3fqUwqSFz+Yc8fy2J6AGhYxCfGYUU8qM9LDZyHB sHajadjakxypqm8o4OO+QqcnCQ+xZDQmZQndvfRR4a0t+MYMqiLFFjrlijOCWp7+qQ XQoz7c/M5IFtn6navOTi/4B1AtURlCKaLo3zuBfySbHDbDwC1+yZ/xIBzK57BJ/CA9 8QjE8TQk6dDtc+0STnmD6C0ktI2iGpcxO7Bs/4yatKDznjW5UZPnb0FpKlva94X+cf AvNc7xfXfsVHrUqBkZqUcx7AH+aZ+02lJyB0XRJlXo/S8N1UWy/lLNVTJlh4WBCwqG 6rDN+m4HX2yQw== Date: Tue, 24 Feb 2026 17:37:38 +0100 Message-ID: <20260224163430.737600486@kernel.org> User-Agent: quilt/0.68 From: Thomas Gleixner To: LKML Cc: Anna-Maria Behnsen , John Stultz , Stephen Boyd , Daniel Lezcano , Juri Lelli , Vincent Guittot , Dietmar Eggemann , Steven Rostedt , Ben Segall , Mel Gorman , Valentin Schneider , x86@kernel.org, Peter Zijlstra , Frederic Weisbecker , Eric Dumazet Subject: [patch 30/48] hrtimer: Separate remove/enqueue handling for local timers References: <20260224163022.795809588@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 As the base switch can be avoided completely when the base stays the same the remove/enqueue handling can be more streamlined. Split it out into a separate function which handles both in one go which is way more efficient and makes the code simpler to follow. Signed-off-by: Thomas Gleixner --- kernel/time/hrtimer.c | 72 +++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 29 deletions(-) --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1147,13 +1147,11 @@ static void __remove_hrtimer(struct hrti } static inline bool remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, - bool restart, bool keep_base) + bool newstate) { - bool queued_state = timer->is_queued; - lockdep_assert_held(&base->cpu_base->lock); - if (queued_state) { + if (timer->is_queued) { bool reprogram; debug_hrtimer_deactivate(timer); @@ -1168,23 +1166,35 @@ static inline bool remove_hrtimer(struct */ reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); - /* - * If the timer is not restarted then reprogramming is - * required if the timer is local. If it is local and about - * to be restarted, avoid programming it twice (on removal - * and a moment later when it's requeued). - */ - if (!restart) - queued_state = HRTIMER_STATE_INACTIVE; - else - reprogram &= !keep_base; - - __remove_hrtimer(timer, base, queued_state, reprogram); + __remove_hrtimer(timer, base, newstate, reprogram); return true; } return false; } +static inline bool +remove_and_enqueue_same_base(struct hrtimer *timer, struct hrtimer_clock_base *base, + const enum hrtimer_mode mode, ktime_t expires, u64 delta_ns) +{ + /* Remove it from the timer queue if active */ + if (timer->is_queued) { + debug_hrtimer_deactivate(timer); + timerqueue_del(&base->active, &timer->node); + } + + /* Set the new expiry time */ + hrtimer_set_expires_range_ns(timer, expires, delta_ns); + + debug_activate(timer, mode, timer->is_queued); + base->cpu_base->active_bases |= 1 << base->index; + + /* Pairs with the lockless read in hrtimer_is_queued() */ + WRITE_ONCE(timer->is_queued, HRTIMER_STATE_ENQUEUED); + + /* Returns true if this is the first expiring timer */ + return timerqueue_add(&base->active, &timer->node); +} + static inline ktime_t hrtimer_update_lowres(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) { @@ -1267,7 +1277,7 @@ static bool __hrtimer_start_range_ns(str const enum hrtimer_mode mode, struct hrtimer_clock_base *base) { struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); - bool is_pinned, first, was_first, was_armed, keep_base = false; + bool is_pinned, first, was_first, keep_base = false; struct hrtimer_cpu_base *cpu_base = base->cpu_base; was_first = cpu_base->next_timer == timer; @@ -1283,6 +1293,12 @@ static bool __hrtimer_start_range_ns(str keep_base = hrtimer_keep_base(timer, is_local, was_first, is_pinned); } + /* Calculate absolute expiry time for relative timers */ + if (mode & HRTIMER_MODE_REL) + tim = ktime_add_safe(tim, __hrtimer_cb_get_time(base->clockid)); + /* Compensate for low resolution granularity */ + tim = hrtimer_update_lowres(timer, tim, mode); + /* * Remove an active timer from the queue. In case it is not queued * on the current CPU, make sure that remove_hrtimer() updates the @@ -1297,22 +1313,20 @@ static bool __hrtimer_start_range_ns(str * @keep_base is also true if the timer callback is running on a * remote CPU and for local pinned timers. */ - was_armed = remove_hrtimer(timer, base, true, keep_base); - - if (mode & HRTIMER_MODE_REL) - tim = ktime_add_safe(tim, __hrtimer_cb_get_time(base->clockid)); - - tim = hrtimer_update_lowres(timer, tim, mode); + if (likely(keep_base)) { + first = remove_and_enqueue_same_base(timer, base, mode, tim, delta_ns); + } else { + /* Keep the ENQUEUED state in case it is queued */ + bool was_armed = remove_hrtimer(timer, base, HRTIMER_STATE_ENQUEUED); - hrtimer_set_expires_range_ns(timer, tim, delta_ns); + hrtimer_set_expires_range_ns(timer, tim, delta_ns); - /* Switch the timer base, if necessary: */ - if (!keep_base) { + /* Switch the timer base, if necessary: */ base = switch_hrtimer_base(timer, base, is_pinned); cpu_base = base->cpu_base; - } - first = enqueue_hrtimer(timer, base, mode, was_armed); + first = enqueue_hrtimer(timer, base, mode, was_armed); + } /* * If the hrtimer interrupt is running, then it will reevaluate the @@ -1432,7 +1446,7 @@ int hrtimer_try_to_cancel(struct hrtimer base = lock_hrtimer_base(timer, &flags); if (!hrtimer_callback_running(timer)) { - ret = remove_hrtimer(timer, base, false, false); + ret = remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE); if (ret) trace_hrtimer_cancel(timer); }