All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tejun Heo <tj@kernel.org>
To: torvalds@linux-foundation.org, mingo@elte.hu,
	peterz@infradead.org, awalls@radix.net,
	linux-kernel@vger.kernel.org, jeff@garzik.org,
	akpm@linux-foundation.org, jens.axboe@oracle.com,
	rusty@rustcorp.com.au, cl@linux-foundation.org,
	dhowells@redhat.com, arjan@linux.intel.com, avi@redhat.com,
	johannes@sipsolutions.net, andi@firstfloor.org
Cc: Tejun Heo <tj@kernel.org>, Arjan van de Ven <arjan@infradead.org>
Subject: [PATCH 32/40] async: introduce workqueue based alternative implementation
Date: Mon, 18 Jan 2010 09:57:44 +0900	[thread overview]
Message-ID: <1263776272-382-33-git-send-email-tj@kernel.org> (raw)
In-Reply-To: <1263776272-382-1-git-send-email-tj@kernel.org>

Now that cmwq can handle high concurrency, there's no reason to
implement separate thread pool for async.  Introduce alternative
implementation based on workqueue.

The new implementation uses two workqueues - async_wq and
async_ordered_wq.  The former multithreaded and the latter
singlethreaded.  async_call() schedules unordered asynchronous
excution on async_wq.  async_call_ordered() schedules ordered excution
on async_ordered_wq.  Functions scheduled using the ordered variant
are guaranteed to be excecuted only after all async excutions
scheduled previously have finished.

This patch doesn't convert any existing user.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Arjan van de Ven <arjan@infradead.org>
---
 drivers/base/core.c    |    1 +
 drivers/base/dd.c      |    1 +
 include/linux/async.h  |    6 ++
 init/do_mounts.c       |    1 +
 init/main.c            |    1 +
 kernel/async.c         |  147 ++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/irq/autoprobe.c |    1 +
 kernel/module.c        |    2 +
 8 files changed, 160 insertions(+), 0 deletions(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2820257..14774c9 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1744,4 +1744,5 @@ void device_shutdown(void)
 		}
 	}
 	async_synchronize_full();
+	async_barrier();
 }
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index ee95c76..5c9c923 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -179,6 +179,7 @@ void wait_for_device_probe(void)
 	/* wait for the known devices to complete their probing */
 	wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
 	async_synchronize_full();
+	async_barrier();
 }
 EXPORT_SYMBOL_GPL(wait_for_device_probe);
 
diff --git a/include/linux/async.h b/include/linux/async.h
index 68a9530..49658dc 100644
--- a/include/linux/async.h
+++ b/include/linux/async.h
@@ -12,6 +12,7 @@
 
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/workqueue.h>
 
 typedef u64 async_cookie_t;
 typedef void (async_func_ptr) (void *data, async_cookie_t cookie);
@@ -25,3 +26,8 @@ extern void async_synchronize_cookie(async_cookie_t cookie);
 extern void async_synchronize_cookie_domain(async_cookie_t cookie,
 					    struct list_head *list);
 
+typedef void (*async_func_t)(void *data);
+
+extern bool async_call(async_func_t func, void *data);
+extern bool async_call_ordered(async_func_t func, void *data);
+extern void async_barrier(void);
diff --git a/init/do_mounts.c b/init/do_mounts.c
index bb008d0..608ac17 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -406,6 +406,7 @@ void __init prepare_namespace(void)
 			(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
 			msleep(100);
 		async_synchronize_full();
+		async_barrier();
 	}
 
 	is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
diff --git a/init/main.c b/init/main.c
index adb09f8..e35dfdd 100644
--- a/init/main.c
+++ b/init/main.c
@@ -802,6 +802,7 @@ static noinline int init_post(void)
 {
 	/* need to finish all async __init code before freeing the memory */
 	async_synchronize_full();
+	async_barrier();
 	free_initmem();
 	unlock_kernel();
 	mark_rodata_ro();
diff --git a/kernel/async.c b/kernel/async.c
index 27235f5..4cd52bc 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -395,3 +395,150 @@ static int __init async_init(void)
 }
 
 core_initcall(async_init);
