[Sheepdog] [PATCH] remove coroutine code
Liu Yuan
namei.unix at gmail.com
Mon Apr 16 09:40:05 CEST 2012
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
More information about the sheepdog
mailing list