On 04/11/2012 01:13 AM, MORITA Kazutaka wrote: > It was overkill to use coroutine for group_handler race conditions. > > Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp> > --- > include/coroutine.h | 20 --- > lib/Makefile.am | 2 +- > lib/coroutine.c | 324 --------------------------------------------------- > 3 files changed, 1 insertions(+), 345 deletions(-) > delete mode 100644 include/coroutine.h > delete mode 100644 lib/coroutine.c > > diff --git a/include/coroutine.h b/include/coroutine.h > deleted file mode 100644 > index a69097f..0000000 > --- a/include/coroutine.h > +++ /dev/null > @@ -1,20 +0,0 @@ > -#ifndef __COROUTINE__ > -#define __COROUTINE__ > - > -#include <stdio.h> > -#include <stdarg.h> > -#include <unistd.h> > - > -#include "list.h" > - > -struct coroutine; > - > -typedef void coroutine_entry_func_t(void *opaque); > - > -struct coroutine *coroutine_create(coroutine_entry_func_t *entry); > -void coroutine_enter(struct coroutine *coroutine, void *opaque); > -void coroutine_yield(void); > -struct coroutine *coroutine_self(void); > -int in_coroutine(void); > - > -#endif > diff --git a/lib/Makefile.am b/lib/Makefile.am > index d9e8429..eda3c9a 100644 > --- a/lib/Makefile.am > +++ b/lib/Makefile.am > @@ -4,4 +4,4 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include > > noinst_LIBRARIES = libsheepdog.a > > -libsheepdog_a_SOURCES = event.c logger.c net.c util.c coroutine.c rbtree.c ring_buffer.c > +libsheepdog_a_SOURCES = event.c logger.c net.c util.c rbtree.c ring_buffer.c > diff --git a/lib/coroutine.c b/lib/coroutine.c > deleted file mode 100644 > index 3d79b40..0000000 > --- a/lib/coroutine.c > +++ /dev/null > @@ -1,324 +0,0 @@ > -/* > - * Copyright (C) 2011 MORITA Kazutaka <morita.kazutaka at gmail.com> > - * > - * This library is free software; you can redistribute it and/or > - * modify it under the terms of the GNU Lesser General Public > - * License as published by the Free Software Foundation; either > - * version 2.0 of the License, or (at your option) any later version. > - * > - * This library is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > - * Lesser General Public License for more details. > - * > - * You should have received a copy of the GNU Lesser General Public > - * License along with this library; if not, see <http://www.gnu.org/licenses/>. > - * > - * This code is based on coroutine-ucontext.c and qemu-coroutine.c from QEMU: > - * Copyright (C) 2006 Anthony Liguori <anthony at codemonkey.ws> > - * Copyright (C) 2011 Stefan Hajnoczi <stefanha at linux.vnet.ibm.com> > - * Copyright (C) 2011 Kevin Wolf <kwolf at redhat.com> > - */ > - > -/* disable glibc's stack check for longjmp which doesn't work well > - * with our code */ > -#ifdef _FORTIFY_SOURCE > -#undef _FORTIFY_SOURCE > -#endif > - > -#include <stdlib.h> > -#include <setjmp.h> > -#include <stdint.h> > -#include <ucontext.h> > -#include <errno.h> > -#include <assert.h> > -#include <arpa/inet.h> > -#include <netinet/in.h> > -#include <netinet/tcp.h> > -#include <sys/socket.h> > - > -#include "util.h" > -#include "coroutine.h" > -#include "logger.h" > - > -enum co_action { > - COROUTINE_YIELD = 1, > - COROUTINE_TERMINATE = 2, > -}; > - > -/* Maximum free pool size prevents holding too many freed coroutines */ > -#ifdef COROUTINE_DEBUG > -#define POOL_MAX_SIZE 1 > -#else > -#define POOL_MAX_SIZE 64 > -#endif > - > -#define STACK_MAX_SIZE (1 << 20) /* 1 MB */ > - > -struct coroutine { > - coroutine_entry_func_t *entry; > - void *entry_arg; > - struct coroutine *caller; > - struct list_head pool_next; > - struct list_head co_queue_next; > -}; > - > -struct co_ucontext { > - struct coroutine base; > - void *stack; > - jmp_buf env; > -}; > - > -/** > - * Per-thread coroutine bookkeeping > - */ > -__thread struct co_thread_state{ > - /** Currently executing coroutine */ > - struct coroutine *current; > - > - /** Free list to speed up creation */ > - struct list_head pool; > - unsigned int pool_size; > - > - /** The default coroutine */ > - struct co_ucontext leader; > -} co_ts; > - > -static enum co_action coroutine_switch(struct coroutine *from, > - struct coroutine *to, > - enum co_action action); > - > -/* > - * va_args to makecontext() must be type 'int', so passing > - * the pointer we need may require several int args. This > - * union is a quick hack to let us do that > - */ > -union cc_arg { > - void *p; > - int i[2]; > -}; > - > -static struct co_thread_state *coroutine_get_thread_state(void) > -{ > - struct co_thread_state *s = &co_ts; > - > - if (!s->current) { > - s->current = &s->leader.base; > - INIT_LIST_HEAD(&s->pool); > - } > - return s; > -} > - > -static void coroutine_trampoline(int i0, int i1) > -{ > - union cc_arg arg; > - struct co_ucontext *self; > - struct coroutine *co; > - > - arg.i[0] = i0; > - arg.i[1] = i1; > - self = arg.p; > - co = &self->base; > - > - /* Initialize longjmp environment and switch back the caller */ > - if (!setjmp(self->env)) > - longjmp(*(jmp_buf *)co->entry_arg, 1); > - > - for (;;) { > - co->entry(co->entry_arg); > - coroutine_switch(co, co->caller, COROUTINE_TERMINATE); > - } > -} > - > -#ifdef COROUTINE_DEBUG > - > -#define MAGIC_NUMBER 0x1234567890123456 > - > -static void init_stack(struct co_ucontext *co) > -{ > - uint64_t *stack = co->stack; > - int i; > - > - for (i = 0; i < STACK_MAX_SIZE / sizeof(stack[0]); i++) > - stack[i] = MAGIC_NUMBER; > -} > - > -static int get_stack_size(struct co_ucontext *co) > -{ > - uint64_t *stack = co->stack; > - int i; > - > - for (i = 0; i < STACK_MAX_SIZE / sizeof(stack[0]); i++) > - if (stack[i] != MAGIC_NUMBER) > - break; > - > - if (i == 0) > - panic("stack overflow\n"); > - > - return STACK_MAX_SIZE - i * sizeof(stack[0]); > -} > - > -#endif > - > -static struct coroutine *__coroutine_new(void) > -{ > - const size_t stack_size = STACK_MAX_SIZE; > - struct co_ucontext *co; > - ucontext_t old_uc, uc; > - jmp_buf old_env; > - union cc_arg arg = {0}; > - > - /* The ucontext functions preserve signal masks which incurs a > - * system call overhead. setjmp()/longjmp() does not preserve > - * signal masks but only works on the current stack. Since we > - * need a way to create and switch to a new stack, use the > - * ucontext functions for that but setjmp()/longjmp() for > - * everything else. > - */ > - > - if (getcontext(&uc) == -1) > - abort(); > - > - co = zalloc(sizeof(*co)); > - if (!co) > - abort(); > - co->stack = zalloc(stack_size); > - if (!co->stack) > - abort(); > -#ifdef COROUTINE_DEBUG > - init_stack(co); > -#endif > - co->base.entry_arg = &old_env; /* stash away our jmp_buf */ > - > - uc.uc_link = &old_uc; > - uc.uc_stack.ss_sp = co->stack; > - uc.uc_stack.ss_size = stack_size; > - uc.uc_stack.ss_flags = 0; > - > - arg.p = co; > - > - makecontext(&uc, (void (*)(void))coroutine_trampoline, > - 2, arg.i[0], arg.i[1]); > - > - /* swapcontext() in, longjmp() back out */ > - if (!setjmp(old_env)) > - swapcontext(&old_uc, &uc); > - > - return &co->base; > -} > - > -static struct coroutine *coroutine_new(void) > -{ > - struct co_thread_state *s = coroutine_get_thread_state(); > - struct coroutine *co; > - > - if (!list_empty(&s->pool)) { > - co = list_first_entry(&s->pool, struct coroutine, pool_next); > - list_del(&co->pool_next); > - s->pool_size--; > - } else > - co = __coroutine_new(); > - > - return co; > -} > - > -static void coroutine_delete(struct coroutine *co_) > -{ > - struct co_thread_state *s = coroutine_get_thread_state(); > - struct co_ucontext *co = container_of(co_, struct co_ucontext, base); > - > -#ifdef COROUTINE_DEBUG > - fprintf(stdout, "%d bytes are consumed\n", get_stack_size(co)); > -#endif > - > - if (s->pool_size < POOL_MAX_SIZE) { > - list_add(&co->base.pool_next, &s->pool); > - co->base.caller = NULL; > - s->pool_size++; > - return; > - } > - > - free(co->stack); > - free(co); > -} > - > -static enum co_action coroutine_switch(struct coroutine *from_, > - struct coroutine *to_, > - enum co_action action) > -{ > - struct co_ucontext *from = container_of(from_, struct co_ucontext, base); > - struct co_ucontext *to = container_of(to_, struct co_ucontext, base); > - struct co_thread_state *s = coroutine_get_thread_state(); > - int ret; > - > - s->current = to_; > - > - ret = setjmp(from->env); > - if (ret == 0) > - longjmp(to->env, action); > - > - return ret; > -} > - > -struct coroutine *coroutine_self(void) > -{ > - struct co_thread_state *s = coroutine_get_thread_state(); > - > - return s->current; > -} > - > -int in_coroutine(void) > -{ > - struct co_thread_state *s = &co_ts; > - > - return s->current && s->current->caller; > -} > - > - > -struct coroutine *coroutine_create(coroutine_entry_func_t *entry) > -{ > - struct coroutine *co = coroutine_new(); > - co->entry = entry; > - return co; > -} > - > -static void coroutine_swap(struct coroutine *from, struct coroutine *to) > -{ > - enum co_action ret; > - > - ret = coroutine_switch(from, to, COROUTINE_YIELD); > - > - switch (ret) { > - case COROUTINE_YIELD: > - return; > - case COROUTINE_TERMINATE: > - coroutine_delete(to); > - return; > - default: > - abort(); > - } > -} > - > -void coroutine_enter(struct coroutine *co, void *opaque) > -{ > - struct coroutine *self = coroutine_self(); > - > - if (co->caller) > - panic("Co-routine re-entered recursively\n"); > - > - co->caller = self; > - co->entry_arg = opaque; > - coroutine_swap(self, co); > -} > - > -void coroutine_yield(void) > -{ > - struct coroutine *self = coroutine_self(); > - struct coroutine *to = self->caller; > - > - if (!to) > - panic("Co-routine is yielding to no one\n"); > - > - self->caller = NULL; > - coroutine_swap(self, to); > -} Applied Thanks, Yuan |