+
+struct async_ent {
+	struct work_struct	work;
+	async_func_t		func;
+	void			*data;
+	bool			ordered;
+};
+
+static struct workqueue_struct *async_wq;
+static struct workqueue_struct *async_ordered_wq;
+
+static void async_work_func(struct work_struct *work)
+{
+	struct async_ent *ent = container_of(work, struct async_ent, work);
+	ktime_t calltime, delta, rettime;
+
+	if (initcall_debug && system_state == SYSTEM_BOOTING) {
+		printk("calling  %pF @ %i\n",
+		       ent->func, task_pid_nr(current));
+		calltime = ktime_get();
+	}
+
+	if (ent->ordered)
+		flush_workqueue(async_wq);
+
+	ent->func(ent->data);
+
+	if (initcall_debug && system_state == SYSTEM_BOOTING) {
+		rettime = ktime_get();
+		delta = ktime_sub(rettime, calltime);
+		printk("initcall %pF returned 0 after %lld usecs\n",
+		       ent->func, (long long)ktime_to_ns(delta) >> 10);
+	}
+}
+
+static bool __async_call(async_func_t func, void *data, bool ordered)
+{
+	struct async_ent *ent;
+
+	ent = kzalloc(sizeof(struct async_ent), GFP_ATOMIC);
+	if (!ent) {
+		kfree(ent);
+		if (ordered) {
+			flush_workqueue(async_wq);
+			flush_workqueue(async_ordered_wq);
+		}
+		func(data);
+		return false;
+	}
+
+	ent->func = func;
+	ent->data = data;
+	ent->ordered = ordered;
+	/*
+	 * Use separate INIT_WORK for sync and async so that they end
+	 * up with different lockdep keys.
+	 */
+	if (ordered) {
+		INIT_WORK(&ent->work, async_work_func);
+		queue_work(async_ordered_wq, &ent->work);
+	} else {
+		INIT_WORK(&ent->work, async_work_func);
+		queue_work(async_wq, &ent->work);
+	}
+	return true;
+}
+
+/**
+ * async_call - schedule a function for asynchronous execution
+ * @func: function to execute asynchronously
+ * @data: data pointer to pass to the function
+ *
+ * Schedule @func(@data) for asynchronous execution.  The function
+ * might be called directly if memory allocation fails.
+ *
+ * CONTEXT:
+ * Don't care but keep in mind that @func may be executed directly.
+ *
+ * RETURNS:
+ * %true if async execution is scheduled, %false if executed locally.
+ */
+bool async_call(async_func_t func, void *data)
+{
+	return __async_call(func, data, false);
+}
+EXPORT_SYMBOL_GPL(async_call);
+
+/**
+ * async_call_ordered - schedule ordered asynchronous execution
+ * @func: function to execute asynchronously
+ * @data: data pointer to pass to the function
+ *
+ * Schedule @func(data) for ordered asynchronous excution.  It will be
+ * executed only after all async functions scheduled upto this point
+ * have finished.
+ *
+ * CONTEXT:
+ * Might sleep.
+ *
+ * RETURNS:
+ * %true if async execution is scheduled, %false if executed locally.
+ */
+bool async_call_ordered(async_func_t func, void *data)
+{
+	might_sleep();
+	return __async_call(func, data, true);
+}
+EXPORT_SYMBOL_GPL(async_call_ordered);
+
+/**
+ * async_barrier - asynchronous execution barrier
+ *
+ * Wait till all currently scheduled async executions are finished.
+ *
+ * CONTEXT:
+ * Might sleep.
+ */
+void async_barrier(void)
+{
+	ktime_t starttime, delta, endtime;
+
+	if (initcall_debug && system_state == SYSTEM_BOOTING) {
+		printk("async_waiting @ %i\n", task_pid_nr(current));
+		starttime = ktime_get();
+	}
+
+	flush_workqueue(async_wq);
+	flush_workqueue(async_ordered_wq);
+
+	if (initcall_debug && system_state == SYSTEM_BOOTING) {
+		endtime = ktime_get();
+		delta = ktime_sub(endtime, starttime);
+		printk("async_continuing @ %i after %lli usec\n",
+		       task_pid_nr(current),
+		       (long long)ktime_to_ns(delta) >> 10);
+	}
+}
+EXPORT_SYMBOL_GPL(async_barrier);
+
+static int __init init_async(void)
+{
+	async_wq = __create_workqueue("async", 0, WQ_MAX_ACTIVE);
+	async_ordered_wq = create_singlethread_workqueue("async_ordered");
+	BUG_ON(!async_wq || !async_ordered_wq);
+	return 0;
+}
+core_initcall(init_async);
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c
index 2295a31..39188cd 100644
--- a/kernel/irq/autoprobe.c
+++ b/kernel/irq/autoprobe.c
@@ -39,6 +39,7 @@ unsigned long probe_irq_on(void)
 	 * quiesce the kernel, or at least the asynchronous portion
 	 */
 	async_synchronize_full();
+	async_barrier();
 	mutex_lock(&probing_active);
 	/*
 	 * something may have generated an irq long ago and we want to
diff --git a/kernel/module.c b/kernel/module.c
index f82386b..623a9b6 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -717,6 +717,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
 	blocking_notifier_call_chain(&module_notify_list,
 				     MODULE_STATE_GOING, mod);
 	async_synchronize_full();
+	async_barrier();
 	mutex_lock(&module_mutex);
 	/* Store the name of the last unloaded module for diagnostic purposes */
 	strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
