[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20070214082642.GA17096@elte.hu>
Date: Wed, 14 Feb 2007 09:26:42 +0100
From: Ingo Molnar <mingo@...e.hu>
To: Davide Libenzi <davidel@...ilserver.org>
Cc: Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
Linus Torvalds <torvalds@...ux-foundation.org>,
Arjan van de Ven <arjan@...radead.org>,
Christoph Hellwig <hch@...radead.org>,
Andrew Morton <akpm@....com.au>,
Alan Cox <alan@...rguk.ukuu.org.uk>,
Ulrich Drepper <drepper@...hat.com>,
Zach Brown <zach.brown@...cle.com>,
Evgeniy Polyakov <johnpol@....mipt.ru>,
"David S. Miller" <davem@...emloft.net>,
Benjamin LaHaise <bcrl@...ck.org>,
Suparna Bhattacharya <suparna@...ibm.com>,
Thomas Gleixner <tglx@...utronix.de>
Subject: Re: [patch 00/11] ANNOUNCE: "Syslets", generic asynchronous system call support
* Davide Libenzi <davidel@...ilserver.org> wrote:
> > There's another problem AFAICS:
> >
> > - We woke up one of the cachemiss_loop threads in pick_new_async_thread
> >
> > - The threads wakes up, mark itself as busy, and look at the ->work
> > pointer hoping to find something to work on
> >
> > But we never set that pointer to a userspace atom AFAICS. Me blind? :)
>
> I still don't see at->work ever set to a valid userspace atom
> though...
yeah - i havent added support for 'submit syslet from within a syslet'
support yet :-)
note that current normal syslet operation (both async and sync alike)
does not need at->work at all. When we cachemiss then the new head task
just wants to return a NULL pointer to user-space, to signal that work
is continuing in the background. A ready 'cachemiss' thread is really
not there to do cachemisses, it is a 'new head task in the waiting'. The
name comes from Tux and i guess it's time for a rename :)
but i do plan a SYSLET_ASYNC_CONTINUE flag, roughly along the patch i've
attached below: this would skip to the linearly next syslet and would
let the original syslet execute in the. I have not fully thought this
through though (let alone tested it ;) - can you see any hole in this
approach? This would in essence allow the following construct:
syslet1 &
syslet2 &
syslet3 &
syslet4 &
submitted in parallel, straight to cachemiss threads, from a syslet
itself.
there's yet another work submission variant that makes sense to do, a
true syslet vector submission: to do a loop over syslet atoms in
sys_async_exec(). That would have the added advantage of enabling
caching. If one vector component generates a cachemiss then the head
would continue with the next vector. (this too needs at->work alike
communication between ex-head and new-head)
maybe the latter would be the cleaner approach - SYSLET_ASYNC_CONTINUE
has no effect in cachemiss context, so it only makes sense if the
submitted syslet is a pure vector of parallel atoms. Alternatively,
SYSLET_ASYNC_CONTINUE would have to be made work from cachemiss contexts
too. (because that makes sense too, to start new async execution from
another async context.)
another not yet clear area is when there's no cachemiss thread
available. Right now SYSLET_ASYNC_CONTINUE will just fail - which makes
it nondeterministic.
Ingo
---
include/linux/async.h | 13 +++++++++++--
include/linux/sched.h | 3 +--
include/linux/syslet.h | 20 +++++++++++++-------
kernel/async.c | 43 +++++++++++++++++++++++++++++--------------
kernel/sched.c | 2 +-
5 files changed, 56 insertions(+), 27 deletions(-)
# *DOCUMENTATION*
Index: linux/include/linux/async.h
===================================================================
--- linux.orig/include/linux/async.h
+++ linux/include/linux/async.h
@@ -1,15 +1,23 @@
#ifndef _LINUX_ASYNC_H
#define _LINUX_ASYNC_H
+
+#include <linux/compiler.h>
+
/*
* The syslet subsystem - asynchronous syscall execution support.
*
* Generic kernel API definitions:
*/
+struct syslet_uatom;
+struct async_thread;
+struct async_head;
+
#ifdef CONFIG_ASYNC_SUPPORT
extern void async_init(struct task_struct *t);
extern void async_exit(struct task_struct *t);
-extern void __async_schedule(struct task_struct *t);
+extern void
+__async_schedule(struct task_struct *t, struct syslet_uatom __user *next_uatom);
#else /* !CONFIG_ASYNC_SUPPORT */
static inline void async_init(struct task_struct *t)
{
@@ -17,7 +25,8 @@ static inline void async_init(struct tas
static inline void async_exit(struct task_struct *t)
{
}
-static inline void __async_schedule(struct task_struct *t)
+static inline void
+__async_schedule(struct task_struct *t, struct syslet_uatom __user *next_uatom)
{
}
#endif /* !CONFIG_ASYNC_SUPPORT */
Index: linux/include/linux/sched.h
===================================================================
--- linux.orig/include/linux/sched.h
+++ linux/include/linux/sched.h
@@ -83,13 +83,12 @@ struct sched_param {
#include <linux/timer.h>
#include <linux/hrtimer.h>
#include <linux/task_io_accounting.h>
+#include <linux/async.h>
#include <asm/processor.h>
struct exec_domain;
struct futex_pi_state;
-struct async_thread;
-struct async_head;
/*
* List of flags we want to share for kernel threads,
* if only because they are not used by them anyway.
Index: linux/include/linux/syslet.h
===================================================================
--- linux.orig/include/linux/syslet.h
+++ linux/include/linux/syslet.h
@@ -56,10 +56,16 @@ struct syslet_uatom {
#define SYSLET_ASYNC 0x00000001
/*
+ * Queue this syslet asynchronously and continue executing the
+ * next linear atom:
+ */
+#define SYSLET_ASYNC_CONTINUE 0x00000002
+
+/*
* Never queue this syslet asynchronously - even if synchronous
* execution causes a context-switching:
*/
-#define SYSLET_SYNC 0x00000002
+#define SYSLET_SYNC 0x00000004
/*
* Do not queue the syslet in the completion ring when done.
@@ -70,7 +76,7 @@ struct syslet_uatom {
* Some syscalls generate implicit completion events of their
* own.
*/
-#define SYSLET_NO_COMPLETE 0x00000004
+#define SYSLET_NO_COMPLETE 0x00000008
/*
* Execution control: conditions upon the return code
@@ -78,10 +84,10 @@ struct syslet_uatom {
* execution is stopped and the atom is put into the
* completion ring:
*/
-#define SYSLET_STOP_ON_NONZERO 0x00000008
-#define SYSLET_STOP_ON_ZERO 0x00000010
-#define SYSLET_STOP_ON_NEGATIVE 0x00000020
-#define SYSLET_STOP_ON_NON_POSITIVE 0x00000040
+#define SYSLET_STOP_ON_NONZERO 0x00000010
+#define SYSLET_STOP_ON_ZERO 0x00000020
+#define SYSLET_STOP_ON_NEGATIVE 0x00000040
+#define SYSLET_STOP_ON_NON_POSITIVE 0x00000080
#define SYSLET_STOP_MASK \
( SYSLET_STOP_ON_NONZERO | \
@@ -97,7 +103,7 @@ struct syslet_uatom {
*
* This is what allows true branches of execution within syslets.
*/
-#define SYSLET_SKIP_TO_NEXT_ON_STOP 0x00000080
+#define SYSLET_SKIP_TO_NEXT_ON_STOP 0x00000100
/*
* This is the (per-user-context) descriptor of the async completion
Index: linux/kernel/async.c
===================================================================
--- linux.orig/kernel/async.c
+++ linux/kernel/async.c
@@ -75,13 +75,14 @@ mark_async_thread_busy(struct async_thre
static void
__async_thread_init(struct task_struct *t, struct async_thread *at,
- struct async_head *ah)
+ struct async_head *ah,
+ struct syslet_uatom __user *work)
{
INIT_LIST_HEAD(&at->entry);
at->exit = 0;
at->task = t;
at->ah = ah;
- at->work = NULL;
+ at->work = work;
t->at = at;
ah->nr_threads++;
@@ -92,7 +93,7 @@ async_thread_init(struct task_struct *t,
struct async_head *ah)
{
spin_lock(&ah->lock);
- __async_thread_init(t, at, ah);
+ __async_thread_init(t, at, ah, NULL);
__mark_async_thread_ready(at, ah);
spin_unlock(&ah->lock);
}
@@ -130,8 +131,10 @@ pick_ready_cachemiss_thread(struct async
return at;
}
-static void pick_new_async_head(struct async_head *ah,
- struct task_struct *t, struct pt_regs *old_regs)
+static void
+pick_new_async_head(struct async_head *ah, struct task_struct *t,
+ struct pt_regs *old_regs,
+ struct syslet_uatom __user *next_uatom)
{
struct async_thread *new_async_thread;
struct async_thread *async_ready;
@@ -158,28 +161,31 @@ static void pick_new_async_head(struct a
wake_up_process(new_task);
- __async_thread_init(t, async_ready, ah);
+ __async_thread_init(t, async_ready, ah, next_uatom);
__mark_async_thread_busy(t->at, ah);
out_unlock:
spin_unlock(&ah->lock);
}
-void __async_schedule(struct task_struct *t)
+void
+__async_schedule(struct task_struct *t, struct syslet_uatom __user *next_uatom)
{
struct async_head *ah = t->ah;
struct pt_regs *old_regs = task_pt_regs(t);
- pick_new_async_head(ah, t, old_regs);
+ pick_new_async_head(ah, t, old_regs, next_uatom);
}
-static void async_schedule(struct task_struct *t)
+static void
+async_schedule(struct task_struct *t, struct syslet_uatom __user *next_uatom)
{
if (t->async_ready)
- __async_schedule(t);
+ __async_schedule(t, next_uatom);
}
-static long __exec_atom(struct task_struct *t, struct syslet_atom *atom)
+static long __exec_atom(struct task_struct *t, struct syslet_atom *atom,
+ struct syslet_uatom __user *uatom)
{
struct async_thread *async_ready_save;
long ret;
@@ -189,8 +195,17 @@ static long __exec_atom(struct task_stru
* (try to) switch user-space to another thread straight
* away and execute the syscall asynchronously:
*/
- if (unlikely(atom->flags & SYSLET_ASYNC))
- async_schedule(t);
+ if (unlikely(atom->flags & (SYSLET_ASYNC | SYSLET_ASYNC_CONTINUE))) {
+ /*
+ * If this is a parallel (vectored) submission straight to
+ * a cachemiss context then the linearly next (uatom + 1)
+ * uatom will be executed by this context.
+ */
+ if (atom->flags & SYSLET_ASYNC_CONTINUE)
+ async_schedule(t, uatom + 1);
+ else
+ async_schedule(t, NULL);
+ }
/*
* Does user-space want synchronous execution for this atom?:
*/
@@ -432,7 +447,7 @@ exec_atom(struct async_head *ah, struct
return ERR_PTR(-EFAULT);
last_uatom = uatom;
- ret = __exec_atom(t, &atom);
+ ret = __exec_atom(t, &atom, uatom);
if (unlikely(signal_pending(t) || need_resched()))
goto stop;
Index: linux/kernel/sched.c
===================================================================
--- linux.orig/kernel/sched.c
+++ linux/kernel/sched.c
@@ -3442,7 +3442,7 @@ asmlinkage void __sched schedule(void)
if (prev->state && !(preempt_count() & PREEMPT_ACTIVE) &&
(!(prev->state & TASK_INTERRUPTIBLE) ||
!signal_pending(prev)))
- __async_schedule(prev);
+ __async_schedule(prev, NULL);
}
need_resched:
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists