Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 83909a2f authored by Patrick Daly's avatar Patrick Daly Committed by Gerrit - the friendly Code Review server
Browse files

PM / Wakeup: Use rcu callbacks for better performance



Use rcu to free objects in wakeup_source_unregister(). These objects must
be allocated through wakeup_source_register().

Replacing synchronize_rcu() with call_rcu() allows multiple calls to
wakeup_source_unregister() to be combined into a single grace period.

CRs-Fixed: 845110
Change-Id: Ib4002db042cf63abb28e6b3df6e3c70c97043bd9
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent 67b6b070
Loading
Loading
Loading
Loading
+31 −2
Original line number Diff line number Diff line
@@ -125,6 +125,15 @@ void wakeup_source_destroy(struct wakeup_source *ws)
}
EXPORT_SYMBOL_GPL(wakeup_source_destroy);

/**
 * wakeup_source_destroy_cb
 * defer processing until all rcu references have expired
 */
static void wakeup_source_destroy_cb(struct rcu_head *head)
{
	wakeup_source_destroy(container_of(head, struct wakeup_source, rcu));
}

/**
 * wakeup_source_add - Add given object to the list of wakeup sources.
 * @ws: Wakeup source object to add to the list.
@@ -165,6 +174,26 @@ void wakeup_source_remove(struct wakeup_source *ws)
}
EXPORT_SYMBOL_GPL(wakeup_source_remove);

/**
 * wakeup_source_remove_async - Remove given object from the wakeup sources
 * list.
 * @ws: Wakeup source object to remove from the list.
 *
 * Use only for wakeup source objects created with wakeup_source_create().
 * Memory for ws must be freed via rcu.
 */
static void wakeup_source_remove_async(struct wakeup_source *ws)
{
	unsigned long flags;

	if (WARN_ON(!ws))
		return;

	spin_lock_irqsave(&events_lock, flags);
	list_del_rcu(&ws->entry);
	spin_unlock_irqrestore(&events_lock, flags);
}

/**
 * wakeup_source_register - Create wakeup source and add it to the list.
 * @name: Name of the wakeup source to register.
@@ -188,8 +217,8 @@ EXPORT_SYMBOL_GPL(wakeup_source_register);
void wakeup_source_unregister(struct wakeup_source *ws)
{
	if (ws) {
		wakeup_source_remove(ws);
		wakeup_source_destroy(ws);
		wakeup_source_remove_async(ws);
		call_rcu(&ws->rcu, wakeup_source_destroy_cb);
	}
}
EXPORT_SYMBOL_GPL(wakeup_source_unregister);
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@
struct wakeup_source {
	const char 		*name;
	struct list_head	entry;
	struct rcu_head		rcu;
	spinlock_t		lock;
	struct timer_list	timer;
	unsigned long		timer_expires;