├── ChangeLog ├── m4 ├── .gitignore └── ax_good_mprotect.m4 ├── Makefile.am ├── test ├── asm_lock_perf.c ├── coro_sw_perf.c ├── coro_cr_perf.c ├── lock_perf.c ├── mm_perf.c ├── Makefile.am ├── testcase.c ├── test_coro_mt.c └── perf_main.c ├── src ├── Makefile.am ├── mt_utils.c ├── coro_mm.h ├── uctx_coro_impl.c ├── x86_coro_impl.c ├── coro_comm.h ├── x86_coro_sw_O0.c ├── x86_mt_utils.h ├── mt_utils.h ├── coro_mm_malloc.c ├── micoro.h ├── coro_sched.c └── coro_mm_pool.c ├── COPYING ├── cleanup.sh ├── README └── configure.ac /ChangeLog: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | SUBDIRS = src test 4 | 5 | EXTRA_DIST = \ 6 | cleanup.sh \ 7 | COPYING \ 8 | ChangeLog 9 | 10 | -------------------------------------------------------------------------------- /test/asm_lock_perf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "mt_utils.h" 6 | 7 | #define N (50000) 8 | 9 | struct block { 10 | char buf[4096]; 11 | }; 12 | static struct block array[N]; 13 | static volatile size_t cur; 14 | static volatile size_t tmp; 15 | 16 | void prepare() 17 | { 18 | } 19 | 20 | void testcase() 21 | { 22 | __asm__ __volatile__ ( 23 | "lock; decl %0\n\t" 24 | :"=m"(tmp)); 25 | 26 | array[cur].buf[0] = 1; 27 | cur = (cur + 1) % N; 28 | } 29 | -------------------------------------------------------------------------------- /test/coro_sw_perf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "micoro.h" 5 | 6 | #define _assert 7 | 8 | #define N (100000) 9 | static coro_t tab[N]; 10 | static size_t cur = 0; 11 | 12 | void* coro(void *arg) 13 | { 14 | while (1) 15 | coro_yield(NULL); 16 | return NULL; 17 | } 18 | 19 | void prepare() 20 | { 21 | size_t sz = 4096, i; 22 | assert(coro_init(sz, N) == 0); 23 | for (i=0; i 2 | #include 3 | #include 4 | #include "micoro.h" 5 | 6 | #define _assert 7 | 8 | #define N (10000) 9 | static coro_t tab[N]; 10 | static size_t cur = 0; 11 | 12 | void* coro(void *arg) 13 | { 14 | return NULL; 15 | } 16 | 17 | void prepare() 18 | { 19 | size_t sz = 4096, i; 20 | assert(coro_init(sz, N) == 0); 21 | for (i=0; i 2 | #include 3 | #include 4 | #include 5 | #include "mt_utils.h" 6 | 7 | //#define MT 8 | #define YIELD 9 | 10 | static MICORO_LOCK_T lock = MICORO_LOCK_INITVAL; 11 | static unsigned long count; 12 | 13 | void testcase2() 14 | { 15 | MICORO_LOCK(&lock); 16 | #ifdef YIELD 17 | sched_yield(); 18 | #endif 19 | MICORO_UNLOCK(&lock); 20 | count++; 21 | } 22 | 23 | void* entry(void *arg) 24 | { 25 | while (1) { 26 | testcase2(); 27 | } 28 | return NULL; 29 | } 30 | 31 | void done() 32 | { 33 | printf("thread loop %lu\n", count); 34 | } 35 | 36 | void prepare() 37 | { 38 | #ifdef MT 39 | pthread_t t; 40 | assert(pthread_create(&t, NULL, entry, NULL) == 0); 41 | #endif 42 | } 43 | 44 | void testcase() 45 | { 46 | MICORO_LOCK(&lock); 47 | MICORO_UNLOCK(&lock); 48 | } 49 | -------------------------------------------------------------------------------- /m4/ax_good_mprotect.m4: -------------------------------------------------------------------------------- 1 | AC_DEFUN([AX_GOOD_MPROTECT], [ 2 | AC_MSG_CHECKING([for mprotect function]) 3 | AC_CACHE_VAL([ac_cv_good_mprotect], [ 4 | AC_RUN_IFELSE( 5 | [AC_LANG_PROGRAM([ 6 | #include 7 | ], [ 8 | #ifndef MAP_ANONYMOUS 9 | # define MAP_ANONYMOUS MAP_ANON 10 | #endif 11 | void *ptr; 12 | ptr = mmap((void*)0, 8192, PROT_READ|PROT_WRITE, 13 | MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 14 | if (ptr == MAP_FAILED) 15 | return 1; 16 | if (mprotect(ptr, 4096, PROT_NONE) < 0) 17 | return 2; 18 | (*(char *)(ptr + 4096)) = 0; 19 | ])], 20 | ac_cv_good_mprotect=yes, 21 | ac_cv_good_mprotect=no 22 | )]) 23 | AS_IF([test "x$ac_cv_good_mprotect" = xyes], 24 | [AC_DEFINE(HAVE_GOOD_MPROTECT, 1, [define if have good mprotect])]) 25 | AC_MSG_RESULT($ac_cv_good_mprotect) 26 | ]) 27 | -------------------------------------------------------------------------------- /test/mm_perf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "coro_mm.h" 6 | 7 | //#define USE_MALLOC 8 | 9 | #define N (100000) 10 | static void *tab[N]; 11 | static size_t cur = 0; 12 | 13 | void prepare() 14 | { 15 | size_t sz = 4096, i; 16 | #ifndef USE_MALLOC 17 | assert(coro_mm_default_ops->init(&sz, N) == 0); 18 | #endif 19 | assert(sz == 4096); 20 | for (i=0; ialloc()); 25 | #endif 26 | } 27 | srand(time(NULL)); 28 | cur = rand() % N; 29 | } 30 | 31 | void testcase() 32 | { 33 | #ifdef USE_MALLOC 34 | free(tab[cur]); 35 | assert(tab[cur] = malloc(4096)); 36 | #else 37 | assert(coro_mm_default_ops->release(tab[cur]) == 0); 38 | assert(tab[cur] = coro_mm_default_ops->alloc()); 39 | #endif 40 | cur = (cur + 1) % N; 41 | } 42 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -D_GNU_SOURCE -D_XOPEN_SOURCE 2 | if GCC 3 | AM_CFLAGS += -Wall 4 | endif 5 | 6 | include_HEADERS = \ 7 | micoro.h 8 | 9 | lib_LTLIBRARIES = \ 10 | libmicoro.la \ 11 | libmicoro_mt.la 12 | 13 | libmicoro_SOURCES = \ 14 | coro_comm.h \ 15 | coro_mm.h \ 16 | coro_mm_malloc.c \ 17 | coro_mm_pool.c \ 18 | coro_sched.c \ 19 | micoro.h \ 20 | mt_utils.c \ 21 | mt_utils.h 22 | 23 | libmicoro_la_SOURCES = $(libmicoro_SOURCES) 24 | libmicoro_la_CPPFLAGS = $(AM_CPPFLAGS) -DMICORO_MT=0 25 | libmicoro_la_LDFLAGS = -static 26 | 27 | libmicoro_mt_la_SOURCES = $(libmicoro_SOURCES) 28 | libmicoro_mt_la_CPPFLAGS = $(AM_CPPFLAGS) -DMICORO_MT=1 29 | libmicoro_mt_la_LDFLAGS = -static 30 | 31 | if MICORO_X86_OPTIMIZE 32 | libmicoro_SOURCES += \ 33 | x86_coro_impl.c \ 34 | x86_mt_utils.h 35 | 36 | libmicoro_la_LIBADD = libtmp.la 37 | libmicoro_mt_la_LIBADD = libtmp.la 38 | 39 | noinst_LTLIBRARIES = libtmp.la 40 | libtmp_la_SOURCES = \ 41 | x86_coro_sw_O0.c 42 | libtmp_la_CFLAGS = $(AM_CFLAGS) -O0 43 | libtmp_la_LDFLAGS = -static 44 | else 45 | libmicoro_SOURCES += uctx_coro_impl.c 46 | endif 47 | 48 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | if GCC 2 | AM_CFLAGS += -Wall 3 | endif 4 | 5 | AM_CPPFLAGS = -I$(top_srcdir)/src 6 | 7 | LIBMICORO = ../src/libmicoro.la 8 | LIBMICORO_MT = ../src/libmicoro_mt.la 9 | 10 | LDADD = $(LIBMICORO) libperf_main.la -lpthread 11 | 12 | noinst_LTLIBRARIES = libperf_main.la 13 | 14 | libperf_main_la_SOURCES = perf_main.c 15 | libperf_main_la_LDFLAGS = -static 16 | 17 | noinst_PROGRAMS = \ 18 | coro_cr_perf \ 19 | coro_cr_mt_perf \ 20 | coro_sw_perf \ 21 | coro_sw_mt_perf \ 22 | lock_perf \ 23 | mm_perf \ 24 | mm_mt_perf \ 25 | testcase \ 26 | test_coro_mt 27 | 28 | if MICORO_X86_OPTIMIZE 29 | noinst_PROGRAMS += asm_lock_perf 30 | asm_lock_perf_SOURCES = asm_lock_perf.c 31 | endif 32 | 33 | coro_cr_perf_SOURCES = coro_cr_perf.c 34 | coro_sw_perf_SOURCES = coro_sw_perf.c 35 | lock_perf_SOURCES = lock_perf.c 36 | mm_perf_SOURCES = mm_perf.c 37 | testcase_SOURCES = testcase.c 38 | 39 | coro_cr_mt_perf_SOURCES = coro_cr_perf.c 40 | coro_cr_mt_perf_LDADD = $(LIBMICORO_MT) $(LDADD) 41 | 42 | coro_sw_mt_perf_SOURCES = coro_sw_perf.c 43 | coro_sw_mt_perf_LDADD = $(LIBMICORO_MT) $(LDADD) 44 | 45 | mm_mt_perf_SOURCES = mm_perf.c 46 | mm_mt_perf_LDADD = $(LIBMICORO_MT) $(LDADD) 47 | 48 | test_coro_mt_SOURCES = test_coro_mt.c 49 | test_coro_mt_LDADD = $(LIBMICORO_MT) $(LDADD) 50 | 51 | -------------------------------------------------------------------------------- /test/testcase.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "micoro.h" 3 | 4 | void* test1_coro(void *arg) 5 | { 6 | int idx = 0; 7 | char buf[1024]; 8 | char *s; 9 | idx = snprintf(buf + idx, sizeof(buf) - idx, "%s ", (char *)arg); 10 | s = coro_yield("works!"); 11 | idx = snprintf(buf + idx, sizeof(buf) - idx, "%s\n", (char *)s); 12 | printf("%s", buf); 13 | return "done"; 14 | } 15 | 16 | int test1() 17 | { 18 | void *s; 19 | coro_t coro; 20 | if (coro_init(4096*64, 10) < 0) 21 | return -1; 22 | if (coro_create(&coro, test1_coro) < 0) 23 | return -2; 24 | printf("new coro: %p\n", coro.ctx); 25 | s = coro_resume(&coro, "coro"); 26 | s = coro_resume(&coro, s); 27 | printf("%s\n", (char *)s); 28 | return 0; 29 | } 30 | 31 | void* test2_producer(void *arg) 32 | { 33 | int i; 34 | for (i = 0; i < 10; i++) 35 | coro_yield((void *)&i); 36 | return NULL; 37 | } 38 | 39 | void* test2_consumer(void *arg) 40 | { 41 | coro_t *prod = (coro_t *)arg; 42 | while (1) { 43 | int *pi = coro_resume(prod, NULL); 44 | if (coro_err(prod)) break; 45 | printf("%d ", *pi); 46 | } 47 | printf("\n"); 48 | return NULL; 49 | } 50 | 51 | int test2() 52 | { 53 | coro_t prod, cons; 54 | if (coro_create(&prod, test2_producer) < 0 55 | || coro_create(&cons, test2_consumer) < 0) 56 | return -1; 57 | coro_resume(&cons, &prod); 58 | return 0; 59 | } 60 | 61 | int main() 62 | { 63 | if (test1() < 0) return 1; 64 | if (test2() < 0) return 2; 65 | return 0; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Bin Wei 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * The name of of its contributors may not be used to endorse or 15 | promote products derived from this software without specific prior 16 | written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /src/mt_utils.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include "mt_utils.h" 31 | 32 | int init_once(int *init_flag) 33 | { 34 | int flag; 35 | 36 | static MICORO_LOCK_T init_lock = MICORO_LOCK_INITVAL; 37 | MICORO_LOCK(&init_lock); 38 | flag = *init_flag; 39 | *init_flag = 1; 40 | MICORO_UNLOCK(&init_lock); 41 | 42 | return (flag ? -1 : 0); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /test/test_coro_mt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "micoro.h" 7 | #include "mt_utils.h" 8 | 9 | #define LOOP 100 10 | 11 | struct wait_list { 12 | struct wait_list *next; 13 | coro_t coro; 14 | }; 15 | 16 | static struct wait_list * volatile g_wait_list; 17 | static MICORO_LOCK_T g_lock = MICORO_LOCK_INITVAL; 18 | 19 | void* coro_func(void *arg) 20 | { 21 | struct wait_list wl; 22 | 23 | assert(coro_self(&wl.coro) == 0); 24 | assert(wl.coro.ctx != NULL); 25 | 26 | MICORO_LOCK(&g_lock); 27 | wl.next = g_wait_list; 28 | g_wait_list = &wl; 29 | MICORO_UNLOCK(&g_lock); 30 | 31 | coro_yield(NULL); 32 | 33 | return NULL; 34 | } 35 | 36 | void* worker(void *arg) 37 | { 38 | while (1) { 39 | struct wait_list *wl = NULL; 40 | 41 | MICORO_LOCK(&g_lock); 42 | if (g_wait_list) { 43 | wl = g_wait_list; 44 | g_wait_list = g_wait_list->next; 45 | } 46 | MICORO_UNLOCK(&g_lock); 47 | 48 | if (wl) 49 | coro_resume(&wl->coro, NULL); 50 | else 51 | usleep(1000); 52 | } 53 | return NULL; 54 | } 55 | 56 | void* launcher(void *arg) 57 | { 58 | coro_t coro; 59 | 60 | while (1) { 61 | int i; 62 | for (i = 0; i < LOOP; i++) { 63 | assert(coro_create(&coro, coro_func) == 0); 64 | coro_resume(&coro, NULL); 65 | } 66 | usleep(1000); 67 | } 68 | return NULL; 69 | } 70 | 71 | int main() 72 | { 73 | pthread_t lt1, lt2, wt1, wt2; 74 | struct coro_stat cur_stat, last_stat = {0}; 75 | 76 | assert(coro_init(4096*8, 10000) == 0); 77 | assert(pthread_create(<1, NULL, launcher, NULL) == 0); 78 | assert(pthread_create(<2, NULL, launcher, NULL) == 0); 79 | assert(pthread_create(&wt1, NULL, worker, NULL) == 0); 80 | assert(pthread_create(&wt2, NULL, worker, NULL) == 0); 81 | 82 | while (1) { 83 | coro_get_stat(&cur_stat); 84 | printf("create: %llu\tdestroy: %llu\tresume: %llu\tyield: %llu\tpending: %llu\n", 85 | #define diff_stat(field) ((unsigned long long)(cur_stat.field - last_stat.field)) 86 | diff_stat(create_count), diff_stat(destroy_count), 87 | diff_stat(resume_count), diff_stat(yield_count), 88 | (unsigned long long)cur_stat.alive_coro_num); 89 | last_stat = cur_stat; 90 | sleep(1); 91 | } 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright (c) 2012, Bin Wei 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following disclaimer 14 | # in the documentation and/or other materials provided with the 15 | # distribution. 16 | # * The name of of its contributors may not be used to endorse or 17 | # promote products derived from this software without specific prior 18 | # written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | # 32 | 33 | cd "`dirname $0`" 34 | 35 | if test -r Makefile; then 36 | make maintainer-clean 37 | fi 38 | 39 | find . -name Makefile.in -exec rm -f {} \; 40 | 41 | rm -R -f \ 42 | autom4te.cache \ 43 | build-aux \ 44 | m4/libtool.m4 \ 45 | m4/ltoptions.m4 \ 46 | m4/ltsugar.m4 \ 47 | m4/ltversion.m4 \ 48 | m4/lt~obsolete.m4 \ 49 | aclocal.m4 \ 50 | autoscan.log \ 51 | config.guess \ 52 | config.h \ 53 | config.h.in \ 54 | config.h.in~ \ 55 | config.hin \ 56 | config.hin~ \ 57 | config.log \ 58 | config.status \ 59 | config.status.lineno \ 60 | config.sub \ 61 | configure \ 62 | configure.lineno \ 63 | configure.scan 64 | 65 | -------------------------------------------------------------------------------- /src/coro_mm.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #ifndef __CORO_MM_H__ 31 | #define __CORO_MM_H__ 32 | 33 | #include 34 | #include 35 | 36 | struct coro_mm_stat 37 | { 38 | uint64_t alloc_count; 39 | uint64_t release_count; 40 | uint32_t use_block_num; 41 | uint32_t free_block_num; 42 | }; 43 | 44 | struct coro_mm_ops 45 | { 46 | int (*init)(size_t *alloc_size, size_t pool_size); 47 | void* (*alloc)(); 48 | int (*release)(void *ptr); 49 | void* (*locate)(void *ptr); 50 | void (*get_stat)(struct coro_mm_stat *stat); 51 | }; 52 | 53 | extern struct coro_mm_ops *coro_mm_malloc_ops; 54 | extern struct coro_mm_ops *coro_mm_pool_ops; 55 | 56 | #define coro_mm_default_ops coro_mm_pool_ops 57 | 58 | #endif // __CORO_MM_H__ 59 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 1. Introduction 2 | 3 | micoro (for MIcro COROutine & MIke's COROtine) is a light weight, high 4 | performance coroutine implementation. 5 | The basic idea of micoro come from the paper "Revisiting Coroutines" 6 | (http://www.inf.puc-rio.br/~roberto/docs/MCC15-04.pdf). As the paper proved, 7 | the "full asymmetric coroutine" model is powerful, easier to use and 8 | expressive power equivalent to other similar models. So micoro is actually 9 | a "full asymmetric coroutine" implemenation with simple API and clear 10 | semantics. 11 | The original motivation of micoro is to implement a light-weight 12 | cooperative multitasking infrastructure for server environment, so simple, 13 | performance and robust (rather than portability) is often the top 14 | considerations across disign and implementation. 15 | 16 | some features: 17 | * x86 user space fast context switch 18 | * x86 user level light-weight lock 19 | * thread-safe operations 20 | * stack overflow detection 21 | * robust code with careful design and test 22 | * portable for non-x86 using ucontext 23 | * running activity statistics 24 | 25 | 2. Requirement 26 | 27 | Currently only POSIX systems are supported. 28 | Some tested platform: 29 | Linux-2.6.16 x86_32 30 | Linux-2.6.32 x86_64 31 | Linux-3.2 x86_64 GCC-4.7.1 32 | MacOS-10.7.4 x86_64 LLVM-GCC-4.2.1 33 | FreeBSD-9.0 x86_64 GCC-4.2.1 34 | Cygwin_NT-6.1 i686 GCC-4.5.3 35 | 36 | 3. Install 37 | 38 | 3.1 install from tarball 39 | 40 | tar -xvf micoro-1.0.tar.gz 41 | cd micoro-1.0 42 | ./configure 43 | make 44 | sudo make install 45 | 46 | 3.2 install from git source 47 | 48 | * require GNU autotools & libtool installed 49 | 50 | git clone git://github.com/mikewei/micoro.git 51 | cd micoro 52 | autoreconf -i 53 | ./configure 54 | make 55 | sudo make install 56 | 57 | 4. Performance 58 | 59 | micoro has much higher performance compared with others 60 | (e.g. GNU Pth, PCL, pthread ...) 61 | 62 | * my benchmark with a Linux-3.2 CoreDuo 2.1G PC 63 | context switch performance for 10000 concurrent routines: 64 | 65 | GNU Pth - 5,876 switches per second 66 | pthread - 237,318 switches per second 67 | PCL - 879,165 switches per second 68 | micoro - 4,577,256 switches per second 69 | 70 | 5. Bug report 71 | 72 | please email to 73 | -------------------------------------------------------------------------------- /src/uctx_coro_impl.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include 31 | #include 32 | #include "coro_comm.h" 33 | 34 | static void uctx_coro_main(int arg1, int arg2) 35 | { 36 | __coro_main((void*(*)(void*))( 37 | ((uintptr_t)(unsigned int)arg1) + 38 | ((uintptr_t)(unsigned int)arg2 << (sizeof(int)*8)) 39 | )); 40 | } 41 | 42 | void uctx_coro_makectx(struct coro_ctx *ctx, size_t ctx_size, void* (*f)(void*)) 43 | { 44 | if (getcontext(&ctx->uctx) < 0) { 45 | perror("getcontext"); 46 | abort(); 47 | } 48 | ctx->uctx.uc_stack.ss_sp = (void *)ctx + sizeof(struct coro_ctx); 49 | ctx->uctx.uc_stack.ss_size = ctx_size - sizeof(struct coro_ctx); 50 | ctx->uctx.uc_link = NULL; 51 | /* according to makecontext(3), to be portable we must pass pointer 52 | by a pair of int args */ 53 | makecontext(&ctx->uctx, (void(*)())uctx_coro_main, 2, 54 | (int)f, (int)((uintptr_t)f >> (sizeof(int)*8))); 55 | } 56 | 57 | void uctx_coro_switch(struct coro_ctx *from, struct coro_ctx *to) 58 | { 59 | if (swapcontext(&from->uctx, &to->uctx) < 0) { 60 | perror("swapcontext"); 61 | abort(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/x86_coro_impl.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include "coro_comm.h" 31 | 32 | void x86_coro_makectx(struct coro_ctx *ctx, size_t ctx_size, void* (*f)(void*)) 33 | { 34 | unsigned long *stack; 35 | 36 | stack = (void *)ctx + ctx_size - sizeof(unsigned long); 37 | /* now stack point to the last word of the context space */ 38 | *stack = 0UL; 39 | 40 | /* make stack-frame of coro_main 16-byte aligned 41 | * for amd64-ABI and some systems (such as Mac OS) require this 42 | */ 43 | stack = (void *)((unsigned long)stack & ~0x0fUL); 44 | 45 | stack[0] = (unsigned long)f; 46 | /* here is 16-byte alignment boundary */ 47 | stack[-1] = 0UL; // IP 48 | stack[-2] = (unsigned long)__coro_main; 49 | stack[-3] = 0UL; // BP 50 | stack[-4] = 0UL; // BX 51 | stack[-5] = (unsigned long)&stack[-3]; // BP 52 | stack[-6] = stack[0]; // DI 53 | #ifdef __x86_64__ 54 | stack[-7] = 0UL; // R12 55 | stack[-8] = 0UL; // R13 56 | stack[-9] = 0UL; // R14 57 | stack[-10] = 0UL; // R15 58 | # define _stack_top (-10) 59 | #else 60 | stack[-7] = 0UL; // SI 61 | # define _stack_top (-7) 62 | #endif 63 | ctx->sp = &stack[_stack_top]; 64 | } 65 | -------------------------------------------------------------------------------- /test/perf_main.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #ifndef TEST_TIME 37 | # define TEST_TIME 10 38 | #endif 39 | 40 | void prepare() __attribute__((weak)); 41 | void testcase(); 42 | 43 | static unsigned long long count; 44 | static unsigned long timeout; 45 | 46 | void on_timeout(int sig) 47 | { 48 | timeout = 1; 49 | } 50 | 51 | int main(int argc, char *argv[]) 52 | { 53 | struct timeval tv_begin, tv_end, tv_use; 54 | 55 | setlocale(LC_ALL, ""); 56 | signal(SIGALRM, on_timeout); 57 | 58 | if (prepare) prepare(); 59 | 60 | alarm(TEST_TIME); 61 | gettimeofday(&tv_begin, NULL); 62 | 63 | for (count = 0; !timeout; count++) 64 | testcase(); 65 | 66 | gettimeofday(&tv_end, NULL); 67 | 68 | timersub(&tv_end, &tv_begin, &tv_use); 69 | 70 | printf("count: %'llu\n", count); 71 | printf(" time: %'d.%06d s\n", (int)tv_use.tv_sec, (int)tv_use.tv_usec); 72 | printf(" HZ: %'f\n", count/(tv_use.tv_sec+0.000001*tv_use.tv_usec)); 73 | printf(" 1/HZ: %'.9f s\n", (tv_use.tv_sec+0.000001*tv_use.tv_usec)/count); 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.59]) 5 | AC_INIT([micoro], [1.0], [bin@vip.qq.com]) 6 | AC_CONFIG_MACRO_DIR([m4]) 7 | AC_CONFIG_SRCDIR([src/micoro.h]) 8 | AC_CONFIG_HEADERS([config.h]) 9 | AC_CONFIG_AUX_DIR([build-aux]) 10 | 11 | AM_INIT_AUTOMAKE([foreign -Wall -Werror]) 12 | AM_PROG_AR 13 | LT_INIT 14 | 15 | AC_ARG_ENABLE([x86-optimize], 16 | [AS_HELP_STRING([--disable-x86-optimize], 17 | [do not optimize for x86, more portable but lower performace])], 18 | [], 19 | [enable_x86_optimize=yes]) 20 | AC_ARG_ENABLE([force-x86], 21 | [AS_HELP_STRING([--enable-force-x86], 22 | [force to consider cpu as x86])], 23 | [], 24 | [enable_force_x86=no]) 25 | AC_ARG_ENABLE([force-gcc], 26 | [AS_HELP_STRING([--enable-force-gcc], 27 | [force to consider cc as gcc])], 28 | [], 29 | [enable_force_gcc=no]) 30 | 31 | # Check for cpu. 32 | AC_CANONICAL_HOST 33 | AS_CASE(["$host_cpu"], 34 | [x86_64], [arch_type=x86], 35 | [i?86], [arch_type=x86], 36 | [i?86-*], [arch_type=x86], 37 | [arch_type=other]]) 38 | AS_IF([test "x$enable_force_x86" = xyes], [arch_type=x86]) 39 | AS_IF([test "x$arch_type" != xx86], [enable_x86_optimize=no]) 40 | 41 | # Checks for programs. 42 | AC_PROG_CC 43 | AM_PROG_CC_C_O 44 | AS_IF([test "x$GCC" = xyes -o "x$enable_force_gcc" = xyes], 45 | [use_gcc=yes],[use_gcc=no]) 46 | AM_CONDITIONAL(GCC, test "x$use_gcc" = xyes) 47 | AC_SUBST([AM_CFLAGS], ["$CFLAGS"]) 48 | CFLAGS="" 49 | 50 | AS_IF([test "x$use_gcc" != xyes], [enable_x86_optimize=no]) 51 | AM_CONDITIONAL(MICORO_X86_OPTIMIZE, test "x$enable_x86_optimize" = xyes) 52 | AS_IF([test "x$enable_x86_optimize" = xyes], 53 | [AC_DEFINE([MICORO_X86_OPTIMIZE], [1], [use optimized x86 implementation])]) 54 | 55 | # Checks for libraries. 56 | 57 | # Checks for header files. 58 | AC_CHECK_HEADERS([locale.h stdint.h stdlib.h string.h sys/time.h unistd.h \ 59 | sys/mman.h ucontext.h sys/ucontext.h]) 60 | 61 | # Checks for typedefs, structures, and compiler characteristics. 62 | AC_C_INLINE 63 | AC_TYPE_SIZE_T 64 | AC_TYPE_UINT32_T 65 | AC_TYPE_UINT64_T 66 | 67 | # Checks for library functions. 68 | AC_FUNC_MALLOC 69 | AC_FUNC_MMAP 70 | AC_CHECK_FUNCS([alarm gettimeofday memset munmap setlocale mprotect]) 71 | 72 | # Custom checks 73 | AX_GOOD_MPROTECT 74 | 75 | AH_TOP([ 76 | #ifndef __MICORO_CONFIG_H__ 77 | #define __MICORO_CONFIG_H__ 78 | ]) 79 | AH_BOTTOM([ 80 | #endif /* __MICORO_CONFIG_H__ */ 81 | ]) 82 | 83 | AC_CONFIG_FILES([Makefile src/Makefile test/Makefile]) 84 | AC_OUTPUT 85 | 86 | AS_IF([test "x$enable_x86_optimize" = xyes], 87 | [impl_mode=optimized-x86-asm], [impl_mode=ucontext]) 88 | AC_MSG_NOTICE([use $impl_mode implementation]) 89 | 90 | -------------------------------------------------------------------------------- /src/coro_comm.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #ifndef __CORO_COMM_H__ 31 | #define __CORO_COMM_H__ 32 | 33 | #include 34 | #if !MICORO_X86_OPTIMIZE 35 | # if HAVE_UCONTEXT_H 36 | # include 37 | # elif HAVE_SYS_UCONTEXT_H 38 | # include 39 | # endif 40 | #endif 41 | #include 42 | #include "micoro.h" 43 | #include "mt_utils.h" 44 | 45 | #define CORO_FLAG_END 0x00000001 46 | 47 | #define CORO_CTX_TAG 0x9988abcd 48 | 49 | struct coro_ctx 50 | { 51 | #if MICORO_X86_OPTIMIZE 52 | void *sp; 53 | #else 54 | ucontext_t uctx; 55 | #endif 56 | struct coro_ctx *prev; 57 | struct coro_ctx *next; 58 | void *ret; 59 | MICORO_LOCK_T lock; 60 | unsigned int flag; 61 | unsigned int tag; 62 | }; 63 | 64 | #if MICORO_X86_OPTIMIZE 65 | # define coro_switch x86_coro_switch 66 | # define coro_makectx x86_coro_makectx 67 | #else 68 | # define coro_switch uctx_coro_switch 69 | # define coro_makectx uctx_coro_makectx 70 | #endif 71 | 72 | void coro_makectx(struct coro_ctx *ctx, size_t ctx_size, void* (*f)(void*)); 73 | void coro_switch(struct coro_ctx *from, struct coro_ctx *to) 74 | __attribute__ ((noinline, regparm(0))); 75 | 76 | void __coro_main(void* (*f)(void*)) 77 | __attribute__ ((noinline, regparm(0))); 78 | 79 | #endif // __CORO_COMM_H__ 80 | -------------------------------------------------------------------------------- /src/x86_coro_sw_O0.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include "coro_comm.h" 31 | 32 | /* 33 | * x86_coro_makectx assume a fixed stack layout, so here 34 | * the code (e.g. save frame-pointer) should NOT be optimized (use -O0) 35 | * maybed replace by pure asm code in the future 36 | */ 37 | void x86_coro_switch(struct coro_ctx *from, struct coro_ctx *to) 38 | { 39 | asm volatile ( 40 | #ifdef __x86_64__ 41 | /* 42 | * [amd64 ABI] callee-saved register: RBX,RBP,R12~R15 43 | * use RDI to pass param for coro_main 44 | */ 45 | "pushq %%rbx\n\t" 46 | "pushq %%rbp\n\t" 47 | "pushq %%rdi\n\t" 48 | "pushq %%r12\n\t" 49 | "pushq %%r13\n\t" 50 | "pushq %%r14\n\t" 51 | "pushq %%r15\n\t" 52 | "movq %%rsp, %0\n\t" 53 | "movq %1, %%rsp\n\t" 54 | "popq %%r15\n\t" 55 | "popq %%r14\n\t" 56 | "popq %%r13\n\t" 57 | "popq %%r12\n\t" 58 | "popq %%rdi\n\t" 59 | "popq %%rbp\n\t" 60 | "popq %%rbx\n\t" 61 | #else 62 | /* 63 | * [i386 ABI] callee-saved register: EBX,EBP,ESI,EDI 64 | */ 65 | "pushl %%ebx\n\t" 66 | "pushl %%ebp\n\t" 67 | "pushl %%edi\n\t" 68 | "pushl %%esi\n\t" 69 | "movl %%esp, %0\n\t" 70 | "movl %1, %%esp\n\t" 71 | "popl %%esi\n\t" 72 | "popl %%edi\n\t" 73 | "popl %%ebp\n\t" 74 | "popl %%ebx\n\t" 75 | #endif 76 | : 77 | : "m"(from->sp), "r"(to->sp)); 78 | } 79 | 80 | -------------------------------------------------------------------------------- /src/x86_mt_utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #ifndef __X86_MT_UTILS_H__ 31 | #define __X86_MT_UTILS_H__ 32 | 33 | static inline void xchg_swap32(uint32_t *target, uint32_t *value) 34 | { 35 | __asm__ __volatile__ ( 36 | "xchgl %0, %1" 37 | :"=r"(*value) 38 | :"m"(*target), "0"(*value) 39 | :"memory" ); 40 | } 41 | 42 | typedef struct { 43 | volatile int val; 44 | } light_lock_t; 45 | 46 | #define LIGHT_LOCK_INIT {1} 47 | #define light_lock_init light_unlock 48 | 49 | static inline void light_lock(light_lock_t *lock) 50 | { 51 | /* fast spin 52 | * borrowed from kernel-2.6.16 53 | * ~16ns if no spin 54 | */ 55 | __asm__ __volatile__ ( 56 | "\n1:\t" ); 57 | 58 | __asm__ __volatile__ ( 59 | "\n2:\t" 60 | "lock ; " 61 | "decl %0\n\t" 62 | "jns 5f\n" 63 | "3:\t" 64 | "rep;nop\n\t" 65 | "incl %1\n\t" 66 | "cmpl $5000,%1\n\t" /* ~ 3us */ 67 | "jae 4f\n\t" 68 | "cmpl $0,%0\n\t" 69 | "jle 3b\n\t" 70 | "jmp 2b\n" 71 | "4:\n\t" 72 | :"=m"(lock->val) 73 | :"r"(0) 74 | :"memory" ); 75 | /* slow spin 76 | * if the lock-owner-thread is SUSPENDED busywait is meaningless 77 | * sched_yield may help or less harmful 78 | */ 79 | while (lock->val <= 0) { 80 | sched_yield(); 81 | } 82 | __asm__ __volatile__ ( 83 | "jmp 1b\n" 84 | "5:\n\t"); 85 | } 86 | 87 | static inline void light_unlock(light_lock_t *lock) 88 | { 89 | __asm__ __volatile__ ( 90 | "movl $1,%0" 91 | :"=m"(lock->val) 92 | : :"memory" ); 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/mt_utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #ifndef __MT_UTILS_H__ 31 | #define __MT_UTILS_H__ 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #define CASSERT(predicate) _impl_CASSERT_LINE(predicate,__LINE__) 38 | #define _impl_PASTE(a,b) a##b 39 | #define _impl_CASSERT_LINE(predicate, line) \ 40 | typedef char _impl_PASTE(assertion_failed_line_,line)[2*!!(predicate)-1]; 41 | 42 | #ifndef MICORO_MT 43 | # define MICORO_MT 1 44 | #endif 45 | 46 | #if MICORO_MT 47 | # if MICORO_X86_OPTIMIZE 48 | # include "x86_mt_utils.h" 49 | # define ATOM_SWAP32 xchg_swap32 50 | # define MICORO_LOCK_T light_lock_t 51 | # define MICORO_LOCK_INITVAL LIGHT_LOCK_INIT 52 | # define MICORO_LOCK_INIT light_lock_init 53 | # define MICORO_LOCK light_lock 54 | # define MICORO_UNLOCK light_unlock 55 | # else 56 | # include 57 | # define ATOM_SWAP32 lock_swap32 58 | # define MICORO_LOCK_T pthread_mutex_t 59 | # define MICORO_LOCK_INITVAL PTHREAD_MUTEX_INITIALIZER 60 | # define MICORO_LOCK_INIT(lock) pthread_mutex_init(lock, NULL) 61 | # define MICORO_LOCK pthread_mutex_lock 62 | # define MICORO_UNLOCK pthread_mutex_unlock 63 | # endif 64 | #else 65 | # define ATOM_SWAP32 simple_swap32 66 | # define MICORO_LOCK_T int 67 | # define MICORO_LOCK_INITVAL {0} 68 | # define MICORO_LOCK_INIT(lock) do { (void)(lock); } while (0) 69 | # define MICORO_LOCK(lock) do { (void)(lock); } while (0) 70 | # define MICORO_UNLOCK(lock) do { (void)(lock); } while (0) 71 | #endif 72 | 73 | static inline void simple_swap32(uint32_t *target, uint32_t *value) 74 | { 75 | uint32_t tmp = *target; 76 | *target = *value; 77 | *value = tmp; 78 | } 79 | 80 | static inline void lock_swap32(uint32_t *target, uint32_t *value) 81 | { 82 | MICORO_LOCK_T lock = MICORO_LOCK_INITVAL; 83 | MICORO_LOCK(&lock); 84 | simple_swap32(target, value); 85 | MICORO_UNLOCK(&lock); 86 | } 87 | 88 | int init_once(int *init_flag); 89 | 90 | #endif // __MT_UTILS_H__ 91 | -------------------------------------------------------------------------------- /src/coro_mm_malloc.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include 31 | #include 32 | #include "coro_mm.h" 33 | 34 | static size_t g_alloc_size; 35 | static size_t g_pool_size; 36 | 37 | static void **g_alloc_table; 38 | static void *g_max_addr = NULL; 39 | 40 | static struct coro_mm_stat g_stat; 41 | 42 | static int init(size_t *alloc_size, size_t pool_size) 43 | { 44 | g_alloc_size = *alloc_size; 45 | g_pool_size = pool_size; 46 | if (!(g_alloc_table = calloc(pool_size, sizeof(void*)))) { 47 | return -1; 48 | } 49 | return 0; 50 | } 51 | 52 | static void* alloc() 53 | { 54 | static size_t index = 0; 55 | void *ptr = NULL; 56 | size_t i; 57 | for (i = 0; i < g_pool_size && !ptr; i++) { 58 | if (g_alloc_table[index] == NULL) { 59 | ptr = g_alloc_table[index] = malloc(g_alloc_size); 60 | g_stat.alloc_count++; 61 | g_stat.use_block_num++; 62 | } 63 | index = (index + 1) % g_pool_size; 64 | } 65 | if (ptr + g_alloc_size - 1 > g_max_addr) 66 | g_max_addr = ptr + g_alloc_size - 1; 67 | return ptr; 68 | } 69 | 70 | static int release(void *ptr) 71 | { 72 | size_t i; 73 | for (i = 0; i < g_pool_size; i++) { 74 | if (g_alloc_table[i] == ptr) { 75 | g_alloc_table[i] = NULL; 76 | free(ptr); 77 | g_stat.release_count++; 78 | g_stat.use_block_num--; 79 | return 0; 80 | } 81 | } 82 | return -1; 83 | } 84 | 85 | static void* locate(void *ptr) 86 | { 87 | size_t i; 88 | if (ptr > g_max_addr) 89 | return NULL; 90 | for (i = 0; i < g_pool_size; i++) { 91 | if (ptr >= g_alloc_table[i] && ptr < g_alloc_table[i] + g_alloc_size) { 92 | return g_alloc_table[i]; 93 | } 94 | } 95 | return NULL; 96 | } 97 | 98 | static void get_stat(struct coro_mm_stat *stat) 99 | { 100 | stat->alloc_count = g_stat.alloc_count; 101 | stat->release_count = g_stat.release_count; 102 | stat->use_block_num = g_stat.use_block_num; 103 | assert(g_pool_size >= g_stat.use_block_num); 104 | stat->free_block_num = g_pool_size - g_stat.use_block_num; 105 | } 106 | 107 | static struct coro_mm_ops g_ops = { 108 | .init = init, 109 | .alloc = alloc, 110 | .release = release, 111 | .locate = locate, 112 | .get_stat = get_stat 113 | }; 114 | 115 | struct coro_mm_ops *coro_mm_malloc_ops = &g_ops; 116 | -------------------------------------------------------------------------------- /src/micoro.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #ifndef __COROUTINE_H__ 31 | #define __COROUTINE_H__ 32 | 33 | #include 34 | #include 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | struct coro_ctx; 41 | 42 | typedef struct { 43 | struct coro_ctx *ctx; 44 | } coro_t; 45 | 46 | /* @coro_init 47 | * initialize coroutine library (e.g. alloc context pool) 48 | * must do this before calling any other functions 49 | * 50 | * @ctx_size : fixed context (including the stack) size for each coroutine, 51 | * to avoid stack overflow >=8K is suggested 52 | * @pool_size: size of pre-allocated context pool, also means max 53 | * concurrent coroutines 54 | * @return : 0 for success, <0 for error 55 | */ 56 | int coro_init(size_t ctx_size, size_t pool_size); 57 | 58 | /* @coro_create 59 | * create a new coroutine 60 | * this function create context for the new coroutine without lauching it, 61 | * after this call done use coro_resume to launch the coroutine 62 | * 63 | * @coro : output param, return handler of the new coroutine if no error 64 | * @f : entry function of the new coroutine 65 | * @return: 0 for success, <0 for error 66 | */ 67 | int coro_create(coro_t *coro, void* (*f)(void*)); 68 | 69 | /* @coro_resume 70 | * resume execution of the suspending coroutine (as sub-coro of the caller 71 | * which is either a coroutine or non-coroutine code) 72 | * a suspending coroutine may come from either case: 73 | * 1) a new coroutine created by coro_create 74 | * 2) a running coroutine had yield cpu by coro_yield 75 | * in case 1) the new coroutine is resumed to run from the beginning of the 76 | * entry function 77 | * in case 2) the coroutine is resumed as if the coro_yield() returns 78 | * the caller is suspended as parent-coro waiting for the sub-coro to 79 | * yield or exit 80 | * 81 | * @coro : the coroutine to resume 82 | * @arg : param passed to the coroutine (sub-coro) 83 | * in case 1) @arg is assigned to the argument of entry function 84 | * in case 2) @arg is returned from coro_yield() 85 | * @return: value of argument @arg in coro_yiled() from sub-coro 86 | */ 87 | void* coro_resume(coro_t *coro, void *arg); 88 | 89 | /* @coro_yield 90 | * yield execution of current coroutine and resume execution of the 91 | * parent-coro which is actually either a coroutine or non-coroutine code 92 | * current coroutine is suspended in this call and will be resumed by 93 | * later coro_resume() 94 | * 95 | * @arg : param passed to parent-coro 96 | * @arg is returned from coro_resume() when parent-coro is resumed 97 | * @return: value of argument @arg in coro_resume() that resume the coro 98 | */ 99 | void* coro_yield(void *arg); 100 | 101 | /* @coro_self 102 | * get current coroutine in which this function is called 103 | * note that all coroutines do come from coro_create, so calling coro_self 104 | * from non-coroutine code (e.g. from main() ) will fail 105 | * 106 | * @coro : output param, return handler of current coroutine if no error 107 | * @return: 0 for success, <0 for error 108 | */ 109 | int coro_self(coro_t *coro); 110 | 111 | /* @coro_err 112 | * get error status of the coroutine 113 | * 114 | * @coro : the coroutine to check 115 | * @return: 0 for no error, >0 indicate error number 116 | */ 117 | static inline int coro_err(const coro_t *coro) 118 | { 119 | if (!coro || !coro->ctx) 120 | return 1; 121 | return 0; 122 | } 123 | 124 | /* coroutine library running status */ 125 | struct coro_stat 126 | { 127 | /* total coro_create count */ 128 | uint64_t create_count; 129 | /* total coro_resume count */ 130 | uint64_t resume_count; 131 | /* total coro_yield count */ 132 | uint64_t yield_count; 133 | /* total coroutine exit count */ 134 | uint64_t destroy_count; 135 | /* concurrent running coroutine number now */ 136 | uint32_t alive_coro_num; 137 | /* free slots number of context-pool now */ 138 | uint32_t pool_left_num; 139 | }; 140 | 141 | /* @coro_get_stat 142 | * get coroutine library running status 143 | * 144 | * @stat: output param, return coro_stat structure 145 | */ 146 | void coro_get_stat(struct coro_stat *stat); 147 | 148 | #ifdef __cplusplus 149 | } 150 | #endif 151 | 152 | #endif // __COROUTINE_H__ 153 | -------------------------------------------------------------------------------- /src/coro_sched.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include 31 | #include 32 | #include 33 | #include "coro_comm.h" 34 | #include "coro_mm.h" 35 | 36 | static int g_init_flag = 0; 37 | static struct coro_mm_ops *g_mm_ops = NULL; 38 | static size_t g_ctx_size = 0; 39 | static struct coro_stat g_stat; 40 | 41 | int coro_init(size_t ctx_size, size_t pool_size) 42 | { 43 | if (init_once(&g_init_flag) < 0) { 44 | fprintf(stderr, "coro init more than once!\n"); 45 | return -1; 46 | } 47 | 48 | g_mm_ops = coro_mm_default_ops; 49 | g_ctx_size = ctx_size; 50 | 51 | if (g_mm_ops->init(&g_ctx_size, pool_size) < 0) { 52 | fprintf(stderr, "mm init failed!\n"); 53 | return -2; 54 | } 55 | 56 | return 0; 57 | } 58 | 59 | static inline int check_ctx(struct coro_ctx *ctx, int prev, int next) 60 | { 61 | if (!ctx) return 0; 62 | if (ctx->tag != CORO_CTX_TAG) return 0; 63 | if (prev >= 0 && !!ctx->prev != !!prev) return 0; 64 | if (next >= 0 && !!ctx->next != !!next) return 0; 65 | return 1; 66 | } 67 | 68 | static inline void check_ctx_or_die(struct coro_ctx *ctx, 69 | int prev, int next, const char *str) 70 | { 71 | if (!check_ctx(ctx, prev, next)) { 72 | // bug found 73 | fprintf(stderr, "%s\n", str); 74 | abort(); 75 | } 76 | } 77 | 78 | void* coro_resume(coro_t *coro, void *arg) 79 | { 80 | struct coro_ctx main_ctx; 81 | struct coro_ctx *cur, *to = coro->ctx; 82 | 83 | /* using a old/wild coro ? */ 84 | check_ctx_or_die(to, -1, -1, "resuming bad coro (1)"); 85 | 86 | if ((cur = g_mm_ops->locate(&arg))) { 87 | check_ctx_or_die(cur, 1, 0, "resuming from bad coro"); 88 | } 89 | else { 90 | memset(&main_ctx, 0, sizeof(struct coro_ctx)); 91 | main_ctx.tag = CORO_CTX_TAG; 92 | cur = &main_ctx; 93 | } 94 | 95 | MICORO_LOCK(&to->lock); 96 | 97 | /* using a dying coro ? */ 98 | check_ctx_or_die(to, 0, 0, "resuming bad coro (2)"); 99 | 100 | cur->next = to; 101 | to->prev = cur; 102 | to->ret = arg; 103 | 104 | g_stat.resume_count++; 105 | coro_switch(cur, to); 106 | 107 | if (to->flag & CORO_FLAG_END) { 108 | memset(to, 0, sizeof(struct coro_ctx)); 109 | /* give a chance to avoid dead-locking */ 110 | MICORO_UNLOCK(&to->lock); 111 | /* must before release because coro maybe in the stack */ 112 | coro->ctx = NULL; 113 | g_mm_ops->release(to); 114 | } else { 115 | MICORO_UNLOCK(&to->lock); 116 | } 117 | 118 | return cur->ret; 119 | } 120 | 121 | static void* do_coro_yield(void *arg, unsigned int flag) 122 | { 123 | struct coro_ctx *to, *cur = NULL; 124 | 125 | cur = g_mm_ops->locate(&arg); 126 | check_ctx_or_die(cur, 1, 0, "yielding from bad coro"); 127 | check_ctx_or_die(cur->prev, -1, 1, "yielding to bad coro"); 128 | to = cur->prev; 129 | cur->prev = NULL; 130 | to->next = NULL; 131 | to->ret = arg; 132 | cur->flag = flag; 133 | g_stat.yield_count++; 134 | coro_switch(cur, to); 135 | return cur->ret; 136 | } 137 | 138 | void* coro_yield(void *arg) 139 | { 140 | return do_coro_yield(arg, 0); 141 | } 142 | 143 | void __coro_main(void* (*f)(void*)) 144 | { 145 | struct coro_ctx *cur; 146 | void *arg, *ret; 147 | 148 | cur = g_mm_ops->locate(&arg); 149 | check_ctx_or_die(cur, 1, 0, "coro_main found bad coro"); 150 | arg = cur->ret; 151 | ret = f(arg); 152 | do_coro_yield(ret, CORO_FLAG_END); 153 | fprintf(stderr, "bug! resume dead coro_main\n"); 154 | abort(); 155 | } 156 | 157 | int coro_create(coro_t *coro, void* (*f)(void*)) 158 | { 159 | struct coro_ctx *ctx; 160 | 161 | if (!g_init_flag) { 162 | fprintf(stderr, "bug! coro_create without coro_init! abort\n"); 163 | abort(); 164 | } 165 | coro->ctx = NULL; 166 | 167 | if (!(ctx = g_mm_ops->alloc())) 168 | return -1; 169 | memset(ctx, 0, sizeof(struct coro_ctx)); 170 | 171 | coro_makectx(ctx, g_ctx_size, f); 172 | 173 | ctx->tag = CORO_CTX_TAG; 174 | MICORO_LOCK_INIT(&ctx->lock); 175 | 176 | coro->ctx = ctx; 177 | return 0; 178 | } 179 | 180 | int coro_self(coro_t *coro) 181 | { 182 | struct coro_ctx *ctx; 183 | 184 | coro->ctx = NULL; 185 | if (!g_init_flag) 186 | return -1; 187 | ctx = g_mm_ops->locate(&coro); 188 | if (ctx == NULL) 189 | return -2; 190 | coro->ctx = ctx; 191 | return 0; 192 | } 193 | 194 | void coro_get_stat(struct coro_stat *stat) 195 | { 196 | struct coro_mm_stat mm_stat; 197 | g_mm_ops->get_stat(&mm_stat); 198 | stat->create_count = mm_stat.alloc_count; 199 | stat->destroy_count = mm_stat.release_count; 200 | stat->alive_coro_num = mm_stat.use_block_num; 201 | stat->pool_left_num = mm_stat.free_block_num; 202 | stat->resume_count = g_stat.resume_count; 203 | stat->yield_count = g_stat.yield_count; 204 | } 205 | 206 | -------------------------------------------------------------------------------- /src/coro_mm_pool.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012, Bin Wei 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * * The name of of its contributors may not be used to endorse or 15 | * promote products derived from this software without specific prior 16 | * written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "coro_mm.h" 36 | #include "mt_utils.h" 37 | 38 | #define PAGE_SHIFT 12 39 | #define PAGE_SIZE (1UL << PAGE_SHIFT) 40 | #define BLOCK_TAG_1 0xaabb7788 41 | #define BLOCK_TAG_2 0xccdd9900 42 | 43 | struct block_info 44 | { 45 | /* TAGs for error detection */ 46 | volatile unsigned long tag1; 47 | struct block_info * volatile next; 48 | volatile unsigned long tag2; 49 | }; 50 | 51 | struct page_info 52 | { 53 | volatile unsigned int use_flag : 1; 54 | volatile unsigned int head_page : 31; 55 | }; 56 | /* for 32bit atomic operation */ 57 | CASSERT(sizeof(struct page_info) == sizeof(uint32_t)); 58 | 59 | static int g_init_flag; 60 | static size_t g_block_pages; 61 | static size_t g_pool_blocks; 62 | static size_t g_pool_pages; 63 | static void *g_pool_addr; 64 | static struct page_info *g_page_map; 65 | static struct block_info * volatile g_free_list; 66 | static MICORO_LOCK_T g_lock = MICORO_LOCK_INITVAL; 67 | static struct coro_mm_stat g_stat; 68 | 69 | #define IN_POOL(addr) ((void *)(addr) < (g_pool_addr + (g_pool_pages<= g_pool_addr) 71 | #define PAGE_NO(addr) ((size_t)(((void *)(addr) - g_pool_addr) >> PAGE_SHIFT)) 72 | #define NO_PTR(no) ((no) ? (void *)(g_pool_addr + ((size_t)(no) << PAGE_SHIFT)) : NULL) 73 | #define PTR_HEAD(addr) (NO_PTR(g_page_map[PAGE_NO(addr)].head_page)) 74 | 75 | static inline size_t guard_pages(size_t blocks) 76 | { 77 | /* 78 | * garde-page(G) & block-pages(B) interleaved as: 79 | * 80 | * 81 | * blocks guard-pages 82 | * (00, 01] -> 1 +1 83 | * (01, 03] -> 2 +1 84 | * (03, 07] -> 3 +1 85 | * (07, 0F] -> 4 +1 86 | * ... 87 | * 88 | * Algo: effective_bit_width(blocks) + 1 89 | */ 90 | size_t i; 91 | for (i = 1; blocks &~ ((1UL<tag1 = BLOCK_TAG_1; 118 | cur->tag2 = BLOCK_TAG_2; 119 | cur->next = NULL; 120 | if (prev) 121 | prev->next = cur; 122 | else 123 | g_free_list = cur; 124 | prev = cur; 125 | 126 | blk_page_no = PAGE_NO(cur); 127 | for (i = 0; i < g_block_pages; i++) { 128 | g_page_map[blk_page_no + i].head_page = blk_page_no; 129 | } 130 | 131 | cur = (void *)cur + (g_block_pages << PAGE_SHIFT); 132 | } 133 | /* end by a guard-page */ 134 | #if HAVE_GOOD_MPROTECT 135 | if (mprotect(cur, PAGE_SIZE, PROT_NONE) < 0) 136 | return -1; 137 | #endif 138 | g_page_map[PAGE_NO(cur)].head_page = 0; 139 | cur = (void *)cur + PAGE_SIZE; 140 | /* last check */ 141 | assert(cur == g_pool_addr + (g_pool_pages << PAGE_SHIFT)); 142 | 143 | return 0; 144 | } 145 | 146 | static int init(size_t *alloc_size, size_t pool_size) 147 | { 148 | if (init_once(&g_init_flag) < 0) { 149 | fprintf(stderr, "init multi times!"); 150 | return -1; 151 | } 152 | 153 | g_block_pages = (*alloc_size + PAGE_SIZE - 1) >> PAGE_SHIFT; 154 | g_pool_blocks = pool_size; 155 | if (g_block_pages <= 0 || g_pool_blocks <= 0) 156 | return -1; 157 | g_pool_pages = g_block_pages * g_pool_blocks + guard_pages(g_pool_blocks); 158 | 159 | #ifndef MAP_ANONYMOUS 160 | # define MAP_ANONYMOUS MAP_ANON 161 | #endif 162 | g_pool_addr = mmap(NULL, (g_pool_pages << PAGE_SHIFT), PROT_READ|PROT_WRITE, 163 | MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 164 | if (g_pool_addr == MAP_FAILED) { 165 | perror("mmap failed"); 166 | return -2; 167 | } 168 | 169 | g_page_map = calloc(g_pool_pages, sizeof(struct page_info)); 170 | if (g_page_map == NULL) { 171 | perror("calloc failed"); 172 | munmap(g_pool_addr, (g_pool_pages << PAGE_SHIFT)); 173 | return -3; 174 | } 175 | 176 | if (do_init_pool() < 0) { 177 | perror("do_init_pool failed"); 178 | free(g_page_map); 179 | munmap(g_pool_addr, (g_pool_pages << PAGE_SHIFT)); 180 | return -4; 181 | } 182 | 183 | *alloc_size = g_block_pages << PAGE_SHIFT; 184 | return 0; 185 | } 186 | 187 | static void* alloc() 188 | { 189 | struct block_info *block; 190 | 191 | MICORO_LOCK(&g_lock); 192 | block = g_free_list; 193 | if (block) { 194 | g_free_list = block->next; 195 | g_stat.alloc_count++; 196 | g_stat.use_block_num++; 197 | } 198 | MICORO_UNLOCK(&g_lock); 199 | 200 | if (!block) return NULL; 201 | 202 | assert(block->tag1 == BLOCK_TAG_1 203 | && block->tag2 == BLOCK_TAG_2); 204 | assert(g_page_map[PAGE_NO(block)].use_flag == 0); 205 | 206 | g_page_map[PAGE_NO(block)].use_flag = 1; 207 | 208 | return block; 209 | } 210 | 211 | static int release(void *ptr) 212 | { 213 | struct block_info *block = ptr; 214 | struct page_info pi; 215 | 216 | if (!IN_POOL(ptr) || PTR_HEAD(ptr) != ptr) { 217 | abort(); 218 | return -1; 219 | } 220 | 221 | pi = g_page_map[PAGE_NO(ptr)]; 222 | pi.use_flag = 0; 223 | ATOM_SWAP32((uint32_t*)&g_page_map[PAGE_NO(ptr)], (uint32_t*)&pi); 224 | if (pi.use_flag == 0) { 225 | abort(); 226 | return -2; 227 | } 228 | 229 | MICORO_LOCK(&g_lock); 230 | /* within lock for mem concurrency */ 231 | block->tag1 = BLOCK_TAG_1; 232 | block->tag2 = BLOCK_TAG_2; 233 | block->next = g_free_list; 234 | g_free_list = block; 235 | g_stat.release_count++; 236 | g_stat.use_block_num--; 237 | MICORO_UNLOCK(&g_lock); 238 | 239 | return 0; 240 | } 241 | 242 | static void* locate(void *ptr) 243 | { 244 | if (!IN_POOL(ptr)) 245 | return NULL; 246 | return PTR_HEAD(ptr); 247 | } 248 | 249 | static void get_stat(struct coro_mm_stat *stat) 250 | { 251 | stat->alloc_count = g_stat.alloc_count; 252 | stat->release_count = g_stat.release_count; 253 | stat->use_block_num = g_stat.use_block_num; 254 | assert(g_pool_blocks >= g_stat.use_block_num); 255 | stat->free_block_num = g_pool_blocks - g_stat.use_block_num; 256 | } 257 | 258 | static struct coro_mm_ops g_ops = { 259 | .init = init, 260 | .alloc = alloc, 261 | .release = release, 262 | .locate = locate, 263 | .get_stat = get_stat 264 | }; 265 | 266 | struct coro_mm_ops *coro_mm_pool_ops = &g_ops; 267 | 268 | --------------------------------------------------------------------------------