public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Ingo Molnar <mingo@elte.hu>
To: linux-kernel@vger.kernel.org
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	Arjan van de Ven <arjan@infradead.org>,
	Christoph Hellwig <hch@infradead.org>,
	Andrew Morton <akpm@zip.com.au>,
	Alan Cox <alan@lxorguk.ukuu.org.uk>,
	Ulrich Drepper <drepper@redhat.com>,
	Zach Brown <zach.brown@oracle.com>,
	Evgeniy Polyakov <johnpol@2ka.mipt.ru>,
	"David S. Miller" <davem@davemloft.net>,
	Benjamin LaHaise <bcrl@kvack.org>,
	Suparna Bhattacharya <suparna@in.ibm.com>,
	Davide Libenzi <davidel@xmailserver.org>,
	Thomas Gleixner <tglx@linutronix.de>
Subject: [patch 05/11] syslets: core code
Date: Tue, 13 Feb 2007 15:20:35 +0100	[thread overview]
Message-ID: <20070213142035.GF638@elte.hu> (raw)
In-Reply-To: <20060529212109.GA2058@elte.hu>

From: Ingo Molnar <mingo@elte.hu>

the core syslet / async system calls infrastructure code.

Is built only if CONFIG_ASYNC_SUPPORT is enabled.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
 kernel/Makefile |    1 
 kernel/async.c  |  811 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 812 insertions(+)

Index: linux/kernel/Makefile
===================================================================
--- linux.orig/kernel/Makefile
+++ linux/kernel/Makefile
@@ -10,6 +10,7 @@ obj-y     = sched.o fork.o exec_domain.o
 	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
 	    hrtimer.o rwsem.o latency.o nsproxy.o srcu.o
 
+obj-$(CONFIG_ASYNC_SUPPORT) += async.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-y += time/
 obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
