All of lore.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
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 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.