├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── docs └── zh_cn │ ├── CoroC Language Specification.md │ └── How to build clang CoroC frontend.md ├── examples ├── C │ ├── CMakeLists.txt │ ├── chan.c │ ├── file.c │ ├── findmax.c │ ├── findmax_msg.c │ ├── httpload.c │ ├── mandelbrot.c │ ├── primes.c │ ├── select.c │ ├── spectral-norm.c │ ├── tcpproxy.c │ ├── ticker.c │ └── timeshare.c └── CoroC │ ├── CMakeLists.txt │ ├── file_co.co │ ├── findmax_co.co │ ├── group_co.co │ ├── httpload_co.co │ ├── mandelbrot_co.co │ ├── primes_co.co │ ├── select_co.co │ ├── smart-pointer-2_co.co │ ├── smart-pointer_co.co │ ├── spectral-norm_co.co │ ├── tcpproxy_co.co │ └── ticker_co.co ├── include ├── CMakeLists.txt ├── inter │ ├── CMakeLists.txt │ ├── async.h │ ├── channel.h │ ├── config.h.in │ ├── context.h │ ├── coroc_clock.h │ ├── coroc_group.h │ ├── coroc_hash.h │ ├── coroc_lock.h │ ├── coroc_queue.h │ ├── coroc_time.h │ ├── coroutine.h │ ├── darwin │ │ ├── 386-ucontext.h │ │ ├── CMakeLists.txt │ │ ├── amd64-ucontext.h │ │ ├── power-ucontext.h │ │ ├── pthread_barrier.h │ │ ├── pthread_spinlock.h │ │ └── time_.h │ ├── futex_lock.h │ ├── lock_chain.h │ ├── message.h │ ├── netpoll.h │ ├── notify.h │ ├── refcnt.h │ ├── support.h │ ├── vfs.h │ └── vpu.h └── libcoroc.h ├── scripts ├── gdb_helper.py └── vimrc_co │ ├── ftdetect │ └── cofiletype.vim │ └── syntax │ └── co.vim └── src ├── CMakeLists.txt ├── async.c ├── boot.c ├── channel.c ├── clock.c ├── context.c ├── coroc_main.c ├── coroutine.c ├── darwin ├── asm.S ├── pthread_barrier.c └── ucontext.c ├── futex_impl.c ├── futex_lock.c ├── group.c ├── hash.c ├── message.c ├── net.c ├── netpoll.c ├── netpoll_epoll.c ├── netpoll_kqueue.c ├── netpoll_poll.c ├── notify.c ├── time.c ├── vfs.c └── vpu.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.so 4 | *.run 5 | *.swp 6 | *.dSYM 7 | core 8 | 9 | cscope.* 10 | 11 | tags 12 | 13 | .DS_Store 14 | build 15 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | IF(WIN32) 3 | MESSAGE(FATAL_ERROR "LibCoroC not support Windows now!") 4 | ELSE(WIN32) 5 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0 FATAL_ERROR) 6 | ENDIF(WIN32) 7 | 8 | PROJECT(LibCoroC) 9 | 10 | ## Get the architecture of current platform 11 | EXECUTE_PROCESS(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCH) 12 | MESSAGE(STATUS "Architecture: ${ARCH}") 13 | 14 | ## Default include path: 15 | INCLUDE_DIRECTORIES(${LibCoroC_SOURCE_DIR}/include) 16 | INCLUDE_DIRECTORIES(${LibCoroC_SOURCE_DIR}/include/inter) 17 | 18 | ## Check the version of GCC to decide if it support `-fsplit-stack' 19 | ## option or not. 20 | MACRO(SET_SPLITSTACK_FLAGS) 21 | IF(${CMAKE_C_COMPILER_ID} MATCHES "GNU") 22 | EXECUTE_PROCESS( 23 | COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) 24 | 25 | IF(NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)) 26 | MESSAGE(FATAL_ERROR "\"split-stack\" requires gcc 4.7 or greater.") 27 | ELSE() 28 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsplit-stack") 29 | ENDIF() 30 | ELSE() 31 | MESSAGE(FATAL_ERROR "\"split-stack\" requires gcc 4.7 or greater.") 32 | ENDIF() 33 | ENDMACRO() 34 | 35 | ## Option to enable Split-stack 36 | OPTION(ENABLE_SPLITSTACK "Enable the split-stack for coroutines" OFF) 37 | IF(ENABLE_SPLITSTACK) 38 | IF(CMAKE_SYSTEM MATCHES "Linux") 39 | IF(${ARCH} MATCHES "x86.*") 40 | SET_SPLITSTACK_FLAGS() 41 | ELSE() 42 | MESSAGE(FATAL_ERROR "split-stack only supported on x86/amd64 architures!") 43 | ENDIF() 44 | ELSE() 45 | MESSAGE(FATAL_ERROR "split-stack only supported on Linux!") 46 | ENDIF() 47 | ENDIF(ENABLE_SPLITSTACK) 48 | 49 | ## Option to enable time-sharing schedule 50 | OPTION(ENABLE_TIMESHARE "Enable the time-sharing scheduler" OFF) 51 | 52 | IF(CMAKE_SYSTEM MATCHES "Linux") 53 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -rdynamic") 54 | ENDIF() 55 | 56 | OPTION(ENABLE_NOTIFY "Enable kernel notify (Linux only)" ON) 57 | 58 | ## Option to enable futex-based lock 59 | OPTION(ENABLE_FUTEX "Enable futex based locks (Linux only)" OFF) 60 | IF(ENABLE_FUTEX OR ENABLE_NOTIFY) 61 | IF(NOT CMAKE_SYSTEM MATCHES "Linux") 62 | MESSAGE(FATAL_ERROR "FUTEX / NOTIFY is only supported on Linux!") 63 | ENDIF() 64 | ENDIF(ENABLE_FUTEX OR ENABLE_NOTIFY) 65 | 66 | ## Option to use the tc-malloc 67 | OPTION(ENABLE_TCMALLOC "Using tc-malloc for memory management" OFF) 68 | IF(ENABLE_TCMALLOC) 69 | FIND_LIBRARY(LIB_TCMALLOC "libtcmalloc_minimal") 70 | IF(LIB_TCMALLOC) 71 | MESSAGE(STATUS "found libtcmalloc as ${LIB_TCMALLOC}") 72 | ELSE() 73 | MESSAGE(FATAL_ERROR "libtcmalloc not found") 74 | ENDIF() 75 | ENDIF(ENABLE_TCMALLOC) 76 | 77 | ## The config header auto-generating in config time 78 | CONFIGURE_FILE(include/inter/config.h.in include/inter/config.h) 79 | 80 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include/) 81 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/include/inter) 82 | 83 | ########################################## 84 | ## Optional build components 85 | 86 | # C Examples 87 | OPTION(BUILD_C_EXAMPLES "Enable to build C Examples" ON) 88 | 89 | # CoroC Examples 90 | OPTION(BUILD_COROC_EXAMPLES "Enable to build CoroC Examples" OFF) 91 | 92 | # Core Library 93 | ADD_SUBDIRECTORY(src) 94 | 95 | IF(BUILD_C_EXAMPLES) 96 | ADD_SUBDIRECTORY(examples/C) 97 | ENDIF(BUILD_C_EXAMPLES) 98 | 99 | IF(BUILD_COROC_EXAMPLES) 100 | FIND_PROGRAM(CLANG_COROC "clang-co") 101 | IF(CLANG_COROC) 102 | MESSAGE(STATUS "Found CLANG_COROC as ${CLANG_COROC}") 103 | ADD_SUBDIRECTORY(examples/CoroC) 104 | ELSE(CLANG_COROC) 105 | MESSAGE(FATAL_ERROR "clang-co not found -- ${CLANG_COROC}") 106 | ENDIF(CLANG_COROC) 107 | ENDIF(BUILD_COROC_EXAMPLES) 108 | 109 | ADD_SUBDIRECTORY(include) 110 | 111 | ## install the auto-generated config header 112 | INSTALL_FILES(/include/inter FILES ${CMAKE_CURRENT_BINARY_DIR}/include/inter/config.h) 113 | 114 | ## install the gdb-helper script 115 | INSTALL_FILES(/share FILES ${CMAKE_CURRENT_SOURCE_DIR}/scripts/gdb_helper.py) 116 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LibCoroC -- Yet another coroutine library 2 | 3 | The LibCoroC is a coroutine library for Unix like systems written by C. 4 | 5 | ## Introduction 6 | 7 | Coroutine is a kind of light-weight task mechanism which implemented in user space. As less resources usage and less overhead during context-switch than OS level threads or processes, the coroutines are well-suited for implementing the user level concurrent system or library. 8 | 9 | The [Go](http://golang.org) and its ancestor [libtask](http://swtch.com/libtask/) use the coroutine mechanism to implement the user-level tasks, called Goroutine in Go and task in libtask. 10 | 11 | The LibCoroC is yet another coroutine library just like the libtask and Go. 12 | Furthermore, our goal is to support the multi-core platforms, time-sharing and priority-scheduling mechanism which not or not all supported in Go or libtask, 13 | or any other coroutine libraries. 14 | 15 | In current version, we use the [ucontext](http://en.wikipedia.org/wiki/Setcontext) API defined in GNU libc to implement the coroutine, 16 | called `coroc_coroutine_t` in our library and use the POSIX Threads API to support the OS-level threads. 17 | And the per-thread signal mechanism is used to emulate the interrupt for computing-intensive coroutines, which is the basis of the time-sharing in libCoroC. 18 | 19 | ## Build 20 | 21 | LibCoroC is designed for all Unix like systems, include Linux, *BSD and Darwin, 22 | but only Linux (x86, amd64 and armv7) and Darwin (amd64) have been tested now. 23 | 24 | It is simple to build the library and examples by **CMake**, and the following options 25 | are provided: 26 | 27 | - `BUILD_COROC_EXAMPLES` to build all examples written in CoroC (**you need a CoroC clang frontend for this **) 28 | - `BUILD_C_EXAMPLES` to build all examples written in C and use libCoroC as library calls 29 | - `ENABLE_FUTEX` to use the futex based lock mechanism instead of the pthread spinlock (**Linux only**) 30 | - `ENABLE_NOTIFY` to enable the kernel notify (**Linux only**) 31 | - `ENABLE_SPLITSTACK` to enable the split-stack feature, make sure your complier (gcc 4.6.0+) and linker (GNU gold) support that feature! 32 | - `ENABLE_TCMALLOC` to use google's tc-malloc instead of the pt-malloc default in GNU libc. 33 | - `ENABLE_TIMESHARE` to enable the time-sharing scheduler, which is disable default. 34 | 35 | 36 | ## Examples 37 | 38 | LibCoroC is built as a static library now, in order to use it, you need to link it with your own programs. 39 | 40 | Some examples are provided for users to test the library: 41 | 42 | - **findmax.c**: for testing the basic thread and channel API 43 | - **findmax_msg.c**: for testing the message-passing API 44 | - **timeshare.c**: for testing the time-sharing mechanism 45 | - **select.c**: for testing the select operation among multi-channels 46 | - **ticker.c**: for testing the ticker/timer API 47 | - **file.c**: for testing the file API 48 | - **chan.c**: for testing the channel API 49 | - **primes.c**: example migrated from libtask 50 | - **tcpproxy.c**: example migrated from libtask 51 | - **httpload.c**: example migrated from libtask 52 | - **mandelbrot.c**: benchmark migrated from the [benchmarksgame.org](http://benchmarksgame.alioth.debian.org) 53 | - **spectral-norm.c**: benchmark migrated from the [benchmarksgame.org](http://benchmarksgame.alioth.debian.org) 54 | 55 | ## Debug 56 | 57 | We provide a python script to enhance the GDB to debug the applications using libCoroC. 58 | 59 | Make sure your GDB is compiled with the option "--with-python", 60 | you can open GDB and type such command to test whether python plugin is available for you: 61 | 62 | (gdb) python print(1 + 1) 63 | 64 | You can go through if it output "2"; otherwise, try to re-compile your gdb. 65 | 66 | At the beginning, you should load our simple script `src/gdb_hepler.py`: 67 | 68 | (gdb) source where/is/gdb_helper.py 69 | 70 | then, you can use the command `info coroutines` to list all the live coroutines. 71 | 72 | Further more, if you want to trace the stack frame of a given coroutine, you can type: 73 | 74 | (gdb) coroutine id backtrace 75 | 76 | replace the *id* with the coroutine id number you want to trace, which can be found after running 77 | the command `info coroutines`. 78 | 79 | If the *cmd* (*backtrace* in previous example) is omitted, and the coroutine with *id* is running, 80 | then you can switch to that coroutine. 81 | 82 | This script is very simple and the functions provided are very limited now. 83 | We hope that lots of new features will be added in the future. 84 | 85 | ## Platforms Requirement 86 | 87 | Linux on x86/x86-64 or armv7 using the GCC toolchain, 88 | if compiling with option `enable_splitstack=1`, you need to use GCC 4.6.0 or later, binutils 2.21 or later with `--enable-gold`. 89 | 90 | OS X on x86-64 using the GCC or XCode toolchain, 91 | the "splitstack" feature is not enable on OS X because we only support 64-bit arch, which not need the "splitstack". 92 | 93 | The GDB debug helper script is available for each supported platforms, however, 94 | make sure your GDB is version 7.0 or later and built with python enable. 95 | 96 | ## License 97 | 98 | The libtsc is under a BSD-style opensource license, as same as the golang. 99 | However, the frontend of CoroC based on clang is under the BSD license used by clang/llvm.See `LICENSE.txt` for details. 100 | 101 | ## TODO 102 | 103 | There are lots of things needed to improve both the functionality and the performance: 104 | 105 | - A more efficient way for work-stealing among the schedulers (*A new random stealing mechanism is added by ZHJ*) 106 | - Wrappers for the system calls which may suspend the current scheduler 107 | - Asynchronous API for socket IO operations (**DNOE**) 108 | - [Segment-stack](http://gcc.gnu.org/wiki/SplitStacks) support for coroutines (**DONE**) 109 | - A more efficient memory management module, like [tc_malloc](http://goog-perftools.sourceforge.net/doc/tcmalloc.html) 110 | - Garbage-Collection mechanism for auto deallocation (*A simple reference-counting mechanism is provided now*) 111 | 112 | -------------------------------------------------------------------------------- /docs/zh_cn/How to build clang CoroC frontend.md: -------------------------------------------------------------------------------- 1 | # 关于CoroC编译器及运行时库的构建 2 | 3 | ## 具体步骤如下: 4 | 5 | 1. 从 git 仓库下载最新的 Clang-Coroc 代码: `git clone https://amalcao@bitbucket.org/amalcao/clang-coroc.git` 6 | 7 | 2. 从llvm.org下载[llvm3.5.0](http://llvm.org/releases/3.5.0/llvm-3.5.0.src.tar.xz)并解压(`tar Jxf llvm-3.5.0.src.tar.xz`),然后下载[compiler-rt-3.5.0](http://llvm.org/releases/3.5.0/compiler-rt-3.5.0.src.tar.xz)源代码,解压到llvm的projects子目录中,并重命名为`compiler-rt`。 8 | 9 | 3. 编译llvm3.5和clang-coroc-3.5源代码,具体方法是: 10 | 11 | - 将clang-coroc-3.5源码目录移至llvm源码目录的tools子目录下; 12 | - 在源码目录外单独创建一个用来进行编译工作的目录,运行`cmake`或`configure`进行配置(*可以省略一些无关项以加快编译流程*); 13 | - 生成Makefile后,通过`make && make install` 进行编译、安装。 14 | - 注意:由于新版clang代码采用了一些C++0x/C++11标准的特性,因此要求C++编译器及标准C++库支持最新的C++语言标准,因此最好升级到gcc4.7(>= libstdc++-4.7)以上版本。 15 | 16 | 4. 使用CoroC的编译器命令行工具: 17 | 18 | - clang-coroc 编译安装成功后,将安装路径下的`bin`子目录加入系统的`PATH`环境变量中 19 | - 在终端运行`clang-co`命令进行CoroC代码的编译工作:`clang-co -rewrite-coroc input.co` 20 | - 编译成功后会生成一个后缀名为".cc"的C++文件,就是翻译后的文件;如果提示找不到`clang-co`,那么请检查安装是否正确以及PATH变量设置情况。 21 | 22 | 5. 编译runtime及其示例程序 23 | 24 | - 将新编译好的clang二进制可执行文件安装路径添加到PATH环境变量中; 25 | - 直接进入runtime的源码路径,键入`make`进行编译,如果编译正确,则当前目录下会出现一个`bin`子目录,其中包含了测试程序;如果出错,检查一下Makefile的相关设置,如编译器版本等,修改后再进行编译。 26 | 27 | 6. 利用gdb进行程序调试 28 | 29 | - 按照普通方式启动gdb调试,如: `gdb ./bin/primes.run` ; 30 | - 运行 `r` 命令前,先加载 runtime 目录下的 `scripts/gdb_helper.py` 脚本,方法是在gdb的CLI交互界面下输入 `source where/is/gdb_helper.py`(*将路径替换为实际的路径*); 31 | - 成功加载后,就可以运行针对CoroC运行时设计的新命令了,如`info coroutine` 等,具体参见 runtime 目录下的 readme.md 文件。 32 | 33 | 34 | ## 备注 35 | 36 | 鉴于CoroC开发尚处于初级阶段,测试并不完善,各种问题可能会比较多,请大家及时将BUG或问题反馈给我(amalcaowei@gmail.com),以便及早修正。 37 | 38 | 另外,本文档内容可能比较简略,也希望大家在实际操作过程中根据自己的经验,不断完善本文档,以便后面加入的同学可以节省一些时间,谢谢大家! -------------------------------------------------------------------------------- /examples/C/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(INCLUDE_FILES ${LibCoroC_SOURCE_DIR}/include/libcoroc.h) 2 | SET(COROC_LIB coroc) 3 | LINK_DIRECTORIES(${LibCoroC_SOURCE_DIR}/src) 4 | 5 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Dmain=user_main") 6 | 7 | SET(SYS_LIB pthread m) 8 | 9 | IF(NOT APPLE) 10 | SET(SYS_LIB ${SYS_LIB} rt) 11 | ENDIF() 12 | 13 | MACRO(add_libcoroc_c_example name) 14 | ADD_EXECUTABLE( 15 | ${name}.run 16 | ${name}.c 17 | ${INCLUDE_FILES} 18 | ) 19 | 20 | IF(LIB_TCMALLOC) 21 | TARGET_LINK_LIBRARIES( 22 | ${name}.run 23 | ${COROC_LIB} ${LIB_TCMALLOC} ${SYS_LIB} 24 | ) 25 | ELSE(LIB_TCMALLOC) 26 | TARGET_LINK_LIBRARIES( 27 | ${name}.run 28 | ${COROC_LIB} ${SYS_LIB} 29 | ) 30 | ENDIF(LIB_TCMALLOC) 31 | ENDMACRO(add_libcoroc_c_example) 32 | 33 | add_libcoroc_c_example(chan) 34 | add_libcoroc_c_example(findmax) 35 | add_libcoroc_c_example(findmax_msg) 36 | add_libcoroc_c_example(file) 37 | add_libcoroc_c_example(httpload) 38 | add_libcoroc_c_example(mandelbrot) 39 | add_libcoroc_c_example(primes) 40 | add_libcoroc_c_example(select) 41 | add_libcoroc_c_example(spectral-norm) 42 | add_libcoroc_c_example(tcpproxy) 43 | add_libcoroc_c_example(ticker) 44 | 45 | IF(ENABLE_TIMESHARE) 46 | add_libcoroc_c_example(timeshare) 47 | ENDIF(ENABLE_TIMESHARE) 48 | -------------------------------------------------------------------------------- /examples/C/chan.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | 8 | #include "libcoroc.h" 9 | 10 | coroc_coroutine_t init; 11 | 12 | int subtask(coroc_chan_t chan) { 13 | int ret, id; 14 | while (1) { 15 | ret = coroc_chan_recv(chan, &id); 16 | // printf ("[subtask] %x\n", ret); 17 | if (ret == CHAN_CLOSED) break; 18 | printf("[subtask] recv id is %d.\n", id); 19 | } 20 | 21 | coroc_sendp(init, NULL, 0); 22 | coroc_refcnt_put((coroc_refcnt_t)chan); 23 | coroc_coroutine_exit(0); 24 | } 25 | 26 | int main(int argc, char** argv) { 27 | init = coroc_coroutine_self(); 28 | 29 | uint64_t awaken = 0; 30 | int i = 0; 31 | coroc_chan_t chan = coroc_chan_allocate(sizeof(int), 0); 32 | 33 | coroc_timer_t timer = coroc_timer_allocate(1000000 * 1, NULL); 34 | coroc_timer_after(timer, 1000000 * 1); // 1 seconds later 35 | 36 | coroc_coroutine_allocate(subtask, coroc_refcnt_get(chan), "sub", 37 | TSC_COROUTINE_NORMAL, TSC_DEFAULT_PRIO, 0); 38 | 39 | for (i = 0; i < 5; i++) { 40 | printf("waiting for 1 seconds!\n"); 41 | coroc_chan_recv((coroc_chan_t)timer, &awaken); 42 | coroc_chan_sende(chan, i + 1); 43 | } 44 | 45 | printf("release the timer ..\n"); 46 | coroc_chan_close(chan); 47 | coroc_refcnt_put((coroc_refcnt_t)chan); 48 | 49 | coroc_timer_stop(timer); 50 | coroc_timer_dealloc(timer); 51 | 52 | coroc_recv(NULL, 0, true); 53 | 54 | coroc_coroutine_exit(0); 55 | } 56 | -------------------------------------------------------------------------------- /examples/C/file.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include "libcoroc.h" 7 | 8 | const char wbuf[] = "Hello the world!\n"; 9 | char rbuf[100]; 10 | 11 | int main(int argc, char **argv) { 12 | int fd; 13 | 14 | if (argc != 2) { 15 | fprintf(stderr, "usage: %s filename\n", argv[0]); 16 | coroc_coroutine_exit(-1); 17 | } 18 | 19 | fd = coroc_vfs_open(argv[1], O_RDWR | O_APPEND | O_CREAT, 0644); 20 | coroc_vfs_write(fd, wbuf, sizeof(wbuf)); 21 | coroc_vfs_flush(fd); 22 | coroc_vfs_close(fd); 23 | 24 | fd = coroc_vfs_open_sync(argv[1], O_RDONLY); 25 | coroc_vfs_read(fd, rbuf, sizeof(wbuf)); 26 | printf("%s\n", rbuf); 27 | 28 | coroc_vfs_close_sync(fd); 29 | 30 | coroc_coroutine_exit(0); 31 | } 32 | -------------------------------------------------------------------------------- /examples/C/findmax.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "libcoroc.h" 10 | 11 | #define MAX 16 12 | 13 | int* array; 14 | 15 | void gen_array_elem(int* array, int size) { 16 | int i; 17 | 18 | srand(array); 19 | 20 | for (i = 0; i < size; i++) { 21 | array[i] = rand(); 22 | } 23 | } 24 | 25 | bool check_max_elem(int* array, int size, int max) { 26 | int i; 27 | for (i = 0; i < size; i++) { 28 | if (array[i] > max) return false; 29 | } 30 | 31 | return true; 32 | } 33 | 34 | /* -- the slave entry -- */ 35 | int find_max(coroc_chan_t chan) { 36 | coroc_coroutine_t self = coroc_coroutine_self(); 37 | int size, start, max[2]; 38 | 39 | // get the size firstly 40 | coroc_chan_recv(chan, &size); 41 | if (size <= 0) coroc_coroutine_exit(-1); 42 | // get my tasks' start index 43 | coroc_chan_recv(chan, &start); 44 | 45 | max[0] = array[start]; 46 | max[1] = array[start + 1]; 47 | if (size > 1) { 48 | if (size > 2) { 49 | 50 | coroc_coroutine_t slave[2]; 51 | coroc_chan_t ch[2]; 52 | int sz[2], st[2]; 53 | 54 | sz[0] = size / 2; 55 | st[0] = start; 56 | sz[1] = size - sz[0]; 57 | st[1] = start + sz[0]; 58 | 59 | int i = 0; 60 | for (; i < 2; ++i) { 61 | ch[i] = coroc_chan_allocate(sizeof(int), 0); 62 | slave[i] = coroc_coroutine_allocate(find_max, ch[i], "", 63 | TSC_COROUTINE_NORMAL, 64 | TSC_DEFAULT_PRIO, 0); 65 | coroc_chan_send(ch[i], &sz[i]); 66 | coroc_chan_send(ch[i], &st[i]); 67 | } 68 | 69 | coroc_chan_recv(ch[0], &max[0]); 70 | coroc_chan_recv(ch[1], &max[1]); 71 | } 72 | if (max[0] < max[1]) max[0] = max[1]; 73 | } 74 | 75 | coroc_chan_send(chan, &max[0]); 76 | coroc_coroutine_exit(0); 77 | } 78 | 79 | /* -- the user entry -- */ 80 | int main(int argc, char** argv) { 81 | int max = 0, size = MAX, start = 0; 82 | array = malloc(size * sizeof(int)); 83 | coroc_coroutine_t slave = NULL; 84 | coroc_chan_t chan = NULL; 85 | 86 | gen_array_elem(array, size); 87 | chan = coroc_chan_allocate(sizeof(int), 0); 88 | slave = coroc_coroutine_allocate(find_max, chan, "s", 89 | TSC_COROUTINE_NORMAL, 90 | TSC_DEFAULT_PRIO, 0); 91 | 92 | coroc_chan_send(chan, &size); // send the size of array 93 | coroc_chan_send(chan, &start); // send the start index of array 94 | 95 | coroc_chan_recv(chan, &max); // recv the result 96 | 97 | printf("The MAX element is %d\n", max); 98 | if (!check_max_elem(array, size, max)) printf("The answer is wrong!\n"); 99 | 100 | free(array); 101 | coroc_coroutine_exit(0); 102 | } 103 | -------------------------------------------------------------------------------- /examples/C/findmax_msg.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "libcoroc.h" 10 | 11 | #define MAX 16 12 | 13 | void gen_array_elem(int* array, int size) { 14 | int i; 15 | 16 | srand(array); 17 | 18 | for (i = 0; i < size; i++) { 19 | array[i] = rand(); 20 | } 21 | } 22 | 23 | bool check_max_elem(int* array, int size, int max) { 24 | int i; 25 | for (i = 0; i < size; i++) { 26 | if (array[i] > max) return false; 27 | } 28 | 29 | return true; 30 | } 31 | 32 | /* -- the slave entry -- */ 33 | int find_max(void* arg) { 34 | coroc_coroutine_t parent = (coroc_coroutine_t)arg; 35 | coroc_coroutine_t self = coroc_coroutine_self(); 36 | int size, *buf; 37 | 38 | // firstly, get the size .. 39 | coroc_recvp(&buf, &size, true); 40 | if (size < sizeof(int)) coroc_coroutine_exit(-1); 41 | 42 | size /= sizeof(int); 43 | 44 | if (size > 1) { 45 | if (size > 2) { 46 | 47 | coroc_coroutine_t slave0, slave1; 48 | int sz0, sz1; 49 | 50 | sz0 = size / 2; 51 | sz1 = size - sz0; 52 | 53 | slave0 = coroc_coroutine_allocate(find_max, coroc_refcnt_get(self), "s0", 54 | TSC_COROUTINE_NORMAL, 55 | TSC_DEFAULT_PRIO, 0); 56 | coroc_send(slave0, buf, sz0 * sizeof(int)); 57 | 58 | slave1 = coroc_coroutine_allocate(find_max, coroc_refcnt_get(self), "s1", 59 | TSC_COROUTINE_NORMAL, 60 | TSC_DEFAULT_PRIO, 0); 61 | coroc_send(slave1, buf + sz0, sz1 * sizeof(int)); 62 | 63 | coroc_recv(&buf[0], sizeof(int), true); 64 | coroc_recv(&buf[1], sizeof(int), true); 65 | } 66 | if (buf[0] < buf[1]) buf[0] = buf[1]; 67 | } 68 | 69 | coroc_send(parent, buf, sizeof(int)); 70 | 71 | free(buf); 72 | 73 | coroc_refcnt_put((coroc_refcnt_t)(parent)); 74 | coroc_coroutine_exit(0); 75 | } 76 | 77 | /* -- the user entry -- */ 78 | int main(void* arg) { 79 | int max = 0, size = MAX; 80 | int* array = malloc(size * sizeof(int)); 81 | coroc_coroutine_t slave = NULL; 82 | coroc_coroutine_t self = coroc_coroutine_self(); 83 | 84 | gen_array_elem(array, size); 85 | slave = coroc_coroutine_allocate(find_max, coroc_refcnt_get(self), "s", 86 | TSC_COROUTINE_NORMAL, 87 | TSC_DEFAULT_PRIO, 0); 88 | 89 | coroc_send(slave, array, size * sizeof(int)); // coroc_send the content of array 90 | coroc_recv(&max, sizeof(int), true); 91 | 92 | printf("The MAX element is %d\n", max); 93 | if (!check_max_elem(array, size, max)) printf("The answer is wrong!\n"); 94 | 95 | free(array); 96 | coroc_coroutine_exit(0); 97 | } 98 | -------------------------------------------------------------------------------- /examples/C/httpload.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "libcoroc.h" 12 | 13 | char *server; 14 | char *url; 15 | 16 | int fetchtask(void *); 17 | 18 | int main(int argc, char **argv) { 19 | int i, n; 20 | 21 | if (argc != 4) { 22 | fprintf(stderr, "usage: httpload n server url\n"); 23 | coroc_coroutine_exit(-1); 24 | } 25 | n = atoi(argv[1]); 26 | server = argv[2]; 27 | url = argv[3]; 28 | 29 | for (i = 0; i < n; i++) { 30 | coroc_coroutine_allocate(fetchtask, 0, "fetch", 31 | TSC_COROUTINE_NORMAL, TSC_DEFAULT_PRIO, 0); 32 | coroc_udelay(1000); 33 | } 34 | 35 | while (1) coroc_coroutine_yield(); 36 | 37 | coroc_coroutine_exit(0); 38 | } 39 | 40 | int fetchtask(void *v) { 41 | int fd, n; 42 | char buf[512]; 43 | 44 | fprintf(stderr, "starting...\n"); 45 | for (;;) { 46 | if ((fd = coroc_net_dial(true, server, 80)) < 0) { 47 | fprintf(stderr, "dial %s: %s\n", server, strerror(errno)); 48 | continue; 49 | } 50 | snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", url, 51 | server); 52 | coroc_net_write(fd, buf, strlen(buf)); 53 | while ((n = coroc_net_read(fd, buf, sizeof buf)) > 0) 54 | ; 55 | close(fd); 56 | write(1, ".", 1); 57 | } 58 | 59 | coroc_coroutine_exit(0); 60 | } 61 | -------------------------------------------------------------------------------- /examples/C/mandelbrot.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "libcoroc.h" 11 | 12 | const double ZERO = 0; 13 | const double LIMIT = 2.0; 14 | const int ITER = 50; 15 | const int SIZE = 16000; 16 | 17 | uint8_t* rows; 18 | int bytesPerRow; 19 | 20 | int w, h, iter; 21 | 22 | // This func is responsible for rendering a row of pixels, 23 | // and when complete writing it out to the file. 24 | 25 | void renderRow(coroc_chan_t* chans) { 26 | coroc_chan_t workChan = chans[0]; 27 | coroc_chan_t finishChan = chans[1]; 28 | 29 | double Zr, Zi, Tr, Ti, Cr, Ci; 30 | int x, y, i; 31 | int offset; 32 | 33 | coroc_chan_recv(workChan, &y); 34 | offset = y * bytesPerRow; 35 | Ci = (2 * (double)y / (double)h - 1.0); 36 | 37 | for (x = 0; x < w; x++) { 38 | Zr = Zi = Tr = Ti = ZERO; 39 | Cr = (2 * (double)x / (double)w - 1.5); 40 | 41 | for (i = 0; i < iter && Tr + Ti <= LIMIT * LIMIT; i++) { 42 | Zi = 2 * Zi * Zr + Ci; 43 | Zr = Tr - Ti + Cr; 44 | Tr = Zr * Zr; 45 | Ti = Zi * Zi; 46 | } 47 | 48 | // Store tje value in the array of ints 49 | if (Tr + Ti <= LIMIT * LIMIT) 50 | rows[offset + x / 8] |= (1 << (uint32_t)(7 - (x % 8))); 51 | } 52 | 53 | bool finish = true; 54 | coroc_chan_send(finishChan, &finish); 55 | } 56 | 57 | #define POOL 4 58 | #define WORK_CHAN 0 59 | #define FINISH_CHAN 1 60 | 61 | void main(int argc, char** argv) { 62 | int size, y; 63 | coroc_chan_t chans[2]; 64 | 65 | size = (argc > 1) ? atoi(argv[1]) : SIZE; 66 | 67 | iter = ITER; 68 | w = h = size; 69 | bytesPerRow = w / 8; 70 | 71 | rows = malloc(sizeof(uint8_t) * bytesPerRow * h); 72 | memset(rows, 0, bytesPerRow * h); 73 | 74 | chans[WORK_CHAN] = coroc_chan_allocate(sizeof(int), 2 * POOL + 1); 75 | chans[FINISH_CHAN] = coroc_chan_allocate(sizeof(bool), 0); 76 | 77 | for (y = 0; y < size; y++) { 78 | coroc_coroutine_t slave = coroc_coroutine_allocate(renderRow, chans, "", 79 | TSC_COROUTINE_NORMAL, 80 | TSC_DEFAULT_PRIO, NULL); 81 | coroc_chan_send(chans[WORK_CHAN], &y); 82 | } 83 | 84 | for (y = 0; y < size; y++) { 85 | bool finish; 86 | coroc_chan_recv(chans[FINISH_CHAN], &finish); 87 | } 88 | 89 | /* -- uncomment the next line to output the result -- */ 90 | /* fwrite (rows, h * w / 8, 1, stdout); */ 91 | 92 | free(rows); 93 | 94 | return; 95 | } 96 | -------------------------------------------------------------------------------- /examples/C/primes.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | /* Copyright (c) 2005 Russ Cox, MIT; see COPYRIGHT */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "libcoroc.h" 12 | 13 | int quiet = 0; 14 | int goal = 100; 15 | int buffer = 0; 16 | 17 | int primetask(void *arg) { 18 | coroc_chan_t c, nc; 19 | unsigned long p, i; 20 | c = arg; 21 | 22 | coroc_chan_recv(c, &p); 23 | 24 | if (p > goal) exit(0); 25 | 26 | if (!quiet) printf("%d\n", p); 27 | 28 | nc = coroc_chan_allocate(sizeof(unsigned long), buffer); 29 | coroc_coroutine_allocate(primetask, nc, "", 30 | TSC_COROUTINE_NORMAL, TSC_DEFAULT_PRIO, NULL); 31 | for (;;) { 32 | coroc_chan_recv(c, &i); 33 | if (i % p) coroc_chan_send(nc, &i); 34 | } 35 | return 0; 36 | } 37 | 38 | void main(int argc, char **argv) { 39 | unsigned long i; 40 | coroc_chan_t c; 41 | 42 | printf("goal=%d\n", goal); 43 | 44 | c = coroc_chan_allocate(sizeof(unsigned long), buffer); 45 | coroc_coroutine_allocate(primetask, c, "", 46 | TSC_COROUTINE_NORMAL, TSC_DEFAULT_PRIO, NULL); 47 | for (i = 2;; i++) coroc_chan_send(c, &i); 48 | } 49 | -------------------------------------------------------------------------------- /examples/C/select.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | 8 | #include "libcoroc.h" 9 | 10 | #define SIZE 4 11 | 12 | int sub_task(coroc_chan_t chan) { 13 | int id = random(); 14 | coroc_chan_send(chan, &id); 15 | 16 | coroc_coroutine_exit(0); 17 | } 18 | 19 | int sub_task2(coroc_coroutine_t parent) { 20 | // note: since the `&id' is sent just as a pointer, 21 | // so the `id' must be allocated on DATA segment (using static keyword), 22 | // not on the stack which released after coroc_coroutine_exit.. 23 | static int id = 12345; 24 | 25 | coroc_udelay(10000); 26 | coroc_sendp(parent, &id, sizeof(int)); 27 | 28 | coroc_coroutine_exit(0); 29 | } 30 | 31 | int main(int argc, char** argv) { 32 | coroc_coroutine_t me = coroc_coroutine_self(); 33 | coroc_coroutine_t thrds[SIZE]; 34 | coroc_chan_t chans[SIZE]; 35 | coroc_chan_set_t set = coroc_chan_set_allocate(SIZE + 1); 36 | coroc_msg_t message; 37 | int i = 0, id; 38 | 39 | for (; i < SIZE; i++) { 40 | chans[i] = coroc_chan_allocate(sizeof(int), 0); 41 | thrds[i] = coroc_coroutine_allocate(sub_task, chans[i], "", 42 | TSC_COROUTINE_NORMAL, 43 | TSC_DEFAULT_PRIO, NULL); 44 | coroc_chan_set_recv(set, chans[i], &id); 45 | } 46 | 47 | coroc_coroutine_allocate(sub_task2, me, "msg", 48 | TSC_COROUTINE_NORMAL, TSC_DEFAULT_PRIO, NULL); 49 | coroc_chan_set_recv(set, NULL, &message); 50 | 51 | for (i = 0; i <= SIZE; i++) { 52 | coroc_chan_t ch = NULL; 53 | coroc_chan_set_select(set, &ch); 54 | 55 | if (ch == me) { 56 | id = *(int*)(message.msg); 57 | } 58 | 59 | if (ch != NULL) { 60 | printf("[main task]: recv id is %d!\n", id); 61 | } 62 | } 63 | 64 | coroc_chan_set_dealloc(set); 65 | for (i = 0; i < SIZE; i++) coroc_chan_dealloc(chans[i]); 66 | 67 | coroc_coroutine_exit(0); 68 | } 69 | -------------------------------------------------------------------------------- /examples/C/spectral-norm.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "libcoroc.h" 11 | 12 | int Num = 1000; 13 | int NumCPU = 2; 14 | double *U, *V, *T; 15 | double *_u, *_v; 16 | coroc_chan_t finishChan = NULL; 17 | 18 | static inline double Dot(double *v, double *u, int n) { 19 | double sum = 0.0; 20 | int i; 21 | 22 | for (i = 0; i < n; i++) sum += v[i] * u[i]; 23 | return sum; 24 | } 25 | 26 | static inline double A(int i, int j) { 27 | return ((i + j) * (i + j + 1) / 2 + i + 1); 28 | } 29 | 30 | void task_Atv(int kk) { 31 | int size = (Num + NumCPU - 1) / NumCPU; 32 | int start = size * kk; 33 | int end = size * (kk + 1); 34 | if (end > Num) end = Num; 35 | 36 | int ul = Num; 37 | int i, j; 38 | for (i = start; i < end; i++) { 39 | double vi = 0; 40 | for (j = 0; j < ul; j++) vi += (_u[j] / (double)(A(j, i))); 41 | 42 | _v[i] = vi; 43 | } 44 | 45 | bool finish = true; 46 | coroc_chan_send(finishChan, &finish); 47 | } 48 | 49 | void task_Av(int kk) { 50 | int size = (Num + NumCPU - 1) / NumCPU; 51 | int start = size * kk; 52 | int end = size * (kk + 1); 53 | if (end > Num) end = Num; 54 | 55 | int ul = Num; 56 | int i, j; 57 | for (i = start; i < end; i++) { 58 | double vi = 0; 59 | for (j = 0; j < ul; j++) vi += (_u[j] / (double)(A(i, j))); 60 | 61 | _v[i] = vi; 62 | } 63 | 64 | bool finish = true; 65 | coroc_chan_send(finishChan, &finish); 66 | } 67 | 68 | void mult_Atv(double *v, double *u) { 69 | int k; 70 | bool finish; 71 | _v = v; 72 | _u = u; 73 | for (k = 0; k < NumCPU; k++) { 74 | coroc_coroutine_t task = 75 | coroc_coroutine_allocate(task_Atv, k, "", 76 | TSC_COROUTINE_NORMAL, 77 | TSC_DEFAULT_PRIO, NULL); 78 | } 79 | 80 | for (k = 0; k < NumCPU; k++) coroc_chan_recv(finishChan, &finish); 81 | } 82 | 83 | void mult_Av(double *v, double *u) { 84 | int k; 85 | bool finish; 86 | _v = v; 87 | _u = u; 88 | for (k = 0; k < NumCPU; k++) { 89 | coroc_coroutine_t task = 90 | coroc_coroutine_allocate(task_Av, k, "", 91 | TSC_COROUTINE_NORMAL, 92 | TSC_DEFAULT_PRIO, NULL); 93 | } 94 | 95 | for (k = 0; k < NumCPU; k++) coroc_chan_recv(finishChan, &finish); 96 | } 97 | 98 | void mult_AtAv(double *v, double *u, double *x) { 99 | mult_Av(x, u); 100 | mult_Atv(v, x); 101 | } 102 | 103 | double SpectralNorm(int n) { 104 | U = malloc(sizeof(double) * n); 105 | V = malloc(sizeof(double) * n); 106 | T = malloc(sizeof(double) * n); 107 | 108 | int i; 109 | 110 | for (i = 0; i < n; i++) U[i] = 1; 111 | 112 | for (i = 0; i < 10; i++) { 113 | mult_AtAv(V, U, T); 114 | mult_AtAv(U, V, T); 115 | } 116 | 117 | double dot_uv = Dot(U, V, n); 118 | double dot_vv = Dot(V, V, n); 119 | 120 | free(U); 121 | free(V); 122 | free(T); 123 | return sqrt(dot_uv / dot_vv); 124 | } 125 | 126 | void main(int argc, char **argv) { 127 | if (argc > 1) Num = atoi(argv[1]); 128 | 129 | finishChan = coroc_chan_allocate(sizeof(bool), 0); 130 | printf("%0.9f\n", SpectralNorm(Num)); 131 | // coroc_chan_dealloc (finishChan); 132 | } 133 | -------------------------------------------------------------------------------- /examples/C/tcpproxy.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "libcoroc.h" 13 | 14 | char *server; 15 | int port; 16 | int proxy_task(void *); 17 | int rwtask(void *); 18 | 19 | int *mkfd2(int fd1, int fd2) { 20 | int *a; 21 | 22 | a = malloc(2 * sizeof a[0]); 23 | if (a == 0) { 24 | fprintf(stderr, "out of memory\n"); 25 | abort(); 26 | } 27 | 28 | a[0] = fd1; 29 | a[1] = fd2; 30 | 31 | return a; 32 | } 33 | 34 | int main(int argc, char **argv) { 35 | int cfd, fd; 36 | int rport; 37 | char remote[16]; 38 | 39 | if (argc != 4) { 40 | fprintf(stderr, "usage: tcpproxy localport server remoteport\n"); 41 | coroc_coroutine_exit(-1); 42 | } 43 | 44 | server = argv[2]; 45 | port = atoi(argv[3]); 46 | 47 | if ((fd = coroc_net_announce(true, 0, atoi(argv[1]))) < 0) { 48 | fprintf(stderr, "cannot announce on tcp port %d: %s\n", atoi(argv[1]), 49 | strerror(errno)); 50 | coroc_coroutine_exit(-1); 51 | } 52 | 53 | coroc_net_nonblock(fd); 54 | while ((cfd = coroc_net_accept(fd, remote, &rport)) >= 0) { 55 | fprintf(stderr, "connection from %s:%d\n", remote, rport); 56 | coroc_coroutine_allocate(proxy_task, (void*)cfd, "proxy", 57 | TSC_COROUTINE_NORMAL, TSC_DEFAULT_PRIO, NULL); 58 | } 59 | 60 | coroc_coroutine_exit(0); 61 | } 62 | 63 | int proxy_task(void *v) { 64 | int fd, remotefd; 65 | 66 | fd = (int)v; 67 | if ((remotefd = coroc_net_dial(true, server, port)) < 0) { 68 | close(fd); 69 | coroc_coroutine_exit(-1); 70 | } 71 | 72 | fprintf(stderr, "connected to %s:%d\n", server, port); 73 | 74 | coroc_coroutine_allocate(rwtask, mkfd2(fd, remotefd), "rwtask", 75 | TSC_COROUTINE_NORMAL, TSC_DEFAULT_PRIO, NULL); 76 | coroc_coroutine_allocate(rwtask, mkfd2(remotefd, fd), "rwtask", 77 | TSC_COROUTINE_NORMAL, TSC_DEFAULT_PRIO, NULL); 78 | 79 | coroc_coroutine_exit(0); 80 | } 81 | 82 | int rwtask(void *v) { 83 | int *a, rfd, wfd, n; 84 | char buf[2048]; 85 | 86 | a = v; 87 | rfd = a[0]; 88 | wfd = a[1]; 89 | free(a); 90 | 91 | while ((n = coroc_net_read(rfd, buf, sizeof buf)) > 0) 92 | coroc_net_write(wfd, buf, n); 93 | 94 | shutdown(wfd, SHUT_WR); 95 | close(rfd); 96 | 97 | coroc_coroutine_exit(0); 98 | } 99 | -------------------------------------------------------------------------------- /examples/C/ticker.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | 8 | #include "libcoroc.h" 9 | 10 | void callback(void) { printf("\ttime out!\n"); } 11 | 12 | int main(int argc, char** argv) { 13 | uint64_t awaken = 0; 14 | int i = 0; 15 | coroc_timer_t timer = coroc_timer_allocate(1000000 * 2, callback); 16 | coroc_timer_after(timer, 1000000 * 2); // 2 seconds later 17 | 18 | for (i = 0; i < 3; i++) { 19 | printf("waiting for 2 seconds!\n"); 20 | coroc_chan_recv((coroc_chan_t)timer, &awaken); 21 | printf("awaken, time is %llu!\n", (long long unsigned)awaken); 22 | } 23 | 24 | printf("release the timer ..\n"); 25 | coroc_timer_stop(timer); 26 | coroc_timer_dealloc(timer); 27 | 28 | coroc_coroutine_exit(0); 29 | } 30 | -------------------------------------------------------------------------------- /examples/C/timeshare.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | /* - - - - 6 | * The User APP using LibTSC .. 7 | * - - - - */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "libcoroc.h" 14 | 15 | void sub_task(void* arg) { 16 | uint64_t id = (uint64_t)arg; 17 | 18 | printf("[sub_task:] id is %i!\n", id); 19 | 20 | for (;;) { 21 | #ifndef ENABLE_TIMESHARE 22 | coroc_coroutine_yield(); 23 | #endif 24 | } 25 | 26 | coroc_coroutine_exit(0); 27 | } 28 | 29 | int main(int argc, char** argv) { 30 | coroc_coroutine_t threads[100]; 31 | 32 | int i; 33 | for (i = 0; i < 100; ++i) { 34 | threads[i] = 35 | coroc_coroutine_allocate(sub_task, i, "", TSC_COROUTINE_NORMAL, 0); 36 | } 37 | 38 | for (;;) { 39 | #ifndef ENABLE_TIMESHARE 40 | coroc_coroutine_yield(); 41 | #endif 42 | } 43 | 44 | coroc_coroutine_exit(0); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /examples/CoroC/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(INCLUDE_FILES ${LibCoroC_SOURCE_DIR}/include/libcoroc.h) 2 | SET(COROC_LIB coroc) 3 | LINK_DIRECTORIES(${LibCoroC_SOURCE_DIR}/src) 4 | 5 | SET(COROC_DIR ${LibCoroC_SOURCE_DIR}/examples/CoroC) 6 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Dmain=user_main") 7 | 8 | SET(COROC_FLAGS "-rewrite-coroc" 9 | "-I${LibCoroC_SOURCE_DIR}/include" 10 | "-I${LibCoroC_SOURCE_DIR}/include/inter" 11 | "-I${LibCoroC_BINARY_DIR}/include/inter") 12 | 13 | SET(SYS_LIB pthread m) 14 | 15 | ## Fix this for OS X Yosemite. 16 | IF(APPLE) 17 | SET(COROC_FLAGS "-isysroot" 18 | ${CMAKE_OSX_SYSROOT} 19 | ${COROC_FLAGS}) 20 | ELSE() 21 | SET(SYS_LIB ${SYS_LIB} rt) 22 | ENDIF(APPLE) 23 | 24 | MACRO(add_libcoroc_coroc_example name) 25 | 26 | SET(COROC_COMMAND ${CLANG_COROC} 27 | ${COROC_FLAGS} 28 | ${COROC_DIR}/${name}_co.co) 29 | 30 | ADD_CUSTOM_COMMAND( 31 | OUTPUT ${name}_co.c 32 | PRE_BUILD 33 | COMMAND ${COROC_COMMAND} 34 | DEPENDS ${name}_co.co) 35 | 36 | ADD_EXECUTABLE( 37 | ${name}_co.run 38 | ${name}_co.c 39 | ${INCLUDE_FILES} 40 | ) 41 | 42 | IF(LIB_TCMALLOC) 43 | TARGET_LINK_LIBRARIES( 44 | ${name}_co.run 45 | ${COROC_LIB} ${LIB_TCMALLOC} ${SYS_LIB} 46 | ) 47 | ELSE(LIB_TCMALLOC) 48 | TARGET_LINK_LIBRARIES( 49 | ${name}_co.run 50 | ${COROC_LIB} ${SYS_LIB} 51 | ) 52 | ENDIF(LIB_TCMALLOC) 53 | 54 | ENDMACRO(add_libcoroc_coroc_example) 55 | 56 | add_libcoroc_coroc_example(findmax) 57 | add_libcoroc_coroc_example(file) 58 | add_libcoroc_coroc_example(httpload) 59 | add_libcoroc_coroc_example(mandelbrot) 60 | add_libcoroc_coroc_example(primes) 61 | add_libcoroc_coroc_example(select) 62 | add_libcoroc_coroc_example(spectral-norm) 63 | add_libcoroc_coroc_example(tcpproxy) 64 | add_libcoroc_coroc_example(ticker) 65 | add_libcoroc_coroc_example(smart-pointer) 66 | add_libcoroc_coroc_example(smart-pointer-2) 67 | -------------------------------------------------------------------------------- /examples/CoroC/file_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | const char wbuf[] = "Hello the world!\n"; 10 | char rbuf[100]; 11 | 12 | int main(int argc, char **argv) { 13 | int fd; 14 | 15 | if (argc != 2) { 16 | fprintf(stderr, "usage: %s filename\n", argv[0]); 17 | __CoroC_Exit(-1); 18 | } 19 | 20 | fd = __CoroC_Async_Call open(argv[1], O_RDWR | O_APPEND | O_CREAT, 0644); 21 | __CoroC_Async_Call write(fd, wbuf, sizeof(wbuf)); 22 | __CoroC_Async_Call close(fd); 23 | 24 | fd = open(argv[1], O_RDONLY); 25 | 26 | __CoroC_Async_Call read(fd, rbuf, sizeof(wbuf)); 27 | printf("%s\n", rbuf); 28 | 29 | close(fd); 30 | 31 | __CoroC_Quit; 32 | } 33 | -------------------------------------------------------------------------------- /examples/CoroC/findmax_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #define MAX 16 12 | 13 | /* define a macro to slim the channel type name */ 14 | #define ICHAN_T __chan_t 15 | 16 | int* array; 17 | 18 | void gen_array_elem(int* array, int size) { 19 | int i; 20 | srand(123456); 21 | 22 | for (i = 0; i < size; i++) { 23 | array[i] = rand(); 24 | } 25 | } 26 | 27 | int check_max_elem(int* array, int size, int max) { 28 | int i; 29 | for (i = 0; i < size; i++) { 30 | if (array[i] > max) return 0; 31 | } 32 | return 1; 33 | } 34 | 35 | /* -- the slave entry -- */ 36 | int find_max(ICHAN_T chan) { 37 | int size, start, max[2]; 38 | ICHAN_T ch[2]; 39 | 40 | // get the size firstly 41 | chan >> size; 42 | if (size <= 0) 43 | return -1; 44 | 45 | // get my tasks' start index 46 | chan >> start; 47 | 48 | max[0] = array[start]; 49 | max[1] = array[start + 1]; 50 | if (size > 1) { 51 | if (size > 2) { 52 | 53 | int sz[2], st[2]; 54 | 55 | sz[0] = size / 2; 56 | st[0] = start; 57 | sz[1] = size - sz[0]; 58 | st[1] = start + sz[0]; 59 | 60 | int i; 61 | for (i = 0; i < 2; ++i) { 62 | ch[i] = __CoroC_Chan; 63 | __CoroC_Spawn find_max(ch[i]); 64 | ch[i] << sz[i]; 65 | ch[i] << st[i]; 66 | } 67 | 68 | ch[0] >> max[0]; 69 | ch[1] >> max[1]; 70 | } 71 | if (max[0] < max[1]) max[0] = max[1]; 72 | } 73 | 74 | chan << max[0]; 75 | 76 | return 0; 77 | } 78 | 79 | /* -- the user entry -- */ 80 | int main(int argc, char** argv) { 81 | int max = 0, size = MAX, start = 0; 82 | array = (int*)malloc(size * sizeof(int)); 83 | gen_array_elem(array, size); 84 | 85 | ICHAN_T chan = __CoroC_Chan; 86 | __CoroC_Spawn find_max(chan); 87 | 88 | chan << size; //send the size of array 89 | chan << start; // send the start index of array 90 | 91 | chan >> max; // recv the result 92 | 93 | printf("The MAX element is %d\n", max); 94 | if (!check_max_elem(array, size, max)) printf("The answer is wrong!\n"); 95 | 96 | free(array); 97 | 98 | __CoroC_Exit(0); 99 | } 100 | -------------------------------------------------------------------------------- /examples/CoroC/group_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include "libcoroc.h" 6 | #include 7 | #include 8 | 9 | #define N 10 10 | 11 | int subtask(unsigned *a) { 12 | *a = rand() % N; 13 | return 0; 14 | } 15 | 16 | int main() { 17 | __group_t grp = __CoroC_Group(); 18 | unsigned i, A[N]; 19 | 20 | for (i = 0; i < N; ++i) { 21 | __CoroC_Spawn subtask(&A[i]); 22 | } 23 | 24 | __CoroC_Sync(grp); 25 | 26 | for (i = 0; i < N; ++i) { 27 | printf("%d : %d\n", i, A[i]); 28 | } 29 | 30 | __CoroC_Quit 0; 31 | } 32 | -------------------------------------------------------------------------------- /examples/CoroC/httpload_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | char *server; 14 | char *url; 15 | 16 | int fetchtask(void) { 17 | int fd, n; 18 | char buf[512]; 19 | 20 | fprintf(stderr, "starting...\n"); 21 | while (1) { 22 | if ((fd = coroc_net_dial(true, server, 80)) < 0) { 23 | fprintf(stderr, "dial %s: %s\n", server, strerror(errno)); 24 | continue; 25 | } 26 | snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", url, server); 27 | coroc_net_write(fd, buf, strlen(buf)); 28 | while ((n = coroc_net_read(fd, buf, sizeof buf)) > 0); 29 | 30 | close(fd); 31 | write(1, ".", 1); 32 | } 33 | 34 | return 0; 35 | } 36 | 37 | int main (int argc, char **argv) { 38 | int i, n; 39 | 40 | if (argc != 4) { 41 | fprintf(stderr, "usage: httpload n server url\n"); 42 | __CoroC_Quit -1; 43 | } 44 | 45 | n = atoi(argv[1]); 46 | server = argv[2]; 47 | url = argv[3]; 48 | 49 | for (i = 0; i < n; i++) { 50 | __CoroC_Spawn fetchtask(); 51 | coroc_udelay(1000); 52 | } 53 | 54 | while (1) __CoroC_Yield; 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/CoroC/mandelbrot_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | const double ZERO = 0; 14 | const double LIMIT = 2.0; 15 | const int ITER = 50; 16 | const int SIZE = 16000; 17 | 18 | uint8_t* rows; 19 | int bytesPerRow; 20 | 21 | int w, h, iter; 22 | 23 | // This func is responsible for rendering a row of pixels, 24 | // and when complete writing it out to the file. 25 | 26 | void renderRow(__chan_t workChan, __chan_t finishChan) { 27 | double Zr, Zi, Tr, Ti, Cr, Ci; 28 | int x, y, i; 29 | int offset; 30 | 31 | workChan >> y; 32 | offset = y * bytesPerRow; 33 | Ci = (2 * (double)y / (double)h - 1.0); 34 | 35 | for (x = 0; x < w; x++) { 36 | Zr = Zi = Tr = Ti = ZERO; 37 | Cr = (2 * (double)x / (double)w - 1.5); 38 | 39 | for (i = 0; i < iter && Tr + Ti <= LIMIT * LIMIT; i++) { 40 | Zi = 2 * Zi * Zr + Ci; 41 | Zr = Tr - Ti + Cr; 42 | Tr = Zr * Zr; 43 | Ti = Zi * Zi; 44 | } 45 | 46 | // Store tje value in the array of ints 47 | if (Tr + Ti <= LIMIT * LIMIT) 48 | rows[offset + x / 8] |= (1 << (uint32_t)(7 - (x % 8))); 49 | } 50 | 51 | bool finish = true; 52 | finishChan << finish; 53 | } 54 | 55 | #define POOL 4 56 | 57 | int main(int argc, char** argv) { 58 | int size, y; 59 | 60 | size = (argc > 1) ? atoi(argv[1]) : SIZE; 61 | 62 | iter = ITER; 63 | w = h = size; 64 | bytesPerRow = w / 8; 65 | 66 | rows = (uint8_t*)malloc(sizeof(uint8_t) * bytesPerRow * h); 67 | memset(rows, 0, bytesPerRow * h); 68 | 69 | __chan_t workChan = __CoroC_Chan ; 70 | __chan_t finishChan = __CoroC_Chan ; 71 | 72 | for (y = 0; y < size; y++) { 73 | __CoroC_Spawn renderRow(workChan, finishChan); 74 | workChan << y; 75 | } 76 | 77 | for (y = 0; y < size; y++) { 78 | bool finish; 79 | finishChan >> finish; 80 | } 81 | 82 | /* -- uncomment the next line to output the result -- */ 83 | /* fwrite (rows, h * w / 8, 1, stdout); */ 84 | 85 | free(rows); 86 | 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /examples/CoroC/primes_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | /* Copyright (c) 2005 Russ Cox, MIT; see COPYRIGHT */ 6 | #include 7 | #include 8 | #include 9 | 10 | int quiet = 0; 11 | int goal = 100; 12 | int buffer = 0; 13 | 14 | int primetask(__chan_t c) { 15 | unsigned long p, i; 16 | 17 | c >> p; 18 | 19 | if (p > goal) exit(0); 20 | 21 | if (!quiet) printf("%lu\n", p); 22 | 23 | __chan_t nc = __CoroC_Chan; 24 | __CoroC_Spawn primetask(nc); 25 | 26 | for (;;) { 27 | c >> i; 28 | if (i % p) nc << i; 29 | } 30 | return 0; 31 | } 32 | 33 | int main(int argc, char **argv) { 34 | unsigned long i; 35 | __chan_t c = __CoroC_Chan; 36 | 37 | printf("goal=%d\n", goal); 38 | 39 | __CoroC_Spawn primetask(c); 40 | 41 | for (i = 2;; i++) 42 | c << i; 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /examples/CoroC/select_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define SIZE 4 10 | #define MAKE_CHAN 2 11 | 12 | #if (MAKE_CHAN == 1) 13 | void make_chan(__chan_t *chan) { 14 | *chan = __CoroC_Chan; 15 | } 16 | #elif (MAKE_CHAN == 2) 17 | __chan_t make_chan() { 18 | return __CoroC_Chan; 19 | } 20 | #endif 21 | 22 | int sub_task(__chan_t chan) { 23 | int id = random(); 24 | chan << id; 25 | __CoroC_Quit 0; 26 | } 27 | 28 | int main(int argc, char** argv) { 29 | __chan_t chans[SIZE]; 30 | int i = 0, id; 31 | 32 | for (; i < SIZE; i++) { 33 | #if (MAKE_CHAN == 0) 34 | chans[i] = __CoroC_Chan; 35 | #elif (MAKE_CHAN == 1) 36 | make_chan(&chans[i]); 37 | #elif (MAKE_CHAN == 2) 38 | chans[i] = make_chan(); 39 | #endif 40 | __CoroC_Spawn sub_task(chans[i]); 41 | } 42 | 43 | for (i = 0; i < SIZE; i++) { 44 | __CoroC_Select { 45 | __CoroC_Case (chans[0] >> id) {} 46 | __CoroC_Case (chans[1] >> id) {} 47 | __CoroC_Case (chans[2] >> id) {} 48 | __CoroC_Case (chans[3] >> id) {} 49 | } 50 | 51 | printf("[main task]: recv id is %d!\n", id); 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /examples/CoroC/smart-pointer-2_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | 8 | #include "libcoroc.h" 9 | 10 | struct TreeNode { 11 | unsigned level; 12 | __refcnt_t leftTree; 13 | __refcnt_t rigthTree; 14 | }; 15 | 16 | void freeTree(struct TreeNode *node) { 17 | printf("delete tree node level %d..\n", node->level); 18 | } 19 | 20 | typedef __refcnt_t TreeNodePtr; 21 | 22 | int buildTree(TreeNodePtr *pNode, unsigned level) { 23 | *pNode = __CoroC_New; 24 | 25 | // using `$' to get the C pointer inside. 26 | (*pNode)->level = level; 27 | if (level < 3) { 28 | __group_t grp = __CoroC_Group(); 29 | // using `->' / '*' as same as normal C pointers. 30 | __CoroC_Spawn buildTree(&((*pNode)->leftTree), level+1); 31 | __CoroC_Spawn buildTree(&((*pNode)->rigthTree),level+1); 32 | 33 | // wait for the child tasks finish their job.. 34 | __CoroC_Sync(grp); 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | int main() { 41 | TreeNodePtr root; 42 | buildTree(&root, 0); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /examples/CoroC/smart-pointer_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | 8 | #include "libcoroc.h" 9 | 10 | struct TreeNode { 11 | unsigned level; 12 | __refcnt_t leftTree; 13 | __refcnt_t rigthTree; 14 | }; 15 | 16 | void freeTree(struct TreeNode *node) { 17 | printf("delete tree node level %d..\n", node->level); 18 | } 19 | 20 | typedef __refcnt_t TreeNodePtr; 21 | 22 | TreeNodePtr buildTree(unsigned level) { 23 | TreeNodePtr node = __CoroC_New; 24 | 25 | // using `$' to get the C pointer inside. 26 | ($node)->level = level; 27 | if (level < 3) { 28 | // using `->' / '*' as same as normal C pointers. 29 | node->leftTree = buildTree(level+1); 30 | (*node).rigthTree = buildTree(level+1); 31 | } 32 | return node; 33 | } 34 | 35 | int main() { 36 | TreeNodePtr root = buildTree(0); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /examples/CoroC/spectral-norm_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int Num = 1000; 11 | int NumCPU = 2; 12 | double *U, *V, *T; 13 | double *_u, *_v; 14 | 15 | static inline double Dot(double *v, double *u, int n) { 16 | double sum = 0.0; 17 | int i; 18 | 19 | for (i = 0; i < n; i++) sum += v[i] * u[i]; 20 | return sum; 21 | } 22 | 23 | static inline double A(int i, int j) { 24 | return ((i + j) * (i + j + 1) / 2 + i + 1); 25 | } 26 | 27 | void task_Atv(int kk, __chan_t finishChan) { 28 | int size = (Num + NumCPU - 1) / NumCPU; 29 | int start = size * kk; 30 | int end = size * (kk + 1); 31 | if (end > Num) end = Num; 32 | 33 | int ul = Num; 34 | int i, j; 35 | for (i = start; i < end; i++) { 36 | double vi = 0; 37 | for (j = 0; j < ul; j++) vi += (_u[j] / (double)(A(j, i))); 38 | 39 | _v[i] = vi; 40 | } 41 | 42 | finishChan << 1; 43 | } 44 | 45 | void task_Av(int kk, __chan_t finishChan) { 46 | int size = (Num + NumCPU - 1) / NumCPU; 47 | int start = size * kk; 48 | int end = size * (kk + 1); 49 | if (end > Num) end = Num; 50 | 51 | int ul = Num; 52 | int i, j; 53 | for (i = start; i < end; i++) { 54 | double vi = 0; 55 | for (j = 0; j < ul; j++) vi += (_u[j] / (double)(A(i, j))); 56 | 57 | _v[i] = vi; 58 | } 59 | 60 | finishChan << 1; 61 | } 62 | 63 | void mult_Atv(double *v, double *u, __chan_t finishChan) { 64 | int k; 65 | int finish; 66 | _v = v; 67 | _u = u; 68 | 69 | for (k = 0; k < NumCPU; k++) 70 | __CoroC_Spawn task_Atv(k, finishChan); 71 | 72 | for (k = 0; k < NumCPU; k++) 73 | finishChan >> finish; 74 | } 75 | 76 | void mult_Av(double *v, double *u, __chan_t finishChan) { 77 | int k; 78 | int finish; 79 | _v = v; 80 | _u = u; 81 | 82 | for (k = 0; k < NumCPU; k++) 83 | __CoroC_Spawn task_Av(k, finishChan); 84 | 85 | for (k = 0; k < NumCPU; k++) 86 | finishChan >> finish; 87 | } 88 | 89 | void mult_AtAv(double *v, double *u, double *x, __chan_t chan) { 90 | mult_Av(x, u, chan); 91 | mult_Atv(v, x, chan); 92 | } 93 | 94 | double SpectralNorm(int n) { 95 | __chan_t finishChan = __CoroC_Chan ; 96 | 97 | U = (double*)malloc(sizeof(double) * n); 98 | V = (double*)malloc(sizeof(double) * n); 99 | T = (double*)malloc(sizeof(double) * n); 100 | 101 | int i; 102 | 103 | for (i = 0; i < n; i++) U[i] = 1; 104 | 105 | for (i = 0; i < 10; i++) { 106 | mult_AtAv(V, U, T, finishChan); 107 | mult_AtAv(U, V, T, finishChan); 108 | } 109 | 110 | double dot_uv = Dot(U, V, n); 111 | double dot_vv = Dot(V, V, n); 112 | 113 | free(U); 114 | free(V); 115 | free(T); 116 | return sqrt(dot_uv / dot_vv); 117 | } 118 | 119 | int main(int argc, char **argv) { 120 | if (argc > 1) 121 | Num = atoi(argv[1]); 122 | 123 | printf("%0.9f\n", SpectralNorm(Num)); 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /examples/CoroC/tcpproxy_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | char *server; 16 | int port; 17 | int proxy_task(int); 18 | int rwtask(int, int); 19 | 20 | int main(int argc, char **argv) { 21 | int cfd, fd; 22 | int rport; 23 | char remote[16]; 24 | 25 | if (argc != 4) { 26 | fprintf(stderr, "usage: tcpproxy localport server remoteport\n"); 27 | return -1; 28 | } 29 | 30 | server = argv[2]; 31 | port = atoi(argv[3]); 32 | 33 | if ((fd = coroc_net_announce(true, 0, atoi(argv[1]))) < 0) { 34 | fprintf(stderr, "cannot announce on tcp port %d: %s\n", atoi(argv[1]), 35 | strerror(errno)); 36 | return -1; 37 | } 38 | 39 | coroc_net_nonblock(fd); 40 | while ((cfd = coroc_net_accept(fd, remote, &rport)) >= 0) { 41 | fprintf(stderr, "connection from %s:%d\n", remote, rport); 42 | __CoroC_Spawn proxy_task(cfd); 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | int proxy_task(int fd) { 49 | int remotefd; 50 | 51 | if ((remotefd = coroc_net_dial(true, server, port)) < 0) { 52 | close(fd); 53 | __CoroC_Quit -1; 54 | } 55 | 56 | fprintf(stderr, "connected to %s:%d\n", server, port); 57 | 58 | __CoroC_Spawn rwtask(fd, remotefd); 59 | __CoroC_Spawn rwtask(remotefd, fd); 60 | 61 | return 0; 62 | } 63 | 64 | int rwtask(int rfd, int wfd) { 65 | int n; 66 | char buf[2048]; 67 | 68 | while ((n = coroc_net_read(rfd, buf, sizeof buf)) > 0) 69 | coroc_net_write(wfd, buf, n); 70 | 71 | shutdown(wfd, SHUT_WR); 72 | close(rfd); 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /examples/CoroC/ticker_co.co: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char** argv) { 10 | __coroc_time_t awaken = 0; 11 | int i = 0; 12 | __chan_t<__coroc_time_t> Timer = __CoroC_Ticker(2000000); 13 | 14 | for (i = 0; i < 3; i++) { 15 | printf("waiting for 2 seconds...\n"); 16 | Timer >> awaken; 17 | printf("awaken, time is %llu!\n", (long long unsigned)awaken); 18 | } 19 | 20 | printf("release the timer ..\n"); 21 | 22 | __CoroC_Stop(Timer); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | INSTALL_FILES(/include "\\.h$") 2 | ADD_SUBDIRECTORY(inter) 3 | -------------------------------------------------------------------------------- /include/inter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | INSTALL_FILES(/include/inter "\\.h$") 2 | 3 | IF(APPLE) 4 | ADD_DEFINITIONS(darwin) 5 | ENDIF(APPLE) 6 | -------------------------------------------------------------------------------- /include/inter/async.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_CORE_ASYNC_POOL_H_ 6 | #define _TSC_CORE_ASYNC_POOL_H_ 7 | 8 | #include 9 | #include 10 | 11 | #include "support.h" 12 | #include "coroutine.h" 13 | 14 | typedef void (*coroc_async_callback_t)(void *); 15 | 16 | // the asynchronize request type .. 17 | typedef struct { 18 | queue_item_t link; 19 | coroc_coroutine_t wait; 20 | coroc_async_callback_t func; 21 | void *argument; 22 | } coroc_async_request_t; 23 | 24 | // the API for the coroutines .. 25 | void coroc_async_request_submit(coroc_async_callback_t func, void *argument); 26 | 27 | // the API for the vpus or framework .. 28 | coroc_coroutine_t coroc_async_pool_fetch(void); 29 | void coroc_async_pool_initialize(int); 30 | bool coroc_async_pool_working(void); 31 | 32 | #endif // _TSC_CORE_ASYNC_POOL_H_ 33 | -------------------------------------------------------------------------------- /include/inter/channel.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_CORE_CHANNEL_H_ 6 | #define _TSC_CORE_CHANNEL_H_ 7 | 8 | #include 9 | #include 10 | #include "support.h" 11 | #include "refcnt.h" 12 | #include "coroc_queue.h" 13 | #include "lock_chain.h" 14 | 15 | enum { CHAN_SUCCESS = 0, CHAN_AWAKEN = 1, CHAN_BUSY = 2, CHAN_CLOSED = 4, }; 16 | 17 | struct coroc_chan; 18 | typedef bool (*coroc_chan_handler)(struct coroc_chan *, void *); 19 | 20 | // the general channel type .. 21 | typedef struct coroc_chan { 22 | struct coroc_refcnt refcnt; 23 | bool close; 24 | bool select; 25 | coroc_lock lock; 26 | int32_t isref:1; 27 | int32_t elemsize:31; 28 | queue_t recv_que; 29 | queue_t send_que; 30 | coroc_chan_handler copy_to_buff; 31 | coroc_chan_handler copy_from_buff; 32 | } *coroc_chan_t; 33 | 34 | // the buffered channel .. 35 | typedef struct coroc_buffered_chan { 36 | struct coroc_chan _chan; 37 | int32_t bufsize; 38 | int32_t nbuf; 39 | int32_t recvx; 40 | int32_t sendx; 41 | uint8_t *buf; 42 | } *coroc_buffered_chan_t; 43 | 44 | extern void _coroc_chan_dealloc(coroc_chan_t); 45 | 46 | // init the general channel .. 47 | static inline void coroc_chan_init(coroc_chan_t ch, int32_t elemsize, bool isref, 48 | coroc_chan_handler to, coroc_chan_handler from) { 49 | coroc_refcnt_init(&ch->refcnt, (release_handler_t)_coroc_chan_dealloc); 50 | 51 | ch->close = false; 52 | ch->select = false; 53 | ch->isref = isref ? 1 : 0; 54 | ch->elemsize = elemsize; 55 | ch->copy_to_buff = to; 56 | ch->copy_from_buff = from; 57 | 58 | lock_init(&ch->lock); 59 | queue_init(&ch->recv_que); 60 | queue_init(&ch->send_que); 61 | } 62 | 63 | extern bool __coroc_copy_to_buff(coroc_chan_t, void *); 64 | extern bool __coroc_copy_from_buff(coroc_chan_t, void *); 65 | 66 | // init the buffered channel .. 67 | static inline void coroc_buffered_chan_init(coroc_buffered_chan_t ch, 68 | int32_t elemsize, 69 | int32_t bufsize, bool isref) { 70 | coroc_chan_init((coroc_chan_t)ch, elemsize, isref, __coroc_copy_to_buff, 71 | __coroc_copy_from_buff); 72 | 73 | ch->bufsize = bufsize; 74 | ch->buf = (uint8_t *)(ch + 1); 75 | ch->nbuf = 0; 76 | ch->recvx = ch->sendx = 0; 77 | } 78 | 79 | coroc_chan_t _coroc_chan_allocate(int32_t elemsize, int32_t bufsize, bool isref); 80 | void _coroc_chan_dealloc(coroc_chan_t chan); 81 | 82 | #define coroc_chan_allocate(es, bs) _coroc_chan_allocate(es, bs, false) 83 | #define coroc_chan_dealloc(chan) _coroc_chan_dealloc(chan) 84 | 85 | extern int _coroc_chan_send(coroc_chan_t chan, void *buf, bool block); 86 | extern int _coroc_chan_recv(coroc_chan_t chan, void *buf, bool block); 87 | 88 | #define coroc_chan_send(chan, buf) _coroc_chan_send(chan, buf, true) 89 | #define coroc_chan_recv(chan, buf) _coroc_chan_recv(chan, buf, true) 90 | #define coroc_chan_nbsend(chan, buf) _coroc_chan_send(chan, buf, false) 91 | #define coroc_chan_nbrecv(chan, buf) _coroc_chan_recv(chan, buf, false) 92 | 93 | #if 0 94 | extern int _coroc_chan_sendp(coroc_chan_t chan, void *ptr, bool block); 95 | extern int _coroc_chan_recvp(coroc_chan_t chan, void **pptr, bool block); 96 | #else 97 | #define _coroc_chan_sende(chan, exp, block) \ 98 | ({ \ 99 | typeof(exp) __temp = exp; \ 100 | assert(sizeof(__temp) == chan->elemsize); \ 101 | int rc = _coroc_chan_send(chan, &__temp, block); \ 102 | rc; \ 103 | }) 104 | 105 | #define coroc_chan_sende(chan, exp) _coroc_chan_sende(chan, exp, true) 106 | #define coroc_chan_nbsende(chan, exp) _coroc_chan_sende(chan, exp, false) 107 | 108 | #define _coroc_chan_sendp _coroc_chan_sende 109 | #endif 110 | 111 | #define coroc_chan_sendp(chan, ptr) _coroc_chan_sendp(chan, ptr, true) 112 | #define coroc_chan_nbsendp(chan, ptr) _coroc_chan_sendp(chan, ptr, false) 113 | 114 | extern int coroc_chan_close(coroc_chan_t chan); 115 | 116 | enum { CHAN_SEND = 0, CHAN_RECV, }; 117 | 118 | typedef struct { 119 | int type; 120 | coroc_chan_t chan; 121 | void *buf; 122 | } coroc_scase_t; 123 | 124 | typedef struct coroc_chan_set { 125 | // this is a lock chain actrually .. 126 | struct { 127 | bool sorted; 128 | int volume; 129 | int size; 130 | lock_t *locks; 131 | }; 132 | coroc_scase_t cases[0]; 133 | } *coroc_chan_set_t; 134 | 135 | #define CHAN_SET_SIZE(n) \ 136 | (sizeof(struct coroc_chan_set) + (n) * (sizeof(coroc_scase_t) + sizeof(lock_t))) 137 | 138 | /* multi-channel send / recv , like select clause in GoLang .. */ 139 | coroc_chan_set_t coroc_chan_set_allocate(int n); 140 | void coroc_chan_set_dealloc(coroc_chan_set_t set); 141 | 142 | static inline 143 | void coroc_chan_set_init(coroc_chan_set_t set, int n) { 144 | set->sorted = false; 145 | set->volume = n; 146 | set->size = 0; 147 | set->locks = (lock_t*)(&set->cases[n]); 148 | } 149 | 150 | void coroc_chan_set_send(coroc_chan_set_t set, coroc_chan_t chan, void *buf); 151 | void coroc_chan_set_recv(coroc_chan_set_t set, coroc_chan_t chan, void *buf); 152 | 153 | extern int _coroc_chan_set_select(coroc_chan_set_t set, bool block, 154 | coroc_chan_t *active); 155 | 156 | #define coroc_chan_set_select(set, pchan) _coroc_chan_set_select(set, true, pchan) 157 | #define coroc_chan_set_nbselect(set, pchan) \ 158 | _coroc_chan_set_select(set, false, pchan) 159 | 160 | static inline void __chan_memcpy(void *dst, const void *src, size_t size) { 161 | if (dst && src) memcpy(dst, src, size); 162 | } 163 | 164 | #endif // _TSC_CORE_CHANNEL_H_ 165 | -------------------------------------------------------------------------------- /include/inter/config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef _LIBCOROC_CONFIG_H_ 2 | #define _LIBCOROC_CONFIG_H_ 3 | 4 | #cmakedefine ENABLE_TIMESHARE 5 | #cmakedefine ENABLE_FUTEX 6 | #cmakedefine ENABLE_SPLITSTACK 7 | #cmakedefine ENABLE_WORKSTEALING 8 | #cmakedefine ENABLE_LOCKFREE_RUNQ 9 | #cmakedefine ENABLE_NOTIFY 10 | 11 | #endif // _LIBCOROC_CONFIG_H_ 12 | 13 | -------------------------------------------------------------------------------- /include/inter/context.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_PLATFORM_CONTEXT_H 6 | #define _TSC_PLATFORM_CONTEXT_H 7 | 8 | #if defined(__APPLE__) 9 | #include 10 | #if defined(MAC_OS_X_VERSION_10_5) 11 | #undef USE_UCONTEXT 12 | #define USE_UCONTEXT 0 13 | #endif 14 | #endif 15 | 16 | #if defined(__APPLE__) 17 | #define mcontext libthread_mcontext 18 | #define mcontext_t libthread_mcontext_t 19 | #define ucontext libthread_ucontext 20 | #define ucontext_t libthread_ucontext_t 21 | #if defined(__i386__) 22 | #include "darwin/386-ucontext.h" 23 | #elif defined(__x86_64__) 24 | #include "darwin/amd64-ucontext.h" 25 | #else 26 | #include "darwin/power-ucontext.h" 27 | #endif 28 | #else 29 | #define USE_UCONTEXT 1 // default for the linux platform 30 | #endif // __APPLE__ 31 | 32 | #if USE_UCONTEXT 33 | #include 34 | #endif // USE_UCONTEXT 35 | 36 | #if defined(ENABLE_SPLITSTACK) 37 | typedef struct { 38 | ucontext_t ctx; 39 | void* stack_ctx[10]; 40 | } TSC_CONTEXT; 41 | 42 | extern void* __splitstack_makecontext(size_t stack_size, void* context[10], 43 | size_t* size); 44 | extern void __splitstack_setcontext(void* context[10]); 45 | extern void __splitstack_getcontext(void* context[10]); 46 | 47 | #define TSC_CONTEXT_LOAD(cp) setcontext(&(cp)->ctx) 48 | #define TSC_CONTEXT_SAVE(cp) getcontext(&(cp)->ctx) 49 | #define TSC_CONTEXT_MAKE(cp, ...) makecontext(&(cp)->ctx, __VA_ARGS__) 50 | 51 | #define TSC_STACK_CONTEXT_MAKE(sz, cp, ...) \ 52 | __splitstack_makecontext(sz, &(cp)->stack_ctx[0], __VA_ARGS__) 53 | #define TSC_STACK_CONTEXT_LOAD(cp) __splitstack_setcontext(&(cp)->stack_ctx[0]) 54 | #define TSC_STACK_CONTEXT_SAVE(cp) __splitstack_getcontext(&(cp)->stack_ctx[0]) 55 | 56 | #define TSC_CONTEXT_SIGADDMASK(cp, sig) sigaddset(&(cp)->ctx.uc_sigmask, sig) 57 | 58 | #else 59 | typedef ucontext_t TSC_CONTEXT; 60 | 61 | #define TSC_CONTEXT_LOAD setcontext 62 | #define TSC_CONTEXT_SAVE getcontext 63 | #define TSC_CONTEXT_SWAP swapcontext 64 | #define TSC_CONTEXT_MAKE makecontext 65 | 66 | #define TSC_CONTEXT_SIGADDMASK(cp, sig) sigaddset(&(cp)->uc_sigmask, sig) 67 | 68 | #endif 69 | 70 | extern void TSC_CONTEXT_INIT(TSC_CONTEXT* ctx, void* stack, size_t stack_sz, 71 | void* thread); 72 | 73 | #endif // _TSC_PLATFORM_CONTEXT_H 74 | -------------------------------------------------------------------------------- /include/inter/coroc_clock.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_CORE_CLOCK_H 6 | #define _TSC_CORE_CLOCK_H 7 | 8 | #include "support.h" 9 | #include "coroc_queue.h" 10 | 11 | typedef struct clock_manager { 12 | queue_t sleep_queue; // TODO 13 | } clock_manager_t; 14 | 15 | extern clock_manager_t clock_manager; 16 | 17 | extern void coroc_clock_initialize(void); 18 | extern void clock_wait(uint32_t us); // TODO 19 | extern void clock_deadline_inspector(void* item, int value); // TODO 20 | extern void clock_routine(void); 21 | 22 | #endif // _TSC_CORE_CLOCK_H 23 | -------------------------------------------------------------------------------- /include/inter/coroc_group.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_GROUP_H_ 6 | #define _TSC_GROUP_H_ 7 | 8 | #include "support.h" 9 | #include "coroutine.h" 10 | 11 | /* the structure for subtask group control */ 12 | typedef struct coroc_group { 13 | uint32_t count; 14 | uint32_t errors; 15 | coroc_lock lock; 16 | coroc_coroutine_t parent; 17 | } *coroc_group_t; 18 | 19 | /// Init the coroc_group_t 20 | static inline 21 | void coroc_group_init(coroc_group_t group) { 22 | assert(group != NULL); 23 | 24 | lock_init(& group->lock); 25 | group->count = 1; 26 | group->errors = 0; 27 | // this field will be assgined when parent task 28 | // calls the `coroc_group_sync' .. 29 | group->parent = NULL; 30 | } 31 | 32 | /// Alloc the group from heap and init it 33 | coroc_group_t coroc_group_alloc(void); 34 | 35 | /// Called when parent spawn a new subtask into this group 36 | void coroc_group_add_task(coroc_group_t group); 37 | 38 | /// Called when the subtask finish its work, notify the parent 39 | void coroc_group_notify(coroc_group_t group, int retval); 40 | 41 | /// Called by the parent to check if all subtasks are finish 42 | bool coroc_group_check(coroc_group_t group); 43 | 44 | /// Called by the parent, this will block the parent until all 45 | /// subtasks are finish and call coroc_group_notify(). 46 | /// NOTE: this call will release the group, means that the group 47 | /// CANNOT use more than once!! 48 | int coroc_group_sync(coroc_group_t group); 49 | 50 | #endif /* _TSC_GROUP_H_ */ 51 | -------------------------------------------------------------------------------- /include/inter/coroc_hash.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_SUPPORT_HASH_ 6 | #define _TSC_SUPPORT_HASH_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "support.h" 14 | #include "coroc_lock.h" 15 | 16 | /** Max hash code.*/ 17 | #define MAX_HASH 2147483647 18 | /** The initial capacity of the hash table. */ 19 | #define CAPACITY 128 20 | /** The max string length. */ 21 | #define LEN 1024 22 | /** The max searching time for an element. */ 23 | #define LIMIT 6 24 | 25 | #define A 17 26 | #define B 72343 27 | #define C 19 28 | #define D 89145 29 | #define M 9275507 30 | #define N 8232341 31 | 32 | /** The entry of the hash table. */ 33 | typedef struct { 34 | uint64_t key; 35 | void *value; 36 | } hash_entry_t; 37 | 38 | /** The structure of the hash table. */ 39 | typedef struct { 40 | coroc_lock lock; 41 | int capacity; 42 | int cursor; 43 | hash_entry_t **table[2]; 44 | } hash_t; 45 | 46 | void hash_init(hash_t *hash); 47 | int hash_insert(hash_t *hash, uint64_t key, void *value); 48 | void *hash_get(hash_t *hash, uint64_t key, bool remove); 49 | void hash_fini(hash_t *hash); 50 | 51 | void atomic_hash_init(hash_t *hash); 52 | int atomic_hash_insert(hash_t *hash, uint64_t key, void *value); 53 | void *atomic_hash_get(hash_t *hash, uint64_t key, bool remove); 54 | void atomic_hash_fini(hash_t *hash); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /include/inter/coroc_lock.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_SUPPORT_LOCK_H_ 6 | #define _TSC_SUPPORT_LOCK_H_ 7 | 8 | #ifdef ENABLE_FUTEX 9 | /* use a customized futex lock like Go */ 10 | #include "futex_lock.h" 11 | 12 | typedef _coroc_futex_t coroc_lock; 13 | typedef coroc_lock* lock_t; 14 | 15 | #define lock_init _coroc_futex_init 16 | #define lock_acquire _coroc_futex_lock 17 | #define lock_try_acquire _coroc_futex_trylock 18 | #define lock_release _coroc_futex_unlock 19 | #define lock_fini _coroc_futex_destroy 20 | 21 | #else 22 | 23 | /* use pthread_spinlock */ 24 | #include 25 | #if defined(__APPLE__) 26 | #include "darwin/pthread_spinlock.h" 27 | #endif 28 | 29 | typedef pthread_spinlock_t coroc_lock; 30 | typedef coroc_lock* lock_t; 31 | 32 | #define lock_init(lock) pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE) 33 | #define lock_acquire pthread_spin_lock 34 | #define lock_try_acquire pthread_spin_trylock 35 | #define lock_release pthread_spin_unlock 36 | #define lock_fini pthread_spin_destroy 37 | 38 | #endif // ENABLE_FUTEXT 39 | 40 | #endif // _TSC_SUPPORT_LOCK_H_ 41 | -------------------------------------------------------------------------------- /include/inter/coroc_queue.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_SUPPORT_QUEUE_H_ 6 | #define _TSC_SUPPORT_QUEUE_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "coroc_lock.h" 13 | 14 | struct queue; 15 | 16 | typedef struct queue_item { 17 | struct queue_item *next; 18 | struct queue_item *prev; 19 | struct queue *que; 20 | void *owner; 21 | } queue_item_t; 22 | 23 | typedef struct queue { 24 | coroc_lock lock; 25 | queue_item_t *head; 26 | queue_item_t *tail; 27 | volatile uint32_t status; 28 | } queue_t; 29 | 30 | /*-----------------------------------* 31 | * Inlined queue management function * 32 | * The prev/next fields of the task * 33 | * parameter are NULLified her ! * 34 | *-----------------------------------*/ 35 | 36 | /*---- Initilization functions ----*/ 37 | static inline void queue_item_init(queue_item_t *item, void *owner) { 38 | item->next = NULL; 39 | item->prev = NULL; 40 | item->que = NULL; 41 | item->owner = owner; 42 | } 43 | 44 | static inline void queue_init(queue_t *queue) { 45 | queue->head = NULL; 46 | queue->tail = NULL; 47 | queue->status = 0; 48 | } 49 | 50 | static inline void atomic_queue_init(queue_t *queue) { 51 | lock_init(&queue->lock); 52 | queue_init(queue); 53 | } 54 | 55 | static inline int atomic_queue_size(queue_t *queue) { 56 | int size; 57 | lock_acquire(&queue->lock); 58 | size = queue->status; 59 | lock_release(&queue->lock); 60 | 61 | return size; 62 | } 63 | 64 | static inline void queue_link(queue_item_t *item1, queue_item_t *item2) { 65 | item1->next = item2; 66 | item2->prev = item1; 67 | } 68 | 69 | /*---- Add functions ----*/ 70 | static inline void queue_add(queue_t *queue, queue_item_t *item) { 71 | /*---- Clean the links ----*/ 72 | item->next = NULL; 73 | 74 | /*---- Place the item ----*/ 75 | if (!queue->status) { 76 | queue->head = item; 77 | queue->tail = item; 78 | } else { 79 | queue->tail->next = item; 80 | item->prev = queue->tail; 81 | queue->tail = item; 82 | } 83 | 84 | item->que = queue; 85 | queue->status += 1; 86 | } 87 | 88 | static inline void atomic_queue_add(queue_t *queue, queue_item_t *item) { 89 | lock_acquire(&queue->lock); 90 | queue_add(queue, item); 91 | lock_release(&queue->lock); 92 | } 93 | 94 | static inline void queue_add_range(queue_t *queue, unsigned int n, 95 | queue_item_t *from, 96 | queue_item_t *to) { 97 | if (!queue->status) { 98 | queue->head = from; 99 | queue->tail = to; 100 | } else { 101 | queue->tail->next = from; 102 | from->prev = queue->tail; 103 | queue->tail = to; 104 | } 105 | 106 | from->que = queue; 107 | to->que = queue; 108 | to->next = NULL; 109 | 110 | queue->status += n; 111 | } 112 | 113 | static inline void atomic_queue_add_range(queue_t *queue, unsigned int n, 114 | queue_item_t *from, 115 | queue_item_t *to) { 116 | lock_acquire(&queue->lock); 117 | queue_add_range(queue, n, from, to); 118 | lock_release(&queue->lock); 119 | } 120 | 121 | 122 | /*---- Remove function ----*/ 123 | static inline void *queue_rem(queue_t *queue) { 124 | queue_item_t *kitem = NULL; 125 | 126 | /*---- Check if the queue is empty ----*/ 127 | if (!queue->status) return NULL; 128 | 129 | /*---- Check what item to remove ----*/ 130 | kitem = queue->head; 131 | queue->head = queue->head->next; 132 | if (queue->head) 133 | queue->head->prev = NULL; 134 | else 135 | queue->tail = queue->head; 136 | 137 | queue->status -= 1; 138 | 139 | /*---- Clean the links ----*/ 140 | kitem->prev = kitem->next = NULL; 141 | kitem->que = NULL; 142 | 143 | return kitem->owner; 144 | } 145 | 146 | static inline void *atomic_queue_rem(queue_t *queue) { 147 | void *owner = NULL; 148 | 149 | if (!queue->status) return NULL; 150 | 151 | lock_acquire(&queue->lock); 152 | owner = queue_rem(queue); 153 | lock_release(&queue->lock); 154 | 155 | return owner; 156 | } 157 | 158 | // added by zhj 159 | static inline void *atomic_queue_try_rem(queue_t *queue) { 160 | void *owner = NULL; 161 | 162 | if (!queue->status || lock_try_acquire(&queue->lock)) return NULL; 163 | 164 | owner = queue_rem(queue); 165 | lock_release(&queue->lock); 166 | 167 | return owner; 168 | } 169 | // End added 170 | 171 | /*---- Extract function ----*/ 172 | static inline void queue_extract(queue_t *queue, queue_item_t *item) { 173 | #if 0 174 | queue_item_t * kitem = queue -> head; 175 | 176 | if (queue -> head == item) queue -> head = item -> next; 177 | else { 178 | while (kitem -> next != item) kitem = kitem -> next; 179 | kitem -> next = item -> next; 180 | if (kitem -> next == NULL) queue -> tail = kitem; 181 | } 182 | 183 | queue -> status -= 1; 184 | #else 185 | if (item->que != queue) return; 186 | assert(queue->status > 0); 187 | 188 | if (item->prev) 189 | item->prev->next = item->next; 190 | else 191 | queue->head = item->next; 192 | 193 | if (item->next) 194 | item->next->prev = item->prev; 195 | else 196 | queue->tail = item->prev; 197 | 198 | queue->status--; 199 | 200 | item->prev = item->next = NULL; 201 | item->que = NULL; 202 | 203 | #endif 204 | } 205 | 206 | static inline void atomic_queue_extract(queue_t *queue, queue_item_t *item) { 207 | lock_acquire(&queue->lock); 208 | queue_extract(queue, item); 209 | lock_release(&queue->lock); 210 | } 211 | 212 | #if 0 213 | /*---- Lookup function ----*/ 214 | static inline void * queue_lookup (queue_t * queue, bool (*inspector)(void *, void *), void * value) { 215 | queue_item_t * item = queue -> head; 216 | 217 | if (! queue -> status) return NULL; 218 | 219 | while (item != NULL) { 220 | if (inspector (item -> owner, value)) return item -> owner; 221 | item = item -> next; 222 | } 223 | 224 | return NULL; 225 | } 226 | 227 | static inline void * atomic_queue_lookup (queue_t * queue, bool (*inspector)(void *, void *), void * value) { 228 | void * owner = NULL; 229 | 230 | if (! queue -> status) return NULL; 231 | 232 | lock_acquire(& queue -> lock); 233 | owner = queue_lookup (queue, inspector, value); 234 | lock_release(& queue -> lock); 235 | 236 | return owner; 237 | } 238 | #endif 239 | 240 | /*---- Walk function ----*/ 241 | static inline void queue_walk(queue_t *queue, void (*inspector)(void *)) { 242 | queue_item_t *item = queue->head; 243 | 244 | if (queue->status) { 245 | ; 246 | while (item != NULL) { 247 | inspector(item->owner); 248 | item = item->next; 249 | } 250 | } 251 | } 252 | 253 | static inline void atomic_queue_walk(queue_t *queue, 254 | void (*inspector)(void *)) { 255 | if (queue->status) { 256 | ; 257 | lock_acquire(&queue->lock); 258 | queue_walk(queue, inspector); 259 | lock_release(&queue->lock); 260 | } 261 | } 262 | 263 | // -- general pointer inspector callback -- 264 | static bool general_inspector(void *p0, void *p1) { return p0 == p1; } 265 | 266 | #endif // _TSC_SUPPORT_QUEUE_H_ 267 | -------------------------------------------------------------------------------- /include/inter/coroc_time.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_TIME_H_ 6 | #define _TSC_TIME_H_ 7 | 8 | #include 9 | #include 10 | 11 | #include "support.h" 12 | #include "vpu.h" 13 | #include "channel.h" 14 | #include "coroutine.h" 15 | 16 | struct coroc_timer; 17 | 18 | /* internal timer type */ 19 | typedef struct { 20 | uint64_t when; 21 | uint32_t period; 22 | int32_t index; 23 | void (*func)(void *); 24 | void *args; 25 | struct coroc_timer *owner; 26 | } coroc_inter_timer_t; 27 | 28 | /* userspace timer type */ 29 | typedef struct coroc_timer { 30 | struct coroc_buffered_chan _chan; 31 | uint64_t _buffer; 32 | coroc_inter_timer_t timer; 33 | } *coroc_timer_t; 34 | 35 | /* userspace api */ 36 | 37 | coroc_timer_t coroc_timer_allocate(uint32_t period, void (*func)(void)); 38 | void coroc_timer_dealloc(coroc_timer_t); 39 | coroc_chan_t coroc_timer_after(coroc_timer_t, uint64_t); 40 | coroc_chan_t coroc_timer_at(coroc_timer_t, uint64_t); 41 | 42 | int coroc_timer_start(coroc_timer_t); 43 | int coroc_timer_stop(coroc_timer_t); 44 | int coroc_timer_reset(coroc_timer_t, uint64_t); 45 | 46 | /* internal api */ 47 | int coroc_add_intertimer(coroc_inter_timer_t *); 48 | int coroc_del_intertimer(coroc_inter_timer_t *); 49 | 50 | /* get current time */ 51 | static inline int64_t coroc_getmicrotime(void) { 52 | struct timeval tv; 53 | struct timezone tz; 54 | gettimeofday(&tv, &tz); 55 | return tv.tv_sec * 1000000 + tv.tv_usec; 56 | } 57 | 58 | static inline int64_t coroc_getnanotime(void) { 59 | struct timespec abstime; 60 | clock_gettime(CLOCK_REALTIME, &abstime); 61 | return abstime.tv_sec * 1000000000LL + abstime.tv_nsec; 62 | } 63 | 64 | void coroc_udelay(uint64_t us); 65 | 66 | #endif // _TSC_TIME_H_ 67 | -------------------------------------------------------------------------------- /include/inter/coroutine.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_CORE_COROUTINE_H_ 6 | #define _TSC_CORE_COROUTINE_H_ 7 | 8 | #include 9 | 10 | #include "support.h" 11 | #include "context.h" 12 | #include "message.h" 13 | #include "coroc_queue.h" 14 | 15 | typedef int32_t (*coroc_coroutine_handler_t)(void*); 16 | typedef int32_t (*coroc_coroutine_cleanup_t)(void*, int); 17 | 18 | typedef int32_t coroc_coroutine_id_t; 19 | 20 | struct vpu; 21 | 22 | typedef struct coroc_coroutine_attributes { 23 | uint32_t stack_size; 24 | uint32_t timeslice; 25 | uint32_t affinity; 26 | // TODO : anything else ?? 27 | } coroc_coroutine_attributes_t; 28 | 29 | typedef struct coroc_coroutine { 30 | struct coroc_async_chan _chan; 31 | 32 | coroc_coroutine_id_t id; 33 | coroc_coroutine_id_t pid; // DEBUG 34 | char name[TSC_NAME_LENGTH]; 35 | 36 | uint32_t type:8; 37 | uint32_t vpu_id:8; 38 | uint32_t vpu_affinity:8; 39 | uint32_t async_wait:8; 40 | 41 | uint32_t status; 42 | unsigned priority; 43 | 44 | queue_item_t status_link; 45 | queue_item_t trace_link; 46 | bool syscall; 47 | bool backtrace; // wakeup for backtrace 48 | 49 | void* qtag; // used by channel_select 50 | 51 | uint32_t init_timeslice; 52 | uint32_t rem_timeslice; 53 | 54 | int sigmask_nest; 55 | 56 | uint32_t detachstate; 57 | void* stack_base; 58 | size_t stack_size; 59 | coroc_coroutine_handler_t entry; 60 | coroc_coroutine_cleanup_t cleanup; 61 | void* arguments; 62 | int32_t retval; 63 | 64 | TSC_CONTEXT ctx; 65 | }* coroc_coroutine_t; 66 | 67 | enum coroc_coroutine_status { 68 | TSC_COROUTINE_SLEEP = 0xBAFF, 69 | TSC_COROUTINE_READY = 0xFACE, 70 | TSC_COROUTINE_RUNNING = 0xBEEF, 71 | TSC_COROUTINE_WAIT = 0xBADD, 72 | TSC_COROUTINE_IOWAIT = 0xBADE, 73 | TSC_COROUTINE_EXIT = 0xDEAD, 74 | }; 75 | 76 | enum coroc_coroutine_type { 77 | TSC_COROUTINE_IDLE = 0x0, 78 | TSC_COROUTINE_NORMAL = 0x1, 79 | TSC_COROUTINE_MAIN = 0x2, 80 | }; 81 | 82 | enum { 83 | TSC_PRIO_HIGHEST = 0, 84 | TSC_PRIO_HIGH = 1, 85 | TSC_PRIO_NORMAL = 2, 86 | TSC_PRIO_LOW = 3, 87 | }; 88 | 89 | #define TSC_DEFAULT_PRIO TSC_PRIO_NORMAL 90 | 91 | enum coroc_coroutine_deallocate { 92 | TSC_COROUTINE_UNDETACH = 0x0, 93 | TSC_COROUTINE_DETACH = 0x1, 94 | }; 95 | 96 | extern coroc_coroutine_t 97 | coroc_coroutine_allocate(coroc_coroutine_handler_t entry, 98 | void* arguments, const char* name, 99 | uint32_t type, unsigned priority, 100 | coroc_coroutine_cleanup_t cleanup); 101 | extern void coroc_coroutine_deallocate(coroc_coroutine_t); 102 | extern void coroc_coroutine_exit(int value); 103 | extern void coroc_coroutine_yield(void); 104 | extern coroc_coroutine_t coroc_coroutine_self(void); 105 | extern void coroc_coroutine_backtrace(coroc_coroutine_t); 106 | #ifdef TSC_ENABLE_COROUTINE_JOIN 107 | extern status_t coroc_coroutine_join(coroc_coroutine_t); 108 | extern void coroc_coroutine_detach(void); 109 | #endif // TSC_ENABLE_COROUTINE_JOIN 110 | 111 | #define coroc_coroutine_spawn(entry, args, name) \ 112 | coroc_coroutine_allocate((coroc_coroutine_handler_t)(entry), (void*)(args), \ 113 | (name), TSC_COROUTINE_NORMAL, TSC_DEFAULT_PRIO, NULL) 114 | 115 | 116 | static inline void 117 | coroc_coroutine_set_priority(unsigned priority) { 118 | assert(priority < TSC_PRIO_NUM); 119 | coroc_coroutine_t me = coroc_coroutine_self(); 120 | me->priority = priority; 121 | } 122 | 123 | static inline void 124 | coroc_coroutine_set_name(const char *name) { 125 | assert(name != NULL); 126 | coroc_coroutine_t me = coroc_coroutine_self(); 127 | strncpy(me->name, name, sizeof(me->name) - 1); 128 | } 129 | 130 | #endif // _TSC_CORE_COROUTINE_H_ 131 | -------------------------------------------------------------------------------- /include/inter/darwin/386-ucontext.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 6 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 7 | typedef struct mcontext mcontext_t; 8 | typedef struct ucontext ucontext_t; 9 | 10 | extern int swapcontext(ucontext_t *, const ucontext_t *); 11 | extern void makecontext(ucontext_t *, void (*)(), int, ...); 12 | extern int getmcontext(mcontext_t *); 13 | extern void setmcontext(const mcontext_t *); 14 | 15 | /*- 16 | * Copyright (c) 1999 Marcel Moolenaar 17 | * All rights reserved. 18 | * 19 | * Redistribution and use in source and binary forms, with or without 20 | * modification, are permitted provided that the following conditions 21 | * are met: 22 | * 1. Redistributions of source code must retain the above copyright 23 | * notice, this list of conditions and the following disclaimer 24 | * in this position and unchanged. 25 | * 2. Redistributions in binary form must reproduce the above copyright 26 | * notice, this list of conditions and the following disclaimer in the 27 | * documentation and/or other materials provided with the distribution. 28 | * 3. The name of the author may not be used to endorse or promote products 29 | * derived from this software without specific prior written permission. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 32 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 33 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 34 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 35 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 40 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | * 42 | * $FreeBSD: src/sys/sys/ucontext.h,v 1.4 1999/10/11 20:33:17 luoqi Exp $ 43 | */ 44 | 45 | /* #include */ 46 | 47 | /*- 48 | * Copyright (c) 1999 Marcel Moolenaar 49 | * All rights reserved. 50 | * 51 | * Redistribution and use in source and binary forms, with or without 52 | * modification, are permitted provided that the following conditions 53 | * are met: 54 | * 1. Redistributions of source code must retain the above copyright 55 | * notice, this list of conditions and the following disclaimer 56 | * in this position and unchanged. 57 | * 2. Redistributions in binary form must reproduce the above copyright 58 | * notice, this list of conditions and the following disclaimer in the 59 | * documentation and/or other materials provided with the distribution. 60 | * 3. The name of the author may not be used to endorse or promote products 61 | * derived from this software without specific prior written permission. 62 | * 63 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 64 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 65 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 66 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 67 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 68 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 69 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 70 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 | * 74 | * $FreeBSD: src/sys/i386/include/ucontext.h,v 1.4 1999/10/11 20:33:09 luoqi Exp 75 | *$ 76 | */ 77 | 78 | struct mcontext { 79 | /* 80 | * The first 20 fields must match the definition of 81 | * sigcontext. So that we can support sigcontext 82 | * and ucontext_t at the same time. 83 | */ 84 | int mc_onstack; /* XXX - sigcontext compat. */ 85 | int mc_gs; 86 | int mc_fs; 87 | int mc_es; 88 | int mc_ds; 89 | int mc_edi; 90 | int mc_esi; 91 | int mc_ebp; 92 | int mc_isp; 93 | int mc_ebx; 94 | int mc_edx; 95 | int mc_ecx; 96 | int mc_eax; 97 | int mc_trapno; 98 | int mc_err; 99 | int mc_eip; 100 | int mc_cs; 101 | int mc_eflags; 102 | int mc_esp; /* machine state */ 103 | int mc_ss; 104 | 105 | int mc_fpregs[28]; /* env87 + fpacc87 + u_long */ 106 | int __spare__[17]; 107 | }; 108 | 109 | struct ucontext { 110 | /* 111 | * Keep the order of the first two fields. Also, 112 | * keep them the first two fields in the structure. 113 | * This way we can have a union with struct 114 | * sigcontext and ucontext_t. This allows us to 115 | * support them both at the same time. 116 | * note: the union is not defined, though. 117 | */ 118 | sigset_t uc_sigmask; 119 | mcontext_t uc_mcontext; 120 | 121 | struct __ucontext *uc_link; 122 | stack_t uc_stack; 123 | int __spare__[8]; 124 | }; 125 | -------------------------------------------------------------------------------- /include/inter/darwin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | IF(APPLE) 2 | INSTALL_FILES(/include/inter/darwin .h) 3 | ENDIF(APPLE) 4 | -------------------------------------------------------------------------------- /include/inter/darwin/amd64-ucontext.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 6 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 7 | typedef struct mcontext mcontext_t; 8 | typedef struct ucontext ucontext_t; 9 | 10 | extern int swapcontext(ucontext_t *, const ucontext_t *); 11 | extern void makecontext(ucontext_t *, void (*)(), int, ...); 12 | extern int getmcontext(mcontext_t *); 13 | extern void setmcontext(const mcontext_t *); 14 | 15 | /*- 16 | * Copyright (c) 1999 Marcel Moolenaar 17 | * All rights reserved. 18 | * 19 | * Redistribution and use in source and binary forms, with or without 20 | * modification, are permitted provided that the following conditions 21 | * are met: 22 | * 1. Redistributions of source code must retain the above copyright 23 | * notice, this list of conditions and the following disclaimer 24 | * in this position and unchanged. 25 | * 2. Redistributions in binary form must reproduce the above copyright 26 | * notice, this list of conditions and the following disclaimer in the 27 | * documentation and/or other materials provided with the distribution. 28 | * 3. The name of the author may not be used to endorse or promote products 29 | * derived from this software without specific prior written permission. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 32 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 33 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 34 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 35 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 40 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | * 42 | * $FreeBSD: src/sys/sys/ucontext.h,v 1.4 1999/10/11 20:33:17 luoqi Exp $ 43 | */ 44 | 45 | /* #include */ 46 | 47 | /*- 48 | * Copyright (c) 1999 Marcel Moolenaar 49 | * All rights reserved. 50 | * 51 | * Redistribution and use in source and binary forms, with or without 52 | * modification, are permitted provided that the following conditions 53 | * are met: 54 | * 1. Redistributions of source code must retain the above copyright 55 | * notice, this list of conditions and the following disclaimer 56 | * in this position and unchanged. 57 | * 2. Redistributions in binary form must reproduce the above copyright 58 | * notice, this list of conditions and the following disclaimer in the 59 | * documentation and/or other materials provided with the distribution. 60 | * 3. The name of the author may not be used to endorse or promote products 61 | * derived from this software without specific prior written permission. 62 | * 63 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 64 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 65 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 66 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 67 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 68 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 69 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 70 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 | * 74 | * $FreeBSD: src/sys/i386/include/ucontext.h,v 1.4 1999/10/11 20:33:09 luoqi Exp 75 | *$ 76 | */ 77 | 78 | struct mcontext { 79 | /* 80 | * The first 20 fields must match the definition of 81 | * sigcontext. So that we can support sigcontext 82 | * and ucontext_t at the same time. 83 | */ 84 | long mc_onstack; /* XXX - sigcontext compat. */ 85 | long mc_rdi; /* machine state (struct trapframe) */ 86 | long mc_rsi; 87 | long mc_rdx; 88 | long mc_rcx; 89 | long mc_r8; 90 | long mc_r9; 91 | long mc_rax; 92 | long mc_rbx; 93 | long mc_rbp; 94 | long mc_r10; 95 | long mc_r11; 96 | long mc_r12; 97 | long mc_r13; 98 | long mc_r14; 99 | long mc_r15; 100 | long mc_trapno; 101 | long mc_addr; 102 | long mc_flags; 103 | long mc_err; 104 | long mc_rip; 105 | long mc_cs; 106 | long mc_rflags; 107 | long mc_rsp; 108 | long mc_ss; 109 | 110 | long mc_len; /* sizeof(mcontext_t) */ 111 | #define _MC_FPFMT_NODEV 0x10000 /* device not present or configured */ 112 | #define _MC_FPFMT_XMM 0x10002 113 | long mc_fpformat; 114 | #define _MC_FPOWNED_NONE 0x20000 /* FP state not used */ 115 | #define _MC_FPOWNED_FPU 0x20001 /* FP state came from FPU */ 116 | #define _MC_FPOWNED_PCB 0x20002 /* FP state came from PCB */ 117 | long mc_ownedfp; 118 | /* 119 | * See for the internals of mc_fpstate[]. 120 | */ 121 | long mc_fpstate[64]; 122 | long mc_spare[8]; 123 | }; 124 | 125 | struct ucontext { 126 | /* 127 | * Keep the order of the first two fields. Also, 128 | * keep them the first two fields in the structure. 129 | * This way we can have a union with struct 130 | * sigcontext and ucontext_t. This allows us to 131 | * support them both at the same time. 132 | * note: the union is not defined, though. 133 | */ 134 | sigset_t uc_sigmask; 135 | mcontext_t uc_mcontext; 136 | 137 | struct __ucontext *uc_link; 138 | stack_t uc_stack; 139 | int __spare__[8]; 140 | }; 141 | -------------------------------------------------------------------------------- /include/inter/darwin/power-ucontext.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #define setcontext(u) _setmcontext(&(u)->mc) 6 | #define getcontext(u) _getmcontext(&(u)->mc) 7 | typedef struct mcontext mcontext_t; 8 | typedef struct ucontext ucontext_t; 9 | struct mcontext { 10 | ulong pc; /* lr */ 11 | ulong cr; /* mfcr */ 12 | ulong ctr; /* mfcr */ 13 | ulong xer; /* mfcr */ 14 | ulong sp; /* callee saved: r1 */ 15 | ulong toc; /* callee saved: r2 */ 16 | ulong r3; /* first arg to function, return register: r3 */ 17 | ulong gpr[19]; /* callee saved: r13-r31 */ 18 | /* 19 | // XXX: currently do not save vector registers or floating-point state 20 | // ulong pad; 21 | // uvlong fpr[18]; / * callee saved: f14-f31 * / 22 | // ulong vr[4*12]; / * callee saved: v20-v31, 256-bits each * / 23 | */ 24 | }; 25 | 26 | struct ucontext { 27 | struct { 28 | void *ss_sp; 29 | uint ss_size; 30 | } uc_stack; 31 | sigset_t uc_sigmask; 32 | mcontext_t mc; 33 | }; 34 | 35 | void makecontext(ucontext_t *, void (*)(void), int, ...); 36 | int swapcontext(ucontext_t *, const ucontext_t *); 37 | int _getmcontext(mcontext_t *); 38 | void _setmcontext(const mcontext_t *); 39 | -------------------------------------------------------------------------------- /include/inter/darwin/pthread_barrier.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_OSX_PTHREAD_BARRIER_H 6 | #define _TSC_OSX_PTHREAD_BARRIER_H 7 | 8 | #ifdef __APPLE__ 9 | 10 | typedef int pthread_barrierattr_t; 11 | 12 | typedef struct { 13 | pthread_mutex_t mutex; 14 | pthread_cond_t cond; 15 | int count; 16 | int tripCount; 17 | } pthread_barrier_t; 18 | 19 | int pthread_barrier_init(pthread_barrier_t *, const pthread_barrierattr_t *, 20 | unsigned int); 21 | int pthread_barrier_destroy(pthread_barrier_t *); 22 | int pthread_barrier_wait(pthread_barrier_t *); 23 | 24 | #endif // __APPLE__ 25 | 26 | #endif // _TSC_OSX_PTHREAD_BARRIER_H 27 | -------------------------------------------------------------------------------- /include/inter/darwin/pthread_spinlock.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _PTHREAD_SPINLOCK_H_ 6 | #define _PTHREAD_SPINLOCK_H_ 7 | 8 | #include 9 | /** 10 | enum { 11 | PTHREAD_PROCESS_PRIVATE, 12 | PTHREAD_PROCESS_SHARED, 13 | }; 14 | */ 15 | typedef int pthread_spinlock_t; 16 | 17 | static int pthread_spin_init(pthread_spinlock_t *lock, int pshared) { 18 | __asm__ __volatile__("" :: : "memory"); 19 | *lock = 0; 20 | return 0; 21 | } 22 | 23 | static int pthread_spin_destroy(pthread_spinlock_t *lock) { return 0; } 24 | 25 | static int pthread_spin_lock(pthread_spinlock_t *lock) { 26 | while (1) { 27 | int i; 28 | for (i = 0; i < 10000; i++) { 29 | if (__sync_bool_compare_and_swap(lock, 0, 1)) { 30 | return 0; 31 | } 32 | } 33 | sched_yield(); 34 | } 35 | } 36 | 37 | static int pthread_spin_trylock(pthread_spinlock_t *lock) { 38 | if (__sync_bool_compare_and_swap(lock, 0, 1)) { 39 | return 0; 40 | } 41 | return EBUSY; 42 | } 43 | 44 | static int pthread_spin_unlock(pthread_spinlock_t *lock) { 45 | __asm__ __volatile__("" :: : "memory"); 46 | *lock = 0; 47 | return 0; 48 | } 49 | #endif // _PTHREAD_SPINLOCK_H_ 50 | -------------------------------------------------------------------------------- /include/inter/darwin/time_.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _DARWIN_TIME_H_ 6 | #define _DARWIN_TIME_H_ 7 | #include 8 | 9 | enum { 10 | CLOCK_REALTIME, 11 | CLOCK_REALTIME_COARSE, 12 | CLOCK_MONOTONIC, 13 | CLOCK_MONOTONIC_COARSE, 14 | CLOCK_MONOTONIC_RAW, 15 | CLOCK_BOOTTIME, 16 | CLOCK_PROCESS_CPUTIME_ID, 17 | CLOCK_THREAD_CPUTIME_ID 18 | }; 19 | 20 | /// clock_gettime is not implemented in OS X 21 | static int clock_gettime(int clk_id, struct timespec* t) { 22 | struct timeval now; 23 | int rv = gettimeofday(&now, NULL); 24 | if (rv) return rv; 25 | t->tv_sec = now.tv_sec; 26 | t->tv_nsec = now.tv_usec * 1000; 27 | return 0; 28 | } 29 | 30 | #endif // _DARWIN_TIME_H_ 31 | -------------------------------------------------------------------------------- /include/inter/futex_lock.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _FUTEX_LOCK_H_ 6 | #define _FUTEX_LOCK_H_ 7 | 8 | #include 9 | 10 | #include "support.h" 11 | 12 | /* The futex based lock mechanism, 13 | * we've imitated the golang's implementation. 14 | * See [http://golang.org] to get the details .. */ 15 | 16 | enum { 17 | MUTEX_UNLOCKED = 0, 18 | MUTEX_LOCKED = 1, 19 | MUTEX_SLEEPING = 2, 20 | ACTIVE_SPIN = 4, 21 | ACTIVE_SPIN_CNT = 30, 22 | PASSIVE_SPIN = 1, 23 | }; 24 | 25 | typedef volatile struct { 26 | uint32_t key; 27 | #if (ENABLE_DEBUG > 1) 28 | uint64_t cookie; 29 | #endif 30 | } _coroc_futex_t; 31 | 32 | extern void _coroc_futex_init(volatile _coroc_futex_t *lock); 33 | extern void _coroc_futex_lock(volatile _coroc_futex_t *lock); 34 | extern void _coroc_futex_unlock(volatile _coroc_futex_t *lock); 35 | extern int _coroc_futex_trylock(volatile _coroc_futex_t *lock); 36 | extern void _coroc_futex_destroy(volatile _coroc_futex_t *lock); 37 | 38 | #endif // _FUTEX_LOCK_H_ 39 | -------------------------------------------------------------------------------- /include/inter/lock_chain.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_LOCK_CHAIN_H_ 6 | #define _TSC_LOCK_CHAIN_H_ 7 | 8 | #include 9 | #include "coroc_lock.h" 10 | 11 | #define TSC_LOCKCHAIN_DEFAULT_VOLUME 8 12 | 13 | typedef struct { 14 | bool sorted; 15 | int volume; 16 | int size; 17 | lock_t *locks; 18 | } lock_chain_t; 19 | 20 | static int lock_addr_comp(const void *lock1, const void *lock2) { 21 | return *(uint64_t *)(lock1) > *(uint64_t *)(lock2) ? 1 : -1; 22 | } 23 | 24 | static void lock_chain_acquire(lock_chain_t *chain) { 25 | if (!chain->sorted) { 26 | qsort(chain->locks, chain->size, sizeof(lock_t), lock_addr_comp); 27 | chain->sorted = true; 28 | } 29 | 30 | int i = 0; 31 | for (; i < chain->size; i++) lock_acquire(chain->locks[i]); 32 | } 33 | 34 | static void lock_chain_release(lock_chain_t *chain) { 35 | int i = chain->size - 1; 36 | for (; i >= 0; i--) lock_release(chain->locks[i]); 37 | } 38 | 39 | #endif // _TSC_LOCK_CHAIN_H_ 40 | -------------------------------------------------------------------------------- /include/inter/message.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_CORE_MESSAGE_H_ 6 | #define _TSC_CORE_MESSAGE_H_ 7 | 8 | #include "channel.h" 9 | 10 | typedef struct coroc_async_chan { 11 | struct coroc_chan _chan; 12 | queue_t mque; 13 | } *coroc_async_chan_t; 14 | 15 | typedef struct coroc_msg { 16 | int32_t size; 17 | void *msg; 18 | } coroc_msg_t; 19 | 20 | typedef struct { 21 | struct coroc_msg _msg; 22 | queue_item_t link; 23 | } *coroc_msg_item_t; 24 | 25 | struct coroc_coroutine; 26 | 27 | extern void coroc_async_chan_init(coroc_async_chan_t); 28 | extern void coroc_async_chan_fini(coroc_async_chan_t); 29 | 30 | extern int coroc_send(struct coroc_coroutine *, void *, int32_t); 31 | extern int coroc_recv(void *, int32_t, bool); 32 | 33 | extern int coroc_sendp(struct coroc_coroutine *, void *, int32_t); 34 | extern int coroc_recvp(void **, int32_t *, bool); 35 | 36 | #endif // _TSC_CORE_MESSAGE_H_ 37 | -------------------------------------------------------------------------------- /include/inter/netpoll.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_NETPOLL_H_ 6 | #define _TSC_NETPOLL_H_ 7 | 8 | #include 9 | #include 10 | 11 | #include "coroc_lock.h" 12 | #include "coroc_time.h" 13 | #include "support.h" 14 | #include "coroutine.h" 15 | #ifdef ENABLE_REFCNT 16 | #include "refcnt.h" 17 | #endif 18 | 19 | enum { TSC_NETPOLL_READ = 1, TSC_NETPOLL_WRITE = 2, TSC_NETPOLL_ERROR = 4 }; 20 | 21 | typedef struct coroc_poll_desc { 22 | struct coroc_refcnt refcnt; 23 | bool done; 24 | int fd; 25 | int mode; 26 | int id; // for fast delete ... 27 | coroc_coroutine_t wait; 28 | coroc_inter_timer_t *deadline; 29 | coroc_lock lock; 30 | } *coroc_poll_desc_t; 31 | 32 | // internal netpoll API.. 33 | int __coroc_netpoll_init(int max); 34 | int __coroc_netpoll_add(coroc_poll_desc_t desc); 35 | int __coroc_netpoll_rem(coroc_poll_desc_t desc); 36 | int __coroc_netpoll_fini(void); 37 | int __coroc_netpoll_size(void); 38 | bool __coroc_netpoll_polling(int timeout); 39 | 40 | void coroc_netpoll_initialize(void); 41 | int coroc_netpoll_wakeup(coroc_poll_desc_t desc); 42 | 43 | // the public netpoll API .. 44 | int coroc_net_nonblock(int fd); 45 | int coroc_net_read(int fd, void *buf, int size); 46 | int coroc_net_timed_read(int fd, void *buf, int size, int64_t usec); 47 | int coroc_net_write(int fd, void *buf, int size); 48 | int coroc_net_wait(int fd, int mode); 49 | int coroc_net_timedwait(int fd, int mode, int64_t usec); 50 | 51 | int coroc_net_announce(bool istcp, const char *server, int port); 52 | int coroc_net_timed_accept(int fd, char *server, int *port, int64_t usec); 53 | int coroc_net_accept(int fd, char *server, int *port); 54 | int coroc_net_lookup(const char *name, uint32_t *ip); 55 | int coroc_net_timed_dial(bool istcp, const char *server, int port, int64_t usec); 56 | int coroc_net_dial(bool istcp, const char *server, int port); 57 | 58 | #endif // _TSC_NETPOLL_H_ 59 | -------------------------------------------------------------------------------- /include/inter/notify.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_SUPPORT_NOTIFY_H_ 6 | #define _TSC_SUPPORT_NOTIFY_H_ 7 | 8 | #include 9 | 10 | #include "support.h" 11 | #include "async.h" 12 | 13 | // the notify API, just wrap the pthread_cont_t now! 14 | typedef struct { 15 | uint32_t key; 16 | int64_t ns; 17 | } coroc_notify_t; 18 | 19 | // the internal sleep / tsleep 20 | 21 | void coroc_notify_wakeup(coroc_notify_t *note); 22 | void __coroc_notify_tsleep(void *); 23 | 24 | static inline void coroc_notify_clear(coroc_notify_t *note) { 25 | note->key = 0; 26 | note->ns = 0; 27 | } 28 | 29 | static inline void coroc_notify_tsleep(coroc_notify_t *note, int64_t ns) { 30 | if (ns > 0) { 31 | note->ns = ns; 32 | __coroc_notify_tsleep(note); 33 | } 34 | } 35 | 36 | static inline void coroc_notify_tsleep_u(coroc_notify_t *note, int64_t ns) { 37 | // check the waiting time first 38 | if (ns > 0) { 39 | // waiting for the signal .. 40 | note->ns = ns; 41 | coroc_async_request_submit(__coroc_notify_tsleep, note); 42 | } 43 | } 44 | 45 | // user task space nanosleep call 46 | extern void __coroc_nanosleep(void *); 47 | static inline void coroc_nanosleep(uint64_t ns) { 48 | if (ns == 0) return; 49 | coroc_async_request_submit(__coroc_nanosleep, &ns); 50 | } 51 | 52 | #endif // _TSC_SUPPORT_NOTIFY_H_ 53 | -------------------------------------------------------------------------------- /include/inter/refcnt.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_REFCNT_H_ 6 | #define _TSC_REFCNT_H_ 7 | 8 | #include 9 | #include 10 | 11 | typedef void (*release_handler_t)(void *); 12 | 13 | typedef struct coroc_refcnt { 14 | uint32_t count; 15 | release_handler_t release; 16 | } *coroc_refcnt_t; 17 | 18 | static inline void coroc_refcnt_init(coroc_refcnt_t ref, 19 | release_handler_t release) { 20 | ref->count = 1; 21 | ref->release = release; 22 | } 23 | 24 | static inline void *__coroc_refcnt_get(coroc_refcnt_t ref) { 25 | TSC_ATOMIC_INC(ref->count); 26 | return (void *)ref; 27 | } 28 | 29 | static inline bool __coroc_refcnt_put(coroc_refcnt_t ref) { 30 | if (ref != NULL && TSC_ATOMIC_DEC(ref->count) == 0) { 31 | (ref->release)(ref); 32 | return true; 33 | } 34 | return false; 35 | } 36 | 37 | static inline coroc_refcnt_t 38 | __coroc_refcnt_assign(coroc_refcnt_t* to, coroc_refcnt_t from) { 39 | __coroc_refcnt_put(*to); 40 | *to = (from == NULL) ? NULL : __coroc_refcnt_get(from); 41 | return *to; 42 | } 43 | 44 | static inline coroc_refcnt_t 45 | __coroc_refcnt_assign_expr(coroc_refcnt_t* to, coroc_refcnt_t from) { 46 | __coroc_refcnt_put(*to); 47 | return (*to = from); 48 | } 49 | 50 | 51 | #define coroc_refcnt_get(ref) (typeof(ref)) __coroc_refcnt_get((coroc_refcnt_t)(ref)) 52 | #define coroc_refcnt_put(ref) __coroc_refcnt_put((coroc_refcnt_t)(ref)) 53 | 54 | #define coroc_refcnt_assign(to, from) \ 55 | (typeof(to)) __coroc_refcnt_assign((coroc_refcnt_t*)(&(to)), (coroc_refcnt_t)(from)) 56 | 57 | #define coroc_refcnt_assign_expr(to, from) \ 58 | (typeof(to)) __coroc_refcnt_assign_expr((coroc_refcnt_t*)(&(to)), (coroc_refcnt_t)(from)) 59 | 60 | #endif // _TSC_REFCNT_H_ 61 | -------------------------------------------------------------------------------- /include/inter/support.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_PLATFORM_SUPPORT_H_ 6 | #define _TSC_PLATFORM_SUPPORT_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #ifndef IGNORE_CONFIG_H 16 | #include "config.h" 17 | #endif // IGNORE_CONFIG_H 18 | 19 | #ifdef __APPLE__ 20 | 21 | #include "darwin/time_.h" 22 | #include "darwin/pthread_barrier.h" 23 | 24 | #define _XOPEN_SOURCE 700 25 | #define POLLRDHUP 0x2000 26 | 27 | #endif // __APPLE__ 28 | 29 | #define TSC_NAME_LENGTH 32 30 | #define TSC_TASK_NUM_PERPRIO 512 31 | 32 | #define TSC_PRIO_NUM 4 33 | 34 | // -- for thread APIs -- 35 | typedef pthread_t TSC_OS_THREAD_T; 36 | 37 | #define TSC_OS_THREAD_ATTR pthread_attr_t 38 | #define TSC_OS_THREAD_ATTR_INIT pthread_attr_init 39 | #define TSC_OS_THREAD_ATTR_SETSTACKSZ pthread_attr_setstacksize 40 | 41 | #define TSC_OS_THREAD_CREATE pthread_create 42 | #define TSC_OS_THREAD_SENDSIG pthread_kill 43 | 44 | // -- for thread local storages -- 45 | #if USE_PTHREAD_TLS 46 | #define TSC_TLS_DEFINE pthread_key_t __vpu_keys; 47 | 48 | #define TSC_TLS_DECLARE extern TSC_TLS_DEFINE 49 | 50 | #define TSC_TLS_INIT() pthread_key_create(&__vpu_keys, NULL) 51 | 52 | #define TSC_TLS_SET(p) pthread_setspecific(__vpu_keys, (p)) 53 | 54 | #define TSC_TLS_GET() pthread_getspecific(__vpu_keys) 55 | 56 | #else // USE_GCC_TLS 57 | #define TSC_TLS_DEFINE __thread vpu_t* __vpu; 58 | 59 | #define TSC_TLS_DECLARE extern TSC_TLS_DEFINE 60 | 61 | #define TSC_TLS_INIT() \ 62 | do { \ 63 | } while (0) 64 | 65 | #define TSC_TLS_SET(p) __vpu = (vpu_t*)(p) 66 | 67 | #define TSC_TLS_GET() (__vpu) 68 | #endif 69 | 70 | // -- for thread barrier -- 71 | #define TSC_BARRIER_DEFINE static pthread_barrier_t __vpu_barrier; 72 | 73 | #define TSC_BARRIER_INIT(n) pthread_barrier_init(&__vpu_barrier, NULL, n) 74 | 75 | #define TSC_BARRIER_WAIT() pthread_barrier_wait(&__vpu_barrier); 76 | 77 | #if !defined(PTHREAD_STACK_MIN) 78 | #define PTHREAD_STACK_MIN (16 * 1024) // 16KB 79 | #endif 80 | 81 | // -- for memory alloc api -- 82 | #define TSC_ALLOC malloc 83 | #define TSC_REALLOC realloc 84 | #define TSC_DEALLOC free 85 | 86 | // -- for signals -- 87 | #define TSC_CLOCK_SIGNAL SIGUSR1 88 | 89 | #ifdef ENABLE_TIMESHARE 90 | 91 | #define TSC_SIGNAL_MASK_DEFINE \ 92 | sigset_t __vpu_sigmask; \ 93 | __thread int __vpu_sigmask_nest = 0; 94 | 95 | #define TSC_SIGNAL_MASK_DECLARE \ 96 | extern sigset_t __vpu_sigmask; \ 97 | extern __thread int __vpu_sigmask_nest; 98 | 99 | #define TSC_SIGNAL_MASK_INIT() \ 100 | do { \ 101 | sigemptyset(&__vpu_sigmask); \ 102 | sigaddset(&__vpu_sigmask, SIGUSR1); \ 103 | } while (0) 104 | 105 | #define TSC_SIGNAL_MASK() \ 106 | do { \ 107 | if (__vpu_sigmask_nest++ == 0) \ 108 | sigprocmask(SIG_BLOCK, &__vpu_sigmask, NULL); \ 109 | } while (0) 110 | 111 | #define TSC_SIGNAL_UNMASK() \ 112 | do { \ 113 | if (--__vpu_sigmask_nest == 0) \ 114 | sigprocmask(SIG_UNBLOCK, &__vpu_sigmask, NULL); \ 115 | } while (0) 116 | 117 | #define TSC_SIGNAL_STATE_SAVE(p) *(p) = __vpu_sigmask_nest 118 | 119 | #if defined(__APPLE__) 120 | #define TSC_SIGNAL_STATE_LOAD(p) \ 121 | do { \ 122 | __vpu_sigmask_nest = *(p); \ 123 | if (*(p) == 0) sigprocmask(SIG_UNBLOCK, &__vpu_sigmask, NULL); \ 124 | } while (0) 125 | #else 126 | #define TSC_SIGNAL_STATE_LOAD(p) __vpu_sigmask_nest = *(p) 127 | #endif 128 | 129 | #else 130 | #define TSC_SIGNAL_MASK_DEFINE 131 | #define TSC_SIGNAL_MASK_DECLARE 132 | #define TSC_SIGNAL_MASK_INIT() 133 | #define TSC_SIGNAL_MASK() 134 | #define TSC_SIGNAL_UNMASK() 135 | #define TSC_SIGNAL_STATE_SAVE(p) 136 | #define TSC_SIGNAL_STATE_LOAD(p) 137 | #endif 138 | 139 | #define TSC_RESCHED_THRESHOLD 5 140 | 141 | // -- for atomic add op -- 142 | #if defined(__APPLE__) && !defined(__i386__) && !defined(__x86_64__) 143 | #define TSC_ATOMIC_INC(n) (++(n)) 144 | #define TSC_ATOMIC_DEC(n) (--(n)) 145 | #define TSC_SYNC_ALL() 146 | // TODO # define TSC_CAS(pval, old, new) 147 | #else 148 | #define TSC_ATOMIC_INC(n) __sync_add_and_fetch(&(n), 1) 149 | #define TSC_ATOMIC_DEC(n) __sync_add_and_fetch(&(n), -1) 150 | 151 | #define TSC_ATOMIC_READ(n) __atomic_load_n(&(n), __ATOMIC_SEQ_CST) 152 | #define TSC_ATOMIC_WRITE(n, v) __atomic_store_n(&(n), v, __ATOMIC_SEQ_CST) 153 | 154 | #define TSC_CAS(pval, old, new) __sync_bool_compare_and_swap(pval, old, new) 155 | #define TSC_XCHG(pval, new) __atomic_exchange_n(pval, new, __ATOMIC_SEQ_CST) 156 | 157 | #define TSC_SYNC_ALL() __sync_synchronize() 158 | #endif 159 | 160 | #if defined(__GNUC__) && (__GNUC__ < 4 || __GNUC_MINOR__ < 7) 161 | #undef TSC_SYNC_ALL 162 | #undef TSC_XCHG 163 | #undef TSC_ATOMIC_READ 164 | #undef TSC_ATOMIC_WRITE 165 | 166 | #define TSC_SYNC_ALL() __asm__ __volatile__("" :: : "memory") 167 | 168 | #define TSC_XCHG(pval, new) \ 169 | ({ \ 170 | uint32_t __old; \ 171 | for (;;) { \ 172 | __old = *pval; \ 173 | if (TSC_CAS(pval, __old, new)) break; \ 174 | } \ 175 | __old; \ 176 | }) 177 | 178 | #define TSC_ATOMIC_READ(n) __sync_add_and_fetch(&(n), 0) 179 | #define TSC_ATOMIC_WRITE(n, v) \ 180 | ({ \ 181 | volatile uint32_t* __pval = &(n); \ 182 | for (;;) { \ 183 | uint32_t __old = *__pval; \ 184 | if (TSC_CAS(__pval, __old, v)) break; \ 185 | } \ 186 | }) 187 | 188 | #endif 189 | 190 | #ifdef ENABLE_FUTEX 191 | extern void _coroc_futex_sleep(uint32_t*, uint32_t, int64_t); 192 | extern void _coroc_futex_wakeup(uint32_t*, uint32_t); 193 | #endif 194 | 195 | #if defined(__APPLE__) || defined(__FreeBSD__) 196 | #include 197 | #include 198 | static int inline TSC_NP_ONLINE(void) { 199 | int num_cpu; 200 | int mib[4]; 201 | size_t len = sizeof(num_cpu); 202 | 203 | /* set the mib for hw.ncpu */ 204 | mib[0] = CTL_HW; 205 | mib[1] = HW_NCPU; 206 | 207 | /* get the number of CPUs from the system */ 208 | sysctl(mib, 2, &num_cpu, &len, NULL, 0); 209 | if (num_cpu <= 0) return 1; 210 | return num_cpu; 211 | } 212 | #else // linux platforms .. 213 | #include 214 | #define TSC_NP_ONLINE() get_nprocs() 215 | #endif 216 | 217 | /* define the coroc_word_t which match the arch word size */ 218 | #if __x86_64__ // the only 64-bit arch we support now is x86-64 219 | typedef long long coroc_word_t; 220 | #else // other such as i386, armv7 .. 221 | typedef long coroc_word_t; 222 | #endif 223 | 224 | static inline void __procyield(uint32_t cnt) { 225 | volatile uint32_t i; 226 | 227 | for (i = 0; i < cnt; ++i) { 228 | #if defined(__i386) || defined(__x86_64__) 229 | __asm__ __volatile__("pause\n" ::); 230 | #endif 231 | } 232 | } 233 | 234 | /* define the debug output interface */ 235 | #if (ENABLE_DEBUG > 1) 236 | #define TSC_DEBUG(...) fprintf(stderr, __VA_ARGS__) 237 | #else 238 | #define TSC_DEBUG(...) 239 | #endif // ENABLE_DEBUG 240 | 241 | #endif // _TSC_PLATFORM_SUPPORT_H_ 242 | -------------------------------------------------------------------------------- /include/inter/vfs.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef _TSC_VFS_H_ 6 | #define _TSC_VFS_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "support.h" 17 | 18 | // -- the virual file system modules -- 19 | 20 | // the operation types 21 | enum { 22 | TSC_VFS_OPEN = 0, 23 | TSC_VFS_CLOSE, 24 | TSC_VFS_READ, 25 | TSC_VFS_WRITE, 26 | TSC_VFS_LSEEK, 27 | TSC_VFS_FLUSH, 28 | TSC_VFS_IOCTL, 29 | }; 30 | 31 | // define the callback handlers' types 32 | typedef int (*open_callback_t)(const char *, int, ...); 33 | typedef ssize_t (*read_callback_t)(int, void *, size_t); 34 | typedef ssize_t (*write_callback_t)(int, const void *, size_t); 35 | typedef off_t (*lseek_callback_t)(int, off_t, int); 36 | typedef void (*flush_callback_t)(int); 37 | typedef int (*ioctl_callback_t)(int, int, ...); 38 | typedef int (*close_callback_t)(int); 39 | 40 | // the file operation driver 41 | typedef struct coroc_vfs_driver { 42 | open_callback_t open; 43 | read_callback_t read; 44 | write_callback_t write; 45 | lseek_callback_t lseek; 46 | flush_callback_t flush; 47 | ioctl_callback_t ioctl; 48 | close_callback_t close; 49 | } *coroc_vfs_driver_t; 50 | 51 | // the default file driver 52 | extern struct coroc_vfs_driver coroc_vfs_file_drv; 53 | 54 | typedef struct { 55 | int fd; 56 | int ops_type; 57 | int64_t arg0; // also for retval 58 | int64_t arg1; // optional 59 | void *buf; 60 | struct coroc_vfs_driver *driver; // optional 61 | } coroc_vfs_ops; 62 | 63 | // the APIs .. 64 | int __coroc_vfs_open(coroc_vfs_driver_t drv, bool sync, const char *name, int flags, 65 | ...); 66 | int __coroc_vfs_close(coroc_vfs_driver_t drv, bool sync, int fd); 67 | int __coroc_vfs_ioctl(coroc_vfs_driver_t drv, bool sync, int fd, int cmd, ...); 68 | void __coroc_vfs_flush(coroc_vfs_driver_t drv, bool sync, int fd); 69 | ssize_t __coroc_vfs_read(coroc_vfs_driver_t drv, bool sync, int fd, void *buf, 70 | size_t size); 71 | ssize_t __coroc_vfs_write(coroc_vfs_driver_t drv, bool sync, int fd, 72 | const void *buf, size_t size); 73 | off_t __coroc_vfs_lseek(coroc_vfs_driver_t drv, bool sync, int fd, off_t offset, 74 | int whence); 75 | 76 | // asynchronized APIs 77 | #define coroc_vfs_open(...) __coroc_vfs_open(NULL, false, __VA_ARGS__) 78 | #define coroc_vfs_close(...) __coroc_vfs_close(NULL, false, __VA_ARGS__) 79 | #define coroc_vfs_flush(...) __coroc_vfs_flush(NULL, false, __VA_ARGS__) 80 | #define coroc_vfs_read(...) __coroc_vfs_read(NULL, false, __VA_ARGS__) 81 | #define coroc_vfs_write(...) __coroc_vfs_write(NULL, false, __VA_ARGS__) 82 | #define coroc_vfs_lseek(...) __coroc_vfs_lseek(NULL, false, __VA_ARGS__) 83 | #define coroc_vfs_ioctl(...) __coroc_vfs_ioctl(NULL, false, __VA_ARGS__) 84 | 85 | // synchronized APIs 86 | #define coroc_vfs_open_sync(...) __coroc_vfs_open(NULL, true, __VA_ARGS__) 87 | #define coroc_vfs_close_sync(...) __coroc_vfs_close(NULL, true, __VA_ARGS__) 88 | #define coroc_vfs_flush_sync(...) __coroc_vfs_flush(NULL, true, __VA_ARGS__) 89 | #define coroc_vfs_read_sync(...) __coroc_vfs_read(NULL, true, __VA_ARGS__) 90 | #define coroc_vfs_write_sync(...) __coroc_vfs_write(NULL, true, __VA_ARGS__) 91 | #define coroc_vfs_lseek_sync(...) __coroc_vfs_lseek(NULL, true, __VA_ARGS__) 92 | #define coroc_vfs_ioctl_sync(...) __coroc_vfs_ioctl(NULL, true, __VA_ARGS__) 93 | 94 | #endif // _TSC_VFS_H_ 95 | -------------------------------------------------------------------------------- /include/inter/vpu.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | 6 | #ifndef _LIBTSC_DNA_CORE_VPU_H_ 7 | #define _LIBTSC_DNA_CORE_VPU_H_ 8 | 9 | #include 10 | #include "coroutine.h" 11 | #include "support.h" 12 | #include "coroc_queue.h" 13 | 14 | // The unlock handler type 15 | typedef void (*unlock_handler_t)(volatile void *lock); 16 | 17 | // Type of the private task queue 18 | typedef struct private_task_queue { 19 | unsigned prio; // the priority level for this pq 20 | coroc_coroutine_t runq[TSC_TASK_NUM_PERPRIO]; 21 | uint32_t runqhead; 22 | uint32_t runqtail; 23 | } p_task_que; 24 | 25 | // Type of VPU information, 26 | // It's a OS Thread here!! 27 | typedef struct vpu { 28 | TSC_OS_THREAD_T os_thr; 29 | uint32_t id; 30 | bool initialized; 31 | uint32_t watchdog; 32 | uint32_t ticks; 33 | unsigned rand_seed; 34 | coroc_coroutine_t current; 35 | coroc_coroutine_t scheduler; 36 | 37 | // the private queues for each priority level: 38 | p_task_que xt[TSC_PRIO_NUM]; 39 | 40 | void *hold; 41 | unlock_handler_t unlock_handler; 42 | } vpu_t; 43 | 44 | // Type of the VPU manager 45 | typedef struct vpu_manager { 46 | vpu_t *vpu; 47 | 48 | // the global running queue for each priority 49 | queue_t xt[TSC_PRIO_NUM]; 50 | // total ready tasks for each priority 51 | uint32_t ready[TSC_PRIO_NUM + 1]; 52 | 53 | uint32_t xt_index; 54 | uint32_t last_pid; 55 | coroc_coroutine_t main; 56 | queue_t coroutine_list; 57 | pthread_cond_t cond; 58 | pthread_mutex_t lock; 59 | uint16_t alive; 60 | uint16_t idle; 61 | uint32_t total_ready; 62 | uint32_t total_iowait; 63 | } vpu_manager_t; 64 | 65 | extern vpu_manager_t vpu_manager; 66 | 67 | extern int core_wait(void *); 68 | extern int core_yield(void *); 69 | extern int core_exit(void *); 70 | 71 | extern void coroc_vpu_initialize(int cpu_mp_count, coroc_coroutine_handler_t entry); 72 | 73 | extern void vpu_suspend(volatile void *lock, unlock_handler_t handler); 74 | extern void vpu_ready(coroc_coroutine_t coroutine, bool); 75 | extern void vpu_syscall(int (*pfn)(void *)); 76 | extern void vpu_clock_handler(int); 77 | extern void vpu_wakeup_one(void); 78 | extern void vpu_backtrace(vpu_t*); 79 | 80 | #define TSC_ALLOC_TID() TSC_ATOMIC_INC(vpu_manager.last_pid) 81 | 82 | #endif // _LIBTSC_DNA_CORE_VPU_H_ 83 | -------------------------------------------------------------------------------- /include/libcoroc.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #ifndef __LIBCOROC_H__ 6 | #define __LIBCOROC_H__ 7 | 8 | #if (defined(__COROC__) || !defined(__GEN_BY_CLANG_COROC__)) 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif // __cplusplus 21 | 22 | #include "inter/support.h" 23 | #include "inter/coroutine.h" 24 | #include "inter/channel.h" 25 | #include "inter/message.h" 26 | #include "inter/async.h" 27 | #include "inter/netpoll.h" 28 | #include "inter/coroc_group.h" 29 | #include "inter/coroc_time.h" 30 | #include "inter/vfs.h" 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif // __cplusplus 35 | 36 | #elif defined(__GEN_BY_CLANG_COROC__) 37 | 38 | /* standard definations for CoroC internals */ 39 | 40 | /* NOTE: These macros must be designed carefully to avoid 41 | * include other macros which defined in other header files! */ 42 | 43 | /// basic builtin types 44 | 45 | #if !defined(NULL) 46 | # define NULL ((void*)0) 47 | #endif 48 | 49 | #define __chan_t coroc_chan_t 50 | #define __task_t coroc_coroutine_t 51 | #define __select_set_t coroc_chan_set_t 52 | #define __coroc_time_t uint64_t 53 | #define __group_t coroc_group_t 54 | 55 | /// for reference-counting ops 56 | #define __refcnt_t coroc_refcnt_t 57 | #define __refcnt_get(R) (typeof(R))__coroc_refcnt_get((coroc_refcnt_t)(R)) 58 | #define __refcnt_put(R) __coroc_refcnt_put((coroc_refcnt_t)(R)) 59 | 60 | #define __CoroC_release_handler_t release_handler_t 61 | 62 | #define __CoroC_New(F0, T0, T, S, F, A) ({ \ 63 | T0 *ref = calloc(sizeof(T0) + (S-1)*sizeof(T) + A, 1); \ 64 | ref->__refcnt.release = ((release_handler_t)(F0)); \ 65 | ref->__user_fini = ((typeof(ref->__user_fini))(F));\ 66 | ref->__obj_num = (S); \ 67 | __coroc_refcnt_get((coroc_refcnt_t)(ref)); }) 68 | 69 | #define __CoroC_New_Basic(T0, T, S) ({ \ 70 | T0 *ref = calloc(sizeof(T0) + (S-1)*sizeof(T), 1); \ 71 | ref->__refcnt.release = ((release_handler_t)free); \ 72 | __coroc_refcnt_get((coroc_refcnt_t)(ref)); }) 73 | 74 | /* more interfaces for new auto scope branch */ 75 | #define __refcnt_assign(D, S) \ 76 | (typeof(D)) __coroc_refcnt_assign( \ 77 | (coroc_refcnt_t*)(&(D)), \ 78 | (coroc_refcnt_t)(S) ) 79 | 80 | #define __refcnt_assign_expr(D, E) \ 81 | (typeof(D)) __coroc_refcnt_assign_expr( \ 82 | (coroc_refcnt_t*)(&(D)), \ 83 | (coroc_refcnt_t)(E) ) 84 | 85 | #define __refcnt_put_array(A, N) ({ \ 86 | int i = 0; \ 87 | for (i = 0; i < (N); ++i) \ 88 | __coroc_refcnt_put((coroc_refcnt_t)((A)[i])); }) 89 | 90 | /// for coroutine ops 91 | #define __CoroC_spawn_entry_t coroc_coroutine_handler_t 92 | #define __CoroC_spawn_cleanup_t coroc_coroutine_cleanup_t 93 | 94 | #define __CoroC_Spawn(F, A, P, CB) \ 95 | coroc_coroutine_allocate((F), (A), "", \ 96 | TSC_COROUTINE_NORMAL, \ 97 | P, (CB)) 98 | 99 | #define __CoroC_Yield coroc_coroutine_yield 100 | #define __CoroC_Self coroc_coroutine_self 101 | #define __CoroC_Quit coroc_coroutine_exit 102 | #define __CoroC_Exit coroc_coroutine_exit 103 | 104 | #define __CoroC_Set_Name coroc_coroutine_set_name 105 | #define __CoroC_Set_Prio coroc_coroutine_set_priority 106 | 107 | /// for group ops 108 | #define __CoroC_Group coroc_group_alloc 109 | #define __CoroC_Add_Task coroc_group_add_task 110 | #define __CoroC_Notify coroc_group_notify 111 | #define __CoroC_Sync(G) ({ \ 112 | int ret = coroc_group_sync(G);\ 113 | if (G) { free(G); G = 0; } ret; }) 114 | 115 | /// for channel ops 116 | #define __CoroC_Chan _coroc_chan_allocate 117 | #define __CoroC_Chan_Close(C) coroc_chan_close((C)) 118 | #define __CoroC_Null NULL 119 | 120 | #define __CoroC_Chan_SendExpr(C, V) ({ \ 121 | typeof(V) __temp = (V); \ 122 | _Bool ret = _coroc_chan_send(C, (void*)(&__temp), 1) != CHAN_CLOSED; \ 123 | ret;}) 124 | #define __CoroC_Chan_Send(C, P) ({ \ 125 | _Bool ret = _coroc_chan_send(C, (void*)(P), 1) != CHAN_CLOSED; \ 126 | ret;}) 127 | #define __CoroC_Chan_Recv(C, P) ({ \ 128 | _Bool ret = _coroc_chan_recv(C, (void*)(P), 1) != CHAN_CLOSED; \ 129 | ret;}) 130 | 131 | #define __CoroC_Chan_SendExpr_NB(C, V) ({ \ 132 | typeof(V) __temp = (V); \ 133 | _Bool ret = _coroc_chan_send(C, (void*)(&__temp), 0) == CHAN_SUCCESS; \ 134 | ret;}) 135 | #define __CoroC_Chan_Send_NB(C, P) ({ \ 136 | _Bool ret = _coroc_chan_send(C, (void*)(P), 0) == CHAN_SUCCESS; \ 137 | ret;}) 138 | #define __CoroC_Chan_Recv_NB(C, P) ({ \ 139 | _Bool ret = _coroc_chan_recv(C, (void*)(P), 0) == CHAN_SUCCESS; \ 140 | ret;}) 141 | 142 | #define __CoroC_Chan_SendRef(C, R) ({ \ 143 | _Bool ret = 1; \ 144 | __coroc_refcnt_get((coroc_refcnt_t)(*(R))); \ 145 | if (_coroc_chan_send(C, (void*)(R), 1) == CHAN_CLOSED) { \ 146 | ret = 0; __coroc_refcnt_put((coroc_refcnt_t)(*(R))); } \ 147 | ret;}) 148 | #define __CoroC_Chan_RecvRef(C, R) ({ \ 149 | __coroc_refcnt_put((coroc_refcnt_t)(*(R))); \ 150 | _Bool ret = _coroc_chan_recv(C, (void*)(R), 1) != CHAN_CLOSED; \ 151 | ret;}) 152 | 153 | #define __CoroC_Chan_SendRef_NB(C, R) ({ \ 154 | __coroc_refcnt_get((coroc_refcnt_t)(*(R)));\ 155 | _Bool ret = _coroc_chan_send(C, (void*)(R), 0) == CHAN_SUCCESS; \ 156 | if (!ret) __coroc_refcnt_put((coroc_refcnt_t)(*(R))); \ 157 | ret;}) 158 | #define __CoroC_Chan_RecvRef_NB(C, R) ({ \ 159 | __coroc_refcnt_put((coroc_refcnt_t)(*(R)));\ 160 | _Bool ret = _coroc_chan_recv(C, (void*)(R), 0) == CHAN_SUCCESS; \ 161 | ret;}) 162 | 163 | /// channel select ops .. 164 | #if 0 165 | #define __CoroC_Select_Size(N) \ 166 | (sizeof(struct coroc_chan_set) + \ 167 | (N) * (sizeof(coroc_scase_t) + sizeof(lock_t))) 168 | 169 | #define __CoroC_Select_Alloc(N) alloca(__CoroC_Select_Size(N)) 170 | #endif 171 | 172 | #define __CoroC_Select_Alloc(N) coroc_chan_set_allocate(N) 173 | #define __CoroC_Select_Dealloc(S) coroc_chan_set_dealloc(S) 174 | #define __CoroC_Select_Init(S, N) coroc_chan_set_init(S, N) 175 | 176 | #define __CoroC_Select(S, B) ({ \ 177 | coroc_chan_t active = NULL; \ 178 | _coroc_chan_set_select(S, B, &active); \ 179 | active; }) 180 | #define __CoroC_Select_SendExpr(S, C, E) \ 181 | do { typeof(E) __temp = E; \ 182 | coroc_chan_set_send(S, C, &__temp); } while (0) 183 | #define __CoroC_Select_Send coroc_chan_set_send 184 | #define __CoroC_Select_Recv coroc_chan_set_recv 185 | 186 | #define __CoroC_Select_SendRef(S, C, R) do { \ 187 | __coroc_refcnt_get((coroc_refcnt_t)(*(R))); \ 188 | coroc_chan_set_send(S, C, (void*)(R)); } while (0) 189 | #define __CoroC_Select_RecvRef(S, C, R) do { \ 190 | __coroc_refcnt_put((coroc_refcnt_t)(*(R))); \ 191 | coroc_chan_set_recv(S, C, (void*)(R)); } while (0) 192 | 193 | /// for Task based send / recv 194 | #define __CoroC_Task_Send(task, buf, sz) coroc_send(*(task), buf, sz) 195 | #define __CoroC_Task_Recv(buf, sz) coroc_recv(buf, sz, 1) 196 | #define __CoroC_Task_Recv_NB(buf, sz) coroc_recv(buf, sz, 0) 197 | 198 | /// for Timer / Ticker .. 199 | #define __CoroC_Timer_At(at) ({ \ 200 | coroc_timer_t __timer = coroc_timer_allocate(0, NULL); \ 201 | coroc_timer_at(__timer, at); \ 202 | (coroc_chan_t)(__timer); }) 203 | 204 | #define __CoroC_Timer_After(after) ({ \ 205 | coroc_timer_t __timer = coroc_timer_allocate(0, NULL); \ 206 | coroc_timer_after(__timer, after); \ 207 | (coroc_chan_t)(__timer); }) 208 | 209 | #define __CoroC_Ticker(period) ({ \ 210 | coroc_timer_t __ticker = coroc_timer_allocate(period, NULL); \ 211 | coroc_timer_after(__ticker, period); \ 212 | (coroc_chan_t)(__ticker); }) 213 | 214 | #define __CoroC_Stop(T) coroc_timer_stop((coroc_timer_t)(T)) 215 | 216 | /// for time management 217 | #define __CoroC_Now coroc_getmicrotime 218 | #define __CoroC_Sleep coroc_udelay 219 | 220 | /// for explicity release the reference's counter 221 | #define __CoroC_Task_Release(T) \ 222 | if (__coroc_refcnt_put((coroc_refcnt_t)(T))) (T) = NULL; 223 | #define __CoroC_Chan_Release(C) \ 224 | if (__coroc_refcnt_put((coroc_refcnt_t)(C))) (C) = NULL; 225 | 226 | /// for async call APIs 227 | #define __CoroC_async_handler_t coroc_async_callback_t 228 | #define __CoroC_Async_Call coroc_async_request_submit 229 | 230 | #endif // defined(__COROC__) 231 | 232 | #endif // __LIBCOROC_H__ 233 | -------------------------------------------------------------------------------- /scripts/gdb_helper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | 5 | sys.stderr.write("Loading the LibTSC runtime support..\n") 6 | 7 | sts = { 0xBAFF:"sleep", 0xFACE:"ready", 0xBEEF:"run", 0xBADD:"wait", 0xBADE:"iowait", 0xDEAD:"exit"} 8 | 9 | prios = { 0:"HIGHEST", 1:"HIGH", 2:"NORMAL", 3:"LOW", 4:"IDLE" } 10 | 11 | def linked_list(ptr, linkfield): 12 | cop = gdb.lookup_type('struct coroc_coroutine').pointer() 13 | while ptr: 14 | yield ptr['owner'].cast(cop) 15 | ptr = ptr[linkfield] 16 | 17 | 18 | class CoroutinesCmd(gdb.Command): 19 | "List all coroutines." 20 | 21 | def __init__(self): 22 | super(CoroutinesCmd, self).__init__("info coroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE) 23 | 24 | def invoke(self, arg, form_tty): 25 | arch = gdb.selected_frame().architecture() 26 | vp = gdb.lookup_type('void').pointer() 27 | head = gdb.parse_and_eval('vpu_manager.coroutine_list.head') 28 | for ptr in linked_list(head, 'next'): 29 | if ptr['status'] == 0xDEAD: # exit 30 | continue; 31 | 32 | s = ' ' 33 | if ptr['status'] == 0xBEEF: # running 34 | s = '*' 35 | 36 | if arch.name() == 'i386:x86-64': 37 | pc = ptr['ctx']['uc_mcontext']['gregs'][16].cast(vp) 38 | elif arch.name() == 'i386': 39 | pc = ptr['ctx']['uc_mcontext']['gregs'][14].cast(vp) 40 | elif arch.name() == 'arm': 41 | pc = ptr['ctx']['uc_mcontext']['arm_pc'].cast(vp) 42 | 43 | blk = gdb.block_for_pc(int(pc)) 44 | sl = gdb.find_pc_line(int(pc)) 45 | 46 | name = ptr['name'].string() 47 | if len(name) == 0: 48 | name = "" 49 | 50 | print (s, ptr['id'], "%5s" % sts[int(ptr['status'])], \ 51 | "[%s]" % prios[int(ptr['priority'])], \ 52 | "\"%s\"" % name, blk.function, sl.symtab, sl.line) 53 | 54 | 55 | def switch_context(pc, sp, bp): 56 | frame = gdb.selected_frame() 57 | arch = frame.architecture() 58 | 59 | if arch.name() == 'i386:x86-64': 60 | gdb.parse_and_eval('$save_pc = $rip') 61 | gdb.parse_and_eval('$save_sp = $rsp') 62 | gdb.parse_and_eval('$save_bp = $rbp') 63 | gdb.parse_and_eval('$rip = 0x%x' % int(pc)) 64 | gdb.parse_and_eval('$rsp = 0x%x' % int(sp)) 65 | gdb.parse_and_eval('$rbp = 0x%x' % int(bp)) 66 | elif arch.name() == 'i386': 67 | gdb.parse_and_eval('$save_pc = $eip') 68 | gdb.parse_and_eval('$save_sp = $esp') 69 | gdb.parse_and_eval('$save_bp = $ebp') 70 | gdb.parse_and_eval('$eip = 0x%x' % int(pc)) 71 | gdb.parse_and_eval('$esp = 0x%x' % int(sp)) 72 | gdb.parse_and_eval('$ebp = 0x%x' % int(bp)) 73 | elif arch.name() == 'arm': 74 | gdb.parse_and_eval('$save_pc = $pc') 75 | gdb.parse_and_eval('$save_sp = $sp') 76 | gdb.parse_and_eval('$save_bp = $r7') 77 | gdb.parse_and_eval('$pc = 0x%x' % int(pc)) 78 | gdb.parse_and_eval('$sp = 0x%x' % int(sp)) 79 | gdb.parse_and_eval('$r7 = 0x%x' % int(bp)) 80 | 81 | 82 | # TODO : more arch .. 83 | return 84 | 85 | def resume_context(): 86 | frame = gdb.selected_frame() 87 | arch = frame.architecture() 88 | 89 | if arch.name() == 'i386:x86-64': 90 | gdb.parse_and_eval('$rip = $save_pc') 91 | gdb.parse_and_eval('$rsp = $save_sp') 92 | gdb.parse_and_eval('$rbp = $save_bp') 93 | elif arch.name() == 'i386': 94 | gdb.parse_and_eval('$eip = $save_pc') 95 | gdb.parse_and_eval('$esp = $save_sp') 96 | gdb.parse_and_eval('$ebp = $save_bp') 97 | elif arch.name() == 'arm': 98 | gdb.parse_and_eval('$pc = $save_pc') 99 | gdb.parse_and_eval('$sp = $save_sp') 100 | gdb.parse_and_eval('$r7 = $save_bp') 101 | # TODO : more arch .. 102 | return 103 | 104 | 105 | def find_vpu_thread(cid): 106 | num = int(gdb.parse_and_eval("vpu_manager.xt_index")) 107 | found = False 108 | for index in range(0, num): 109 | vpu = gdb.parse_and_eval("& vpu_manager.vpu[%d]" % index) 110 | if int(vpu['current']['id']) == cid: 111 | found = True 112 | break 113 | 114 | if not found: 115 | return None 116 | 117 | cur = gdb.selected_thread() 118 | threads = gdb.selected_inferior().threads() 119 | 120 | for thr in threads: 121 | thr.switch() 122 | if vpu == gdb.parse_and_eval('__vpu'): 123 | return thr 124 | 125 | cur.switch() 126 | return None 127 | 128 | 129 | def find_running(cid): 130 | arch = gdb.selected_frame().architecture() 131 | cur = gdb.selected_thread() 132 | thr = find_vpu_thread(cid) 133 | 134 | if not thr: 135 | return None, None, None 136 | 137 | if arch.name() == 'i386:x86-64': 138 | pc = int(gdb.parse_and_eval('$rip')) 139 | sp = int(gdb.parse_and_eval('$rsp')) 140 | bp = int(gdb.parse_and_eval('$rbp')) 141 | elif arch.name() == 'i386': 142 | pc = int(gdb.parse_and_eval('$eip')) 143 | sp = int(gdb.parse_and_eval('$esp')) 144 | bp = int(gdb.parse_and_eval('$ebp')) 145 | elif arch.name() == 'arm': 146 | pc = int(gdb.parse_and_eval('$pc')) 147 | sp = int(gdb.parse_and_eval('$sp')) 148 | bp = int(gdb.parse_and_eval('$r7')) 149 | 150 | cur.switch() 151 | return pc, sp, bp 152 | 153 | 154 | 155 | def find_coroutine(cid): 156 | arch = gdb.selected_frame().architecture() 157 | vp = gdb.lookup_type('void').pointer() 158 | head = gdb.parse_and_eval('vpu_manager.coroutine_list.head') 159 | for ptr in linked_list(head, 'next'): 160 | if ptr['status'] == 0xDEAD: 161 | continue; 162 | if ptr['id'] == cid: 163 | if ptr['status'] == 0xBEEF: 164 | return find_running(cid) 165 | if arch.name() == 'i386:x86-64': 166 | bp = ptr['ctx']['uc_mcontext']['gregs'][10].cast(vp) 167 | sp = ptr['ctx']['uc_mcontext']['gregs'][15].cast(vp) 168 | pc = ptr['ctx']['uc_mcontext']['gregs'][16].cast(vp) 169 | elif arch.name() == 'i386': 170 | bp = ptr['ctx']['uc_mcontext']['gregs'][6].cast(vp) 171 | sp = ptr['ctx']['uc_mcontext']['gregs'][7].cast(vp) 172 | pc = ptr['ctx']['uc_mcontext']['gregs'][14].cast(vp) 173 | elif arch.name() == 'arm': 174 | bp = ptr['ctx']['uc_mcontext']['arm_r7'].cast(vp) 175 | sp = ptr['ctx']['uc_mcontext']['arm_sp'].cast(vp) 176 | pc = ptr['ctx']['uc_mcontext']['arm_pc'].cast(vp) 177 | 178 | return pc, sp, bp 179 | 180 | return None, None, None 181 | 182 | 183 | class CoroutineCmd(gdb.Command): 184 | """Execute gdb command in the context of coroutine with . 185 | 186 | Switch PC and SP to the ones in the coroutine's VPU, 187 | execute an arbitrary gdb command, and restore the PC and SP. 188 | 189 | Usage: (gdb) coroutine 190 | 191 | Note that it is ill-defined to modify state in the context of a coroutine. 192 | Restrict yourself to inspecting values. 193 | """ 194 | 195 | def __init__(self): 196 | super(CoroutineCmd, self).__init__("coroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE) 197 | 198 | def invoke(self, arg, from_tty): 199 | __args = arg.split(None, 1) 200 | if len(__args) == 0: 201 | ## if no arg provided, just print current cid: 202 | vpu = gdb.parse_and_eval("__vpu") 203 | if vpu: 204 | print (vpu['current']['id']) 205 | return 206 | 207 | cid = gdb.parse_and_eval(__args[0]) 208 | if len(__args) > 1: 209 | cmd = __args[1] 210 | pc, sp, bp = find_coroutine(int(cid)) 211 | if not pc: 212 | print ("No such coroutine: ", cid) 213 | return 214 | 215 | save_frame = gdb.selected_frame() 216 | switch_context(pc, sp, bp) 217 | try: 218 | gdb.execute(cmd) 219 | finally: 220 | resume_context() 221 | save_frame.select() 222 | else: 223 | ## try to switch to this coroutine 224 | ## if it's running on another VPU 225 | thr = find_vpu_thread(cid) 226 | if not thr: 227 | print ("No such coroutine %d is running!" % int(cid)) 228 | return 229 | thr.switch() 230 | # 231 | # Register all CLI commands 232 | CoroutinesCmd() 233 | CoroutineCmd() 234 | -------------------------------------------------------------------------------- /scripts/vimrc_co/ftdetect/cofiletype.vim: -------------------------------------------------------------------------------- 1 | au BufRead,BufNewFile *.co set filetype=co 2 | -------------------------------------------------------------------------------- /scripts/vimrc_co/syntax/co.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: CoroC 3 | " Maintainer: Amal Cao (amalcaowei@gmail.com) 4 | " Last Change: 2014 Jul 18 5 | 6 | " For version 5.x: Clear all syntax items 7 | " For version 6.x: Quit when a syntax file was already loaded 8 | if version < 600 9 | syntax clear 10 | elseif exists("b:current_syntax") 11 | finish 12 | endif 13 | 14 | " Read the C syntax to start with 15 | if version < 600 16 | source :p:h/c.vim 17 | else 18 | runtime! syntax/c.vim 19 | endif 20 | 21 | " CoroC extentions 22 | syn keyword coType __task_t __chan_t __refcnt_t __coroc_time_t 23 | syn keyword coConstant __CoroC_Null 24 | 25 | syn keyword coStatement __CoroC_Spawn __CoroC_Chan 26 | syn keyword coStatement __CoroC_Yield __CoroC_Quit 27 | syn keyword coStatement __CoroC_Chan_Close __CoroC_Self __CoroC_Exit 28 | syn keyword coStatement __CoroC_Task_Send __CoroC_Task_Recv __CoroC_Task_Recv_NB 29 | syn keyword coStatement __CoroC_Set_Name __CoroC_Set_Prio 30 | syn keyword coStatement __CoroC_Timer_At __CoroC_Timer_After 31 | syn keyword coStatement __CoroC_Ticker __CoroC_Stop 32 | syn keyword coStatement __CoroC_Now __CoroC_Sleep 33 | 34 | syn keyword coType __group_t 35 | syn keyword coStatement __CoroC_Group __CoroC_Sync 36 | 37 | syn keyword coStatement __CoroC_Async_Call 38 | syn keyword coStatement __CoroC_New 39 | 40 | syn keyword coConditional __CoroC_Select 41 | syn keyword coLabel __CoroC_Case __CoroC_Default 42 | 43 | hi def link coType Type 44 | hi def link coStatement Statement 45 | hi def link coConditional Conditional 46 | hi def link coLabel Label 47 | hi def link coConstant Constant 48 | 49 | let b:current_syntax = "co" 50 | 51 | " vim: ts=8 52 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(LIBRARY_NAME coroc) 2 | 3 | ENABLE_LANGUAGE(C ASM) 4 | 5 | SET(INCLUDE_FILES ../include/inter/support.h 6 | ../include/inter/coroutine.h 7 | ../include/inter/channel.h 8 | ../include/inter/message.h 9 | ../include/inter/context.h 10 | ../include/inter/vpu.h 11 | ../include/inter/netpoll.h 12 | ../include/inter/async.h 13 | ../include/inter/refcnt.h 14 | ../include/inter/coroc_clock.h 15 | ../include/inter/coroc_lock.h 16 | ../include/inter/coroc_queue.h 17 | ../include/inter/coroc_hash.h 18 | ../include/inter/coroc_time.h 19 | ../include/inter/coroc_group.h) 20 | 21 | SET(SRC_FILES boot.c 22 | vpu.c 23 | coroutine.c 24 | context.c 25 | channel.c 26 | message.c 27 | time.c 28 | netpoll.c 29 | net.c 30 | async.c 31 | group.c 32 | clock.c 33 | coroc_main.c 34 | hash.c 35 | vfs.c) 36 | 37 | IF(APPLE) 38 | SET(SRC_FILES ${SRC_FILES} 39 | darwin/ucontext.c 40 | darwin/pthread_barrier.c 41 | darwin/asm.S) 42 | SET(INCLUDE_FILES ${INCLUDE_FILES} 43 | ../include/inter/darwin/pthread_barrier.h 44 | ../include/inter/darwin/pthread_spinlock.h 45 | ../include/inter/darwin/time_.h) 46 | 47 | IF(${ARCH} MATCHES "x86_64") 48 | SET(INCLUDE_FILES ${INCLUDE_FILES} 49 | ../include/inter/darwin/amd64-ucontext.h) 50 | ELSEIF(${ARCH} MATCHES "x86") 51 | SET(INCLUDE_FILES ${INCLUDE_FILES} 52 | ../include/inter/darwin/386-ucontext.h) 53 | ELSE() 54 | SET(INCLUDE_FILES ${INCLUDE_FILES} 55 | ../include/inter/darwin/power-ucontext.h) 56 | ENDIF() 57 | ENDIF(APPLE) 58 | 59 | IF(CMAKE_SYSTEM MATCHES "Linux") 60 | SET(SRC_FILES ${SRC_FILES} 61 | netpoll_epoll.c 62 | futex_impl.c) 63 | 64 | IF(ENABLE_NOTIFY) 65 | SET(SRC_FILES ${SRC_FILES} notify.c) 66 | ENDIF(ENABLE_NOTIFY) 67 | 68 | IF(ENABLE_FUTEX) 69 | SET(SRC_FILES ${SRC_FILES} futex_lock.c) 70 | ENDIF(ENABLE_FUTEX) 71 | 72 | ELSE() 73 | IF(APPLE) 74 | SET(SRC_FILES ${SRC_FILES} netpoll_kqueue.c) 75 | ELSE() 76 | SET(SRC_FILES ${SRC_FILES} netpoll_poll.c) 77 | ENDIF(APPLE) 78 | ENDIF() 79 | 80 | ADD_LIBRARY( 81 | ${LIBRARY_NAME} 82 | STATIC 83 | ${SRC_FILES} 84 | ${INCLUDE_FILES} 85 | ) 86 | 87 | INSTALL_TARGETS(/lib ${LIBRARY_NAME}) 88 | -------------------------------------------------------------------------------- /src/async.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | 8 | #include "async.h" 9 | #include "vpu.h" 10 | #include "netpoll.h" 11 | 12 | // the asynchronized thread pool manager .. 13 | struct { 14 | pthread_mutex_t mutex; 15 | pthread_cond_t cond; 16 | queue_t wait_que; 17 | TSC_OS_THREAD_T *threads; 18 | } coroc_async_pool_manager; 19 | 20 | // this is the `core' part ! 21 | TSC_SIGNAL_MASK_DECLARE 22 | 23 | // the routine loop of each `async thread' 24 | static void *coroc_async_thread_routine(void *unused) { 25 | pthread_mutex_lock(&coroc_async_pool_manager.mutex); 26 | for (;;) { 27 | while (coroc_async_pool_manager.wait_que.status == 0) { 28 | // prepare to waitting for next job or timeout .. 29 | pthread_cond_wait(&coroc_async_pool_manager.cond, 30 | &coroc_async_pool_manager.mutex); 31 | } 32 | // get a request from the waiting queue 33 | coroc_async_request_t *req = queue_rem(&coroc_async_pool_manager.wait_que); 34 | assert(req != 0); 35 | 36 | pthread_mutex_unlock(&coroc_async_pool_manager.mutex); 37 | 38 | // do the work of this request, 39 | // NOTE that the call will block current thread .. 40 | req->func(req->argument); 41 | 42 | // after the callback done, add the wait coroutine 43 | // to the ready queue.. 44 | vpu_ready(req->wait, false); 45 | 46 | pthread_mutex_lock(&coroc_async_pool_manager.mutex); 47 | } 48 | // never return here maybe .. 49 | pthread_exit(0); 50 | } 51 | 52 | // initialize the asynchronize threads' pool with 53 | // `n' threads, n must be a positive number !! 54 | void coroc_async_pool_initialize(int n) { 55 | // NOTE that the async thread number must not be less than 1! 56 | // assert(n > 0); 57 | 58 | int i; 59 | 60 | // init the async thread pool manager .. 61 | pthread_mutex_init(&coroc_async_pool_manager.mutex, NULL); 62 | 63 | if (n == 0) { // ignore the async threads pool 64 | coroc_async_pool_manager.threads = NULL; 65 | return ; 66 | } 67 | 68 | pthread_cond_init(&coroc_async_pool_manager.cond, NULL); 69 | // the wait queue will be protected by the manager's mutex! 70 | queue_init(&coroc_async_pool_manager.wait_que); 71 | // alloc the thread pool .. 72 | coroc_async_pool_manager.threads = TSC_ALLOC(n * sizeof(TSC_OS_THREAD_T)); 73 | 74 | // start n asynchronize working threads .. 75 | for (i = 0; i < n; ++i) { 76 | TSC_OS_THREAD_CREATE(&coroc_async_pool_manager.threads[i], NULL, 77 | coroc_async_thread_routine, (void *)(coroc_word_t)i); 78 | } 79 | 80 | return; 81 | } 82 | 83 | // init and submit the async request, 84 | // NOTE the req must be allocated on the calling stack 85 | // of the current coroutine !! 86 | void coroc_async_request_submit(coroc_async_callback_t func, void *argument) { 87 | coroc_async_request_t req; 88 | 89 | TSC_SIGNAL_MASK(); 90 | 91 | if (coroc_async_pool_manager.threads == NULL) { 92 | func(argument); 93 | } else { 94 | // init .. 95 | req.wait = coroc_coroutine_self(); 96 | req.func = func; 97 | req.argument = argument; 98 | queue_item_init(&req.link, &req); 99 | 100 | // submit this request to the async pool .. 101 | pthread_mutex_lock(&coroc_async_pool_manager.mutex); 102 | 103 | // add req to the wait queue 104 | queue_add(&coroc_async_pool_manager.wait_que, &req.link); 105 | 106 | pthread_cond_signal(&coroc_async_pool_manager.cond); 107 | 108 | // suspend current coroutine and release the mutex .. 109 | req.wait->async_wait = 1; 110 | vpu_suspend(&coroc_async_pool_manager.mutex, 111 | (unlock_handler_t)pthread_mutex_unlock); 112 | } 113 | 114 | // return from the block func .. 115 | TSC_SIGNAL_UNMASK(); 116 | return; 117 | } 118 | -------------------------------------------------------------------------------- /src/boot.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "vpu.h" 12 | #include "coroutine.h" 13 | #include "coroc_clock.h" 14 | 15 | extern void coroc_vpu_initialize(int, coroc_coroutine_handler_t); 16 | extern void coroc_clock_initialize(void); 17 | extern void coroc_intertimer_initialize(void); 18 | extern void coroc_async_pool_initialize(int); 19 | extern void coroc_netpoll_initialize(void); 20 | extern void coroc_profiler_initialize(int); 21 | 22 | int __argc; 23 | char **__argv; 24 | 25 | static bool __coroc_env2int(const char *env, int *ret) { 26 | const char *value = getenv(env); 27 | char *endp = NULL; 28 | 29 | if (value == NULL) return false; 30 | 31 | errno = 0; 32 | *ret = strtol(value, &endp, 0); 33 | return (errno == 0); 34 | } 35 | 36 | int coroc_boot(int argc, char **argv, int np, int nasync, 37 | coroc_coroutine_handler_t entry) { 38 | int profile = 0; 39 | 40 | __argc = argc; 41 | __argv = argv; 42 | 43 | if (np <= 0) { 44 | __coroc_env2int("TSC_NP", &np); 45 | if (np <= 0) np = TSC_NP_ONLINE(); 46 | } 47 | 48 | if (nasync <= 0 && !__coroc_env2int("TSC_ASYNC", &nasync)) { 49 | nasync = (np > 1) ? (np >> 1) : 1; 50 | } 51 | 52 | __coroc_env2int("TSC_PROFILE", &profile); 53 | 54 | coroc_clock_initialize(); 55 | coroc_intertimer_initialize(); 56 | coroc_netpoll_initialize(); 57 | coroc_async_pool_initialize(nasync); 58 | coroc_vpu_initialize(np, entry); 59 | coroc_profiler_initialize(profile); 60 | // TODO : more modules later .. -- 61 | 62 | clock_routine(); // never return .. 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /src/clock.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include "vpu.h" 9 | #include "coroc_clock.h" 10 | 11 | #define TSC_CLOCK_PERIOD_NANOSEC 500000 // 0.5 ms per signal 12 | 13 | extern bool __coroc_netpoll_polling(bool); 14 | 15 | clock_manager_t clock_manager; 16 | 17 | void coroc_clock_initialize(void) { 18 | #ifdef ENABLE_TIMESHARE 19 | struct sigaction act; 20 | 21 | sigaddset(&act.sa_mask, TSC_CLOCK_SIGNAL); 22 | 23 | act.sa_handler = vpu_clock_handler; 24 | act.sa_flags = SA_RESTART; 25 | 26 | sigaction(TSC_CLOCK_SIGNAL, &act, NULL); 27 | #endif 28 | } 29 | 30 | #define AVG(avg, cur, samples) \ 31 | ((avg) * (double)(samples) + (double)(cur)) / ((double)(samples) + 1.0); 32 | 33 | double avg_alive = 0; 34 | double avg_idle = 0; 35 | double avg_ready = 0; 36 | double avg_total = 0; 37 | double *avg_ready_pervpu; 38 | 39 | static bool do_profile = false; 40 | 41 | static uint32_t __coroc_get_vpu_ready(vpu_t *vpu) { 42 | uint64_t ready = 0; 43 | int prio; 44 | for (prio = 0; prio < TSC_PRIO_NUM; ++prio) { 45 | p_task_que *pq = & vpu->xt[prio]; 46 | if (pq->runqtail > pq->runqhead) 47 | ready += (pq->runqtail - pq->runqhead); 48 | } 49 | return ready; 50 | } 51 | 52 | void coroc_profiler_print(int ret, void *p) { 53 | printf("\n\nThe average alive vpu number is %f\n", avg_alive); 54 | printf("The average idle vpu number is %f\n", avg_idle); 55 | printf("The average total tasks number is %f\n", avg_total); 56 | printf("The average total ready tasks number is %f\n", avg_ready); 57 | int i; 58 | for (i = 0; i < vpu_manager.xt_index; ++i) { 59 | printf("\tThe vpu %d avg ready tasks is %f\n", i, avg_ready_pervpu[i]); 60 | } 61 | 62 | //----------------------------------------- 63 | printf("\nThe current alive vpu number is %d\n", vpu_manager.alive); 64 | printf("The current idle vpu number is %d\n", vpu_manager.idle); 65 | printf("The current total tasks number is %d\n", vpu_manager.coroutine_list.status); 66 | printf("The current total ready tasks number is %d\n", vpu_manager.total_ready); 67 | for (i = 0; i < vpu_manager.xt_index; ++i) { 68 | printf("\tThe vpu %d cur ready tasks is %d\n", i, 69 | __coroc_get_vpu_ready(& vpu_manager.vpu[i])); 70 | } 71 | 72 | } 73 | 74 | 75 | 76 | void coroc_profiler_handler(int signum) { 77 | exit(-1); 78 | } 79 | 80 | void coroc_profiler_initialize(int p) { 81 | 82 | do_profile = (p != 0); 83 | 84 | if (do_profile) { 85 | #ifdef __APPLE__ 86 | atexit(coroc_profiler_print); 87 | #else 88 | on_exit(coroc_profiler_print, NULL); 89 | #endif 90 | 91 | signal(SIGINT, coroc_profiler_handler); 92 | signal(SIGPIPE, SIG_IGN); 93 | } 94 | } 95 | 96 | void clock_routine(void) { 97 | sigset_t sigmask; 98 | sigfillset(&sigmask); 99 | 100 | uint64_t samples = 0; 101 | 102 | avg_ready_pervpu = calloc(sizeof(double), vpu_manager.xt_index); 103 | 104 | for ( ;; samples++) { 105 | struct timespec period = {0, TSC_CLOCK_PERIOD_NANOSEC}; 106 | pselect(0, NULL, NULL, NULL, &period, &sigmask); 107 | 108 | int index = 0; 109 | #ifdef ENABLE_TIMESHARE 110 | for (; index < vpu_manager.xt_index; ++index) { 111 | TSC_OS_THREAD_SENDSIG(vpu_manager.vpu[index].os_thr, TSC_CLOCK_SIGNAL); 112 | } 113 | __coroc_netpoll_polling(0); 114 | #endif // ENABLE_TIMESHARE 115 | 116 | if (!do_profile) continue; 117 | 118 | // try to profiling the current system 119 | uint64_t cur = TSC_ATOMIC_READ(vpu_manager.total_ready); 120 | avg_ready = AVG(avg_ready, cur, samples); 121 | 122 | cur = vpu_manager.coroutine_list.status; 123 | avg_total = AVG(avg_total, cur, samples); 124 | 125 | cur = TSC_ATOMIC_READ(vpu_manager.alive); 126 | avg_alive = AVG(avg_alive, cur, samples); 127 | 128 | cur = TSC_ATOMIC_READ(vpu_manager.idle); 129 | avg_idle = AVG(avg_idle, cur, samples); 130 | 131 | for (index = 0; index < vpu_manager.xt_index; ++index) { 132 | cur = __coroc_get_vpu_ready(& vpu_manager.vpu[index]); 133 | avg_ready_pervpu[index] = 134 | AVG(avg_ready_pervpu[index], cur, samples); 135 | } 136 | 137 | if (samples % 2000 == 0) 138 | coroc_profiler_print(0, NULL); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/context.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "support.h" 10 | #include "context.h" 11 | #include "coroutine.h" 12 | 13 | extern int __argc; 14 | extern char** __argv; 15 | 16 | typedef int (*main_entry_t)(int, char**); 17 | typedef void (*boot_entry_t)(); 18 | 19 | static void bootstrap(uint32_t low, uint32_t high) { 20 | coroc_word_t tmp = high << 16; 21 | tmp <<= 16; 22 | tmp |= low; 23 | 24 | coroc_coroutine_t coroutine = (coroc_coroutine_t)tmp; 25 | if (coroutine->type == TSC_COROUTINE_MAIN) 26 | ((main_entry_t)(coroutine->entry))(__argc, __argv); 27 | else 28 | coroutine->entry(coroutine->arguments); 29 | coroc_coroutine_exit(0); 30 | } 31 | 32 | void TSC_CONTEXT_INIT(TSC_CONTEXT* ctx, void* stack, size_t stack_sz, 33 | void* coroutine) { 34 | uint32_t low, high; 35 | uint64_t tmp = (coroc_word_t)(coroutine); 36 | sigset_t mask; 37 | 38 | low = tmp; 39 | tmp >>= 16; 40 | high = tmp >> 16; 41 | 42 | sigemptyset(&mask); 43 | 44 | memset(ctx, 0, sizeof(TSC_CONTEXT)); 45 | TSC_CONTEXT_SAVE(ctx); 46 | 47 | #ifdef ENABLE_SPLITSTACK 48 | (ctx->ctx).uc_stack.ss_sp = stack; 49 | (ctx->ctx).uc_stack.ss_size = stack_sz; 50 | (ctx->ctx).uc_sigmask = mask; 51 | #else 52 | ctx->uc_stack.ss_sp = stack; 53 | ctx->uc_stack.ss_size = stack_sz; 54 | ctx->uc_sigmask = mask; 55 | #endif 56 | 57 | TSC_CONTEXT_MAKE(ctx, (boot_entry_t)bootstrap, 2, low, high); 58 | } 59 | -------------------------------------------------------------------------------- /src/coroc_main.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | 7 | #include "coroutine.h" 8 | 9 | extern int user_main(void *); 10 | extern int coroc_boot(int, char **, int, int, coroc_coroutine_handler_t); 11 | 12 | #ifdef __APPLE__ 13 | #define __coroc_main main // FIXME: weak alias not support by clang!! 14 | #else 15 | extern int main(int, char **) __attribute__((weak, alias("__coroc_main"))); 16 | #endif 17 | 18 | int __coroc_main(int argc, char **argv) { 19 | return coroc_boot(argc, argv, 0, -1, (coroc_coroutine_handler_t)user_main); 20 | } 21 | -------------------------------------------------------------------------------- /src/coroutine.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "coroutine.h" 12 | #include "vpu.h" 13 | #include "coroc_group.h" 14 | 15 | #if defined(ENABLE_SPLITSTACK) // && defined(LINKER_SUPPORTS_SPLIT_STACK) 16 | #define TSC_DEFAULT_STACK_SIZE PTHREAD_STACK_MIN 17 | #else 18 | #ifdef __APPLE__ 19 | #define TSC_DEFAULT_STACK_SIZE (2 * 1024 * 1024) // 2MB 20 | #else 21 | #define TSC_DEFAULT_STACK_SIZE (1 * 1024 * 1024) // 1MB 22 | #endif 23 | #endif 24 | 25 | #define TSC_BACKTRACE_LEVEL 20 26 | 27 | #define TSC_DEFAULT_AFFINITY (vpu_manager.xt_index) 28 | #define TSC_DEFAULT_TIMESLICE 5 29 | #define TSC_DEFAULT_DETACHSTATE TSC_COROUTINE_UNDETACH 30 | 31 | TSC_TLS_DECLARE 32 | TSC_SIGNAL_MASK_DECLARE 33 | 34 | void coroc_coroutine_attr_init(coroc_coroutine_attributes_t *attr) { 35 | attr->stack_size = TSC_DEFAULT_STACK_SIZE; 36 | attr->timeslice = TSC_DEFAULT_TIMESLICE; 37 | attr->affinity = TSC_DEFAULT_AFFINITY; 38 | } 39 | 40 | coroc_coroutine_t coroc_coroutine_allocate(coroc_coroutine_handler_t entry, 41 | void *arguments, const char *name, 42 | uint32_t type, unsigned priority, 43 | coroc_coroutine_cleanup_t cleanup) { 44 | assert(priority < TSC_PRIO_NUM); 45 | 46 | TSC_SIGNAL_MASK(); 47 | 48 | size_t size; 49 | vpu_t *vpu = TSC_TLS_GET(); 50 | coroc_coroutine_t coroutine = TSC_ALLOC(sizeof(struct coroc_coroutine)); 51 | memset(coroutine, 0, sizeof(struct coroc_coroutine)); 52 | memset(&coroutine->ctx, 0, sizeof(TSC_CONTEXT)); 53 | 54 | if (coroutine != NULL) { 55 | // init the interal channel .. 56 | coroc_async_chan_init((coroc_async_chan_t)coroutine); 57 | 58 | strcpy(coroutine->name, name); 59 | coroutine->type = type; 60 | coroutine->status = TSC_COROUTINE_WAIT; 61 | coroutine->async_wait = 0; 62 | coroutine->id = TSC_ALLOC_TID(); 63 | coroutine->entry = entry; 64 | coroutine->arguments = arguments; 65 | coroutine->cleanup = cleanup; 66 | coroutine->syscall = false; 67 | coroutine->sigmask_nest = 0; 68 | 69 | if (type == TSC_COROUTINE_IDLE) { 70 | coroutine->stack_size = 0; 71 | coroutine->priority = TSC_PRIO_NUM; // lower than default 72 | } else { 73 | coroutine->stack_size = TSC_DEFAULT_STACK_SIZE; 74 | coroutine->priority = priority < TSC_PRIO_NUM ? 75 | priority : TSC_PRIO_LOW; 76 | } 77 | 78 | coroutine->vpu_affinity = TSC_DEFAULT_AFFINITY; 79 | coroutine->init_timeslice = TSC_DEFAULT_TIMESLICE; 80 | 81 | if (coroutine->stack_size > 0) { 82 | #ifdef ENABLE_SPLITSTACK 83 | coroutine->stack_base = 84 | TSC_STACK_CONTEXT_MAKE(coroutine->stack_size, &coroutine->ctx, &size); 85 | #else 86 | size = coroutine->stack_size; 87 | coroutine->stack_base = TSC_ALLOC(coroutine->stack_size); 88 | #endif 89 | assert(coroutine->stack_base != NULL); 90 | } 91 | coroutine->rem_timeslice = coroutine->init_timeslice; 92 | 93 | queue_item_init(&coroutine->status_link, coroutine); 94 | queue_item_init(&coroutine->trace_link, coroutine); 95 | } 96 | 97 | if (coroutine->type != TSC_COROUTINE_IDLE) { 98 | TSC_CONTEXT_INIT(&coroutine->ctx, coroutine->stack_base, size, coroutine); 99 | atomic_queue_add(&vpu_manager.coroutine_list, &coroutine->trace_link); 100 | 101 | if (coroutine->type == TSC_COROUTINE_MAIN) { 102 | vpu_manager.main = coroutine; 103 | } 104 | 105 | // add the `main' task into global runq: 106 | vpu_ready(coroutine, true); 107 | } 108 | TSC_SIGNAL_UNMASK(); 109 | return coroutine; 110 | } 111 | 112 | void coroc_coroutine_deallocate(coroc_coroutine_t coroutine) { 113 | assert(coroutine->status == TSC_COROUTINE_RUNNING); 114 | // TODO : reclaim the coroutine elements .. 115 | coroutine->status = TSC_COROUTINE_EXIT; 116 | atomic_queue_extract(&vpu_manager.coroutine_list, &coroutine->trace_link); 117 | 118 | #ifdef ENABLE_SPLITSTACK 119 | __splitstack_releasecontext(&coroutine->ctx.stack_ctx[0]); 120 | #else 121 | if (coroutine->stack_size > 0) { 122 | TSC_DEALLOC(coroutine->stack_base); 123 | coroutine->stack_base = 0; 124 | } 125 | #endif 126 | 127 | coroc_async_chan_fini((coroc_async_chan_t)coroutine); 128 | coroc_refcnt_put((coroc_refcnt_t)coroutine); 129 | // TSC_DEALLOC(coroutine); 130 | } 131 | 132 | void coroc_coroutine_exit(int value) { 133 | TSC_SIGNAL_MASK(); 134 | 135 | // call notify API before quit, 136 | // if current task belongs to a group!! 137 | vpu_t *vpu = TSC_TLS_GET(); 138 | coroc_coroutine_t self = vpu->current; 139 | 140 | assert(self && (self->status == TSC_COROUTINE_RUNNING)); 141 | 142 | if (self && self->cleanup) 143 | self->cleanup(self->arguments, value); 144 | 145 | vpu_syscall(core_exit); 146 | TSC_SIGNAL_UNMASK(); 147 | } 148 | 149 | void coroc_coroutine_yield(void) { 150 | TSC_SIGNAL_MASK(); 151 | vpu_syscall(core_yield); 152 | TSC_SIGNAL_UNMASK(); 153 | } 154 | 155 | coroc_coroutine_t coroc_coroutine_self(void) { 156 | coroc_coroutine_t self = NULL; 157 | TSC_SIGNAL_MASK(); 158 | vpu_t *vpu = TSC_TLS_GET(); 159 | 160 | self = (vpu != NULL) ? vpu->current : NULL; 161 | TSC_SIGNAL_UNMASK(); 162 | 163 | return self; 164 | } 165 | 166 | void coroc_coroutine_backtrace(coroc_coroutine_t self) { 167 | int level; 168 | void *buffer[TSC_BACKTRACE_LEVEL]; 169 | 170 | TSC_SIGNAL_MASK(); 171 | 172 | fprintf(stderr, "The \"%s\"<#%d> coroutine's stack trace:\n", self->name, 173 | self->id); 174 | 175 | level = backtrace(buffer, TSC_BACKTRACE_LEVEL); 176 | backtrace_symbols_fd(buffer, level, STDERR_FILENO); 177 | 178 | fprintf(stderr, "\n"); 179 | 180 | vpu_syscall(core_exit); 181 | TSC_SIGNAL_UNMASK(); 182 | } 183 | 184 | -------------------------------------------------------------------------------- /src/darwin/asm.S: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | /* Copyright (c) 2005-2006 Russ Cox, MIT; see COPYRIGHT */ 6 | 7 | #if defined(__FreeBSD__) && defined(__i386__) && __FreeBSD__ < 5 8 | #define NEEDX86CONTEXT 1 9 | #define SET setmcontext 10 | #define GET getmcontext 11 | #endif 12 | 13 | #if defined(__OpenBSD__) && defined(__i386__) 14 | #define NEEDX86CONTEXT 1 15 | #define SET setmcontext 16 | #define GET getmcontext 17 | #endif 18 | 19 | #if defined(__APPLE__) 20 | #if defined(__i386__) 21 | #define NEEDX86CONTEXT 1 22 | #define SET _setmcontext 23 | #define GET _getmcontext 24 | #elif defined(__x86_64__) 25 | #define NEEDAMD64CONTEXT 1 26 | #define SET _setmcontext 27 | #define GET _getmcontext 28 | #else 29 | #define NEEDPOWERCONTEXT 1 30 | #define SET __setmcontext 31 | #define GET __getmcontext 32 | #endif 33 | #endif 34 | 35 | #if defined(__linux__) && defined(__arm__) 36 | #define NEEDARMCONTEXT 1 37 | #define SET setmcontext 38 | #define GET getmcontext 39 | #endif 40 | 41 | #if defined(__linux__) && defined(__mips__) 42 | #define NEEDMIPSCONTEXT 1 43 | #define SET setmcontext 44 | #define GET getmcontext 45 | #endif 46 | 47 | #ifdef NEEDX86CONTEXT 48 | .globl SET 49 | SET: 50 | movl 4(%esp), %eax 51 | 52 | movl 8(%eax), %fs 53 | movl 12(%eax), %es 54 | movl 16(%eax), %ds 55 | movl 76(%eax), %ss 56 | movl 20(%eax), %edi 57 | movl 24(%eax), %esi 58 | movl 28(%eax), %ebp 59 | movl 36(%eax), %ebx 60 | movl 40(%eax), %edx 61 | movl 44(%eax), %ecx 62 | 63 | movl 72(%eax), %esp 64 | pushl 60(%eax) /* new %eip */ 65 | movl 48(%eax), %eax 66 | ret 67 | 68 | .globl GET 69 | GET: 70 | movl 4(%esp), %eax 71 | 72 | movl %fs, 8(%eax) 73 | movl %es, 12(%eax) 74 | movl %ds, 16(%eax) 75 | movl %ss, 76(%eax) 76 | movl %edi, 20(%eax) 77 | movl %esi, 24(%eax) 78 | movl %ebp, 28(%eax) 79 | movl %ebx, 36(%eax) 80 | movl %edx, 40(%eax) 81 | movl %ecx, 44(%eax) 82 | 83 | movl $1, 48(%eax) /* %eax */ 84 | movl (%esp), %ecx /* %eip */ 85 | movl %ecx, 60(%eax) 86 | leal 4(%esp), %ecx /* %esp */ 87 | movl %ecx, 72(%eax) 88 | 89 | movl 44(%eax), %ecx /* restore %ecx */ 90 | movl $0, %eax 91 | ret 92 | #endif 93 | 94 | #ifdef NEEDAMD64CONTEXT 95 | .globl SET 96 | SET: 97 | movq 16(%rdi), %rsi 98 | movq 24(%rdi), %rdx 99 | movq 32(%rdi), %rcx 100 | movq 40(%rdi), %r8 101 | movq 48(%rdi), %r9 102 | movq 56(%rdi), %rax 103 | movq 64(%rdi), %rbx 104 | movq 72(%rdi), %rbp 105 | movq 80(%rdi), %r10 106 | movq 88(%rdi), %r11 107 | movq 96(%rdi), %r12 108 | movq 104(%rdi), %r13 109 | movq 112(%rdi), %r14 110 | movq 120(%rdi), %r15 111 | movq 184(%rdi), %rsp 112 | pushq 160(%rdi) /* new %eip */ 113 | movq 8(%rdi), %rdi 114 | ret 115 | 116 | .globl GET 117 | GET: 118 | movq %rdi, 8(%rdi) 119 | movq %rsi, 16(%rdi) 120 | movq %rdx, 24(%rdi) 121 | movq %rcx, 32(%rdi) 122 | movq %r8, 40(%rdi) 123 | movq %r9, 48(%rdi) 124 | movq $1, 56(%rdi) /* %rax */ 125 | movq %rbx, 64(%rdi) 126 | movq %rbp, 72(%rdi) 127 | movq %r10, 80(%rdi) 128 | movq %r11, 88(%rdi) 129 | movq %r12, 96(%rdi) 130 | movq %r13, 104(%rdi) 131 | movq %r14, 112(%rdi) 132 | movq %r15, 120(%rdi) 133 | 134 | movq (%rsp), %rcx /* %rip */ 135 | movq %rcx, 160(%rdi) 136 | leaq 8(%rsp), %rcx /* %rsp */ 137 | movq %rcx, 184(%rdi) 138 | 139 | movq 32(%rdi), %rcx /* restore %rcx */ 140 | movq $0, %rax 141 | ret 142 | #endif 143 | 144 | #ifdef NEEDPOWERCONTEXT 145 | /* get FPR and VR use flags with sc 0x7FF3 */ 146 | /* get vsave with mfspr reg, 256 */ 147 | 148 | .text 149 | .align 2 150 | 151 | .globl GET 152 | GET: /* xxx: instruction scheduling */ 153 | mflr r0 154 | mfcr r5 155 | mfctr r6 156 | mfxer r7 157 | stw r0, 0*4(r3) 158 | stw r5, 1*4(r3) 159 | stw r6, 2*4(r3) 160 | stw r7, 3*4(r3) 161 | 162 | stw r1, 4*4(r3) 163 | stw r2, 5*4(r3) 164 | li r5, 1 /* return value for setmcontext */ 165 | stw r5, 6*4(r3) 166 | 167 | stw r13, (0+7)*4(r3) /* callee-save GPRs */ 168 | stw r14, (1+7)*4(r3) /* xxx: block move */ 169 | stw r15, (2+7)*4(r3) 170 | stw r16, (3+7)*4(r3) 171 | stw r17, (4+7)*4(r3) 172 | stw r18, (5+7)*4(r3) 173 | stw r19, (6+7)*4(r3) 174 | stw r20, (7+7)*4(r3) 175 | stw r21, (8+7)*4(r3) 176 | stw r22, (9+7)*4(r3) 177 | stw r23, (10+7)*4(r3) 178 | stw r24, (11+7)*4(r3) 179 | stw r25, (12+7)*4(r3) 180 | stw r26, (13+7)*4(r3) 181 | stw r27, (14+7)*4(r3) 182 | stw r28, (15+7)*4(r3) 183 | stw r29, (16+7)*4(r3) 184 | stw r30, (17+7)*4(r3) 185 | stw r31, (18+7)*4(r3) 186 | 187 | li r3, 0 /* return */ 188 | blr 189 | 190 | .globl SET 191 | SET: 192 | lwz r13, (0+7)*4(r3) /* callee-save GPRs */ 193 | lwz r14, (1+7)*4(r3) /* xxx: block move */ 194 | lwz r15, (2+7)*4(r3) 195 | lwz r16, (3+7)*4(r3) 196 | lwz r17, (4+7)*4(r3) 197 | lwz r18, (5+7)*4(r3) 198 | lwz r19, (6+7)*4(r3) 199 | lwz r20, (7+7)*4(r3) 200 | lwz r21, (8+7)*4(r3) 201 | lwz r22, (9+7)*4(r3) 202 | lwz r23, (10+7)*4(r3) 203 | lwz r24, (11+7)*4(r3) 204 | lwz r25, (12+7)*4(r3) 205 | lwz r26, (13+7)*4(r3) 206 | lwz r27, (14+7)*4(r3) 207 | lwz r28, (15+7)*4(r3) 208 | lwz r29, (16+7)*4(r3) 209 | lwz r30, (17+7)*4(r3) 210 | lwz r31, (18+7)*4(r3) 211 | 212 | lwz r1, 4*4(r3) 213 | lwz r2, 5*4(r3) 214 | 215 | lwz r0, 0*4(r3) 216 | mtlr r0 217 | lwz r0, 1*4(r3) 218 | mtcr r0 /* mtcrf 0xFF, r0 */ 219 | lwz r0, 2*4(r3) 220 | mtctr r0 221 | lwz r0, 3*4(r3) 222 | mtxer r0 223 | 224 | lwz r3, 6*4(r3) 225 | blr 226 | #endif 227 | 228 | #ifdef NEEDARMCONTEXT 229 | .globl GET 230 | GET: 231 | str r1, [r0,#4] 232 | str r2, [r0,#8] 233 | str r3, [r0,#12] 234 | str r4, [r0,#16] 235 | str r5, [r0,#20] 236 | str r6, [r0,#24] 237 | str r7, [r0,#28] 238 | str r8, [r0,#32] 239 | str r9, [r0,#36] 240 | str r10, [r0,#40] 241 | str r11, [r0,#44] 242 | str r12, [r0,#48] 243 | str r13, [r0,#52] 244 | str r14, [r0,#56] 245 | /* store 1 as r0-to-restore */ 246 | mov r1, #1 247 | str r1, [r0] 248 | /* return 0 */ 249 | mov r0, #0 250 | mov pc, lr 251 | 252 | .globl SET 253 | SET: 254 | ldr r1, [r0,#4] 255 | ldr r2, [r0,#8] 256 | ldr r3, [r0,#12] 257 | ldr r4, [r0,#16] 258 | ldr r5, [r0,#20] 259 | ldr r6, [r0,#24] 260 | ldr r7, [r0,#28] 261 | ldr r8, [r0,#32] 262 | ldr r9, [r0,#36] 263 | ldr r10, [r0,#40] 264 | ldr r11, [r0,#44] 265 | ldr r12, [r0,#48] 266 | ldr r13, [r0,#52] 267 | ldr r14, [r0,#56] 268 | ldr r0, [r0] 269 | mov pc, lr 270 | #endif 271 | 272 | #ifdef NEEDMIPSCONTEXT 273 | .globl GET 274 | GET: 275 | sw $4, 24($4) 276 | sw $5, 28($4) 277 | sw $6, 32($4) 278 | sw $7, 36($4) 279 | 280 | sw $16, 72($4) 281 | sw $17, 76($4) 282 | sw $18, 80($4) 283 | sw $19, 84($4) 284 | sw $20, 88($4) 285 | sw $21, 92($4) 286 | sw $22, 96($4) 287 | sw $23, 100($4) 288 | 289 | sw $28, 120($4) /* gp */ 290 | sw $29, 124($4) /* sp */ 291 | sw $30, 128($4) /* fp */ 292 | sw $31, 132($4) /* ra */ 293 | 294 | xor $2, $2, $2 295 | j $31 296 | nop 297 | 298 | .globl SET 299 | SET: 300 | lw $16, 72($4) 301 | lw $17, 76($4) 302 | lw $18, 80($4) 303 | lw $19, 84($4) 304 | lw $20, 88($4) 305 | lw $21, 92($4) 306 | lw $22, 96($4) 307 | lw $23, 100($4) 308 | 309 | lw $28, 120($4) /* gp */ 310 | lw $29, 124($4) /* sp */ 311 | lw $30, 128($4) /* fp */ 312 | 313 | /* 314 | * If we set $31 directly and j $31, 315 | * we would loose the outer return address. 316 | * Use a temporary register, then. 317 | */ 318 | lw $8, 132($4) /* ra */ 319 | 320 | /* bug: not setting the pc causes a bus error */ 321 | lw $25, 132($4) /* pc */ 322 | 323 | lw $5, 28($4) 324 | lw $6, 32($4) 325 | lw $7, 36($4) 326 | lw $4, 24($4) 327 | 328 | j $8 329 | nop 330 | #endif 331 | -------------------------------------------------------------------------------- /src/darwin/pthread_barrier.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | /* - - - - 6 | * The POSIX Thread barrier implementation for Darwin OS.. 7 | * - - - - */ 8 | 9 | #include 10 | #include 11 | #include "darwin/pthread_barrier.h" 12 | 13 | int pthread_barrier_init(pthread_barrier_t *barrier, 14 | const pthread_barrierattr_t *attr, 15 | unsigned int count) { 16 | if (count == 0) { 17 | errno = EINVAL; 18 | return -1; 19 | } 20 | if (pthread_mutex_init(&barrier->mutex, 0) < 0) { 21 | return -1; 22 | } 23 | if (pthread_cond_init(&barrier->cond, 0) < 0) { 24 | pthread_mutex_destroy(&barrier->mutex); 25 | return -1; 26 | } 27 | barrier->tripCount = count; 28 | barrier->count = 0; 29 | 30 | return 0; 31 | } 32 | 33 | int pthread_barrier_destroy(pthread_barrier_t *barrier) { 34 | pthread_cond_destroy(&barrier->cond); 35 | pthread_mutex_destroy(&barrier->mutex); 36 | return 0; 37 | } 38 | 39 | int pthread_barrier_wait(pthread_barrier_t *barrier) { 40 | pthread_mutex_lock(&barrier->mutex); 41 | ++(barrier->count); 42 | if (barrier->count >= barrier->tripCount) { 43 | barrier->count = 0; 44 | pthread_cond_broadcast(&barrier->cond); 45 | pthread_mutex_unlock(&barrier->mutex); 46 | return 1; 47 | } else { 48 | pthread_cond_wait(&barrier->cond, &(barrier->mutex)); 49 | pthread_mutex_unlock(&barrier->mutex); 50 | return 0; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/darwin/ucontext.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | /* Copyright (c) 2005-2006 Russ Cox, MIT; see COPYRIGHT */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "context.h" 12 | 13 | #if defined(__APPLE__) 14 | #if defined(__i386__) 15 | #define NEEDX86MAKECONTEXT 16 | #define NEEDSWAPCONTEXT 17 | #elif defined(__x86_64__) 18 | #define NEEDAMD64MAKECONTEXT 19 | #define NEEDSWAPCONTEXT 20 | #else 21 | #define NEEDPOWERMAKECONTEXT 22 | #define NEEDSWAPCONTEXT 23 | #endif 24 | #endif 25 | 26 | #if defined(__FreeBSD__) && defined(__i386__) && __FreeBSD__ < 5 27 | #define NEEDX86MAKECONTEXT 28 | #define NEEDSWAPCONTEXT 29 | #endif 30 | 31 | #if defined(__OpenBSD__) && defined(__i386__) 32 | #define NEEDX86MAKECONTEXT 33 | #define NEEDSWAPCONTEXT 34 | #endif 35 | 36 | #if defined(__linux__) && defined(__arm__) 37 | #define NEEDSWAPCONTEXT 38 | #define NEEDARMMAKECONTEXT 39 | #endif 40 | 41 | #if defined(__linux__) && defined(__mips__) 42 | #define NEEDSWAPCONTEXT 43 | #define NEEDMIPSMAKECONTEXT 44 | #endif 45 | 46 | #ifdef NEEDPOWERMAKECONTEXT 47 | void makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) { 48 | ulong *sp, *tos; 49 | va_list arg; 50 | 51 | tos = (ulong *)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size / sizeof(ulong); 52 | sp = tos - 16; 53 | ucp->mc.pc = (long)func; 54 | ucp->mc.sp = (long)sp; 55 | va_start(arg, argc); 56 | ucp->mc.r3 = va_arg(arg, long); 57 | va_end(arg); 58 | } 59 | #endif 60 | 61 | #ifdef NEEDX86MAKECONTEXT 62 | void makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) { 63 | int *sp; 64 | 65 | sp = (int *)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size / 4; 66 | sp -= argc; 67 | sp = (void *)((uintptr_t)sp - (uintptr_t)sp % 16); /* 16-align for OS X */ 68 | memmove(sp, &argc + 1, argc * sizeof(int)); 69 | 70 | *--sp = 0; /* return address */ 71 | ucp->uc_mcontext.mc_eip = (long)func; 72 | ucp->uc_mcontext.mc_esp = (int)sp; 73 | } 74 | #endif 75 | 76 | #ifdef NEEDAMD64MAKECONTEXT 77 | void makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) { 78 | long *sp; 79 | va_list va; 80 | 81 | memset(&ucp->uc_mcontext, 0, sizeof ucp->uc_mcontext); 82 | if (argc != 2) *(volatile int *)0 = 0; 83 | va_start(va, argc); 84 | ucp->uc_mcontext.mc_rdi = va_arg(va, int); 85 | ucp->uc_mcontext.mc_rsi = va_arg(va, int); 86 | va_end(va); 87 | sp = (long *)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size / sizeof(long); 88 | sp -= argc; 89 | sp = (void *)((uintptr_t)sp - (uintptr_t)sp % 16); /* 16-align for OS X */ 90 | *--sp = 0; /* return address */ 91 | ucp->uc_mcontext.mc_rip = (long)func; 92 | ucp->uc_mcontext.mc_rsp = (long)sp; 93 | } 94 | #endif 95 | 96 | #ifdef NEEDARMMAKECONTEXT 97 | void makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) { 98 | int i, *sp; 99 | va_list arg; 100 | 101 | sp = (int *)uc->uc_stack.ss_sp + uc->uc_stack.ss_size / 4; 102 | va_start(arg, argc); 103 | for (i = 0; i < 4 && i < argc; i++) 104 | uc->uc_mcontext.gregs[i] = va_arg(arg, uint); 105 | va_end(arg); 106 | uc->uc_mcontext.gregs[13] = (uint)sp; 107 | uc->uc_mcontext.gregs[14] = (uint)fn; 108 | } 109 | #endif 110 | 111 | #ifdef NEEDMIPSMAKECONTEXT 112 | void makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) { 113 | int i, *sp; 114 | va_list arg; 115 | 116 | va_start(arg, argc); 117 | sp = (int *)uc->uc_stack.ss_sp + uc->uc_stack.ss_size / 4; 118 | for (i = 0; i < 4 && i < argc; i++) 119 | uc->uc_mcontext.mc_regs[i + 4] = va_arg(arg, int); 120 | va_end(arg); 121 | uc->uc_mcontext.mc_regs[29] = (int)sp; 122 | uc->uc_mcontext.mc_regs[31] = (int)fn; 123 | } 124 | #endif 125 | 126 | #ifdef NEEDSWAPCONTEXT 127 | int swapcontext(ucontext_t *oucp, const ucontext_t *ucp) { 128 | if (getcontext(oucp) == 0) setcontext(ucp); 129 | return 0; 130 | } 131 | #endif 132 | -------------------------------------------------------------------------------- /src/futex_impl.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "coroutine.h" 18 | 19 | void _coroc_futex_sleep(uint32_t *addr, uint32_t val, int64_t ns) { 20 | struct timespec ts; 21 | int32_t nsec; 22 | 23 | if (ns < 0) { 24 | syscall(__NR_futex, addr, FUTEX_WAIT, val, NULL, NULL, 0); 25 | return; 26 | } 27 | 28 | ts.tv_sec = ns / 1000000000LL; 29 | ts.tv_nsec = ns % 1000000000LL; 30 | syscall(__NR_futex, addr, FUTEX_WAIT, val, &ts, NULL, 0); 31 | } 32 | 33 | void _coroc_futex_wakeup(uint32_t *addr, uint32_t cnt) { 34 | int64_t ret; 35 | 36 | ret = syscall(__NR_futex, addr, FUTEX_WAKE, cnt, NULL, NULL, 0); 37 | 38 | #ifdef ENABLE_DEBUG 39 | coroc_coroutine_t self = coroc_coroutine_self(); 40 | uint64_t coid = self ? self->id : 0; 41 | TSC_DEBUG("[futex wakeup %p] ret = %ld coid = %ld\n", addr, ret, coid); 42 | #endif 43 | 44 | if (ret >= 0) return; 45 | 46 | // can never reach here!! 47 | assert(0); 48 | } 49 | -------------------------------------------------------------------------------- /src/futex_lock.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "futex_lock.h" 10 | #include "coroutine.h" 11 | 12 | void _coroc_futex_init(volatile _coroc_futex_t *lock) { 13 | lock->key = MUTEX_UNLOCKED; 14 | } 15 | 16 | void _coroc_futex_lock(volatile _coroc_futex_t *lock) { 17 | uint32_t i, v, wait, spin; 18 | #if (ENABLE_DEBUG > 1) 19 | coroc_coroutine_t self = coroc_coroutine_self(); 20 | uint64_t coid = (self != NULL) ? self->id : (uint64_t) - 1; 21 | #endif 22 | 23 | v = TSC_XCHG(&lock->key, MUTEX_LOCKED); 24 | if (v == MUTEX_UNLOCKED) goto __lock_success; 25 | 26 | wait = v; 27 | spin = ACTIVE_SPIN; 28 | 29 | while (1) { 30 | for (i = 0; i < spin; i++) { 31 | while (lock->key == MUTEX_UNLOCKED) 32 | if (TSC_CAS(&lock->key, MUTEX_UNLOCKED, wait)) goto __lock_success; 33 | 34 | __procyield(ACTIVE_SPIN_CNT); 35 | } 36 | 37 | for (i = 0; i < PASSIVE_SPIN; i++) { 38 | while (lock->key == MUTEX_UNLOCKED) 39 | if (TSC_CAS(&lock->key, MUTEX_UNLOCKED, wait)) goto __lock_success; 40 | sched_yield(); 41 | } 42 | 43 | // sleep 44 | v = TSC_XCHG(&lock->key, MUTEX_SLEEPING); 45 | if (v == MUTEX_UNLOCKED) goto __lock_success; 46 | wait = MUTEX_SLEEPING; 47 | _coroc_futex_sleep((uint32_t *)&lock->key, MUTEX_SLEEPING, -1); 48 | } 49 | 50 | __lock_success: 51 | #if (ENABLE_DEBUG > 1) 52 | lock->cookie = coid; 53 | #endif 54 | return; 55 | } 56 | 57 | void _coroc_futex_unlock(volatile _coroc_futex_t *lock) { 58 | uint32_t v; 59 | 60 | #if (ENABLE_DEBUG > 1) 61 | lock->cookie = (uint64_t) - 2; 62 | #endif 63 | 64 | v = TSC_XCHG(&lock->key, MUTEX_UNLOCKED); 65 | assert(v != MUTEX_UNLOCKED); 66 | 67 | if (v == MUTEX_SLEEPING) _coroc_futex_wakeup((uint32_t *)&lock->key, 1); 68 | } 69 | 70 | int _coroc_futex_trylock(volatile _coroc_futex_t *lock) { 71 | if (TSC_CAS(&lock->key, MUTEX_UNLOCKED, MUTEX_LOCKED)) return 0; 72 | return 1; 73 | } 74 | 75 | void _coroc_futex_destroy(volatile _coroc_futex_t *lock) { 76 | // TODO 77 | assert(lock->key == MUTEX_UNLOCKED); 78 | } 79 | -------------------------------------------------------------------------------- /src/group.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include "coroc_group.h" 6 | #include "vpu.h" 7 | 8 | coroc_group_t coroc_group_alloc(void) { 9 | coroc_group_t group = TSC_ALLOC(sizeof(struct coroc_group)); 10 | assert(group != NULL); 11 | coroc_group_init(group); 12 | return group; 13 | } 14 | 15 | #if 0 16 | void coroc_group_add_task(coroc_group_t group) { 17 | assert(group != NULL); 18 | // TSC_ATOMIC_INC(group->count); 19 | lock_acquire(& group->lock); 20 | group->count++; 21 | lock_release(& group->lock); 22 | } 23 | 24 | void coroc_group_notify(coroc_group_t group, int retval) { 25 | assert(group != NULL); 26 | coroc_coroutine_t parent = NULL; 27 | 28 | lock_acquire(& group->lock); 29 | // increase the error number 30 | if (retval != 0) 31 | group->errors++; // TSC_ATOMIC_INC(group->errors); 32 | 33 | // decrease the counter, if reach zero, 34 | // try to wakeup the parent task!! 35 | // if (TSC_ATOMIC_DEC(group->count) == 0) { 36 | if (--(group->count) == 0) { 37 | parent = group->parent; 38 | } 39 | lock_release(& group->lock); 40 | 41 | if (parent != NULL) 42 | vpu_ready(parent); 43 | 44 | return; 45 | } 46 | 47 | bool coroc_group_check(coroc_group_t group) { 48 | assert(group != NULL); 49 | return TSC_ATOMIC_READ(group->count) == 0; 50 | } 51 | 52 | int coroc_group_sync(coroc_group_t group) { 53 | #if 0 54 | // if all subtasks are finish, no need to sleep.. 55 | if (coroc_group_check(group)) 56 | goto __quit_sync; 57 | #endif 58 | lock_acquire(& group->lock); 59 | // FIXME: Do we need to check again to avoid errors? 60 | if (/*TSC_ATOMIC_READ*/(group->count) == 0) { 61 | lock_release(& group->lock); 62 | goto __quit_sync; 63 | } 64 | group->parent = coroc_coroutine_self(); 65 | // goto sleep and wait the last finished subtask to 66 | // wakeup me!! 67 | vpu_suspend(& group->lock, 68 | (unlock_handler_t)lock_release); 69 | 70 | __quit_sync: 71 | return group->errors; 72 | } 73 | #else 74 | 75 | void coroc_group_add_task(coroc_group_t group) { 76 | assert(group != NULL); 77 | TSC_ATOMIC_INC(group->count); 78 | } 79 | 80 | void coroc_group_notify(coroc_group_t group, int retval) { 81 | assert(group != NULL); 82 | coroc_coroutine_t parent; 83 | 84 | if (retval != 0) 85 | TSC_ATOMIC_INC(group->errors); 86 | 87 | if (TSC_ATOMIC_DEC(group->count) == 0) { 88 | lock_acquire(& group->lock); 89 | parent = group->parent; 90 | lock_release(& group->lock); 91 | 92 | if (parent != NULL) 93 | vpu_ready(parent, true); 94 | } 95 | return; 96 | } 97 | 98 | int coroc_group_sync(coroc_group_t group) { 99 | assert(group != NULL); 100 | 101 | if (TSC_ATOMIC_DEC(group->count) > 0) { 102 | lock_acquire(& group->lock); 103 | if (TSC_ATOMIC_READ(group->count) > 0) { 104 | group->parent = coroc_coroutine_self(); 105 | vpu_suspend(& group->lock, 106 | (unlock_handler_t)lock_release); 107 | } 108 | } 109 | 110 | return group->errors; 111 | } 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /src/hash.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include "coroc_hash.h" 6 | 7 | static inline uint64_t __hash_fun0(uint64_t code) { return (A * code + B) % M; } 8 | 9 | static inline uint64_t __hash_fun1(uint64_t code) { return (C * code + D) % N; } 10 | 11 | static void __resize(hash_t *ht) { 12 | hash_entry_t **tmp, *e; 13 | int i, j, newpos; 14 | int capacity = 2 * (ht->capacity); 15 | 16 | for (i = 0; i < 2; i++) { 17 | tmp = malloc(capacity * sizeof(hash_entry_t *)); 18 | memset(tmp, 0, capacity * sizeof(hash_entry_t *)); 19 | 20 | for (j = 0; j < ht->capacity; j++) { 21 | e = ht->table[i][j]; 22 | newpos = 23 | i ? __hash_fun1(e->key) % capacity : __hash_fun0(e->key) % capacity; 24 | 25 | tmp[newpos] = ht->table[i][j]; 26 | } 27 | 28 | free(ht->table[i]); 29 | ht->table[i] = tmp; 30 | } 31 | ht->capacity = capacity; 32 | 33 | return; 34 | } 35 | 36 | static int __add(hash_t *ht, hash_entry_t *e) { 37 | hash_entry_t *tmp = NULL; 38 | int i = 0, k, pos; 39 | 40 | for (k = 0; k < LIMIT; k++) { 41 | pos = i ? __hash_fun1(e->key) % (ht->capacity) 42 | : __hash_fun0(e->key) % (ht->capacity); 43 | 44 | tmp = ht->table[i][pos]; 45 | 46 | if (tmp == NULL) { 47 | ht->table[i][pos] = e; 48 | return 0; 49 | } 50 | 51 | if (e->key == tmp->key) { 52 | return -1; 53 | } 54 | 55 | ht->table[i][pos] = e; 56 | e = tmp; 57 | i = (i + 1) % 2; 58 | } 59 | 60 | __resize(ht); 61 | return __add(ht, e); 62 | } 63 | 64 | void hash_init(hash_t *hash) { 65 | int i; 66 | hash->capacity = CAPACITY; 67 | for (i = 0; i < 2; i++) { 68 | hash->table[i] = malloc(CAPACITY * sizeof(hash_entry_t *)); 69 | memset(hash->table[i], 0, sizeof(hash_entry_t *) * CAPACITY); 70 | } 71 | } 72 | 73 | void hash_fini(hash_t *hash) { 74 | int i, j; 75 | for (i = 0; i < 2; i++) 76 | if (hash->table[i]) { 77 | for (j = 0; j < hash->capacity; j++) 78 | if (hash->table[i][j]) free(hash->table[i][j]); 79 | free(hash->table[i]); 80 | } 81 | } 82 | 83 | int hash_insert(hash_t *hash, uint64_t key, void *value) { 84 | hash_entry_t *e = NULL; 85 | 86 | // Init the new element. 87 | e = malloc(sizeof(hash_entry_t)); 88 | e->key = key; 89 | e->value = value; 90 | 91 | return __add(hash, e); 92 | } 93 | 94 | void *hash_get(hash_t *hash, uint64_t key, bool remove) { 95 | int i, pos; 96 | void *value = NULL; 97 | hash_entry_t *e; 98 | 99 | for (i = 0; i < 2; i++) { 100 | pos = i ? __hash_fun1(key) % hash->capacity 101 | : __hash_fun0(key) % hash->capacity; 102 | e = hash->table[i][pos]; 103 | 104 | if (e && (e->key == key)) { 105 | value = e->value; 106 | if (remove) { 107 | hash->table[i][pos] = NULL; 108 | free(e); 109 | } 110 | break; 111 | } 112 | } 113 | 114 | return value; 115 | } 116 | 117 | #if 0 118 | int set(hash_t *ht, const char *key, char *value) 119 | { 120 | int hash = __hash_code(key); 121 | int i, pos; 122 | hash_entry_t *ret; 123 | 124 | for (i=0; i<2; i++) { 125 | pos = __hash_fun[i](hash) % ht->capacity ; 126 | ret = ht->table[i][pos]; 127 | 128 | if ( ret && !strcmp(ret->key, key) ) { 129 | strcpy(ret->value, value); 130 | return 0; 131 | } 132 | } 133 | 134 | return -1; 135 | } 136 | 137 | 138 | int enumerate(hash_t *ht) 139 | { 140 | if ( ht == NULL ) 141 | return -1; 142 | 143 | ht->cursor = 0; 144 | 145 | return 0; 146 | } 147 | 148 | int next(hash_t *ht, hash_entry_t **entry) 149 | { 150 | if ( ht == NULL ) 151 | return -1; 152 | 153 | int tno, no, found = FALSE; 154 | 155 | tno = ht->cursor / ht->capacity; 156 | no = ht->cursor % ht->capacity; 157 | 158 | while ( tno <= 1 ) { 159 | for ( ; no < ht->capacity && found == FALSE; no++ ) { 160 | if ( ht->table[tno][no] ) { 161 | *entry = ht->table[tno][no]; 162 | found = TRUE; 163 | } 164 | ht->cursor ++; 165 | } 166 | tno ++; 167 | no = 0; 168 | } 169 | 170 | if ( found == TRUE ) 171 | return 0; 172 | 173 | ht->cursor = 0; 174 | return -1; 175 | } 176 | #endif 177 | 178 | void atomic_hash_init(hash_t *hash) { 179 | lock_init(&hash->lock); 180 | hash_init(hash); 181 | } 182 | 183 | int atomic_hash_insert(hash_t *hash, uint64_t key, void *value) { 184 | lock_acquire(&hash->lock); 185 | int ret = hash_insert(hash, key, value); 186 | lock_release(&hash->lock); 187 | return ret; 188 | } 189 | 190 | void *atomic_hash_get(hash_t *hash, uint64_t key, bool remove) { 191 | lock_acquire(&hash->lock); 192 | void *value = hash_get(hash, key, remove); 193 | lock_release(&hash->lock); 194 | return value; 195 | } 196 | -------------------------------------------------------------------------------- /src/message.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | 8 | #include "coroutine.h" 9 | #include "message.h" 10 | 11 | static coroc_msg_item_t __coroc_alloc_msg_item(coroc_msg_t *m) { 12 | coroc_msg_item_t item = TSC_ALLOC(sizeof(*item)); 13 | memcpy(item, m, sizeof(*m)); 14 | 15 | queue_item_init(&item->link, item); 16 | return item; 17 | } 18 | 19 | static bool __coroc_copy_to_mque(coroc_chan_t chan, void *buf) { 20 | coroc_async_chan_t achan = (coroc_async_chan_t)chan; 21 | coroc_msg_item_t msg = __coroc_alloc_msg_item((coroc_msg_t *)buf); 22 | 23 | queue_add(&achan->mque, &msg->link); 24 | return true; 25 | } 26 | 27 | static bool __coroc_copy_from_mque(coroc_chan_t chan, void *buf) { 28 | coroc_async_chan_t achan = (coroc_async_chan_t)chan; 29 | coroc_msg_item_t msg = queue_rem(&achan->mque); 30 | 31 | if (msg != NULL) { 32 | __chan_memcpy(buf, msg, sizeof(struct coroc_msg)); 33 | // TODO : add a free msg_item list .. 34 | free(msg); 35 | return true; 36 | } 37 | 38 | return false; 39 | } 40 | 41 | void coroc_async_chan_init(coroc_async_chan_t achan) { 42 | coroc_chan_init((coroc_chan_t)achan, sizeof(struct coroc_msg), false, __coroc_copy_to_mque, 43 | __coroc_copy_from_mque); 44 | coroc_refcnt_init((coroc_refcnt_t)achan, TSC_DEALLOC); 45 | atomic_queue_init(&achan->mque); 46 | } 47 | 48 | void coroc_async_chan_fini(coroc_async_chan_t achan) { 49 | lock_acquire(&achan->_chan.lock); 50 | coroc_msg_item_t msg = 0; 51 | while ((msg = queue_rem(&achan->mque)) != NULL) { 52 | // FIXME : memory leak may happen here !! 53 | free(msg); 54 | } 55 | achan->_chan.close = true; // !! 56 | lock_release(&achan->_chan.lock); 57 | } 58 | 59 | int coroc_send(coroc_coroutine_t target, void *buf, int32_t size) { 60 | assert(target != NULL); 61 | 62 | struct coroc_msg _msg; 63 | char *tmp = TSC_ALLOC(size); 64 | __chan_memcpy(tmp, buf, size); 65 | 66 | _msg.size = size; 67 | _msg.msg = tmp; 68 | 69 | _coroc_chan_send((coroc_chan_t)target, &_msg, true); 70 | return CHAN_SUCCESS; 71 | } 72 | 73 | int coroc_recv(void *buf, int32_t size, bool block) { 74 | struct coroc_msg _msg; 75 | int ret = _coroc_chan_recv(NULL, &_msg, block); 76 | 77 | // TODO : note the memory has been allocated and copied twice, 78 | // sometimes we can optimize this by just copying a pointer, maybe .. 79 | __chan_memcpy(buf, _msg.msg, (size < _msg.size) ? size : _msg.size); 80 | free(_msg.msg); 81 | 82 | return ret; 83 | } 84 | 85 | int coroc_sendp(coroc_coroutine_t target, void *ptr, int32_t size) { 86 | assert(target != NULL); 87 | struct coroc_msg _msg = {size, ptr}; 88 | 89 | _coroc_chan_send((coroc_chan_t)target, &_msg, true); 90 | return CHAN_SUCCESS; 91 | } 92 | 93 | int coroc_recvp(void **ptr, int32_t *size, bool block) { 94 | struct coroc_msg _msg; 95 | int ret = _coroc_chan_recv(NULL, &_msg, block); 96 | *ptr = _msg.msg; 97 | *size = _msg.size; 98 | 99 | return ret; 100 | } 101 | -------------------------------------------------------------------------------- /src/net.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "support.h" 17 | #include "netpoll.h" 18 | #include "coroutine.h" 19 | 20 | // This is the NET API wrapper for libtsc, 21 | // copy & modify from the LibTask project. 22 | 23 | int coroc_net_lookup(const char *name, uint32_t *ip); 24 | 25 | int coroc_net_announce(bool istcp, const char *server, int port) { 26 | int fd, n, proto; 27 | struct sockaddr_in sa; 28 | socklen_t sn; 29 | uint32_t ip; 30 | 31 | proto = istcp ? SOCK_STREAM : SOCK_DGRAM; 32 | memset(&sa, 0, sizeof(sa)); 33 | sa.sin_family = AF_INET; 34 | 35 | if (server != NULL && strcmp(server, "*") != 0) { 36 | if (coroc_net_lookup(server, &ip) < 0) return -1; 37 | memmove(&sa.sin_addr, &ip, 4); 38 | } 39 | 40 | sa.sin_port = htons(port); 41 | if ((fd = socket(AF_INET, proto, 0)) < 0) return -1; 42 | 43 | // set reuse flag for tcp .. 44 | if (istcp && getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&n, &sn) >= 0) { 45 | n = 1; 46 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof(n)); 47 | } 48 | 49 | if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 50 | close(fd); 51 | return -1; 52 | } 53 | 54 | if (proto == SOCK_STREAM) listen(fd, port); 55 | 56 | coroc_net_nonblock(fd); 57 | return fd; 58 | } 59 | 60 | int coroc_net_timed_accept(int fd, char *server, int *port, int64_t usec) { 61 | int cfd, one; 62 | struct sockaddr_in sa; 63 | uint8_t *ip; 64 | socklen_t len; 65 | 66 | if (usec <= 0) 67 | coroc_net_wait(fd, TSC_NETPOLL_READ); 68 | else if (!coroc_net_timedwait(fd, TSC_NETPOLL_READ, usec)) 69 | return -1; 70 | 71 | len = sizeof sa; 72 | #if defined(__APPLE__) 73 | if ((cfd = accept(fd, (void*)&sa, &len)) < 0) return -1; 74 | coroc_net_nonblock(cfd); 75 | #else 76 | if ((cfd = accept4(fd, (void *)&sa, &len, 77 | SOCK_NONBLOCK | SOCK_CLOEXEC)) < 0) return -1; 78 | #endif 79 | 80 | if (server) { 81 | ip = (uint8_t *)&sa.sin_addr; 82 | snprintf(server, 16, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); 83 | } 84 | 85 | if (port) *port = ntohs(sa.sin_port); 86 | 87 | // coroc_net_nonblock(cfd); 88 | one = 1; 89 | setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof one); 90 | 91 | return cfd; 92 | } 93 | 94 | int coroc_net_accept(int fd, char *server, int *port) { 95 | return coroc_net_timed_accept(fd, server, port, 0); 96 | } 97 | 98 | #define CLASS(p) ((*(unsigned char *)(p)) >> 6) 99 | static int __coroc_parseip(const char *name, uint32_t *ip) { 100 | uint8_t addr[4]; 101 | char *p; 102 | int i, x; 103 | 104 | p = (char *)name; 105 | for (i = 0; i < 4 && *p; i++) { 106 | x = strtoul(p, &p, 0); 107 | if (x < 0 || x > 256) return -1; 108 | if (*p != '.' && *p != 0) return -1; 109 | if (*p == '.') p++; 110 | addr[i] = x; 111 | } 112 | 113 | switch (CLASS(addr)) { 114 | case 0: 115 | case 1: 116 | if (i == 3) { 117 | addr[3] = addr[2]; 118 | addr[2] = addr[1]; 119 | addr[1] = 0; 120 | } else if (i == 2) { 121 | addr[3] = addr[1]; 122 | addr[2] = 0; 123 | addr[1] = 0; 124 | } else if (i != 4) 125 | return -1; 126 | break; 127 | 128 | case 2: 129 | if (i == 3) { 130 | addr[3] = addr[2]; 131 | addr[2] = 0; 132 | } else if (i != 4) 133 | return -1; 134 | break; 135 | } 136 | 137 | *ip = *(uint32_t *)addr; 138 | return 0; 139 | } 140 | 141 | int coroc_net_lookup(const char *name, uint32_t *ip) { 142 | struct hostent *he; 143 | 144 | if (__coroc_parseip(name, ip) >= 0) return 0; 145 | 146 | if ((he = gethostbyname(name)) != 0) { 147 | *ip = *(uint32_t *)he->h_addr; 148 | return 0; 149 | } 150 | 151 | return -1; 152 | } 153 | 154 | int coroc_net_timed_dial(bool istcp, const char *server, int port, int64_t usec) { 155 | int proto, fd, n; 156 | uint32_t ip; 157 | struct sockaddr_in sa; 158 | socklen_t sn; 159 | 160 | if (coroc_net_lookup(server, &ip) < 0) return -1; 161 | 162 | proto = istcp ? SOCK_STREAM : SOCK_DGRAM; 163 | if ((fd = socket(AF_INET, proto, 0)) < 0) return -1; 164 | 165 | coroc_net_nonblock(fd); 166 | 167 | if (!istcp) { 168 | n = 1; 169 | setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &n, sizeof n); 170 | } 171 | 172 | /* start connecting */ 173 | memset(&sa, 0, sizeof sa); 174 | memmove(&sa.sin_addr, &ip, 4); 175 | sa.sin_family = AF_INET; 176 | sa.sin_port = htons(port); 177 | 178 | if (connect(fd, (struct sockaddr *)&sa, sizeof sa) < 0 && 179 | errno != EINPROGRESS) { 180 | close(fd); 181 | return -1; 182 | } 183 | 184 | // wait for the connection finish .. 185 | if (usec <= 0) { 186 | coroc_net_wait(fd, TSC_NETPOLL_WRITE); 187 | } else if (!coroc_net_timedwait(fd, TSC_NETPOLL_WRITE, usec)) { 188 | close(fd); 189 | return -1; 190 | } 191 | 192 | sn = sizeof sa; 193 | if (getpeername(fd, (struct sockaddr *)&sa, &sn) >= 0) return fd; 194 | 195 | // report the error 196 | sn = sizeof n; 197 | getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&n, &sn); 198 | if (n == 0) n = ECONNREFUSED; 199 | close(fd); 200 | errno = n; 201 | 202 | return -1; 203 | } 204 | 205 | int coroc_net_dial(bool istcp, const char *server, int port) { 206 | return coroc_net_timed_dial(istcp, server, port, 0); 207 | } 208 | -------------------------------------------------------------------------------- /src/netpoll.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "vpu.h" 10 | #include "netpoll.h" 11 | #include "time.h" 12 | 13 | TSC_SIGNAL_MASK_DECLARE 14 | 15 | int coroc_net_nonblock(int fd) { 16 | return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); 17 | } 18 | 19 | int coroc_net_read(int fd, void *buf, int n) { 20 | int m, total; 21 | for (total = 0; total < n; total += m) { 22 | while ((m = read(fd, (char*)buf + total, n - total)) < 0 && 23 | errno == EAGAIN) 24 | coroc_net_wait(fd, TSC_NETPOLL_READ); 25 | if (m < 0) return m; 26 | if (m == 0) break; 27 | } 28 | return total; 29 | } 30 | 31 | int coroc_net_timed_read(int fd, void *buf, int n, int64_t timeout) { 32 | int m; 33 | while ((m = read(fd, buf, n)) < 0 && errno == EAGAIN) 34 | if (!coroc_net_timedwait(fd, TSC_NETPOLL_READ, timeout)) 35 | return -1; 36 | return m; 37 | } 38 | 39 | int coroc_net_write(int fd, void *buf, int n) { 40 | int m, total; 41 | 42 | for (total = 0; total < n; total += m) { 43 | while ((m = write(fd, (char *)buf + total, n - total)) < 0 && 44 | errno == EAGAIN) 45 | coroc_net_wait(fd, TSC_NETPOLL_WRITE); 46 | if (m < 0) return m; 47 | if (m == 0) break; 48 | } 49 | 50 | return total; 51 | } 52 | 53 | static void __coroc_poll_desc_init(coroc_poll_desc_t desc, int fd, int mode, 54 | coroc_inter_timer_t *deadline) { 55 | desc->done = false; 56 | desc->fd = fd; 57 | desc->mode = mode; 58 | desc->wait = coroc_coroutine_self(); 59 | desc->deadline = deadline; 60 | lock_init(&desc->lock); 61 | 62 | coroc_refcnt_init(&desc->refcnt, TSC_DEALLOC); 63 | } 64 | 65 | int coroc_net_wait(int fd, int mode) { 66 | coroc_poll_desc_t desc = TSC_ALLOC(sizeof(struct coroc_poll_desc)); 67 | __coroc_poll_desc_init(desc, fd, mode, NULL); 68 | 69 | TSC_SIGNAL_MASK(); 70 | // calling the low level Netpoll APIs to add .. 71 | lock_acquire(&desc->lock); 72 | __coroc_netpoll_add(desc); 73 | // then suspend current thread .. 74 | vpu_suspend(&desc->lock, (unlock_handler_t)lock_release); 75 | 76 | TSC_SIGNAL_UNMASK(); 77 | 78 | mode = desc->mode; 79 | coroc_refcnt_put(desc); 80 | 81 | return mode; 82 | } 83 | 84 | static void __coroc_netpoll_timeout(void *arg) { 85 | TSC_SIGNAL_MASK(); 86 | 87 | bool succ; 88 | coroc_inter_timer_t *timer = (coroc_inter_timer_t *)arg; 89 | coroc_poll_desc_t desc = timer->args; 90 | 91 | lock_acquire(&desc->lock); 92 | // hazard checking .. 93 | if (!(succ = TSC_CAS(&desc->done, false, true))) 94 | goto __exit_netpoll_timeout; 95 | 96 | desc->mode = 0; 97 | 98 | __coroc_netpoll_rem(desc); 99 | 100 | __exit_netpoll_timeout: 101 | // NOTE: the lock must be released before calling 102 | // the `vpu_ready()', since the `vpu_ready()' may 103 | // cause the current task to be scheduled out to 104 | // run a task with higher priority!! 105 | lock_release(&desc->lock); 106 | if (succ) 107 | vpu_ready(desc->wait, true); 108 | coroc_refcnt_put(desc); // dec the refcnt !! 109 | 110 | TSC_SIGNAL_UNMASK(); 111 | } 112 | 113 | int coroc_net_timedwait(int fd, int mode, int64_t usec) { 114 | assert (usec > 0); 115 | 116 | coroc_inter_timer_t deadline; 117 | struct coroc_poll_desc *desc = TSC_ALLOC(sizeof(struct coroc_poll_desc)); 118 | __coroc_poll_desc_init(desc, fd, mode, &deadline); 119 | 120 | deadline.when = coroc_getmicrotime() + usec; 121 | deadline.period = 0; 122 | deadline.func = __coroc_netpoll_timeout; 123 | deadline.args = coroc_refcnt_get(desc); // inc the refcnt!! 124 | deadline.owner = NULL; 125 | 126 | TSC_SIGNAL_MASK(); 127 | lock_acquire(&desc->lock); 128 | __coroc_netpoll_add(desc); 129 | // add the timer to do timeout check.. 130 | coroc_add_intertimer(&deadline); 131 | // then suspend current task .. 132 | vpu_suspend(&desc->lock, (unlock_handler_t)lock_release); 133 | // delete the deadline timer here!! 134 | if (coroc_del_intertimer(&deadline) == 0) coroc_refcnt_put(desc); 135 | 136 | // drop the reference .. 137 | mode = desc->mode; 138 | coroc_refcnt_put(desc); 139 | 140 | TSC_SIGNAL_UNMASK(); 141 | return mode; 142 | } 143 | 144 | int coroc_netpoll_wakeup(coroc_poll_desc_t desc) { 145 | lock_acquire(&desc->lock); 146 | #if 0 147 | // hazard checking, maybe not neccessary.. 148 | // if (desc->done) goto __exit_netpoll_wakeup; 149 | if (!TSC_CAS(&desc->done, false, true)) goto __exit_netpoll_wakeup; 150 | #endif 151 | 152 | // must remove the desc before wakeup the wait task, 153 | // so the netpoll will not return this desc again!! 154 | __coroc_netpoll_rem(desc); 155 | 156 | // since the `desc->wait' will release the desc, 157 | // so we must release the lock before calling vpu_ready 158 | // to wakeup `desc->wait' !! 159 | lock_release(&desc->lock); 160 | 161 | // this function must be called by 162 | // system context, so don not need 163 | // to mask the signals .. 164 | vpu_ready(desc->wait, false); 165 | 166 | return 0; 167 | } 168 | 169 | void coroc_netpoll_initialize(void) { __coroc_netpoll_init(128); } 170 | -------------------------------------------------------------------------------- /src/netpoll_epoll.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "netpoll.h" 11 | #include "refcnt.h" 12 | 13 | static int __coroc_epfd = -1; 14 | static int __coroc_num_op = 0; 15 | 16 | int __coroc_netpoll_init(int max) { 17 | __coroc_epfd = epoll_create(max); 18 | return __coroc_epfd; 19 | } 20 | 21 | int __coroc_netpoll_fini(void) { 22 | // TODO 23 | return 0; 24 | } 25 | 26 | static inline int __coroc_netpoll_ctl(coroc_poll_desc_t desc, int op) { 27 | struct epoll_event ev; 28 | ev.events = EPOLLET; 29 | 30 | if (desc->mode & TSC_NETPOLL_READ) ev.events |= (EPOLLIN | EPOLLRDHUP); 31 | if (desc->mode & TSC_NETPOLL_WRITE) ev.events |= EPOLLOUT; 32 | 33 | ev.data.ptr = desc; 34 | 35 | return epoll_ctl(__coroc_epfd, op, desc->fd, &ev); 36 | } 37 | 38 | int __coroc_netpoll_add(coroc_poll_desc_t desc) { 39 | coroc_refcnt_get(desc); // inc the refcnt !! 40 | TSC_ATOMIC_INC(__coroc_num_op); 41 | return __coroc_netpoll_ctl(desc, EPOLL_CTL_ADD); 42 | } 43 | 44 | int __coroc_netpoll_rem(coroc_poll_desc_t desc) { 45 | // dec the refcnt!! 46 | // NOTE the `desc' will not be freed here 47 | // since the refcnt is at least 1 !! 48 | coroc_refcnt_put(desc); 49 | TSC_ATOMIC_DEC(__coroc_num_op); 50 | return __coroc_netpoll_ctl(desc, EPOLL_CTL_DEL); 51 | } 52 | 53 | bool __coroc_netpoll_polling(int timeout) { 54 | struct epoll_event events[128]; 55 | int ready, i, mode = 0; 56 | 57 | ready = epoll_wait(__coroc_epfd, events, 128, timeout); 58 | 59 | if (ready <= 0) return false; 60 | 61 | for (i = 0; i < ready; i++) { 62 | coroc_poll_desc_t desc = events[i].data.ptr; 63 | 64 | // FIXME: hazard checking here, make sure only one 65 | // thread will wakeup this desc !! 66 | if (!TSC_CAS(&desc->done, false, true)) 67 | continue; 68 | 69 | if (events[i].events & EPOLLERR) { 70 | mode = TSC_NETPOLL_ERROR; 71 | } else { 72 | if ((desc->mode & TSC_NETPOLL_READ) && 73 | (events[i].events & (EPOLLIN | EPOLLRDHUP))) 74 | mode |= TSC_NETPOLL_READ; 75 | 76 | if ((desc->mode & TSC_NETPOLL_WRITE) && (events[i].events & EPOLLOUT)) 77 | mode |= TSC_NETPOLL_WRITE; 78 | } 79 | // the mode as the return value .. 80 | desc->mode = mode; 81 | coroc_netpoll_wakeup(desc); 82 | } 83 | 84 | return true; 85 | } 86 | 87 | int __coroc_netpoll_size(void) { return __coroc_num_op; } 88 | -------------------------------------------------------------------------------- /src/netpoll_kqueue.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "netpoll.h" 13 | #include "refcnt.h" 14 | 15 | static int __coroc_kqueue = -1; 16 | static int __coroc_num_op = 0; 17 | 18 | int __coroc_netpoll_init(int max) { 19 | __coroc_kqueue = kqueue() ; 20 | return __coroc_kqueue; 21 | } 22 | 23 | int __coroc_netpoll_fini(void) { 24 | // TODO 25 | return 0; 26 | } 27 | 28 | static inline int __coroc_netpoll_ctl(coroc_poll_desc_t desc, uint16_t flags) { 29 | struct kevent ev; 30 | 31 | ev.ident = desc->fd; 32 | 33 | if (desc->mode & TSC_NETPOLL_READ) ev.filter |= EVFILT_READ; 34 | if (desc->mode & TSC_NETPOLL_WRITE) ev.filter |= EVFILT_WRITE; 35 | 36 | ev.flags = flags; 37 | ev.fflags = 0; 38 | ev.data = 0; 39 | ev.udata = desc; 40 | 41 | return kevent(__coroc_kqueue, &ev, 1, NULL, 0, NULL); 42 | } 43 | 44 | int __coroc_netpoll_add(coroc_poll_desc_t desc) { 45 | coroc_refcnt_get(desc); // inc the refcnt !! 46 | TSC_ATOMIC_INC(__coroc_num_op); 47 | return __coroc_netpoll_ctl(desc, EV_ADD | EV_ENABLE); 48 | } 49 | 50 | int __coroc_netpoll_rem(coroc_poll_desc_t desc) { 51 | // dec the refcnt!! 52 | // NOTE the `desc' will not be freed here 53 | // since the refcnt is at least 1 !! 54 | coroc_refcnt_put(desc); 55 | TSC_ATOMIC_DEC(__coroc_num_op); 56 | return __coroc_netpoll_ctl(desc, EV_DELETE); 57 | } 58 | 59 | bool __coroc_netpoll_polling(int timeout) { 60 | struct kevent events[128]; 61 | struct timespec tmout, *ptmout = NULL; 62 | int ready, i, mode = 0; 63 | 64 | if (timeout >= 0) { 65 | tmout.tv_sec = timeout / 1000; 66 | tmout.tv_nsec = (timeout % 1000) * 1000000; 67 | ptmout = &tmout; 68 | } 69 | 70 | ready = kevent(__coroc_kqueue, events, 128, NULL, 0, ptmout); 71 | 72 | if (ready <= 0) return false; 73 | 74 | for (i = 0; i < ready; i++) { 75 | coroc_poll_desc_t desc = (coroc_poll_desc_t)events[i].udata; 76 | 77 | // FIXME: hazard checking here, make sure only one 78 | // thread will wakeup this desc !! 79 | if (!TSC_CAS(&desc->done, false, true)) 80 | continue; 81 | 82 | if (events[i].flags & EV_ERROR) { 83 | mode = TSC_NETPOLL_ERROR; 84 | } else { 85 | if ((desc->mode & TSC_NETPOLL_READ) && 86 | (events[i].filter & EVFILT_READ)) 87 | mode |= TSC_NETPOLL_READ; 88 | 89 | if ((desc->mode & TSC_NETPOLL_WRITE) && (events[i].filter & EVFILT_WRITE)) 90 | mode |= TSC_NETPOLL_WRITE; 91 | } 92 | // the mode as the return value .. 93 | desc->mode = mode; 94 | coroc_netpoll_wakeup(desc); 95 | } 96 | 97 | return true; 98 | } 99 | 100 | int __coroc_netpoll_size(void) { return __coroc_num_op; } 101 | -------------------------------------------------------------------------------- /src/netpoll_poll.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "netpoll.h" 12 | 13 | struct { 14 | int cap; 15 | int size; 16 | struct pollfd *fds; 17 | coroc_poll_desc_t *table; 18 | pthread_mutex_t mutex; 19 | } coroc_netpoll_manager; 20 | 21 | int __coroc_netpoll_init(int max) { 22 | coroc_netpoll_manager.cap = max; 23 | coroc_netpoll_manager.size = 0; 24 | coroc_netpoll_manager.fds = malloc(max * sizeof(struct pollfd)); 25 | coroc_netpoll_manager.table = malloc(max * sizeof(void *)); 26 | 27 | pthread_mutex_init(&coroc_netpoll_manager.mutex, NULL); 28 | 29 | return 0; 30 | } 31 | 32 | int __coroc_netpoll_fini(void) { 33 | free(coroc_netpoll_manager.fds); 34 | free(coroc_netpoll_manager.table); 35 | return 0; 36 | } 37 | 38 | int __coroc_netpoll_add(coroc_poll_desc_t desc) { 39 | pthread_mutex_lock(&coroc_netpoll_manager.mutex); 40 | 41 | // realloc the buffer if the number of waiting requests 42 | // exceed the current capacity .. 43 | if (coroc_netpoll_manager.size == coroc_netpoll_manager.cap) { 44 | coroc_netpoll_manager.cap *= 2; 45 | coroc_netpoll_manager.fds = 46 | realloc(coroc_netpoll_manager.fds, 47 | coroc_netpoll_manager.cap * sizeof(struct pollfd)); 48 | coroc_netpoll_manager.table = realloc( 49 | coroc_netpoll_manager.table, coroc_netpoll_manager.cap * sizeof(void *)); 50 | } 51 | 52 | int size = coroc_netpoll_manager.size; 53 | 54 | coroc_netpoll_manager.table[size] = desc; 55 | desc->id = size; // !! 56 | 57 | coroc_netpoll_manager.fds[size].fd = desc->fd; 58 | coroc_netpoll_manager.fds[size].events = 0; 59 | coroc_netpoll_manager.fds[size].revents = 0; 60 | 61 | if (desc->mode & TSC_NETPOLL_READ) 62 | coroc_netpoll_manager.fds[size].events |= POLLIN; 63 | if (desc->mode & TSC_NETPOLL_WRITE) 64 | coroc_netpoll_manager.fds[size].events |= POLLOUT; 65 | 66 | coroc_netpoll_manager.size++; 67 | 68 | pthread_mutex_unlock(&coroc_netpoll_manager.mutex); 69 | return 0; 70 | } 71 | 72 | int __coroc_netpoll_rem(coroc_poll_desc_t desc) { 73 | int id, size; 74 | struct pollfd *pfds = &coroc_netpoll_manager.fds[0]; 75 | 76 | // pthread_mutex_lock (& coroc_netpoll_manager . mutex); 77 | 78 | id = desc->id; 79 | size = coroc_netpoll_manager.size; 80 | // delete current one, and copy the last one 81 | // to current's spot.. 82 | memcpy(&pfds[id], &pfds[size - 1], sizeof(struct pollfd)); 83 | coroc_netpoll_manager.table[id] = coroc_netpoll_manager.table[size - 1]; 84 | coroc_netpoll_manager.table[id]->id = id; 85 | 86 | coroc_netpoll_manager.size--; 87 | 88 | // pthread_mutex_unlock (& coroc_netpoll_manager . mutex); 89 | return 0; 90 | } 91 | 92 | bool __coroc_netpoll_polling(int timeout) { 93 | int size, i, mode = 0; 94 | struct pollfd *pfds = coroc_netpoll_manager.fds; 95 | 96 | size = coroc_netpoll_manager.size; 97 | if (size == 0) return false; 98 | 99 | if (poll(pfds, size, timeout) <= 0) return false; 100 | 101 | pthread_mutex_lock(&coroc_netpoll_manager.mutex); 102 | 103 | for (i = 0; i < size; i++) { 104 | coroc_poll_desc_t desc = coroc_netpoll_manager.table[i]; 105 | 106 | // FIXME: hazard checking here, make sure only one 107 | // thread will wakeup this desc !! 108 | if (!TSC_CAS(&desc->done, false, true)) 109 | continue; 110 | 111 | if (pfds[i].revents & POLLERR) { 112 | mode = TSC_NETPOLL_ERROR; 113 | } else { 114 | if ((desc->mode & TSC_NETPOLL_READ) && 115 | (pfds[i].revents & (POLLIN | POLLRDHUP))) 116 | mode |= TSC_NETPOLL_READ; 117 | if ((desc->mode & TSC_NETPOLL_WRITE) && 118 | (pfds[i].revents & POLLOUT)) 119 | mode |= TSC_NETPOLL_WRITE; 120 | } 121 | 122 | desc->mode = mode; 123 | coroc_netpoll_wakeup(desc); 124 | } 125 | 126 | pthread_mutex_unlock(&coroc_netpoll_manager.mutex); 127 | 128 | return true; 129 | } 130 | 131 | int __coroc_netpoll_size(void) { return coroc_netpoll_manager.size; } 132 | -------------------------------------------------------------------------------- /src/notify.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | #include 6 | 7 | #include "coroc_time.h" 8 | #include "notify.h" 9 | 10 | void coroc_notify_wakeup(coroc_notify_t *note) { 11 | if (TSC_CAS(¬e->key, 0, 1)) 12 | _coroc_futex_wakeup(¬e->key, 1); 13 | } 14 | 15 | void __coroc_notify_tsleep(void *arg) { 16 | coroc_notify_t *note = (coroc_notify_t *)arg; 17 | int64_t ns = note->ns; 18 | int64_t now = coroc_getnanotime(); 19 | int64_t deadline = ns + now; 20 | 21 | for (;;) { 22 | _coroc_futex_sleep(¬e->key, 0, ns); 23 | if (TSC_ATOMIC_READ(note->key) != 0) break; 24 | now = coroc_getnanotime(); 25 | if (now >= deadline) break; 26 | ns = deadline - now; 27 | } 28 | } 29 | 30 | // ---------------------------------- 31 | 32 | void __coroc_nanosleep(void *pns) { 33 | uint64_t ns = *(uint64_t *)pns; 34 | struct timespec req, rem; 35 | 36 | req.tv_sec = ns / 1000000000; 37 | req.tv_nsec = ns % 1000000000; 38 | 39 | nanosleep(&req, &rem); 40 | } 41 | -------------------------------------------------------------------------------- /src/vfs.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Amal Cao (amalcaowei@gmail.com). All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE.txt file. 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "async.h" 12 | #include "vfs.h" 13 | #include "vpu.h" 14 | 15 | // the default file driver 16 | struct coroc_vfs_driver coroc_vfs_file_drv = {.open = open, 17 | .read = read, 18 | .write = write, 19 | .lseek = lseek, 20 | .flush = NULL, 21 | .close = close, 22 | .ioctl = NULL, }; 23 | 24 | // the vfs sub-system APIs 25 | void coroc_vfs_callback(coroc_vfs_ops *ops) { 26 | assert(ops != NULL); 27 | 28 | switch (ops->ops_type) { 29 | case TSC_VFS_OPEN: { 30 | int fd = ops->driver->open((char *)(ops->buf), (int)(ops->arg0), 31 | (int)(ops->arg1)); 32 | ops->arg0 = fd; 33 | break; 34 | } 35 | 36 | case TSC_VFS_CLOSE: 37 | ops->driver->close(ops->fd); 38 | break; 39 | 40 | case TSC_VFS_FLUSH: 41 | if (ops->driver->flush) ops->driver->flush(ops->fd); 42 | break; 43 | 44 | case TSC_VFS_READ: { 45 | ssize_t sz = ops->driver->read(ops->fd, ops->buf, (size_t)(ops->arg0)); 46 | ops->arg0 = sz; 47 | break; 48 | } 49 | 50 | case TSC_VFS_WRITE: { 51 | ssize_t sz = ops->driver->write(ops->fd, ops->buf, (size_t)(ops->arg0)); 52 | ops->arg0 = sz; 53 | break; 54 | } 55 | 56 | case TSC_VFS_LSEEK: { 57 | off_t off; 58 | if (ops->driver->lseek) 59 | off = ops->driver->lseek(ops->fd, (off_t)ops->arg0, (int)ops->arg1); 60 | ops->arg0 = off; 61 | break; 62 | } 63 | 64 | case TSC_VFS_IOCTL: { 65 | int ret = -1; 66 | if (ops->driver->ioctl) 67 | ret = ops->driver->ioctl(ops->fd, (int)ops->arg0, (int)ops->arg1); 68 | ops->arg0 = ret; 69 | break; 70 | } 71 | 72 | default: 73 | assert(0); 74 | } // switch 75 | 76 | return ; 77 | } 78 | 79 | static inline void __coroc_vfs_add_ops(coroc_vfs_ops *ops) { 80 | coroc_async_request_submit((coroc_async_callback_t)coroc_vfs_callback, ops); 81 | } 82 | 83 | static void __coroc_vfs_init_ops(coroc_vfs_ops *ops, int type, int fd, int64_t arg0, 84 | int64_t arg1, void *buf, coroc_vfs_driver_t drv) { 85 | ops->ops_type = type; 86 | ops->fd = fd; 87 | ops->arg0 = arg0; 88 | ops->arg1 = arg1; 89 | ops->buf = buf; 90 | ops->driver = drv; 91 | } 92 | 93 | // implementation of APIs 94 | int __coroc_vfs_open(coroc_vfs_driver_t drv, bool sync, const char *name, int flags, 95 | ...) { 96 | va_list ap; 97 | mode_t mode = 0644; 98 | 99 | if (drv == NULL) drv = &coroc_vfs_file_drv; 100 | 101 | if (flags & O_CREAT) { 102 | va_start(ap, flags); 103 | #ifdef __APPLE__ 104 | // FIXME: it is a BUG that mode_t in OS X is defned as a unsigned short, 105 | // which cannot be supported by var_arg in OS X, so we can only pass a int.. 106 | mode = (mode_t)va_arg(ap, int); 107 | #else 108 | mode = va_arg(ap, mode_t); 109 | #endif 110 | va_end(ap); 111 | } 112 | 113 | if (sync) return drv->open(name, flags, mode); 114 | 115 | coroc_vfs_ops ops; 116 | __coroc_vfs_init_ops(&ops, TSC_VFS_OPEN, 0, flags, mode, (void *)name, drv); 117 | 118 | // this call will suspend currrent thread .. 119 | __coroc_vfs_add_ops(&ops); 120 | 121 | // wake up .. 122 | return (int)(ops.arg0); 123 | } 124 | 125 | int __coroc_vfs_close(coroc_vfs_driver_t drv, bool sync, int fd) { 126 | if (drv == NULL) drv = &coroc_vfs_file_drv; 127 | 128 | if (sync) return drv->close(fd); 129 | 130 | coroc_vfs_ops ops; 131 | __coroc_vfs_init_ops(&ops, TSC_VFS_CLOSE, fd, 0, 0, NULL, drv); 132 | 133 | // this call will suspend currrent thread .. 134 | __coroc_vfs_add_ops(&ops); 135 | 136 | // wake up .. 137 | return (int)(ops.arg0); 138 | } 139 | 140 | void __coroc_vfs_flush(coroc_vfs_driver_t drv, bool sync, int fd) { 141 | if (drv == NULL) drv = &coroc_vfs_file_drv; 142 | 143 | if (sync && drv->flush) return drv->flush(fd); 144 | 145 | coroc_vfs_ops ops; 146 | __coroc_vfs_init_ops(&ops, TSC_VFS_FLUSH, fd, 0, 0, NULL, drv); 147 | 148 | // this call will suspend currrent thread .. 149 | __coroc_vfs_add_ops(&ops); 150 | 151 | // wake up .. 152 | return; 153 | } 154 | 155 | ssize_t __coroc_vfs_read(coroc_vfs_driver_t drv, bool sync, int fd, void *buf, 156 | size_t size) { 157 | if (drv == NULL) drv = &coroc_vfs_file_drv; 158 | 159 | if (sync) return drv->read(fd, buf, size); 160 | 161 | coroc_vfs_ops ops; 162 | __coroc_vfs_init_ops(&ops, TSC_VFS_READ, fd, size, 0, buf, drv); 163 | 164 | __coroc_vfs_add_ops(&ops); 165 | 166 | return (ssize_t)(ops.arg0); 167 | } 168 | 169 | ssize_t __coroc_vfs_write(coroc_vfs_driver_t drv, bool sync, int fd, 170 | const void *buf, size_t size) { 171 | if (drv == NULL) drv = &coroc_vfs_file_drv; 172 | 173 | if (sync) return drv->write(fd, buf, size); 174 | 175 | coroc_vfs_ops ops; 176 | __coroc_vfs_init_ops(&ops, TSC_VFS_WRITE, fd, size, 0, (void *)buf, drv); 177 | 178 | __coroc_vfs_add_ops(&ops); 179 | 180 | return (ssize_t)(ops.arg0); 181 | } 182 | 183 | off_t __coroc_vfs_lseek(coroc_vfs_driver_t drv, bool sync, int fd, off_t offset, 184 | int whence) { 185 | if (drv == NULL) drv = &coroc_vfs_file_drv; 186 | 187 | if (sync) { 188 | if (drv->lseek == NULL) return -1; 189 | return drv->lseek(fd, offset, whence); 190 | } 191 | 192 | coroc_vfs_ops ops; 193 | __coroc_vfs_init_ops(&ops, TSC_VFS_LSEEK, fd, offset, whence, NULL, drv); 194 | 195 | __coroc_vfs_add_ops(&ops); 196 | 197 | return (off_t)(ops.arg0); 198 | } 199 | 200 | int __coroc_vfs_ioctl(coroc_vfs_driver_t drv, bool sync, int fd, int cmd, ...) { 201 | va_list ap; 202 | int option; 203 | 204 | if (drv == NULL) drv = &coroc_vfs_file_drv; 205 | 206 | va_start(ap, cmd); 207 | option = va_arg(ap, int); 208 | va_end(ap); 209 | 210 | if (sync) { 211 | if (drv->ioctl == NULL) return -1; 212 | return drv->ioctl(fd, cmd, option); 213 | } 214 | 215 | coroc_vfs_ops ops; 216 | __coroc_vfs_init_ops(&ops, TSC_VFS_IOCTL, fd, cmd, option, NULL, drv); 217 | 218 | __coroc_vfs_add_ops(&ops); 219 | 220 | return (int)(ops.arg0); 221 | } 222 | --------------------------------------------------------------------------------