Index: linux/kernel/async.c
===================================================================
--- /dev/null
+++ linux/kernel/async.c
@@ -0,0 +1,811 @@
+/*
+ * kernel/async.c
+ *
+ * The syslet subsystem - asynchronous syscall execution support.
+ *
+ * Started by Ingo Molnar:
+ *
+ *  Copyright (C) 2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *
+ * This file is released under the GPLv2.
+ *
+ * This code implements asynchronous syscalls via 'syslets'.
+ *
+ * Syslets consist of a set of 'syslet atoms' which are residing
+ * purely in user-space memory and have no kernel-space resource
+ * attached to them. These atoms can be linked to each other via
+ * pointers. Besides the fundamental ability to execute system
+ * calls, syslet atoms can also implement branches, loops and
+ * arithmetics.
+ *
+ * Thus syslets can be used to build small autonomous programs that
+ * the kernel can execute purely from kernel-space, without having
+ * to return to any user-space context. Syslets can be run by any
+ * unprivileged user-space application - they are executed safely
+ * by the kernel.
+ */
+#include <linux/syscalls.h>
+#include <linux/syslet.h>
+#include <linux/delay.h>
+#include <linux/async.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+
+#include "async.h"
+
+typedef asmlinkage long (*syscall_fn_t)(long, long, long, long, long, long);
+
+extern syscall_fn_t sys_call_table[NR_syscalls];
+
+static void
+__mark_async_thread_ready(struct async_thread *at, struct async_head *ah)
+{
+	list_del(&at->entry);
+	list_add_tail(&at->entry, &ah->ready_async_threads);
+	if (list_empty(&ah->busy_async_threads))
+		wake_up(&ah->wait);
+}
+
+static void
+mark_async_thread_ready(struct async_thread *at, struct async_head *ah)
+{
+	spin_lock(&ah->lock);
+	__mark_async_thread_ready(at, ah);
+	spin_unlock(&ah->lock);
+}
+
+static void
+__mark_async_thread_busy(struct async_thread *at, struct async_head *ah)
+{
+	list_del(&at->entry);
+	list_add_tail(&at->entry, &ah->busy_async_threads);
+}
+
+static void
+mark_async_thread_busy(struct async_thread *at, struct async_head *ah)
+{
+	spin_lock(&ah->lock);
+	__mark_async_thread_busy(at, ah);
+	spin_unlock(&ah->lock);
+}
+
+static void
+__async_thread_init(struct task_struct *t, struct async_thread *at,
+		    struct async_head *ah)
+{
+	INIT_LIST_HEAD(&at->entry);
+	at->exit = 0;
+	at->task = t;
+	at->ah = ah;
+	at->work = NULL;
+
+	t->at = at;
+	ah->nr_threads++;
+}
+
+static void
+async_thread_init(struct task_struct *t, struct async_thread *at,
+		  struct async_head *ah)
+{
+	spin_lock(&ah->lock);
+	__async_thread_init(t, at, ah);
+	__mark_async_thread_ready(at, ah);
+	spin_unlock(&ah->lock);
+}
+
+
+static void
+async_thread_exit(struct async_thread *at, struct task_struct *t)
+{
+	struct async_head *ah;
+
+	ah = at->ah;
+
+	spin_lock(&ah->lock);
+	list_del_init(&at->entry);
+	if (at->exit)
+		complete(&ah->exit_done);
+	t->at = NULL;
+	at->task = NULL;
+	WARN_ON(!ah->nr_threads);
+	ah->nr_threads--;
+	spin_unlock(&ah->lock);
+}
+
+static struct async_thread *
+pick_ready_cachemiss_thread(struct async_head *ah)
+{
+	struct list_head *head = &ah->ready_async_threads;
+	struct async_thread *at;
+
+	if (list_empty(head))
+		return NULL;
+
+	at = list_entry(head->next, struct async_thread, entry);
+
+	return at;
+}
+
+static void pick_new_async_head(struct async_head *ah,
+				struct task_struct *t, struct pt_regs *old_regs)
+{
+	struct async_thread *new_async_thread;
+	struct async_thread *async_ready;
+	struct task_struct *new_task;
+	struct pt_regs *new_regs;
+
+	spin_lock(&ah->lock);
+
+	new_async_thread = pick_ready_cachemiss_thread(ah);
+	if (!new_async_thread)
+		goto out_unlock;
+
+	async_ready = t->async_ready;
+	WARN_ON(!async_ready);
+	t->async_ready = NULL;
+
+	new_task = new_async_thread->task;
+	new_regs = task_pt_regs(new_task);
+	*new_regs = *old_regs;
+
+	new_task->at = NULL;
+	t->ah = NULL;
+	new_task->ah = ah;
+
+	wake_up_process(new_task);
+
+	__async_thread_init(t, async_ready, ah);
+	__mark_async_thread_busy(t->at, ah);
+
+ out_unlock:
+	spin_unlock(&ah->lock);
+}
+
+void __async_schedule(struct task_struct *t)
+{
+	struct async_head *ah = t->ah;
+	struct pt_regs *old_regs = task_pt_regs(t);
+
+	pick_new_async_head(ah, t, old_regs);
+}
+
+static void async_schedule(struct task_struct *t)
+{
+	if (t->async_ready)
+		__async_schedule(t);
+}
+
+static long __exec_atom(struct task_struct *t, struct syslet_atom *atom)
+{
+	struct async_thread *async_ready_save;
+	long ret;
+
+	/*
+	 * If user-space expects the syscall to schedule then
+	 * (try to) switch user-space to another thread straight
+	 * away and execute the syscall asynchronously:
+	 */
+	if (unlikely(atom->flags & SYSLET_ASYNC))
+		async_schedule(t);
+	/*
+	 * Does user-space want synchronous execution for this atom?:
+	 */
+	async_ready_save = t->async_ready;
+	if (unlikely(atom->flags & SYSLET_SYNC))
+		t->async_ready = NULL;
+
+	if (unlikely(atom->nr >= NR_syscalls))
+		return -ENOSYS;
+
+	ret = sys_call_table[atom->nr](atom->args[0], atom->args[1],
+				       atom->args[2], atom->args[3],
+				       atom->args[4], atom->args[5]);
+	if (atom->ret_ptr && put_user(ret, atom->ret_ptr))
+		return -EFAULT;
+
+	if (t->ah)
+		t->async_ready = async_ready_save;
+
+	return ret;
+}
+
+/*
+ * Arithmetics syscall, add a value to a user-space memory location.
+ *
+ * Generic C version - in case the architecture has not implemented it
+ * in assembly.
+ */
+asmlinkage __attribute__((weak)) long
+sys_umem_add(unsigned long __user *uptr, unsigned long inc)
+{
+	unsigned long val, new_val;
+
+	if (get_user(val, uptr))
+		return -EFAULT;
+	/*
+	 * inc == 0 means 'read memory value':
+	 */
+	if (!inc)
+		return val;
+
+	new_val = val + inc;
+	__put_user(new_val, uptr);
+
+	return new_val;
+}
+
+/*
+ * Open-coded because this is a very hot codepath during syslet
+ * execution and every cycle counts ...
+ *
+ * [ NOTE: it's an explicit fastcall because optimized assembly code
+ *   might depend on this. There are some kernels that disable regparm,
+ *   so lets not break those if possible. ]
+ */
+fastcall __attribute__((weak)) long
+copy_uatom(struct syslet_atom *atom, struct syslet_uatom __user *uatom)
+{
+	unsigned long __user *arg_ptr;
+	long ret = 0;
+
+	if (!access_ok(VERIFY_WRITE, uatom, sizeof(*uatom)))
+		return -EFAULT;
+
+	ret = __get_user(atom->nr, &uatom->nr);
+	ret |= __get_user(atom->ret_ptr, &uatom->ret_ptr);
+	ret |= __get_user(atom->flags, &uatom->flags);
+	ret |= __get_user(atom->next, &uatom->next);
+
+	memset(atom->args, 0, sizeof(atom->args));
+
+	ret |= __get_user(arg_ptr, &uatom->arg_ptr[0]);
+	if (!arg_ptr)
+		return ret;
+	if (!access_ok(VERIFY_WRITE, arg_ptr, sizeof(*arg_ptr)))
+		return -EFAULT;
+	ret |= __get_user(atom->args[0], arg_ptr);
+
+	ret |= __get_user(arg_ptr, &uatom->arg_ptr[1]);
+	if (!arg_ptr)
+		return ret;
+	if (!access_ok(VERIFY_WRITE, arg_ptr, sizeof(*arg_ptr)))
+		return -EFAULT;
+	ret |= __get_user(atom->args[1], arg_ptr);
+
+	ret |= __get_user(arg_ptr, &uatom->arg_ptr[2]);
+	if (!arg_ptr)
+		return ret;
+	if (!access_ok(VERIFY_WRITE, arg_ptr, sizeof(*arg_ptr)))
+		return -EFAULT;
+	ret |= __get_user(atom->args[2], arg_ptr);
+
+	ret |= __get_user(arg_ptr, &uatom->arg_ptr[3]);
+	if (!arg_ptr)
+		return ret;
+	if (!access_ok(VERIFY_WRITE, arg_ptr, sizeof(*arg_ptr)))
+		return -EFAULT;
+	ret |= __get_user(atom->args[3], arg_ptr);
+
+	ret |= __get_user(arg_ptr, &uatom->arg_ptr[4]);
+	if (!arg_ptr)
+		return ret;
+	if (!access_ok(VERIFY_WRITE, arg_ptr, sizeof(*arg_ptr)))
+		return -EFAULT;
+	ret |= __get_user(atom->args[4], arg_ptr);
+
+	ret |= __get_user(arg_ptr, &uatom->arg_ptr[5]);
+	if (!arg_ptr)
+		return ret;
+	if (!access_ok(VERIFY_WRITE, arg_ptr, sizeof(*arg_ptr)))
+		return -EFAULT;
+	ret |= __get_user(atom->args[5], arg_ptr);
+
+	return ret;
+}
+
+/*
+ * Should the next atom run, depending on the return value of
+ * the current atom - or should we stop execution?
+ */
+static int run_next_atom(struct syslet_atom *atom, long ret)
+{
+	switch (atom->flags & SYSLET_STOP_MASK) {
+		case SYSLET_STOP_ON_NONZERO:
+			if (!ret)
+				return 1;
+			return 0;
+		case SYSLET_STOP_ON_ZERO:
+			if (ret)
+				return 1;
+			return 0;
+		case SYSLET_STOP_ON_NEGATIVE:
+			if (ret >= 0)
+				return 1;
+			return 0;
+		case SYSLET_STOP_ON_NON_POSITIVE:
+			if (ret > 0)
+				return 1;
+			return 0;
+	}
+	return 1;
+}
+
+static struct syslet_uatom __user *
+next_uatom(struct syslet_atom *atom, struct syslet_uatom *uatom, long ret)
+{
+	/*
+	 * If the stop condition is false then continue
+	 * to atom->next:
+	 */
+	if (run_next_atom(atom, ret))
+		return atom->next;
+	/*
+	 * Special-case: if the stop condition is true and the atom
+	 * has SKIP_TO_NEXT_ON_STOP set, then instead of
+	 * stopping we skip to the atom directly after this atom
+	 * (in linear address-space).
+	 *
+	 * This, combined with the atom->next pointer and the
+	 * stop condition flags is what allows true branches and
+	 * loops in syslets:
+	 */
+	if (atom->flags & SYSLET_SKIP_TO_NEXT_ON_STOP)
+		return uatom + 1;
+
+	return NULL;
+}
+
+/*
+ * If user-space requested a completion event then put the last
+ * executed uatom into the completion ring:
+ */
+static long
+complete_uatom(struct async_head *ah, struct task_struct *t,
+	       struct syslet_atom *atom, struct syslet_uatom __user *uatom)
+{
+	struct syslet_uatom __user **ring_slot, *slot_val = NULL;
+	long ret;
+
+	WARN_ON(!t->at);
+	WARN_ON(t->ah);
+
+	if (unlikely(atom->flags & SYSLET_NO_COMPLETE))
+		return 0;
+
+	/*
+	 * Asynchron threads can complete in parallel so use the
+	 * head-lock to serialize:
+	 */
+	spin_lock(&ah->lock);
+	ring_slot = ah->completion_ring + ah->curr_ring_idx;
+	ret = __copy_from_user_inatomic(&slot_val, ring_slot, sizeof(slot_val));
+	/*
+	 * User-space submitted more work than what fits into the
+	 * completion ring - do not stomp over it silently and signal
+	 * the error condition:
+	 */
+	if (unlikely(slot_val)) {
+		spin_unlock(&ah->lock);
+		return -EFAULT;
+	}
+	slot_val = uatom;
+	ret |= __copy_to_user_inatomic(ring_slot, &slot_val, sizeof(slot_val));
+
+	ah->curr_ring_idx++;
+	if (unlikely(ah->curr_ring_idx == ah->max_ring_idx))
+		ah->curr_ring_idx = 0;
+
+	/*
+	 * See whether the async-head is waiting and needs a wakeup:
+	 */
+	if (ah->events_left) {
+		ah->events_left--;
+		if (!ah->events_left)
+			wake_up(&ah->wait);
+	}
+
+	spin_unlock(&ah->lock);
+
+	return ret;
+}
+
+/*
+ * This is the main syslet atom execution loop. This fetches atoms
+ * and executes them until it runs out of atoms or until the
+ * exit condition becomes false:
+ */
+static struct syslet_uatom __user *
+exec_atom(struct async_head *ah, struct task_struct *t,
+	  struct syslet_uatom __user *uatom)
+{
+	struct syslet_uatom __user *last_uatom;
+	struct syslet_atom atom;
+	long ret;
+
+ run_next:
+	if (unlikely(copy_uatom(&atom, uatom)))
+		return ERR_PTR(-EFAULT);
+
+	last_uatom = uatom;
+	ret = __exec_atom(t, &atom);
+	if (unlikely(signal_pending(t) || need_resched()))
+		goto stop;
+
+	uatom = next_uatom(&atom, uatom, ret);
+	if (uatom)
+		goto run_next;
+ stop:
+	/*
+	 * We do completion only in async context:
+	 */
+	if (t->at && complete_uatom(ah, t, &atom, last_uatom))
+		return ERR_PTR(-EFAULT);
+
+	return last_uatom;
+}
+
+static void cachemiss_execute(struct async_thread *at, struct async_head *ah,
+			      struct task_struct *t)
+{
+	struct syslet_uatom __user *uatom;
+
+	uatom = at->work;
+	WARN_ON(!uatom);
+	at->work = NULL;
+
+	exec_atom(ah, t, uatom);
+}
+
+static void
+cachemiss_loop(struct async_thread *at, struct async_head *ah,
+	       struct task_struct *t)
+{
+	for (;;) {
+		schedule();
+		mark_async_thread_busy(at, ah);
+		set_task_state(t, TASK_INTERRUPTIBLE);
+		if (at->work)
+			cachemiss_execute(at, ah, t);
+		if (unlikely(t->ah || at->exit || signal_pending(t)))
+			break;
+		mark_async_thread_ready(at, ah);
+	}
+	t->state = TASK_RUNNING;
+
+	async_thread_exit(at, t);
+}
+
+static int cachemiss_thread(void *data)
+{
+	struct task_struct *t = current;
+	struct async_head *ah = data;
+	struct async_thread at;
+
+	async_thread_init(t, &at, ah);
+	complete(&ah->start_done);
+
+	cachemiss_loop(&at, ah, t);
+	if (at.exit)
+		do_exit(0);
+
+	if (!t->ah && signal_pending(t)) {
+		WARN_ON(1);
+		do_exit(0);
+	}
+
+	/*
+	 * Return to user-space with NULL:
+	 */
+	return 0;
+}
+
+static void __notify_async_thread_exit(struct async_thread *at,
+				       struct async_head *ah)
+{
+	list_del_init(&at->entry);
+	at->exit = 1;
+	init_completion(&ah->exit_done);
+	wake_up_process(at->task);
+}
+
+static void stop_cachemiss_threads(struct async_head *ah)
+{
+	struct async_thread *at;
+
+repeat:
+	spin_lock(&ah->lock);
+	list_for_each_entry(at, &ah->ready_async_threads, entry) {
+
+		__notify_async_thread_exit(at, ah);
+		spin_unlock(&ah->lock);
+
+		wait_for_completion(&ah->exit_done);
+
+		goto repeat;
+	}
+
+	list_for_each_entry(at, &ah->busy_async_threads, entry) {
+
+		__notify_async_thread_exit(at, ah);
+		spin_unlock(&ah->lock);
+
+		wait_for_completion(&ah->exit_done);
+
+		goto repeat;
+	}
+	spin_unlock(&ah->lock);
+}
+
+static void async_head_exit(struct async_head *ah, struct task_struct *t)
+{
+	stop_cachemiss_threads(ah);
+	WARN_ON(!list_empty(&ah->ready_async_threads));
+	WARN_ON(!list_empty(&ah->busy_async_threads));
+	WARN_ON(ah->nr_threads);
+	WARN_ON(spin_is_locked(&ah->lock));
+	kfree(ah);
+	t->ah = NULL;
+}
+
+/*
+ * Pretty arbitrary for now. The kernel resource-controls the number
+ * of threads anyway.
+ */
+#define DEFAULT_THREAD_LIMIT 1024
+
+/*
+ * Initialize the in-kernel async head, based on the user-space async
+ * head:
+ */
+static long
+async_head_init(struct task_struct *t, struct async_head_user __user *uah)
+{
+	unsigned long max_nr_threads, ring_size_bytes, max_ring_idx;
+	struct syslet_uatom __user **completion_ring;
+	struct async_head *ah;
+	long ret;
+
+	if (get_user(max_nr_threads, &uah->max_nr_threads))
+		return -EFAULT;
+	if (get_user(completion_ring, &uah->completion_ring))
+		return -EFAULT;
+	if (get_user(ring_size_bytes, &uah->ring_size_bytes))
+		return -EFAULT;
+	if (!ring_size_bytes)
+		return -EINVAL;
+	/*
+	 * We pre-check the ring pointer, so that in the fastpath
+	 * we can use __put_user():
+	 */
+	if (!access_ok(VERIFY_WRITE, completion_ring, ring_size_bytes))
+		return -EFAULT;
+
+	max_ring_idx = ring_size_bytes / sizeof(void *);
+	if (ring_size_bytes != max_ring_idx * sizeof(void *))
+		return -EINVAL;
+
+	/*
+	 * Lock down the ring. Note: user-space should not munlock() this,
+	 * because if the ring pages get swapped out then the async
+	 * completion code might return a -EFAULT instead of the expected
+	 * completion. (the kernel safely handles that case too, so this
+	 * isnt a security problem.)
+	 *
+	 * mlock() is better here because it gets resource-accounted
+	 * properly, and even unprivileged userspace has a few pages
+	 * of mlock-able memory available. (which is more than enough
+	 * for the completion-pointers ringbuffer)
+	 */
+	ret = sys_mlock((unsigned long)completion_ring, ring_size_bytes);
+	if (ret)
+		return ret;
+
+	/*
+	 * -1 means: the kernel manages the optimal size of the async pool.
+	 * Simple static limit for now.
+	 */
+	if (max_nr_threads == -1UL)
+		max_nr_threads = DEFAULT_THREAD_LIMIT;
+	/*
+	 * If the ring is smaller than the number of threads requested
+	 * then lower the thread count - otherwise we might lose
+	 * syslet completion events:
+	 */
+	max_nr_threads = min(max_ring_idx, max_nr_threads);
+
+	ah = kmalloc(sizeof(*ah), GFP_KERNEL);
+	if (!ah)
+		return -ENOMEM;
+
+	spin_lock_init(&ah->lock);
+	ah->nr_threads = 0;
+	ah->max_nr_threads = max_nr_threads;
+	INIT_LIST_HEAD(&ah->ready_async_threads);
+	INIT_LIST_HEAD(&ah->busy_async_threads);
+	init_waitqueue_head(&ah->wait);
+	ah->events_left = 0;
+	ah->uah = uah;
+	ah->curr_ring_idx = 0;
+	ah->max_ring_idx = max_ring_idx;
+	ah->completion_ring = completion_ring;
+	ah->ring_size_bytes = ring_size_bytes;
+
+	ah->user_task = t;
+	t->ah = ah;
+
+	return 0;
+}
+
+/**
+ * sys_async_register - enable async syscall support
+ */
+asmlinkage long
+sys_async_register(struct async_head_user __user *uah, unsigned int len)
+{
+	struct task_struct *t = current;
+
+	/*
+	 * This 'len' check enables future extension of
+	 * the async_head ABI:
+	 */
+	if (len != sizeof(struct async_head_user))
+		return -EINVAL;
+	/*
+	 * Already registered?
+	 */
+	if (t->ah)
+		return -EEXIST;
+
+	return async_head_init(t, uah);
+}
+
+/**
+ * sys_async_unregister - disable async syscall support
+ */
+asmlinkage long
+sys_async_unregister(struct async_head_user __user *uah, unsigned int len)
+{
+	struct syslet_uatom __user **completion_ring;
+	struct task_struct *t = current;
+	struct async_head *ah = t->ah;
+	unsigned long ring_size_bytes;
+
+	if (len != sizeof(struct async_head_user))
+		return -EINVAL;
+	/*
+	 * Already unregistered?
+	 */
+	if (!ah)
+		return -EINVAL;
+
+	completion_ring = ah->completion_ring;
+	ring_size_bytes = ah->ring_size_bytes;
+
+	async_head_exit(ah, t);
+
+	/*
+	 * Unpin the ring:
+	 */
+	return sys_munlock((unsigned long)completion_ring, ring_size_bytes);
+}
+
+/*
+ * Simple limit and pool management mechanism for now:
+ */
+static void refill_cachemiss_pool(struct async_head *ah)
+{
+	int pid;
+
+	if (ah->nr_threads >= ah->max_nr_threads)
+		return;
+
+	init_completion(&ah->start_done);
+
+	pid = create_async_thread(cachemiss_thread, (void *)ah,
+			   CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+			   CLONE_PTRACE | CLONE_THREAD | CLONE_SYSVSEM);
+	if (pid < 0)
+		return;
+
+	wait_for_completion(&ah->start_done);
+}
+
+/**
+ * sys_async_wait - wait for async completion events
+ *
+ * This syscall waits for @min_wait_events syslet completion events
+ * to finish or for all async processing to finish (whichever
+ * comes first).
+ */
+asmlinkage long sys_async_wait(unsigned long min_wait_events)
+{
+	struct async_head *ah = current->ah;
+
+	if (!ah)
+		return -EINVAL;
+
+	if (min_wait_events) {
+		spin_lock(&ah->lock);
+		ah->events_left = min_wait_events;
+		spin_unlock(&ah->lock);
+	}
+
+	return wait_event_interruptible(ah->wait,
+		list_empty(&ah->busy_async_threads) || !ah->events_left);
+}
+
+/**
+ * sys_async_exec - execute a syslet.
+ *
+ * returns the uatom that was last executed, if the kernel was able to
+ * execute the syslet synchronously, or NULL if the syslet became
+ * asynchronous. (in the latter case syslet completion will be notified
+ * via the completion ring)
+ *
+ * (Various errors might also be returned via the usual negative numbers.)
+ */
+asmlinkage struct syslet_uatom __user *
+sys_async_exec(struct syslet_uatom __user *uatom)
+{
+	struct syslet_uatom __user *ret;
+	struct task_struct *t = current;
+	struct async_head *ah = t->ah;
+	struct async_thread at;
+
+	if (unlikely(!ah))
+		return ERR_PTR(-EINVAL);
+
+	if (list_empty(&ah->ready_async_threads))
+		refill_cachemiss_pool(ah);
+
+	t->async_ready = &at;
+	ret = exec_atom(ah, t, uatom);
+
+	if (t->ah) {
+		WARN_ON(!t->async_ready);
+		t->async_ready = NULL;
+		return ret;
+	}
+	ret = ERR_PTR(-EINTR);
+	if (!at.exit && !signal_pending(t)) {
+		set_task_state(t, TASK_INTERRUPTIBLE);
+		mark_async_thread_ready(&at, ah);
+		cachemiss_loop(&at, ah, t);
+	}
+	if (t->ah)
+		return NULL;
+	else
+		do_exit(0);
+}
+
+/*
+ * fork()-time initialization:
+ */
+void async_init(struct task_struct *t)
+{
+	t->at = NULL;
+	t->async_ready = NULL;
+	t->ah = NULL;
+}
+
+/*
+ * do_exit()-time cleanup:
+ */
+void async_exit(struct task_struct *t)
+{
+	struct async_thread *at = t->at;
+	struct async_head *ah = t->ah;
+
+	WARN_ON(at && ah);
+	WARN_ON(t->async_ready);
+
+	if (unlikely(at))
+		async_thread_exit(at, t);
+
+	if (unlikely(ah))
+		async_head_exit(ah, t);
+}

  parent reply	other threads:[~2007-02-13 14:24 UTC|newest]

