wifi: cfg80211: Add wiphy_delayed_work_pending()

Add wiphy_delayed_work_pending() to check if any delayed work timer is
pending, that can be used to be sure that wiphy_delayed_work_queue()
won't postpone an already pending delayed work.

Signed-off-by: Remi Pommarel <repk@triplefau.lt>
Link: https://patch.msgid.link/20240924192805.13859-2-repk@triplefau.lt
[fix return value kernel-doc]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Remi Pommarel 2024-09-24 21:28:04 +02:00 committed by Johannes Berg
parent e1a9ae3a73
commit 68d0021fe7
2 changed files with 51 additions and 0 deletions

View File

@ -6129,6 +6129,50 @@ void wiphy_delayed_work_cancel(struct wiphy *wiphy,
void wiphy_delayed_work_flush(struct wiphy *wiphy, void wiphy_delayed_work_flush(struct wiphy *wiphy,
struct wiphy_delayed_work *dwork); struct wiphy_delayed_work *dwork);
/**
* wiphy_delayed_work_pending - Find out whether a wiphy delayable
* work item is currently pending.
*
* @wiphy: the wiphy, for debug purposes
* @dwork: the delayed work in question
*
* Return: true if timer is pending, false otherwise
*
* How wiphy_delayed_work_queue() works is by setting a timer which
* when it expires calls wiphy_work_queue() to queue the wiphy work.
* Because wiphy_delayed_work_queue() uses mod_timer(), if it is
* called twice and the second call happens before the first call
* deadline, the work will rescheduled for the second deadline and
* won't run before that.
*
* wiphy_delayed_work_pending() can be used to detect if calling
* wiphy_work_delayed_work_queue() would start a new work schedule
* or delayed a previous one. As seen below it cannot be used to
* detect precisely if the work has finished to execute nor if it
* is currently executing.
*
* CPU0 CPU1
* wiphy_delayed_work_queue(wk)
* mod_timer(wk->timer)
* wiphy_delayed_work_pending(wk) -> true
*
* [...]
* expire_timers(wk->timer)
* detach_timer(wk->timer)
* wiphy_delayed_work_pending(wk) -> false
* wk->timer->function() |
* wiphy_work_queue(wk) | delayed work pending
* list_add_tail() | returns false but
* queue_work(cfg80211_wiphy_work) | wk->func() has not
* | been run yet
* [...] |
* cfg80211_wiphy_work() |
* wk->func() V
*
*/
bool wiphy_delayed_work_pending(struct wiphy *wiphy,
struct wiphy_delayed_work *dwork);
/** /**
* enum ieee80211_ap_reg_power - regulatory power for an Access Point * enum ieee80211_ap_reg_power - regulatory power for an Access Point
* *

View File

@ -1704,6 +1704,13 @@ void wiphy_delayed_work_flush(struct wiphy *wiphy,
} }
EXPORT_SYMBOL_GPL(wiphy_delayed_work_flush); EXPORT_SYMBOL_GPL(wiphy_delayed_work_flush);
bool wiphy_delayed_work_pending(struct wiphy *wiphy,
struct wiphy_delayed_work *dwork)
{
return timer_pending(&dwork->timer);
}
EXPORT_SYMBOL_GPL(wiphy_delayed_work_pending);
static int __init cfg80211_init(void) static int __init cfg80211_init(void)
{ {
int err; int err;