@@ -2494,6 +2495,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
 
 	/* We need to finish all async code before the module init sequence is done */
 	async_synchronize_full();
+	async_barrier();
 
 	mutex_lock(&module_mutex);
 	/* Drop initial reference. */
-- 
1.6.4.2


  parent reply	other threads:[~2010-01-18  0:55 UTC|newest]

Thread overview: 102+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-18  0:57 [PATCHSET] concurrency managed workqueue, take#3 Tejun Heo
2010-01-18  0:57 ` [PATCH 01/40] sched: consult online mask instead of active in select_fallback_rq() Tejun Heo
2010-01-18 10:13   ` Peter Zijlstra
2010-01-18 11:26     ` Tejun Heo
2010-01-18  0:57 ` [PATCH 02/40] sched: rename preempt_notifiers to sched_notifiers and refactor implementation Tejun Heo
2010-01-18  0:57 ` [PATCH 03/40] sched: refactor try_to_wake_up() Tejun Heo
2010-01-18  0:57 ` [PATCH 04/40] sched: implement __set_cpus_allowed() Tejun Heo
2010-01-18  9:56   ` Peter Zijlstra
2010-01-18 11:22     ` Tejun Heo
2010-01-18 11:41       ` Peter Zijlstra
2010-01-19  1:07         ` Tejun Heo
2010-01-19  8:37           ` Peter Zijlstra
2010-01-20  8:35             ` Tejun Heo
2010-01-20  8:50               ` Peter Zijlstra
2010-01-20  9:00                 ` Tejun Heo
2010-01-20  8:59                   ` Peter Zijlstra
2010-01-24  8:18               ` Tejun Heo
2010-01-18  0:57 ` [PATCH 05/40] sched: make sched_notifiers unconditional Tejun Heo
2010-01-18  0:57 ` [PATCH 06/40] sched: add wakeup/sleep sched_notifiers and allow NULL notifier ops Tejun Heo
2010-01-18  9:57   ` Peter Zijlstra
2010-01-18 11:31     ` Tejun Heo
2010-01-18 12:49       ` Peter Zijlstra
2010-01-19  1:04         ` Tejun Heo
2010-01-19  8:28           ` Tejun Heo
2010-01-19  8:55             ` Peter Zijlstra
2010-01-20  8:47               ` Tejun Heo
2010-01-18  0:57 ` [PATCH 07/40] sched: implement try_to_wake_up_local() Tejun Heo
2010-01-18  0:57 ` [PATCH 08/40] acpi: use queue_work_on() instead of binding workqueue worker to cpu0 Tejun Heo
2010-01-18  0:57 ` [PATCH 09/40] stop_machine: reimplement without using workqueue Tejun Heo
2010-01-18  0:57 ` [PATCH 10/40] workqueue: misc/cosmetic updates Tejun Heo
2010-01-18  0:57 ` [PATCH 11/40] workqueue: merge feature parameters into flags Tejun Heo
2010-01-18  0:57 ` [PATCH 12/40] workqueue: define both bit position and mask for work flags Tejun Heo
2010-01-18  0:57 ` [PATCH 13/40] workqueue: separate out process_one_work() Tejun Heo
2010-01-18  0:57 ` [PATCH 14/40] workqueue: temporarily disable workqueue tracing Tejun Heo
2010-01-18  0:57 ` [PATCH 15/40] workqueue: kill cpu_populated_map Tejun Heo
2010-01-18  0:57 ` [PATCH 16/40] workqueue: update cwq alignement Tejun Heo
2010-01-18  0:57 ` [PATCH 17/40] workqueue: reimplement workqueue flushing using color coded works Tejun Heo
2010-01-18  0:57 ` [PATCH 18/40] workqueue: introduce worker Tejun Heo
2010-01-18  0:57 ` [PATCH 19/40] workqueue: reimplement work flushing using linked works Tejun Heo
2010-01-18  0:57 ` [PATCH 20/40] workqueue: implement per-cwq active work limit Tejun Heo
2010-01-18  0:57 ` [PATCH 21/40] workqueue: reimplement workqueue freeze using max_active Tejun Heo
2010-01-18  0:57 ` [PATCH 22/40] workqueue: introduce global cwq and unify cwq locks Tejun Heo
2010-01-18  0:57 ` [PATCH 23/40] workqueue: implement worker states Tejun Heo
2010-01-18  0:57 ` [PATCH 24/40] workqueue: reimplement CPU hotplugging support using trustee Tejun Heo
2010-01-18  0:57 ` [PATCH 25/40] workqueue: make single thread workqueue shared worker pool friendly Tejun Heo
2010-01-18  0:57 ` [PATCH 26/40] workqueue: use shared worklist and pool all workers per cpu Tejun Heo
2010-01-18  0:57 ` [PATCH 27/40] workqueue: implement concurrency managed dynamic worker pool Tejun Heo
2010-01-18  0:57 ` [PATCH 28/40] workqueue: increase max_active of keventd and kill current_is_keventd() Tejun Heo
2010-01-18  0:57 ` [PATCH 29/40] workqueue: add system_wq and system_single_wq Tejun Heo
2010-01-18  0:57 ` [PATCH 30/40] workqueue: implement work_busy() Tejun Heo
2010-01-18  2:52   ` Andy Walls
2010-01-18  5:41     ` Tejun Heo
2010-01-18  0:57 ` [PATCH 31/40] libata: take advantage of cmwq and remove concurrency limitations Tejun Heo
2010-01-18 15:48   ` Stefan Richter
2010-01-19  0:49     ` Tejun Heo
2010-01-18  0:57 ` Tejun Heo [this message]
2010-01-18  6:01   ` [PATCH 32/40] async: introduce workqueue based alternative implementation Arjan van de Ven
2010-01-18  8:49     ` Tejun Heo
2010-01-18 15:25       ` Arjan van de Ven
2010-01-19  0:57         ` Tejun Heo
2010-01-19  0:57           ` Arjan van de Ven
2010-01-19  7:56             ` Tejun Heo
2010-01-19 14:37               ` Arjan van de Ven
2010-01-20  0:19                 ` Tejun Heo
2010-01-20  0:31                   ` Arjan van de Ven
2010-01-20  2:08                     ` Tejun Heo
2010-01-20  6:03                       ` Arjan van de Ven
2010-01-20  8:24                         ` Tejun Heo
2010-01-22 10:59                           ` [PATCH] async: use workqueue for worker pool Tejun Heo
2010-01-18  0:57 ` [PATCH 33/40] async: convert async users to use the new implementation Tejun Heo
2010-01-18  0:57 ` [PATCH 34/40] async: kill original implementation Tejun Heo
2010-01-18  0:57 ` [PATCH 35/40] fscache: convert object to use workqueue instead of slow-work Tejun Heo
2010-02-12 18:03   ` David Howells
2010-02-13  5:43     ` Tejun Heo
2010-02-15 15:04       ` David Howells
2010-02-16  3:40         ` Tejun Heo
2010-02-16  3:59           ` Tejun Heo
2010-02-16 18:05           ` David Howells
2010-02-16 23:50             ` Tejun Heo
2010-02-18 11:50               ` David Howells
2010-02-18 12:33                 ` Tejun Heo
2010-01-18  0:57 ` [PATCH 36/40] fscache: convert operation " Tejun Heo
2010-01-18  0:57 ` [PATCH 37/40] fscache: drop references to slow-work Tejun Heo
2010-01-18  0:57 ` [PATCH 38/40] cifs: use workqueue instead of slow-work Tejun Heo
2010-01-19 12:20   ` Jeff Layton
2010-01-20  0:15     ` Tejun Heo
2010-01-20  0:56       ` Jeff Layton
2010-01-20  1:23         ` Tejun Heo
2010-01-22 11:14           ` [PATCH UPDATED " Tejun Heo
2010-01-22 11:45             ` Jeff Layton
2010-01-24  8:25               ` Tejun Heo
2010-01-24 12:13                 ` Jeff Layton
2010-01-25 15:25                   ` Tejun Heo
2010-01-18  0:57 ` [PATCH 39/40] gfs2: " Tejun Heo
2010-01-18  9:45   ` Steven Whitehouse
2010-01-18 11:24     ` Tejun Heo
2010-01-18 12:07       ` Steven Whitehouse
2010-01-19  1:00         ` Tejun Heo
2010-01-19  8:46           ` [PATCH UPDATED " Tejun Heo
2010-01-18  0:57 ` [PATCH 40/40] slow-work: kill it Tejun Heo
2010-01-18  1:03 ` perf-wq.c used to generate synthetic workload Tejun Heo
2010-01-18 16:13 ` [PATCHSET] concurrency managed workqueue, take#3 Stefan Richter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1263776272-382-33-git-send-email-tj@kernel.org \
    --to=tj@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=andi@firstfloor.org \
    --cc=arjan@infradead.org \
    --cc=arjan@linux.intel.com \
    --cc=avi@redhat.com \
    --cc=awalls@radix.net \
    --cc=cl@linux-foundation.org \
    --cc=dhowells@redhat.com \
    --cc=jeff@garzik.org \
    --cc=jens.axboe@oracle.com \
    --cc=johannes@sipsolutions.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=peterz@infradead.org \
    --cc=rusty@rustcorp.com.au \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.