Thread overview: 320+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-05-29 21:21 [patch 00/61] ANNOUNCE: lock validator -V1 Ingo Molnar
2006-05-29 21:22 ` [patch 01/61] lock validator: floppy.c irq-release fix Ingo Molnar
2006-05-30  1:32   ` Andrew Morton
2006-05-29 21:23 ` [patch 02/61] lock validator: forcedeth.c fix Ingo Molnar
2006-05-30  1:33   ` Andrew Morton
2006-05-31  5:40     ` Manfred Spraul
2006-05-29 21:23 ` [patch 03/61] lock validator: sound/oss/emu10k1/midi.c cleanup Ingo Molnar
2006-05-30  1:33   ` Andrew Morton
2006-05-30 10:51     ` Takashi Iwai
2006-05-30 11:03       ` Alexey Dobriyan
2006-05-29 21:23 ` [patch 04/61] lock validator: mutex section binutils workaround Ingo Molnar
2006-05-29 21:23 ` [patch 05/61] lock validator: introduce WARN_ON_ONCE(cond) Ingo Molnar
2006-05-30  1:33   ` Andrew Morton
2006-05-30 17:38     ` Steven Rostedt
2006-06-03 18:09       ` Steven Rostedt
2006-06-04  9:18         ` Arjan van de Ven
2006-06-04 13:43           ` Steven Rostedt
2006-05-29 21:23 ` [patch 06/61] lock validator: add __module_address() method Ingo Molnar
2006-05-30  1:33   ` Andrew Morton
2006-05-30 17:45     ` Steven Rostedt
2006-06-23  8:38     ` Ingo Molnar
2006-05-29 21:23 ` [patch 07/61] lock validator: better lock debugging Ingo Molnar
2006-05-30  1:33   ` Andrew Morton
2006-06-23 10:25     ` Ingo Molnar
2006-06-23 11:06       ` Andrew Morton
2006-06-23 11:04         ` Ingo Molnar
2006-05-29 21:23 ` [patch 08/61] lock validator: locking API self-tests Ingo Molnar
2006-05-29 21:23 ` [patch 09/61] lock validator: spin/rwlock init cleanups Ingo Molnar
2006-05-29 21:23 ` [patch 10/61] lock validator: locking init debugging improvement Ingo Molnar
2006-05-29 21:23 ` [patch 11/61] lock validator: lockdep: small xfs init_rwsem() cleanup Ingo Molnar
2006-05-30  1:33   ` Andrew Morton
2006-05-30  1:32     ` Nathan Scott
2006-05-29 21:24 ` [patch 12/61] lock validator: beautify x86_64 stacktraces Ingo Molnar
2006-05-30  1:33   ` Andrew Morton
2006-05-29 21:24 ` [patch 13/61] lock validator: x86_64: document stack frame internals Ingo Molnar
2006-05-29 21:24 ` [patch 14/61] lock validator: stacktrace Ingo Molnar
2006-05-29 21:24 ` [patch 15/61] lock validator: x86_64: use stacktrace to generate backtraces Ingo Molnar
2006-05-30  1:33   ` Andrew Morton
2006-05-29 21:24 ` [patch 16/61] lock validator: fown locking workaround Ingo Molnar
2006-05-30  1:34   ` Andrew Morton
2006-06-23  9:10     ` Ingo Molnar
2006-05-29 21:24 ` [patch 17/61] lock validator: sk_callback_lock workaround Ingo Molnar
2006-05-30  1:34   ` Andrew Morton
2006-06-23  9:19     ` Ingo Molnar
2006-05-29 21:24 ` [patch 18/61] lock validator: irqtrace: core Ingo Molnar
2006-05-30  1:34   ` Andrew Morton
2006-06-23 10:42     ` Ingo Molnar
2006-05-29 21:24 ` [patch 19/61] lock validator: irqtrace: cleanup: include/asm-i386/irqflags.h Ingo Molnar
2006-05-29 21:24 ` [patch 20/61] lock validator: irqtrace: cleanup: include/asm-x86_64/irqflags.h Ingo Molnar
2006-05-29 21:24 ` [patch 21/61] lock validator: lockdep: add local_irq_enable_in_hardirq() API Ingo Molnar
2006-05-30  1:34   ` Andrew Morton
2006-06-23  9:28     ` Ingo Molnar
2006-06-23  9:52       ` Andrew Morton
2006-06-23 10:20         ` Ingo Molnar
2006-05-29 21:24 ` [patch 22/61] lock validator: add per_cpu_offset() Ingo Molnar
2006-05-30  1:34   ` Andrew Morton
2006-06-23  9:30     ` Ingo Molnar
2006-05-29 21:25 ` [patch 23/61] lock validator: core Ingo Molnar
2006-05-29 21:25 ` [patch 24/61] lock validator: procfs Ingo Molnar
2006-05-29 21:25 ` [patch 25/61] lock validator: design docs Ingo Molnar
2006-05-30  9:07   ` Nikita Danilov
2006-05-29 21:25 ` [patch 26/61] lock validator: prove rwsem locking correctness Ingo Molnar
2006-05-29 21:25 ` [patch 27/61] lock validator: prove spinlock/rwlock " Ingo Molnar
2006-05-30  1:35   ` Andrew Morton
2006-06-23 10:44     ` Ingo Molnar
2006-05-29 21:25 ` [patch 28/61] lock validator: prove mutex " Ingo Molnar
2006-05-29 21:25 ` [patch 29/61] lock validator: print all lock-types on SysRq-D Ingo Molnar
2006-05-29 21:25 ` [patch 30/61] lock validator: x86_64 early init Ingo Molnar
2006-05-29 21:25 ` [patch 31/61] lock validator: SMP alternatives workaround Ingo Molnar
2006-05-29 21:25 ` [patch 32/61] lock validator: do not recurse in printk() Ingo Molnar
2006-05-29 21:25 ` [patch 33/61] lock validator: disable NMI watchdog if CONFIG_LOCKDEP Ingo Molnar
2006-05-29 22:49   ` Keith Owens
2006-05-29 21:25 ` [patch 34/61] lock validator: special locking: bdev Ingo Molnar
2006-05-30  1:35   ` Andrew Morton
2006-05-30  5:13     ` Arjan van de Ven
2006-05-30  9:58     ` Al Viro
2006-05-30 10:45     ` Arjan van de Ven
2006-05-29 21:25 ` [patch 35/61] lock validator: special locking: direct-IO Ingo Molnar
2006-05-29 21:26 ` [patch 36/61] lock validator: special locking: serial Ingo Molnar
2006-05-30  1:35   ` Andrew Morton
2006-06-23  9:49     ` Ingo Molnar
2006-06-23 10:04       ` Andrew Morton
2006-06-23 10:18         ` Ingo Molnar
2006-05-29 21:26 ` [patch 37/61] lock validator: special locking: dcache Ingo Molnar
2006-05-30  1:35   ` Andrew Morton
2006-05-30 20:51     ` Steven Rostedt
2006-05-30 21:01       ` Ingo Molnar
2006-06-23  9:51       ` Ingo Molnar
2006-05-29 21:26 ` [patch 38/61] lock validator: special locking: i_mutex Ingo Molnar
2006-05-30 20:53   ` Steven Rostedt
2006-05-30 21:06     ` Ingo Molnar
2006-05-29 21:26 ` [patch 39/61] lock validator: special locking: s_lock Ingo Molnar
2006-05-29 21:26 ` [patch 40/61] lock validator: special locking: futex Ingo Molnar
2006-05-29 21:26 ` [patch 41/61] lock validator: special locking: genirq Ingo Molnar
2006-05-29 21:26 ` [patch 42/61] lock validator: special locking: kgdb Ingo Molnar
2006-05-29 21:26 ` [patch 43/61] lock validator: special locking: completions Ingo Molnar
2006-05-29 21:26 ` [patch 44/61] lock validator: special locking: waitqueues Ingo Molnar
2006-05-29 21:26 ` [patch 45/61] lock validator: special locking: mm Ingo Molnar
2006-05-29 21:26 ` [patch 46/61] lock validator: special locking: slab Ingo Molnar
2006-05-30  1:35   ` Andrew Morton
2006-06-23  9:54     ` Ingo Molnar
2006-05-29 21:26 ` [patch 47/61] lock validator: special locking: skb_queue_head_init() Ingo Molnar
2006-05-29 21:26 ` [patch 48/61] lock validator: special locking: timer.c Ingo Molnar
2006-05-29 21:27 ` [patch 49/61] lock validator: special locking: sched.c Ingo Molnar
2006-05-29 21:27 ` [patch 50/61] lock validator: special locking: hrtimer.c Ingo Molnar
2006-05-30  1:35   ` Andrew Morton
2006-06-23 10:04     ` Ingo Molnar
2006-06-23 10:38       ` Andrew Morton
2006-06-23 10:52         ` Ingo Molnar
2006-06-23 11:52           ` Ingo Molnar
2006-06-23 12:06             ` Andrew Morton
2006-05-29 21:27 ` [patch 51/61] lock validator: special locking: sock_lock_init() Ingo Molnar
2006-05-30  1:36   ` Andrew Morton
2006-06-23 10:06     ` Ingo Molnar
2006-05-29 21:27 ` [patch 52/61] lock validator: special locking: af_unix Ingo Molnar
2006-05-30  1:36   ` Andrew Morton
2006-06-23 10:07     ` Ingo Molnar
2006-05-29 21:27 ` [patch 53/61] lock validator: special locking: bh_lock_sock() Ingo Molnar
2006-05-29 21:27 ` [patch 54/61] lock validator: special locking: mmap_sem Ingo Molnar
2006-05-29 21:27 ` [patch 55/61] lock validator: special locking: sb->s_umount Ingo Molnar
2006-05-30  1:36   ` Andrew Morton
2006-06-23 10:55     ` Ingo Molnar
2006-05-29 21:27 ` [patch 56/61] lock validator: special locking: jbd Ingo Molnar
2006-05-29 21:27 ` [patch 57/61] lock validator: special locking: posix-timers Ingo Molnar
2006-05-29 21:27 ` [patch 58/61] lock validator: special locking: sch_generic.c Ingo Molnar
2006-05-29 21:27 ` [patch 59/61] lock validator: special locking: xfrm Ingo Molnar
2006-05-30  1:36   ` Andrew Morton
2006-05-29 21:27 ` [patch 60/61] lock validator: special locking: sound/core/seq/seq_ports.c Ingo Molnar
2006-05-29 21:28 ` [patch 61/61] lock validator: enable lock validator in Kconfig Ingo Molnar
2006-05-30  1:36   ` Andrew Morton
2006-05-30 13:33   ` Roman Zippel
2006-06-23 11:01     ` Ingo Molnar
2006-06-26 11:37       ` Roman Zippel
2006-05-29 22:28 ` [patch 00/61] ANNOUNCE: lock validator -V1 Michal Piotrowski
2006-05-29 22:41   ` Ingo Molnar
2006-05-29 23:09     ` Dave Jones
2006-05-30  5:45       ` Arjan van de Ven
2006-05-30  6:07         ` Michal Piotrowski
2006-05-30 14:10         ` Dave Jones
2006-05-30 14:19           ` Arjan van de Ven
2006-05-30 14:58             ` Dave Jones
2006-05-30 17:11               ` Dominik Brodowski
2006-05-30 19:02                 ` Dave Jones
2006-05-30 19:25                   ` Roland Dreier
2006-05-30 19:34                     ` Dave Jones
2006-05-30 20:41                     ` Ingo Molnar
2006-05-30 20:44                       ` Ingo Molnar
2006-05-30 21:58                       ` Paolo Ciarrocchi
2006-05-31  8:40                         ` Ingo Molnar
2006-05-30 19:39                 ` Dave Jones
2006-05-30 19:53                   ` Ashok Raj
2006-06-01  5:50                     ` Nathan Lynch
2006-05-30 20:54         ` [patch, -rc5-mm1] lock validator: select KALLSYMS_ALL Ingo Molnar
2006-05-30  5:52       ` [patch 00/61] ANNOUNCE: lock validator -V1 Michal Piotrowski
2006-05-30  5:20   ` Arjan van de Ven
2006-05-30  1:35 ` Andrew Morton
2006-06-23  9:41   ` Ingo Molnar
2006-05-30  4:52 ` Mike Galbraith
2006-05-30  6:20   ` Arjan van de Ven
2006-05-30  6:35   ` Arjan van de Ven
2006-05-30  7:47     ` Ingo Molnar
2006-05-30  6:37   ` Ingo Molnar
2006-05-30  9:25     ` Mike Galbraith
2006-05-30 10:57       ` Ingo Molnar
2006-05-30  9:14 ` Benoit Boissinot
2006-05-30 10:26   ` Arjan van de Ven
2006-05-30 11:42     ` Benoit Boissinot
2006-05-30 12:13       ` Ingo Molnar
2006-06-01 14:42   ` [patch mm1-rc2] lock validator: netlink.c netlink_table_grab fix Frederik Deweerdt
2006-06-02  3:10     ` Zhu Yi
2006-06-02  9:53       ` Frederik Deweerdt
2006-06-05  3:40         ` Zhu Yi
2007-02-13 14:20 ` [patch 00/11] ANNOUNCE: "Syslets", generic asynchronous system call support Ingo Molnar
2007-02-13 15:00   ` Alan
2007-02-13 14:58     ` Benjamin LaHaise
2007-02-13 15:09       ` Arjan van de Ven
2007-02-13 16:24       ` bert hubert
2007-02-13 16:56       ` Ingo Molnar
2007-02-13 18:56         ` Evgeniy Polyakov
2007-02-13 19:12           ` Evgeniy Polyakov
2007-02-13 22:19             ` Ingo Molnar
2007-02-13 22:18           ` Ingo Molnar
2007-02-14  8:59             ` Evgeniy Polyakov
2007-02-14 10:37               ` Ingo Molnar
2007-02-14 11:10                 ` Evgeniy Polyakov
2007-02-14 17:17                 ` Davide Libenzi
2007-02-13 20:34       ` Ingo Molnar
2007-02-13 15:46     ` Dmitry Torokhov
2007-02-13 20:39       ` Ingo Molnar
2007-02-13 22:36         ` Dmitry Torokhov
2007-02-14 11:07         ` Alan
2007-02-13 16:39     ` Andi Kleen
2007-02-13 16:26       ` Linus Torvalds
2007-02-13 17:03         ` Ingo Molnar
2007-02-13 20:26         ` Davide Libenzi
2007-02-13 16:49       ` Ingo Molnar
2007-02-13 16:42     ` Ingo Molnar
2007-02-13 20:22   ` Davide Libenzi
2007-02-13 21:24     ` Davide Libenzi
2007-02-13 22:10       ` Ingo Molnar
2007-02-13 23:28         ` Davide Libenzi
2007-02-13 21:57     ` Ingo Molnar
2007-02-13 22:50       ` Olivier Galibert
2007-02-13 22:59       ` Ulrich Drepper
2007-02-13 23:24       ` Davide Libenzi
2007-02-13 23:25       ` Andi Kleen
2007-02-13 22:26         ` Ingo Molnar
2007-02-13 22:32           ` Andi Kleen
2007-02-13 22:43             ` Ingo Molnar
2007-02-13 22:47               ` Andi Kleen
2007-02-14  3:28   ` Davide Libenzi
2007-02-14  4:49     ` Davide Libenzi
2007-02-14  8:26       ` Ingo Molnar
2007-02-14  4:42   ` Willy Tarreau
2007-02-14 12:37   ` Pavel Machek
2007-02-14 17:14     ` Linus Torvalds
2007-02-14 20:52   ` Jeremy Fitzhardinge
2007-02-14 21:36     ` Davide Libenzi
2007-02-15  0:08       ` Jeremy Fitzhardinge
2007-02-15  2:07         ` Davide Libenzi
2007-02-15  2:44   ` Zach Brown
2007-02-13 14:20 ` [patch 01/11] syslets: add async.h include file, kernel-side API definitions Ingo Molnar
2007-02-13 14:20 ` [patch 02/11] syslets: add syslet.h include file, user API/ABI definitions Ingo Molnar
2007-02-13 20:17   ` Indan Zupancic
2007-02-13 21:43     ` Ingo Molnar
2007-02-13 22:24       ` Indan Zupancic
2007-02-13 22:32         ` Ingo Molnar
2007-02-19  0:22   ` Paul Mackerras
2007-02-13 14:20 ` [patch 03/11] syslets: generic kernel bits Ingo Molnar
2007-02-13 14:20 ` [patch 04/11] syslets: core, data structures Ingo Molnar
2007-02-13 14:20 ` Ingo Molnar [this message]
2007-02-13 23:15   ` [patch 05/11] syslets: core code Andi Kleen
2007-02-13 22:24     ` Ingo Molnar
2007-02-13 22:30       ` Andi Kleen
2007-02-13 22:41         ` Ingo Molnar
2007-02-14  9:13           ` Evgeniy Polyakov
2007-02-14  9:46             ` Ingo Molnar
2007-02-14 10:09               ` Evgeniy Polyakov
2007-02-14 10:30                 ` Arjan van de Ven
2007-02-14 10:41                   ` Evgeniy Polyakov
2007-02-13 22:57       ` Andrew Morton
2007-02-14 12:43   ` Guillaume Chazarain
2007-02-14 13:17   ` Stephen Rothwell
2007-02-14 20:38   ` Linus Torvalds
2007-02-14 21:02     ` Ingo Molnar
2007-02-14 21:12       ` Ingo Molnar
2007-02-14 21:26       ` Linus Torvalds
2007-02-14 21:35         ` Ingo Molnar
2007-02-15  2:52           ` Zach Brown
2007-02-14 21:44         ` Ingo Molnar
2007-02-14 21:56         ` Alan
2007-02-14 22:32           ` Ingo Molnar
2007-02-15  1:01             ` Davide Libenzi
2007-02-15  1:28               ` Davide Libenzi
2007-02-18 20:01                 ` Pavel Machek
2007-02-18 20:37                   ` Davide Libenzi
2007-02-18 21:04                     ` Michael K. Edwards
2007-02-14 21:09     ` Davide Libenzi
2007-02-14 22:09     ` Ingo Molnar
2007-02-14 23:13       ` Linus Torvalds
2007-02-14 23:44         ` Ingo Molnar
2007-02-15  0:04           ` Ingo Molnar
2007-02-15 13:35     ` Evgeniy Polyakov
2007-02-15 16:09       ` Linus Torvalds
2007-02-15 16:37         ` Evgeniy Polyakov
2007-02-15 17:42           ` Linus Torvalds
2007-02-15 18:11             ` Evgeniy Polyakov
2007-02-15 18:25               ` Linus Torvalds
2007-02-15 19:04                 ` Evgeniy Polyakov
2007-02-15 19:28                   ` Linus Torvalds
2007-02-15 20:07                     ` Linus Torvalds
2007-02-15 21:17                       ` Davide Libenzi
2007-02-15 22:34                       ` Michael K. Edwards
2007-02-16 12:28                       ` Ingo Molnar
2007-02-16 13:28                         ` Evgeniy Polyakov
2007-02-16  8:57                     ` Evgeniy Polyakov
2007-02-16 15:54                       ` Linus Torvalds
2007-02-16 16:05                         ` Evgeniy Polyakov
2007-02-16 16:53                           ` Ray Lee
2007-02-16 16:58                             ` Evgeniy Polyakov
2007-02-16 20:20                               ` Cyrill V. Gorcunov
2007-02-17 10:02                                 ` Evgeniy Polyakov
2007-02-17 17:59                                   ` Cyrill V. Gorcunov
2007-02-17  4:54                               ` Ray Lee
2007-02-17 10:15                                 ` Evgeniy Polyakov
2007-02-15 18:46             ` bert hubert
2007-02-15 19:10               ` Evgeniy Polyakov
2007-02-15 19:16               ` Zach Brown
2007-02-15 19:26               ` Eric Dumazet
2007-02-15 17:05         ` Davide Libenzi
2007-02-15 17:17           ` Evgeniy Polyakov
2007-02-15 17:39             ` Davide Libenzi
2007-02-15 18:01               ` Evgeniy Polyakov
2007-02-15 17:17         ` Ulrich Drepper
2007-02-13 14:20 ` [patch 06/11] syslets: core, documentation Ingo Molnar
2007-02-13 20:18   ` Davide Libenzi
2007-02-13 21:34     ` Ingo Molnar
2007-02-13 23:21       ` Davide Libenzi
2007-02-14  0:18         ` Davide Libenzi
2007-02-14 10:36   ` Russell King
2007-02-14 10:50     ` Ingo Molnar
2007-02-14 11:04       ` Russell King
2007-02-14 17:52         ` Davide Libenzi
2007-02-14 18:03           ` Benjamin LaHaise
2007-02-14 19:45             ` Davide Libenzi
2007-02-14 20:03               ` Benjamin LaHaise
2007-02-14 20:14                 ` Davide Libenzi
2007-02-14 20:34                   ` Benjamin LaHaise
2007-02-14 21:06                     ` Davide Libenzi
2007-02-14 21:44                       ` Benjamin LaHaise
2007-02-14 23:17                         ` Davide Libenzi
2007-02-14 23:40                           ` Benjamin LaHaise
2007-02-15  0:35                             ` Davide Libenzi
2007-02-15  1:32                         ` Michael K. Edwards
2007-02-14 21:49                     ` [patch] x86: split FPU state from task state Ingo Molnar
2007-02-14 22:04                       ` Benjamin LaHaise
2007-02-14 22:10                         ` Arjan van de Ven
2007-02-13 14:20 ` [patch 07/11] syslets: x86, add create_async_thread() method Ingo Molnar
     [not found] ` <20061213130211.GT21847@elte.hu>
2007-02-15 10:13   ` [patch 19/31] clockevents: i386 drivers Andrew Morton
  -- strict thread matches above, loose matches on Subject: below --
2007-02-17 14:57 [patch 05/11] syslets: core code Al Boldi

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=20070213142035.GF638@elte.hu \
    --to=mingo@elte.hu \
    --cc=akpm@zip.com.au \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=arjan@infradead.org \
    --cc=bcrl@kvack.org \
    --cc=davem@davemloft.net \
    --cc=davidel@xmailserver.org \
    --cc=drepper@redhat.com \
    --cc=hch@infradead.org \
    --cc=johnpol@2ka.mipt.ru \
    --cc=linux-kernel@vger.kernel.org \
    --cc=suparna@in.ibm.com \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    --cc=zach.brown@oracle.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox