Initial import of coiopp
coiopp grew out of coio library
This commit is contained in:
commit
c925553326
30
CMakeLists.txt
Normal file
30
CMakeLists.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
cmake_minimum_required(VERSION 3.7)
|
||||
project(coiopp)
|
||||
|
||||
add_library(${PROJECT_NAME}
|
||||
libco/libco.c
|
||||
coio.cpp
|
||||
coio_glib.cpp)
|
||||
|
||||
add_custom_target(${PROJECT_NAME}_files SOURCES coioimpl.h)
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
C_STANDARD 99
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -W -Wall -Wextra -Werror)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GLIB2 REQUIRED glib-2.0)
|
||||
pkg_check_modules(GIO2 REQUIRED gio-2.0)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${GLIB2_INCLUDE_DIRS})
|
||||
target_link_libraries(${PROJECT_NAME} ${GLIB2_LIBRARIES})
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${GIO2_INCLUDE_DIRS})
|
||||
target_link_libraries(${PROJECT_NAME} ${GIO2_LIBRARIES})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} m)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC .)
|
13
COPYRIGHT
Normal file
13
COPYRIGHT
Normal file
|
@ -0,0 +1,13 @@
|
|||
Copyright (c) 2015 Moritz Bitsch <moritzbitsch@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
318
Makefile
Normal file
318
Makefile
Normal file
|
@ -0,0 +1,318 @@
|
|||
# CMAKE generated file: DO NOT EDIT!
|
||||
# Generated by "Unix Makefiles" Generator, CMake Version 3.16
|
||||
|
||||
# Default target executed when no arguments are given to make.
|
||||
default_target: all
|
||||
|
||||
.PHONY : default_target
|
||||
|
||||
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
|
||||
.NOTPARALLEL:
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Special targets provided by cmake.
|
||||
|
||||
# Disable implicit rules so canonical targets will work.
|
||||
.SUFFIXES:
|
||||
|
||||
|
||||
# Remove some rules from gmake that .SUFFIXES does not remove.
|
||||
SUFFIXES =
|
||||
|
||||
.SUFFIXES: .hpux_make_needs_suffix_list
|
||||
|
||||
|
||||
# Suppress display of executed commands.
|
||||
$(VERBOSE).SILENT:
|
||||
|
||||
|
||||
# A target that is always out of date.
|
||||
cmake_force:
|
||||
|
||||
.PHONY : cmake_force
|
||||
|
||||
#=============================================================================
|
||||
# Set environment variables for the build.
|
||||
|
||||
# The shell in which to execute make rules.
|
||||
SHELL = /bin/sh
|
||||
|
||||
# The CMake executable.
|
||||
CMAKE_COMMAND = /usr/bin/cmake
|
||||
|
||||
# The command to remove a file.
|
||||
RM = /usr/bin/cmake -E remove -f
|
||||
|
||||
# Escaping for special characters.
|
||||
EQUALS = =
|
||||
|
||||
# The top-level source directory on which CMake was run.
|
||||
CMAKE_SOURCE_DIR = /home/moritzbitsch/Repository/Work/commhandler
|
||||
|
||||
# The top-level build directory on which CMake was run.
|
||||
CMAKE_BINARY_DIR = /home/moritzbitsch/Repository/Work/commhandler
|
||||
|
||||
#=============================================================================
|
||||
# Targets provided globally by CMake.
|
||||
|
||||
# Special rule for the target install/strip
|
||||
install/strip: preinstall
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
|
||||
/usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
|
||||
.PHONY : install/strip
|
||||
|
||||
# Special rule for the target install/strip
|
||||
install/strip/fast: preinstall/fast
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
|
||||
/usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
|
||||
.PHONY : install/strip/fast
|
||||
|
||||
# Special rule for the target install/local
|
||||
install/local: preinstall
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
|
||||
/usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
|
||||
.PHONY : install/local
|
||||
|
||||
# Special rule for the target install/local
|
||||
install/local/fast: preinstall/fast
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
|
||||
/usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
|
||||
.PHONY : install/local/fast
|
||||
|
||||
# Special rule for the target install
|
||||
install: preinstall
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
|
||||
/usr/bin/cmake -P cmake_install.cmake
|
||||
.PHONY : install
|
||||
|
||||
# Special rule for the target install
|
||||
install/fast: preinstall/fast
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
|
||||
/usr/bin/cmake -P cmake_install.cmake
|
||||
.PHONY : install/fast
|
||||
|
||||
# Special rule for the target list_install_components
|
||||
list_install_components:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\""
|
||||
.PHONY : list_install_components
|
||||
|
||||
# Special rule for the target list_install_components
|
||||
list_install_components/fast: list_install_components
|
||||
|
||||
.PHONY : list_install_components/fast
|
||||
|
||||
# Special rule for the target edit_cache
|
||||
edit_cache:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..."
|
||||
/usr/bin/ccmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
|
||||
.PHONY : edit_cache
|
||||
|
||||
# Special rule for the target edit_cache
|
||||
edit_cache/fast: edit_cache
|
||||
|
||||
.PHONY : edit_cache/fast
|
||||
|
||||
# Special rule for the target test
|
||||
test:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..."
|
||||
/usr/bin/ctest --force-new-ctest-process $(ARGS)
|
||||
.PHONY : test
|
||||
|
||||
# Special rule for the target test
|
||||
test/fast: test
|
||||
|
||||
.PHONY : test/fast
|
||||
|
||||
# Special rule for the target rebuild_cache
|
||||
rebuild_cache:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
|
||||
/usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
|
||||
.PHONY : rebuild_cache
|
||||
|
||||
# Special rule for the target rebuild_cache
|
||||
rebuild_cache/fast: rebuild_cache
|
||||
|
||||
.PHONY : rebuild_cache/fast
|
||||
|
||||
# The main all target
|
||||
all: cmake_check_build_system
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(CMAKE_COMMAND) -E cmake_progress_start /home/moritzbitsch/Repository/Work/commhandler/CMakeFiles /home/moritzbitsch/Repository/Work/commhandler/lib/coiopp/CMakeFiles/progress.marks
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f CMakeFiles/Makefile2 lib/coiopp/all
|
||||
$(CMAKE_COMMAND) -E cmake_progress_start /home/moritzbitsch/Repository/Work/commhandler/CMakeFiles 0
|
||||
.PHONY : all
|
||||
|
||||
# The main clean target
|
||||
clean:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f CMakeFiles/Makefile2 lib/coiopp/clean
|
||||
.PHONY : clean
|
||||
|
||||
# The main clean target
|
||||
clean/fast: clean
|
||||
|
||||
.PHONY : clean/fast
|
||||
|
||||
# Prepare targets for installation.
|
||||
preinstall: all
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f CMakeFiles/Makefile2 lib/coiopp/preinstall
|
||||
.PHONY : preinstall
|
||||
|
||||
# Prepare targets for installation.
|
||||
preinstall/fast:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f CMakeFiles/Makefile2 lib/coiopp/preinstall
|
||||
.PHONY : preinstall/fast
|
||||
|
||||
# clear depends
|
||||
depend:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
|
||||
.PHONY : depend
|
||||
|
||||
# Convenience name for target.
|
||||
lib/coiopp/CMakeFiles/coiopp_files.dir/rule:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f CMakeFiles/Makefile2 lib/coiopp/CMakeFiles/coiopp_files.dir/rule
|
||||
.PHONY : lib/coiopp/CMakeFiles/coiopp_files.dir/rule
|
||||
|
||||
# Convenience name for target.
|
||||
coiopp_files: lib/coiopp/CMakeFiles/coiopp_files.dir/rule
|
||||
|
||||
.PHONY : coiopp_files
|
||||
|
||||
# fast build rule for target.
|
||||
coiopp_files/fast:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp_files.dir/build.make lib/coiopp/CMakeFiles/coiopp_files.dir/build
|
||||
.PHONY : coiopp_files/fast
|
||||
|
||||
# Convenience name for target.
|
||||
lib/coiopp/CMakeFiles/coiopp.dir/rule:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f CMakeFiles/Makefile2 lib/coiopp/CMakeFiles/coiopp.dir/rule
|
||||
.PHONY : lib/coiopp/CMakeFiles/coiopp.dir/rule
|
||||
|
||||
# Convenience name for target.
|
||||
coiopp: lib/coiopp/CMakeFiles/coiopp.dir/rule
|
||||
|
||||
.PHONY : coiopp
|
||||
|
||||
# fast build rule for target.
|
||||
coiopp/fast:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/build
|
||||
.PHONY : coiopp/fast
|
||||
|
||||
coio.o: coio.cpp.o
|
||||
|
||||
.PHONY : coio.o
|
||||
|
||||
# target to build an object file
|
||||
coio.cpp.o:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/coio.cpp.o
|
||||
.PHONY : coio.cpp.o
|
||||
|
||||
coio.i: coio.cpp.i
|
||||
|
||||
.PHONY : coio.i
|
||||
|
||||
# target to preprocess a source file
|
||||
coio.cpp.i:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/coio.cpp.i
|
||||
.PHONY : coio.cpp.i
|
||||
|
||||
coio.s: coio.cpp.s
|
||||
|
||||
.PHONY : coio.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
coio.cpp.s:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/coio.cpp.s
|
||||
.PHONY : coio.cpp.s
|
||||
|
||||
coio_glib.o: coio_glib.cpp.o
|
||||
|
||||
.PHONY : coio_glib.o
|
||||
|
||||
# target to build an object file
|
||||
coio_glib.cpp.o:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/coio_glib.cpp.o
|
||||
.PHONY : coio_glib.cpp.o
|
||||
|
||||
coio_glib.i: coio_glib.cpp.i
|
||||
|
||||
.PHONY : coio_glib.i
|
||||
|
||||
# target to preprocess a source file
|
||||
coio_glib.cpp.i:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/coio_glib.cpp.i
|
||||
.PHONY : coio_glib.cpp.i
|
||||
|
||||
coio_glib.s: coio_glib.cpp.s
|
||||
|
||||
.PHONY : coio_glib.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
coio_glib.cpp.s:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/coio_glib.cpp.s
|
||||
.PHONY : coio_glib.cpp.s
|
||||
|
||||
libco/libco.o: libco/libco.c.o
|
||||
|
||||
.PHONY : libco/libco.o
|
||||
|
||||
# target to build an object file
|
||||
libco/libco.c.o:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/libco/libco.c.o
|
||||
.PHONY : libco/libco.c.o
|
||||
|
||||
libco/libco.i: libco/libco.c.i
|
||||
|
||||
.PHONY : libco/libco.i
|
||||
|
||||
# target to preprocess a source file
|
||||
libco/libco.c.i:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/libco/libco.c.i
|
||||
.PHONY : libco/libco.c.i
|
||||
|
||||
libco/libco.s: libco/libco.c.s
|
||||
|
||||
.PHONY : libco/libco.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
libco/libco.c.s:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(MAKE) -f lib/coiopp/CMakeFiles/coiopp.dir/build.make lib/coiopp/CMakeFiles/coiopp.dir/libco/libco.c.s
|
||||
.PHONY : libco/libco.c.s
|
||||
|
||||
# Help Target
|
||||
help:
|
||||
@echo "The following are some of the valid targets for this Makefile:"
|
||||
@echo "... all (the default if no target is provided)"
|
||||
@echo "... clean"
|
||||
@echo "... depend"
|
||||
@echo "... install/strip"
|
||||
@echo "... install/local"
|
||||
@echo "... install"
|
||||
@echo "... list_install_components"
|
||||
@echo "... coiopp_files"
|
||||
@echo "... coiopp"
|
||||
@echo "... edit_cache"
|
||||
@echo "... test"
|
||||
@echo "... rebuild_cache"
|
||||
@echo "... coio.o"
|
||||
@echo "... coio.i"
|
||||
@echo "... coio.s"
|
||||
@echo "... coio_glib.o"
|
||||
@echo "... coio_glib.i"
|
||||
@echo "... coio_glib.s"
|
||||
@echo "... libco/libco.o"
|
||||
@echo "... libco/libco.i"
|
||||
@echo "... libco/libco.s"
|
||||
.PHONY : help
|
||||
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Special targets to cleanup operation of make.
|
||||
|
||||
# Special rule to run CMake to check the build system integrity.
|
||||
# No rule that depends on this can have commands that come from listfiles
|
||||
# because they might be regenerated.
|
||||
cmake_check_build_system:
|
||||
cd /home/moritzbitsch/Repository/Work/commhandler && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
|
||||
.PHONY : cmake_check_build_system
|
||||
|
10
README.md
Normal file
10
README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# libcoio
|
||||
a clean, minimal, portable coroutine library
|
||||
|
||||
## Compiling
|
||||
Just run 'make' in the project dir
|
||||
|
||||
## License
|
||||
ISC License except where otherwise noted.
|
||||
|
||||
BSD-Style/GPL for coro.c/.h
|
320
coio.cpp
Normal file
320
coio.cpp
Normal file
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Moritz Bitsch <moritzbitsch@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "coioimpl.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
CoioTaskList coio_ready_list = { 0, 0 };
|
||||
CoioTaskList coio_sleeping = { 0, 0 };
|
||||
cothread_t coio_sched_ctx;
|
||||
CoioTask* coio_current = NULL;
|
||||
unsigned long coio_taskcount = 0;
|
||||
|
||||
static int
|
||||
msleep(uvlong ms)
|
||||
{
|
||||
struct timespec req, rem;
|
||||
|
||||
if (ms > 999) {
|
||||
req.tv_sec = (int)(ms / 1000);
|
||||
req.tv_nsec = (ms - ((long)req.tv_sec * 1000)) * 1000000;
|
||||
}
|
||||
else {
|
||||
req.tv_sec = 0;
|
||||
req.tv_nsec = ms * 1000000;
|
||||
}
|
||||
|
||||
return nanosleep(&req, &rem);
|
||||
}
|
||||
|
||||
static void
|
||||
_process_events()
|
||||
{
|
||||
uvlong now;
|
||||
int ms = 5;
|
||||
CoioTask* t;
|
||||
|
||||
if ((t = coio_sleeping.head) != NULL && t->timeout != 0) {
|
||||
now = coio_now();
|
||||
if (now >= t->timeout) {
|
||||
ms = 0;
|
||||
}
|
||||
else {
|
||||
ms = (t->timeout - now);
|
||||
}
|
||||
}
|
||||
/* TODO:do I/O polling instead of usleep */
|
||||
msleep(ms);
|
||||
|
||||
/* handle CLOCK_MONOTONIC bugs (VirtualBox anyone?) */
|
||||
while (!coio_ready_list.head) {
|
||||
/* wake up timed out tasks */
|
||||
now = coio_now();
|
||||
while ((t = coio_sleeping.head) && t->timeout && now >= t->timeout) {
|
||||
coio_ready(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
coio_main()
|
||||
{
|
||||
/* initialize empty ctx for scheduler */
|
||||
coio_sched_ctx = co_active();
|
||||
|
||||
/* scheduler mainloop */
|
||||
for (;;) {
|
||||
if (!coio_ready_list.head && coio_sleeping.head)
|
||||
_process_events();
|
||||
|
||||
if (!coio_ready_list.head)
|
||||
break;
|
||||
|
||||
coio_current = coio_ready_list.head;
|
||||
coio_current->ready = 0;
|
||||
coio_del(&coio_ready_list, coio_current);
|
||||
co_switch(coio_current->ctx);
|
||||
|
||||
if (coio_current->eptr) {
|
||||
std::rethrow_exception(coio_current->eptr);
|
||||
}
|
||||
|
||||
if (coio_current->done) {
|
||||
coio_taskcount--;
|
||||
co_delete(coio_current->ctx);
|
||||
delete coio_current;
|
||||
}
|
||||
coio_current = nullptr;
|
||||
}
|
||||
|
||||
if (coio_taskcount) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CoioTask* construction_task = nullptr;
|
||||
|
||||
int
|
||||
coio_create(const char* name, coio_func f, unsigned int stacksize)
|
||||
{
|
||||
CoioTask* task;
|
||||
|
||||
task = new CoioTask();
|
||||
if (!task)
|
||||
return -1;
|
||||
|
||||
task->name = name;
|
||||
task->func = f;
|
||||
|
||||
construction_task = task;
|
||||
|
||||
task->ctx = co_create(stacksize, []() {
|
||||
auto task = construction_task;
|
||||
co_switch(coio_sched_ctx);
|
||||
try {
|
||||
task->func();
|
||||
} catch (...) {
|
||||
task->eptr = std::current_exception();
|
||||
}
|
||||
task->done = 1;
|
||||
co_switch(coio_sched_ctx);
|
||||
});
|
||||
|
||||
co_switch(task->ctx);
|
||||
|
||||
coio_add(&coio_ready_list, task);
|
||||
coio_taskcount++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uvlong
|
||||
coio_timeout(CoioTask* task, int ms)
|
||||
{
|
||||
CoioTask* t;
|
||||
|
||||
if (ms >= 0) {
|
||||
task->timeout = coio_now() + ms;
|
||||
for (t = coio_sleeping.head;
|
||||
t != NULL && t->timeout && t->timeout < task->timeout;
|
||||
t = t->next)
|
||||
;
|
||||
}
|
||||
else {
|
||||
task->timeout = 0;
|
||||
t = NULL;
|
||||
}
|
||||
|
||||
if (t) {
|
||||
task->prev = t->prev;
|
||||
task->next = t;
|
||||
}
|
||||
else {
|
||||
task->prev = coio_sleeping.tail;
|
||||
task->next = NULL;
|
||||
}
|
||||
|
||||
t = coio_current;
|
||||
|
||||
if (t->prev) {
|
||||
t->prev->next = t;
|
||||
}
|
||||
else {
|
||||
coio_sleeping.head = t;
|
||||
}
|
||||
|
||||
if (t->next) {
|
||||
t->next->prev = t;
|
||||
}
|
||||
else {
|
||||
coio_sleeping.tail = t;
|
||||
}
|
||||
|
||||
return task->timeout;
|
||||
}
|
||||
|
||||
int
|
||||
coio_delay(int ms)
|
||||
{
|
||||
uvlong when;
|
||||
when = coio_timeout(coio_current, ms);
|
||||
coio_transfer();
|
||||
return (coio_now() - when);
|
||||
}
|
||||
|
||||
void
|
||||
coio_yield()
|
||||
{
|
||||
coio_ready(coio_current);
|
||||
coio_transfer();
|
||||
}
|
||||
|
||||
void
|
||||
coio_add(CoioTaskList* lst, CoioTask* task)
|
||||
{
|
||||
if (lst->tail) {
|
||||
lst->tail->next = task;
|
||||
task->prev = lst->tail;
|
||||
}
|
||||
else {
|
||||
lst->head = task;
|
||||
task->prev = NULL;
|
||||
}
|
||||
lst->tail = task;
|
||||
task->next = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
coio_del(CoioTaskList* lst, CoioTask* task)
|
||||
{
|
||||
if (task->prev) {
|
||||
task->prev->next = task->next;
|
||||
}
|
||||
else if (lst->head == task) {
|
||||
lst->head = task->next;
|
||||
}
|
||||
|
||||
if (task->next) {
|
||||
task->next->prev = task->prev;
|
||||
}
|
||||
else if (lst->tail == task) {
|
||||
lst->tail = task->prev;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
coio_ready(CoioTask* task)
|
||||
{
|
||||
task->timeout = 0;
|
||||
if (!task->ready) {
|
||||
task->ready = 1;
|
||||
coio_del(&coio_sleeping, task);
|
||||
coio_add(&coio_ready_list, task);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
coio_transfer()
|
||||
{
|
||||
co_switch(coio_sched_ctx);
|
||||
}
|
||||
|
||||
uvlong
|
||||
coio_now()
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t ts;
|
||||
|
||||
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
||||
clock_get_time(cclock, &ts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
#else
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return (uvlong)ts.tv_sec * 1000 + round(ts.tv_nsec / 1000000.0);
|
||||
}
|
||||
|
||||
void
|
||||
coio_debug()
|
||||
{
|
||||
CoioTask* t;
|
||||
|
||||
fprintf(stderr, ">>>\nCurrent tasks: %s\n", coio_current->name);
|
||||
|
||||
fprintf(stderr, "Sleeping tasks: ");
|
||||
for (t = coio_sleeping.head; t != NULL; t = t->next) {
|
||||
fprintf(stderr, "%s ", t->name);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\nReady tasks: ");
|
||||
for (t = coio_ready_list.head; t != NULL; t = t->next) {
|
||||
fprintf(stderr, "%s ", t->name);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
bool
|
||||
coio_active()
|
||||
{
|
||||
return coio_current != nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
coio_active_throw()
|
||||
{
|
||||
if (!coio_active()) {
|
||||
throw std::logic_error("Not inside coroutine");
|
||||
}
|
||||
}
|
45
coio.h
Normal file
45
coio.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Moritz Bitsch <moritzbitsch@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef COIO_H
|
||||
#define COIO_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
typedef struct CoioTask CoioTask;
|
||||
typedef std::function<void()> coio_func;
|
||||
|
||||
typedef unsigned long long uvlong;
|
||||
|
||||
extern CoioTask* coio_current;
|
||||
|
||||
int
|
||||
coio_main();
|
||||
int
|
||||
coio_create(const char* name, coio_func f, unsigned int stacksize);
|
||||
void
|
||||
coio_yield();
|
||||
uvlong
|
||||
coio_now();
|
||||
int
|
||||
coio_delay(int ms);
|
||||
void
|
||||
coio_ready(CoioTask* task);
|
||||
bool
|
||||
coio_active();
|
||||
void
|
||||
coio_active_throw();
|
||||
|
||||
#endif
|
150
coio_glib.cpp
Normal file
150
coio_glib.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Moritz Bitsch <moritzbitsch@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "coio_glib.h"
|
||||
#include "coio.h"
|
||||
#include "coioimpl.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
|
||||
struct coio_source
|
||||
{
|
||||
GSource base;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
coio_source_prepare(GSource* source, gint* timeout_)
|
||||
{
|
||||
(void)source;
|
||||
uvlong now;
|
||||
int ms = -1;
|
||||
CoioTask* t;
|
||||
|
||||
if (coio_ready_list.head) {
|
||||
*timeout_ = 0;
|
||||
|
||||
/* if we return true here our check functions do not get called */
|
||||
if (coio_sleeping.head) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ((t = coio_sleeping.head) != NULL && t->timeout != 0) {
|
||||
now = coio_now();
|
||||
if (now >= t->timeout) {
|
||||
ms = 0;
|
||||
}
|
||||
else {
|
||||
ms = (t->timeout - now);
|
||||
}
|
||||
}
|
||||
|
||||
*timeout_ = ms;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
coio_source_check(GSource* source)
|
||||
{
|
||||
(void)source;
|
||||
CoioTask* t;
|
||||
|
||||
if (coio_sleeping.head) {
|
||||
/* wake up timed out tasks */
|
||||
uvlong now = coio_now();
|
||||
while ((t = coio_sleeping.head) && t->timeout && now >= t->timeout) {
|
||||
coio_ready(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (coio_ready_list.head)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
coio_source_dispatch(GSource* source, GSourceFunc callback, gpointer user_data)
|
||||
{
|
||||
(void)source;
|
||||
CoioTask* last;
|
||||
gboolean result = G_SOURCE_CONTINUE;
|
||||
|
||||
if (!coio_ready_list.head)
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
last = coio_ready_list.tail;
|
||||
|
||||
do {
|
||||
coio_current = coio_ready_list.head;
|
||||
coio_current->ready = 0;
|
||||
coio_del(&coio_ready_list, coio_current);
|
||||
co_switch(coio_current->ctx);
|
||||
|
||||
/* glib is C, don't let the exception go wild */
|
||||
try {
|
||||
if (coio_current->eptr) {
|
||||
std::rethrow_exception(coio_current->eptr);
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Exception in coroutine " << coio_current->name << ": "
|
||||
<< ex.what() << std::endl;
|
||||
} catch (...) {
|
||||
std::cerr << "Unknown exception in coroutine " << coio_current->name
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if (coio_current->done) {
|
||||
coio_taskcount--;
|
||||
co_delete(coio_current->ctx);
|
||||
delete coio_current;
|
||||
}
|
||||
} while (coio_current != last);
|
||||
|
||||
coio_current = NULL;
|
||||
|
||||
if (callback) {
|
||||
result = callback(user_data);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
coio_source_finalize(GSource* source)
|
||||
{
|
||||
(void)source;
|
||||
}
|
||||
|
||||
GSource*
|
||||
coio_gsource_create()
|
||||
{
|
||||
coio_sched_ctx = co_active();
|
||||
|
||||
static GSourceFuncs funcs = { coio_source_prepare,
|
||||
coio_source_check,
|
||||
coio_source_dispatch,
|
||||
coio_source_finalize,
|
||||
NULL,
|
||||
NULL };
|
||||
|
||||
return g_source_new(&funcs, sizeof(struct coio_source));
|
||||
}
|
26
coio_glib.h
Normal file
26
coio_glib.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Moritz Bitsch <moritzbitsch@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef COIO_GLIB_H
|
||||
#define COIO_GLIB_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
#include "coio.h"
|
||||
|
||||
GSource* coio_gsource_create();
|
||||
|
||||
#endif
|
64
coioimpl.h
Normal file
64
coioimpl.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Moritz Bitsch <moritzbitsch@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef COIOIMPL_H
|
||||
#define COIOIMPL_H
|
||||
|
||||
#include "coio.h"
|
||||
#include "libco/libco.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
typedef struct CoioTaskList CoioTaskList;
|
||||
|
||||
struct CoioTask
|
||||
{
|
||||
cothread_t ctx;
|
||||
|
||||
const char* name;
|
||||
coio_func func;
|
||||
|
||||
uvlong timeout;
|
||||
int ready;
|
||||
int done;
|
||||
|
||||
std::exception_ptr eptr;
|
||||
|
||||
/* linked list support */
|
||||
CoioTask* next;
|
||||
CoioTask* prev;
|
||||
};
|
||||
|
||||
struct CoioTaskList
|
||||
{
|
||||
CoioTask* head;
|
||||
CoioTask* tail;
|
||||
};
|
||||
|
||||
extern CoioTaskList coio_ready_list;
|
||||
extern CoioTaskList coio_sleeping;
|
||||
extern cothread_t coio_sched_ctx;
|
||||
extern unsigned long coio_taskcount;
|
||||
|
||||
void
|
||||
coio_add(CoioTaskList* lst, CoioTask* task);
|
||||
void
|
||||
coio_del(CoioTaskList* lst, CoioTask* task);
|
||||
void
|
||||
coio_transfer();
|
||||
void
|
||||
coio_debug();
|
||||
|
||||
#endif
|
107
libco/aarch64.c
Normal file
107
libco/aarch64.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local unsigned long co_active_buffer[64];
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
static void (*co_swap)(cothread_t, cothread_t) = 0;
|
||||
|
||||
#ifdef LIBCO_MPROTECT
|
||||
alignas(4096)
|
||||
#else
|
||||
section(text)
|
||||
#endif
|
||||
static const uint32_t co_swap_function[1024] = {
|
||||
0xa9002428, /* stp x8,x9,[x1] */
|
||||
0xa9012c2a, /* stp x10,x11,[x1,#16] */
|
||||
0xa902342c, /* stp x12,x13,[x1,#32] */
|
||||
0xa9033c2e, /* stp x14,x15,[x1,#48] */
|
||||
0xf9002433, /* str x19,[x1,#72] */
|
||||
0xa9055434, /* stp x20,x21,[x1,#80] */
|
||||
0xa9065c36, /* stp x22,x23,[x1,#96] */
|
||||
0xa9076438, /* stp x24,x25,[x1,#112] */
|
||||
0xa9086c3a, /* stp x26,x27,[x1,#128] */
|
||||
0xa909743c, /* stp x28,x29,[x1,#144] */
|
||||
0x910003f0, /* mov x16,sp */
|
||||
0xa90a7830, /* stp x16,x30,[x1,#160] */
|
||||
|
||||
0xa9402408, /* ldp x8,x9,[x0] */
|
||||
0xa9412c0a, /* ldp x10,x11,[x0,#16] */
|
||||
0xa942340c, /* ldp x12,x13,[x0,#32] */
|
||||
0xa9433c0e, /* ldp x14,x15,[x0,#48] */
|
||||
0xf9402413, /* ldr x19,[x0,#72] */
|
||||
0xa9455414, /* ldp x20,x21,[x0,#80] */
|
||||
0xa9465c16, /* ldp x22,x23,[x0,#96] */
|
||||
0xa9476418, /* ldp x24,x25,[x0,#112] */
|
||||
0xa9486c1a, /* ldp x26,x27,[x0,#128] */
|
||||
0xa949741c, /* ldp x28,x29,[x0,#144] */
|
||||
0xa94a4410, /* ldp x16,x17,[x0,#160] */
|
||||
0x9100021f, /* mov sp,x16 */
|
||||
0xd61f0220, /* br x17 */
|
||||
};
|
||||
|
||||
static void co_init() {
|
||||
#ifdef LIBCO_MPROTECT
|
||||
unsigned long addr = (unsigned long)co_swap_function;
|
||||
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
|
||||
unsigned long size = (addr - base) + sizeof co_swap_function;
|
||||
mprotect((void*)base, size, PROT_READ | PROT_EXEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) {
|
||||
unsigned long* handle;
|
||||
if(!co_swap) {
|
||||
co_init();
|
||||
co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
|
||||
}
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
|
||||
if(handle = (unsigned long*)memory) {
|
||||
unsigned int offset = (size & ~15);
|
||||
unsigned long* p = (unsigned long*)((unsigned char*)handle + offset);
|
||||
handle[19] = (unsigned long)p; /* x29 (frame pointer) */
|
||||
handle[20] = (unsigned long)p; /* x30 (stack pointer) */
|
||||
handle[21] = (unsigned long)entrypoint; /* x31 (link register) */
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
|
||||
void* memory = malloc(size);
|
||||
if(!memory) return (cothread_t)0;
|
||||
return co_derive(memory, size, entrypoint);
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle) {
|
||||
cothread_t co_previous_handle = co_active_handle;
|
||||
co_swap(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
|
||||
int co_serializable() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
163
libco/amd64.c
Executable file
163
libco/amd64.c
Executable file
|
@ -0,0 +1,163 @@
|
|||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local long long co_active_buffer[64];
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
static void (*co_swap)(cothread_t, cothread_t) = 0;
|
||||
|
||||
#ifdef LIBCO_MPROTECT
|
||||
alignas(4096)
|
||||
#else
|
||||
section(text)
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
/* ABI: Win64 */
|
||||
static const unsigned char co_swap_function[4096] = {
|
||||
0x48, 0x89, 0x22, /* mov [rdx],rsp */
|
||||
0x48, 0x8b, 0x21, /* mov rsp,[rcx] */
|
||||
0x58, /* pop rax */
|
||||
0x48, 0x89, 0x6a, 0x08, /* mov [rdx+ 8],rbp */
|
||||
0x48, 0x89, 0x72, 0x10, /* mov [rdx+16],rsi */
|
||||
0x48, 0x89, 0x7a, 0x18, /* mov [rdx+24],rdi */
|
||||
0x48, 0x89, 0x5a, 0x20, /* mov [rdx+32],rbx */
|
||||
0x4c, 0x89, 0x62, 0x28, /* mov [rdx+40],r12 */
|
||||
0x4c, 0x89, 0x6a, 0x30, /* mov [rdx+48],r13 */
|
||||
0x4c, 0x89, 0x72, 0x38, /* mov [rdx+56],r14 */
|
||||
0x4c, 0x89, 0x7a, 0x40, /* mov [rdx+64],r15 */
|
||||
#if !defined(LIBCO_NO_SSE)
|
||||
0x0f, 0x29, 0x72, 0x50, /* movaps [rdx+ 80],xmm6 */
|
||||
0x0f, 0x29, 0x7a, 0x60, /* movaps [rdx+ 96],xmm7 */
|
||||
0x44, 0x0f, 0x29, 0x42, 0x70, /* movaps [rdx+112],xmm8 */
|
||||
0x48, 0x83, 0xc2, 0x70, /* add rdx,112 */
|
||||
0x44, 0x0f, 0x29, 0x4a, 0x10, /* movaps [rdx+ 16],xmm9 */
|
||||
0x44, 0x0f, 0x29, 0x52, 0x20, /* movaps [rdx+ 32],xmm10 */
|
||||
0x44, 0x0f, 0x29, 0x5a, 0x30, /* movaps [rdx+ 48],xmm11 */
|
||||
0x44, 0x0f, 0x29, 0x62, 0x40, /* movaps [rdx+ 64],xmm12 */
|
||||
0x44, 0x0f, 0x29, 0x6a, 0x50, /* movaps [rdx+ 80],xmm13 */
|
||||
0x44, 0x0f, 0x29, 0x72, 0x60, /* movaps [rdx+ 96],xmm14 */
|
||||
0x44, 0x0f, 0x29, 0x7a, 0x70, /* movaps [rdx+112],xmm15 */
|
||||
#endif
|
||||
0x48, 0x8b, 0x69, 0x08, /* mov rbp,[rcx+ 8] */
|
||||
0x48, 0x8b, 0x71, 0x10, /* mov rsi,[rcx+16] */
|
||||
0x48, 0x8b, 0x79, 0x18, /* mov rdi,[rcx+24] */
|
||||
0x48, 0x8b, 0x59, 0x20, /* mov rbx,[rcx+32] */
|
||||
0x4c, 0x8b, 0x61, 0x28, /* mov r12,[rcx+40] */
|
||||
0x4c, 0x8b, 0x69, 0x30, /* mov r13,[rcx+48] */
|
||||
0x4c, 0x8b, 0x71, 0x38, /* mov r14,[rcx+56] */
|
||||
0x4c, 0x8b, 0x79, 0x40, /* mov r15,[rcx+64] */
|
||||
#if !defined(LIBCO_NO_SSE)
|
||||
0x0f, 0x28, 0x71, 0x50, /* movaps xmm6, [rcx+ 80] */
|
||||
0x0f, 0x28, 0x79, 0x60, /* movaps xmm7, [rcx+ 96] */
|
||||
0x44, 0x0f, 0x28, 0x41, 0x70, /* movaps xmm8, [rcx+112] */
|
||||
0x48, 0x83, 0xc1, 0x70, /* add rcx,112 */
|
||||
0x44, 0x0f, 0x28, 0x49, 0x10, /* movaps xmm9, [rcx+ 16] */
|
||||
0x44, 0x0f, 0x28, 0x51, 0x20, /* movaps xmm10,[rcx+ 32] */
|
||||
0x44, 0x0f, 0x28, 0x59, 0x30, /* movaps xmm11,[rcx+ 48] */
|
||||
0x44, 0x0f, 0x28, 0x61, 0x40, /* movaps xmm12,[rcx+ 64] */
|
||||
0x44, 0x0f, 0x28, 0x69, 0x50, /* movaps xmm13,[rcx+ 80] */
|
||||
0x44, 0x0f, 0x28, 0x71, 0x60, /* movaps xmm14,[rcx+ 96] */
|
||||
0x44, 0x0f, 0x28, 0x79, 0x70, /* movaps xmm15,[rcx+112] */
|
||||
#endif
|
||||
0xff, 0xe0, /* jmp rax */
|
||||
};
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
static void co_init() {
|
||||
#ifdef LIBCO_MPROTECT
|
||||
DWORD old_privileges;
|
||||
VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
/* ABI: SystemV */
|
||||
static const unsigned char co_swap_function[4096] = {
|
||||
0x48, 0x89, 0x26, /* mov [rsi],rsp */
|
||||
0x48, 0x8b, 0x27, /* mov rsp,[rdi] */
|
||||
0x58, /* pop rax */
|
||||
0x48, 0x89, 0x6e, 0x08, /* mov [rsi+ 8],rbp */
|
||||
0x48, 0x89, 0x5e, 0x10, /* mov [rsi+16],rbx */
|
||||
0x4c, 0x89, 0x66, 0x18, /* mov [rsi+24],r12 */
|
||||
0x4c, 0x89, 0x6e, 0x20, /* mov [rsi+32],r13 */
|
||||
0x4c, 0x89, 0x76, 0x28, /* mov [rsi+40],r14 */
|
||||
0x4c, 0x89, 0x7e, 0x30, /* mov [rsi+48],r15 */
|
||||
0x48, 0x8b, 0x6f, 0x08, /* mov rbp,[rdi+ 8] */
|
||||
0x48, 0x8b, 0x5f, 0x10, /* mov rbx,[rdi+16] */
|
||||
0x4c, 0x8b, 0x67, 0x18, /* mov r12,[rdi+24] */
|
||||
0x4c, 0x8b, 0x6f, 0x20, /* mov r13,[rdi+32] */
|
||||
0x4c, 0x8b, 0x77, 0x28, /* mov r14,[rdi+40] */
|
||||
0x4c, 0x8b, 0x7f, 0x30, /* mov r15,[rdi+48] */
|
||||
0xff, 0xe0, /* jmp rax */
|
||||
};
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
static void co_init() {
|
||||
#ifdef LIBCO_MPROTECT
|
||||
unsigned long long addr = (unsigned long long)co_swap_function;
|
||||
unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
|
||||
unsigned long long size = (addr - base) + sizeof co_swap_function;
|
||||
mprotect((void*)base, size, PROT_READ | PROT_EXEC);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void crash() {
|
||||
assert(0); /* called only if cothread_t entrypoint returns */
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) {
|
||||
cothread_t handle;
|
||||
if(!co_swap) {
|
||||
co_init();
|
||||
co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
|
||||
}
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
|
||||
if((handle = (cothread_t)memory)) {
|
||||
unsigned int offset = (size & ~15) - 32;
|
||||
long long *p = (long long*)((char*)handle + offset); /* seek to top of stack */
|
||||
*--p = (long long)crash; /* crash if entrypoint returns */
|
||||
*--p = (long long)entrypoint; /* start of function */
|
||||
*(long long*)handle = (long long)p; /* stack pointer */
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
|
||||
void* memory = malloc(size);
|
||||
if(!memory) return (cothread_t)0;
|
||||
return co_derive(memory, size, entrypoint);
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle) {
|
||||
register cothread_t co_previous_handle = co_active_handle;
|
||||
co_swap(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
|
||||
int co_serializable() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
82
libco/arm.c
Normal file
82
libco/arm.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local unsigned long co_active_buffer[64];
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
static void (*co_swap)(cothread_t, cothread_t) = 0;
|
||||
|
||||
#ifdef LIBCO_MPROTECT
|
||||
alignas(4096)
|
||||
#else
|
||||
section(text)
|
||||
#endif
|
||||
static const unsigned long co_swap_function[1024] = {
|
||||
0xe8a16ff0, /* stmia r1!, {r4-r11,sp,lr} */
|
||||
0xe8b0aff0, /* ldmia r0!, {r4-r11,sp,pc} */
|
||||
0xe12fff1e, /* bx lr */
|
||||
};
|
||||
|
||||
static void co_init() {
|
||||
#ifdef LIBCO_MPROTECT
|
||||
unsigned long addr = (unsigned long)co_swap_function;
|
||||
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
|
||||
unsigned long size = (addr - base) + sizeof co_swap_function;
|
||||
mprotect((void*)base, size, PROT_READ | PROT_EXEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) {
|
||||
unsigned long* handle;
|
||||
if(!co_swap) {
|
||||
co_init();
|
||||
co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
|
||||
}
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
|
||||
if((handle = (unsigned long*)memory)) {
|
||||
unsigned int offset = (size & ~15);
|
||||
unsigned long* p = (unsigned long*)((unsigned char*)handle + offset);
|
||||
handle[8] = (unsigned long)p;
|
||||
handle[9] = (unsigned long)entrypoint;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
|
||||
void* memory = malloc(size);
|
||||
if(!memory) return (cothread_t)0;
|
||||
return co_derive(memory, size, entrypoint);
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle) {
|
||||
cothread_t co_previous_handle = co_active_handle;
|
||||
co_swap(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
|
||||
int co_serializable() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
12
libco/doc/style.css
Executable file
12
libco/doc/style.css
Executable file
|
@ -0,0 +1,12 @@
|
|||
body {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
code {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #aaf;
|
||||
}
|
89
libco/doc/targets.html
Executable file
89
libco/doc/targets.html
Executable file
|
@ -0,0 +1,89 @@
|
|||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<link href="style.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<b>Supported targets:</b><br/><br/>
|
||||
|
||||
Note that supported targets are only those that have been tested and confirmed
|
||||
working. It is quite possible that libco will work on more processors, compilers
|
||||
and operating systems than those listed below.
|
||||
<hr/>
|
||||
|
||||
<b>libco.x86</b><br/>
|
||||
Overhead: ~5x<br/>
|
||||
Supported processor(s): 32-bit x86<br/>
|
||||
Supported compiler(s): any<br/>
|
||||
Supported operating system(s):<ul>
|
||||
<li>Windows</li>
|
||||
<li>Mac OS X</li>
|
||||
<li>Linux</li>
|
||||
<li>BSD</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
|
||||
<b>libco.amd64</b><br/>
|
||||
Overhead: ~10x (Windows), ~6x (all other platforms)<br/>
|
||||
Supported processor(s): 64-bit amd64<br/>
|
||||
Supported compiler(s): any<br/>
|
||||
Supported operating system(s):<ul>
|
||||
<li>Windows</li>
|
||||
<li>Mac OS X</li>
|
||||
<li>Linux</li>
|
||||
<li>BSD</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
|
||||
<b>libco.ppc</b><br/>
|
||||
Overhead: ~20x<br/>
|
||||
Supported processor(s): 32-bit PowerPC, 64-bit PowerPC<br/>
|
||||
Supported compiler(s): GNU GCC<br/>
|
||||
Supported operating system(s):<ul>
|
||||
</ul>
|
||||
<li>Mac OS X</li>
|
||||
<li>Linux</li>
|
||||
<li>BSD</li>
|
||||
<li>Playstation 3</li>
|
||||
</ul>
|
||||
<br/>
|
||||
|
||||
Note: this module contains compiler flags to enable/disable FPU and Altivec
|
||||
support.
|
||||
|
||||
<hr/>
|
||||
|
||||
<b>libco.fiber</b><br/>
|
||||
Overhead: ~15x<br/>
|
||||
Supported processor(s): Processor independent<br/>
|
||||
Supported compiler(s): any<br/>
|
||||
Supported operating system(s):<ul>
|
||||
<li>Windows</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
|
||||
<b>libco.sjlj</b><br/>
|
||||
Overhead: ~30x<br/>
|
||||
Supported processor(s): Processor independent<br/>
|
||||
Supported compiler(s): any<br/>
|
||||
Supported operating system(s):<ul>
|
||||
<li>Mac OS X</li>
|
||||
<li>Linux</li>
|
||||
<li>BSD</li>
|
||||
<li>Solaris</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
|
||||
<b>libco.ucontext</b><br/>
|
||||
Overhead: <b><font color="#ff0000">~300x</font></b><br/>
|
||||
Supported processor(s): Processor independent<br/>
|
||||
Supported compiler(s): any<br/>
|
||||
Supported operating system(s):<ul>
|
||||
<li>Linux</li>
|
||||
<li>BSD</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
|
||||
</body>
|
||||
</html>
|
108
libco/doc/usage.html
Executable file
108
libco/doc/usage.html
Executable file
|
@ -0,0 +1,108 @@
|
|||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<link href="style.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<b>License:</b><br/><br/>
|
||||
libco is released under the ISC license.
|
||||
<hr/>
|
||||
|
||||
<b>Foreword:</b><br/><br/>
|
||||
libco is a cross-platform, permissively licensed implementation of
|
||||
cooperative-multithreading; a feature that is sorely lacking from the ISO C/C++
|
||||
standard.<br/>
|
||||
The library is designed for maximum speed and portability, and not for safety or
|
||||
features. If safety or extra functionality is desired, a wrapper API can easily
|
||||
be written to encapsulate all library functions.<br/>
|
||||
Behavior of executing operations that are listed as not permitted below result
|
||||
in undefined behavior. They may work anyway, they may cause undesired / unknown
|
||||
behavior, or they may crash the program entirely.<br/>
|
||||
The goal of this library was to simplify the base API as much as possible,
|
||||
implementing only that which cannot be implemented using pure C. Additional
|
||||
functionality after this would only complicate ports of this library to new
|
||||
platforms.
|
||||
<hr/>
|
||||
|
||||
<b>Porting:</b><br/><br/>
|
||||
This document is included as a reference for porting libco. Please submit any
|
||||
ports you create to me, so that libco can become more useful. Please note that
|
||||
since libco is permissively licensed, you must submit your code as a work of the
|
||||
public domain in order for it to be included in the official distribution.
|
||||
Full credit will be given in the source code of the official release. Please
|
||||
do not bother submitting code to me under any other license -- including GPL,
|
||||
LGPL, BSD or CC -- I am not interested in creating a library with multiple
|
||||
different licenses depending on which targets are used.
|
||||
<hr/>
|
||||
|
||||
<b>Synopsis:</b><br/><br/>
|
||||
<code>
|
||||
typedef void* cothread_t;<br/>
|
||||
<br/>
|
||||
cothread_t co_active();<br/>
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)(void));<br/>
|
||||
void co_delete(cothread_t cothread);<br/>
|
||||
void co_switch(cothread_t cothread);<br/>
|
||||
</code>
|
||||
<hr/>
|
||||
|
||||
<b>Usage:</b>
|
||||
<hr/>
|
||||
|
||||
<code>typedef void* cothread_t;</code><br/><br/>
|
||||
Handle to cothread.<br/>
|
||||
Handle must be of type void*.<br/>
|
||||
A value of null (0) indicates an uninitialized or invalid
|
||||
handle, whereas a non-zero value indicates a valid handle.
|
||||
<hr/>
|
||||
|
||||
<code>cothread_t co_active();</code><br/><br/>
|
||||
Return handle to current cothread. Always returns a valid handle, even when
|
||||
called from the main program thread.
|
||||
<hr/>
|
||||
|
||||
<code>cothread_t co_derive(void* memory, unsigned int heapsize, void (*coentry)(void));</code><br/><br/>
|
||||
Initializes new cothread.</br>
|
||||
This function is identical to co_create, only it attempts to use the provided
|
||||
memory instead of allocating new memory on the heap. Please note that certain
|
||||
implementations (currently only Windows Fibers) cannot be created using existing
|
||||
memory, and as such, this function will fail.
|
||||
<hr/>
|
||||
|
||||
<code>cothread_t co_create(unsigned int heapsize, void (*coentry)(void));</code><br/><br/>
|
||||
Create new cothread.<br/>
|
||||
Heapsize is the amount of memory allocated for the cothread stack, specified
|
||||
in bytes. This is unfortunately impossible to make fully portable. It is
|
||||
recommended to specify sizes using `n * sizeof(void*)'. It is better to err
|
||||
on the side of caution and allocate more memory than will be needed to ensure
|
||||
compatibility with other platforms, within reason. A typical heapsize for a
|
||||
32-bit architecture is ~1MB.<br/>
|
||||
When the new cothread is first called, program execution jumps to coentry.
|
||||
This function does not take any arguments, due to portability issues with
|
||||
passing function arguments. However, arguments can be simulated by the use
|
||||
of global variables, which can be set before the first call to each cothread.<br/>
|
||||
coentry() must not return, and should end with an appropriate co_switch()
|
||||
statement. Behavior is undefined if entry point returns normally.<br/>
|
||||
Library is responsible for allocating cothread stack memory, to free
|
||||
the user from needing to allocate special memory capable of being used
|
||||
as program stack memory on platforms where this is required.<br/>
|
||||
User is always responsible for deleting cothreads with co_delete().<br/>
|
||||
Return value of null (0) indicates cothread creation failed.
|
||||
<hr/>
|
||||
|
||||
<code>void co_delete(cothread_t cothread);</code><br/><br/>
|
||||
Delete specified cothread.<br/>
|
||||
Null (0) or invalid cothread handle is not allowed.<br/>
|
||||
Passing handle of active cothread to this function is not allowed.<br/>
|
||||
Passing handle of primary cothread is not allowed.
|
||||
<hr/>
|
||||
|
||||
<code>void co_switch(cothread_t cothread);</code><br/><br/>
|
||||
Switch to specified cothread.<br/>
|
||||
Null (0) or invalid cothread handle is not allowed.<br/>
|
||||
Passing handle of active cothread to this function is not allowed.
|
||||
<hr/>
|
||||
|
||||
</body>
|
||||
</html>
|
55
libco/fiber.c
Executable file
55
libco/fiber.c
Executable file
|
@ -0,0 +1,55 @@
|
|||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define WINVER 0x0400
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local cothread_t co_active_ = 0;
|
||||
|
||||
static void __stdcall co_thunk(void* coentry) {
|
||||
((void (*)(void))coentry)();
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_) {
|
||||
ConvertThreadToFiber(0);
|
||||
co_active_ = GetCurrentFiber();
|
||||
}
|
||||
return co_active_;
|
||||
}
|
||||
|
||||
cothread_t co_derive(void* memory, unsigned int heapsize, void (*coentry)(void)) {
|
||||
//Windows fibers do not allow users to supply their own memory
|
||||
return (cothread_t)0;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {
|
||||
if(!co_active_) {
|
||||
ConvertThreadToFiber(0);
|
||||
co_active_ = GetCurrentFiber();
|
||||
}
|
||||
return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
DeleteFiber(cothread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
co_active_ = cothread;
|
||||
SwitchToFiber(cothread);
|
||||
}
|
||||
|
||||
int co_serializable() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
37
libco/libco.c
Executable file
37
libco/libco.c
Executable file
|
@ -0,0 +1,37 @@
|
|||
#if defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Wparentheses"
|
||||
|
||||
/* placing code in section(text) does not mark it executable with Clang. */
|
||||
#undef LIBCO_MPROTECT
|
||||
#define LIBCO_MPROTECT
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#if defined(__i386__)
|
||||
#include "x86.c"
|
||||
#elif defined(__amd64__)
|
||||
#include "amd64.c"
|
||||
#elif defined(__arm__)
|
||||
#include "arm.c"
|
||||
#elif defined(__aarch64__)
|
||||
#include "aarch64.c"
|
||||
#elif defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
|
||||
#include "ppc64v2.c"
|
||||
#elif defined(_ARCH_PPC) && !defined(__LITTLE_ENDIAN__)
|
||||
#include "ppc.c"
|
||||
#elif defined(_WIN32)
|
||||
#include "fiber.c"
|
||||
#else
|
||||
#include "sjlj.c"
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_M_IX86)
|
||||
#include "x86.c"
|
||||
#elif defined(_M_AMD64)
|
||||
#include "amd64.c"
|
||||
#else
|
||||
#include "fiber.c"
|
||||
#endif
|
||||
#else
|
||||
#error "libco: unsupported processor, compiler or operating system"
|
||||
#endif
|
28
libco/libco.h
Executable file
28
libco/libco.h
Executable file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
libco v20 (2019-10-16)
|
||||
author: byuu
|
||||
license: ISC
|
||||
*/
|
||||
|
||||
#ifndef LIBCO_H
|
||||
#define LIBCO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void* cothread_t;
|
||||
|
||||
cothread_t co_active();
|
||||
cothread_t co_derive(void*, unsigned int, void (*)(void));
|
||||
cothread_t co_create(unsigned int, void (*)(void));
|
||||
void co_delete(cothread_t);
|
||||
void co_switch(cothread_t);
|
||||
int co_serializable();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ifndef LIBCO_H */
|
||||
#endif
|
431
libco/ppc.c
Executable file
431
libco/ppc.c
Executable file
|
@ -0,0 +1,431 @@
|
|||
/* ppc64le (ELFv2) is not currently supported */
|
||||
|
||||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if LIBCO_MPROTECT
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
/* state format (offsets in 32-bit words)
|
||||
|
||||
+0 pointer to swap code
|
||||
rest of function descriptor for entry function
|
||||
+8 PC
|
||||
+10 SP
|
||||
special registers
|
||||
GPRs
|
||||
FPRs
|
||||
VRs
|
||||
stack
|
||||
*/
|
||||
|
||||
enum { state_size = 1024 };
|
||||
enum { above_stack = 2048 };
|
||||
enum { stack_align = 256 };
|
||||
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
|
||||
/* determine environment */
|
||||
|
||||
#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)
|
||||
|
||||
/* whether function calls are indirect through a descriptor, or are directly to function */
|
||||
#ifndef LIBCO_PPCDESC
|
||||
#if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || (LIBCO_PPC64 && (!defined(_CALL_ELF) || _CALL_ELF == 1)))
|
||||
#define LIBCO_PPCDESC 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LIBCO_MPROTECT
|
||||
alignas(4096)
|
||||
#else
|
||||
section(text)
|
||||
#endif
|
||||
static const uint32_t libco_ppc_code[1024] = {
|
||||
#if LIBCO_PPC64
|
||||
0x7d000026, /* mfcr r8 */
|
||||
0xf8240028, /* std r1,40(r4) */
|
||||
0x7d2802a6, /* mflr r9 */
|
||||
0xf9c40048, /* std r14,72(r4) */
|
||||
0xf9e40050, /* std r15,80(r4) */
|
||||
0xfa040058, /* std r16,88(r4) */
|
||||
0xfa240060, /* std r17,96(r4) */
|
||||
0xfa440068, /* std r18,104(r4) */
|
||||
0xfa640070, /* std r19,112(r4) */
|
||||
0xfa840078, /* std r20,120(r4) */
|
||||
0xfaa40080, /* std r21,128(r4) */
|
||||
0xfac40088, /* std r22,136(r4) */
|
||||
0xfae40090, /* std r23,144(r4) */
|
||||
0xfb040098, /* std r24,152(r4) */
|
||||
0xfb2400a0, /* std r25,160(r4) */
|
||||
0xfb4400a8, /* std r26,168(r4) */
|
||||
0xfb6400b0, /* std r27,176(r4) */
|
||||
0xfb8400b8, /* std r28,184(r4) */
|
||||
0xfba400c0, /* std r29,192(r4) */
|
||||
0xfbc400c8, /* std r30,200(r4) */
|
||||
0xfbe400d0, /* std r31,208(r4) */
|
||||
0xf9240020, /* std r9,32(r4) */
|
||||
0xe8e30020, /* ld r7,32(r3) */
|
||||
0xe8230028, /* ld r1,40(r3) */
|
||||
0x48000009, /* bl 1 */
|
||||
0x7fe00008, /* trap */
|
||||
0x91040030, /*1:stw r8,48(r4) */
|
||||
0x80c30030, /* lwz r6,48(r3) */
|
||||
0x7ce903a6, /* mtctr r7 */
|
||||
0xe9c30048, /* ld r14,72(r3) */
|
||||
0xe9e30050, /* ld r15,80(r3) */
|
||||
0xea030058, /* ld r16,88(r3) */
|
||||
0xea230060, /* ld r17,96(r3) */
|
||||
0xea430068, /* ld r18,104(r3) */
|
||||
0xea630070, /* ld r19,112(r3) */
|
||||
0xea830078, /* ld r20,120(r3) */
|
||||
0xeaa30080, /* ld r21,128(r3) */
|
||||
0xeac30088, /* ld r22,136(r3) */
|
||||
0xeae30090, /* ld r23,144(r3) */
|
||||
0xeb030098, /* ld r24,152(r3) */
|
||||
0xeb2300a0, /* ld r25,160(r3) */
|
||||
0xeb4300a8, /* ld r26,168(r3) */
|
||||
0xeb6300b0, /* ld r27,176(r3) */
|
||||
0xeb8300b8, /* ld r28,184(r3) */
|
||||
0xeba300c0, /* ld r29,192(r3) */
|
||||
0xebc300c8, /* ld r30,200(r3) */
|
||||
0xebe300d0, /* ld r31,208(r3) */
|
||||
0x7ccff120, /* mtcr r6 */
|
||||
#else
|
||||
0x7d000026, /* mfcr r8 */
|
||||
0x90240028, /* stw r1,40(r4) */
|
||||
0x7d2802a6, /* mflr r9 */
|
||||
0x91a4003c, /* stw r13,60(r4) */
|
||||
0x91c40040, /* stw r14,64(r4) */
|
||||
0x91e40044, /* stw r15,68(r4) */
|
||||
0x92040048, /* stw r16,72(r4) */
|
||||
0x9224004c, /* stw r17,76(r4) */
|
||||
0x92440050, /* stw r18,80(r4) */
|
||||
0x92640054, /* stw r19,84(r4) */
|
||||
0x92840058, /* stw r20,88(r4) */
|
||||
0x92a4005c, /* stw r21,92(r4) */
|
||||
0x92c40060, /* stw r22,96(r4) */
|
||||
0x92e40064, /* stw r23,100(r4) */
|
||||
0x93040068, /* stw r24,104(r4) */
|
||||
0x9324006c, /* stw r25,108(r4) */
|
||||
0x93440070, /* stw r26,112(r4) */
|
||||
0x93640074, /* stw r27,116(r4) */
|
||||
0x93840078, /* stw r28,120(r4) */
|
||||
0x93a4007c, /* stw r29,124(r4) */
|
||||
0x93c40080, /* stw r30,128(r4) */
|
||||
0x93e40084, /* stw r31,132(r4) */
|
||||
0x91240020, /* stw r9,32(r4) */
|
||||
0x80e30020, /* lwz r7,32(r3) */
|
||||
0x80230028, /* lwz r1,40(r3) */
|
||||
0x48000009, /* bl 1 */
|
||||
0x7fe00008, /* trap */
|
||||
0x91040030, /*1:stw r8,48(r4) */
|
||||
0x80c30030, /* lwz r6,48(r3) */
|
||||
0x7ce903a6, /* mtctr r7 */
|
||||
0x81a3003c, /* lwz r13,60(r3) */
|
||||
0x81c30040, /* lwz r14,64(r3) */
|
||||
0x81e30044, /* lwz r15,68(r3) */
|
||||
0x82030048, /* lwz r16,72(r3) */
|
||||
0x8223004c, /* lwz r17,76(r3) */
|
||||
0x82430050, /* lwz r18,80(r3) */
|
||||
0x82630054, /* lwz r19,84(r3) */
|
||||
0x82830058, /* lwz r20,88(r3) */
|
||||
0x82a3005c, /* lwz r21,92(r3) */
|
||||
0x82c30060, /* lwz r22,96(r3) */
|
||||
0x82e30064, /* lwz r23,100(r3) */
|
||||
0x83030068, /* lwz r24,104(r3) */
|
||||
0x8323006c, /* lwz r25,108(r3) */
|
||||
0x83430070, /* lwz r26,112(r3) */
|
||||
0x83630074, /* lwz r27,116(r3) */
|
||||
0x83830078, /* lwz r28,120(r3) */
|
||||
0x83a3007c, /* lwz r29,124(r3) */
|
||||
0x83c30080, /* lwz r30,128(r3) */
|
||||
0x83e30084, /* lwz r31,132(r3) */
|
||||
0x7ccff120, /* mtcr r6 */
|
||||
#endif
|
||||
|
||||
#ifndef LIBCO_PPC_NOFP
|
||||
0xd9c400e0, /* stfd f14,224(r4) */
|
||||
0xd9e400e8, /* stfd f15,232(r4) */
|
||||
0xda0400f0, /* stfd f16,240(r4) */
|
||||
0xda2400f8, /* stfd f17,248(r4) */
|
||||
0xda440100, /* stfd f18,256(r4) */
|
||||
0xda640108, /* stfd f19,264(r4) */
|
||||
0xda840110, /* stfd f20,272(r4) */
|
||||
0xdaa40118, /* stfd f21,280(r4) */
|
||||
0xdac40120, /* stfd f22,288(r4) */
|
||||
0xdae40128, /* stfd f23,296(r4) */
|
||||
0xdb040130, /* stfd f24,304(r4) */
|
||||
0xdb240138, /* stfd f25,312(r4) */
|
||||
0xdb440140, /* stfd f26,320(r4) */
|
||||
0xdb640148, /* stfd f27,328(r4) */
|
||||
0xdb840150, /* stfd f28,336(r4) */
|
||||
0xdba40158, /* stfd f29,344(r4) */
|
||||
0xdbc40160, /* stfd f30,352(r4) */
|
||||
0xdbe40168, /* stfd f31,360(r4) */
|
||||
0xc9c300e0, /* lfd f14,224(r3) */
|
||||
0xc9e300e8, /* lfd f15,232(r3) */
|
||||
0xca0300f0, /* lfd f16,240(r3) */
|
||||
0xca2300f8, /* lfd f17,248(r3) */
|
||||
0xca430100, /* lfd f18,256(r3) */
|
||||
0xca630108, /* lfd f19,264(r3) */
|
||||
0xca830110, /* lfd f20,272(r3) */
|
||||
0xcaa30118, /* lfd f21,280(r3) */
|
||||
0xcac30120, /* lfd f22,288(r3) */
|
||||
0xcae30128, /* lfd f23,296(r3) */
|
||||
0xcb030130, /* lfd f24,304(r3) */
|
||||
0xcb230138, /* lfd f25,312(r3) */
|
||||
0xcb430140, /* lfd f26,320(r3) */
|
||||
0xcb630148, /* lfd f27,328(r3) */
|
||||
0xcb830150, /* lfd f28,336(r3) */
|
||||
0xcba30158, /* lfd f29,344(r3) */
|
||||
0xcbc30160, /* lfd f30,352(r3) */
|
||||
0xcbe30168, /* lfd f31,360(r3) */
|
||||
#endif
|
||||
|
||||
#ifdef __ALTIVEC__
|
||||
0x7ca042a6, /* mfvrsave r5 */
|
||||
0x39040180, /* addi r8,r4,384 */
|
||||
0x39240190, /* addi r9,r4,400 */
|
||||
0x70a00fff, /* andi. r0,r5,4095 */
|
||||
0x90a40034, /* stw r5,52(r4) */
|
||||
0x4182005c, /* beq- 2 */
|
||||
0x7e8041ce, /* stvx v20,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ea049ce, /* stvx v21,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7ec041ce, /* stvx v22,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ee049ce, /* stvx v23,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f0041ce, /* stvx v24,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f2049ce, /* stvx v25,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f4041ce, /* stvx v26,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f6049ce, /* stvx v27,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f8041ce, /* stvx v28,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7fa049ce, /* stvx v29,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7fc041ce, /* stvx v30,r0,r8 */
|
||||
0x7fe049ce, /* stvx v31,r0,r9 */
|
||||
0x80a30034, /*2:lwz r5,52(r3) */
|
||||
0x39030180, /* addi r8,r3,384 */
|
||||
0x39230190, /* addi r9,r3,400 */
|
||||
0x70a00fff, /* andi. r0,r5,4095 */
|
||||
0x7ca043a6, /* mtvrsave r5 */
|
||||
0x4d820420, /* beqctr */
|
||||
0x7e8040ce, /* lvx v20,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ea048ce, /* lvx v21,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7ec040ce, /* lvx v22,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ee048ce, /* lvx v23,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f0040ce, /* lvx v24,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f2048ce, /* lvx v25,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f4040ce, /* lvx v26,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f6048ce, /* lvx v27,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f8040ce, /* lvx v28,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7fa048ce, /* lvx v29,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7fc040ce, /* lvx v30,r0,r8 */
|
||||
0x7fe048ce, /* lvx v31,r0,r9 */
|
||||
#endif
|
||||
|
||||
0x4e800420, /* bctr */
|
||||
};
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
/* function call goes through indirect descriptor */
|
||||
#define CO_SWAP_ASM(x, y) ((void (*)(cothread_t, cothread_t))(uintptr_t)x)(x, y)
|
||||
#else
|
||||
/* function call goes directly to code */
|
||||
#define CO_SWAP_ASM(x, y) ((void (*)(cothread_t, cothread_t))(uintptr_t)libco_ppc_code)(x, y)
|
||||
#endif
|
||||
|
||||
static uint32_t* co_derive_(void* memory, unsigned size, uintptr_t entry) {
|
||||
(void)entry;
|
||||
|
||||
uint32_t* t = (uint32_t*)memory;
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
if(t) {
|
||||
memcpy(t, (void*)entry, sizeof(void*) * 3); /* copy entry's descriptor */
|
||||
*(const void**)t = libco_ppc_code; /* set function pointer to swap routine */
|
||||
}
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
cothread_t co_derive(void* memory, unsigned int size, void (*entry_)(void)) {
|
||||
uintptr_t entry = (uintptr_t)entry_;
|
||||
uint32_t* t = 0;
|
||||
|
||||
/* be sure main thread was successfully allocated */
|
||||
if(co_active()) {
|
||||
t = co_derive_(memory, size, entry);
|
||||
}
|
||||
|
||||
if(t) {
|
||||
uintptr_t sp;
|
||||
int shift;
|
||||
|
||||
/* save current registers into new thread, so that any special ones will have proper values when thread is begun */
|
||||
CO_SWAP_ASM(t, t);
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
entry = (uintptr_t)*(void**)entry; /* get real address */
|
||||
#endif
|
||||
|
||||
/* put stack near end of block, and align */
|
||||
sp = (uintptr_t)t + size - above_stack;
|
||||
sp -= sp % stack_align;
|
||||
|
||||
/* on PPC32, we save and restore GPRs as 32 bits. for PPC64, we
|
||||
save and restore them as 64 bits, regardless of the size the ABI
|
||||
uses. so, we manually write pointers at the proper size. we always
|
||||
save and restore at the same address, and since PPC is big-endian,
|
||||
we must put the low byte first on PPC32. */
|
||||
|
||||
/* if uintptr_t is 32 bits, >>32 is undefined behavior,
|
||||
so we do two shifts and don't have to care how many bits uintptr_t is. */
|
||||
#if LIBCO_PPC64
|
||||
shift = 16;
|
||||
#else
|
||||
shift = 0;
|
||||
#endif
|
||||
|
||||
/* set up so entry will be called on next swap */
|
||||
t[ 8] = (uint32_t)(entry >> shift >> shift);
|
||||
t[ 9] = (uint32_t)entry;
|
||||
|
||||
t[10] = (uint32_t)(sp >> shift >> shift);
|
||||
t[11] = (uint32_t)sp;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static uint32_t* co_create_(unsigned size, uintptr_t entry) {
|
||||
(void)entry;
|
||||
|
||||
uint32_t* t = (uint32_t*)malloc(size);
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
if(t) {
|
||||
memcpy(t, (void*)entry, sizeof(void*) * 3); /* copy entry's descriptor */
|
||||
*(const void**)t = libco_ppc_code; /* set function pointer to swap routine */
|
||||
}
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entry_)(void)) {
|
||||
uintptr_t entry = (uintptr_t)entry_;
|
||||
uint32_t* t = 0;
|
||||
|
||||
/* be sure main thread was successfully allocated */
|
||||
if(co_active()) {
|
||||
size += state_size + above_stack + stack_align;
|
||||
t = co_create_(size, entry);
|
||||
}
|
||||
|
||||
if(t) {
|
||||
uintptr_t sp;
|
||||
int shift;
|
||||
|
||||
/* save current registers into new thread, so that any special ones will have proper values when thread is begun */
|
||||
CO_SWAP_ASM(t, t);
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
entry = (uintptr_t)*(void**)entry; /* get real address */
|
||||
#endif
|
||||
|
||||
/* put stack near end of block, and align */
|
||||
sp = (uintptr_t)t + size - above_stack;
|
||||
sp -= sp % stack_align;
|
||||
|
||||
/* on PPC32, we save and restore GPRs as 32 bits. for PPC64, we
|
||||
save and restore them as 64 bits, regardless of the size the ABI
|
||||
uses. so, we manually write pointers at the proper size. we always
|
||||
save and restore at the same address, and since PPC is big-endian,
|
||||
we must put the low byte first on PPC32. */
|
||||
|
||||
/* if uintptr_t is 32 bits, >>32 is undefined behavior,
|
||||
so we do two shifts and don't have to care how many bits uintptr_t is. */
|
||||
#if LIBCO_PPC64
|
||||
shift = 16;
|
||||
#else
|
||||
shift = 0;
|
||||
#endif
|
||||
|
||||
/* set up so entry will be called on next swap */
|
||||
t[ 8] = (uint32_t)(entry >> shift >> shift);
|
||||
t[ 9] = (uint32_t)entry;
|
||||
|
||||
t[10] = (uint32_t)(sp >> shift >> shift);
|
||||
t[11] = (uint32_t)sp;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t t) {
|
||||
free(t);
|
||||
}
|
||||
|
||||
static void co_init_(void) {
|
||||
#if LIBCO_MPROTECT
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
if(page_size > 0) {
|
||||
uintptr_t align = page_size;
|
||||
uintptr_t begin = (uintptr_t)libco_ppc_code;
|
||||
uintptr_t end = begin + sizeof libco_ppc_code;
|
||||
|
||||
/* align beginning and end */
|
||||
end += align - 1;
|
||||
end -= end % align;
|
||||
begin -= begin % align;
|
||||
|
||||
mprotect((void*)begin, end - begin, PROT_READ | PROT_EXEC);
|
||||
}
|
||||
#endif
|
||||
|
||||
co_active_handle = co_create_(state_size, (uintptr_t)&co_switch);
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_handle) co_init_();
|
||||
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
void co_switch(cothread_t t) {
|
||||
cothread_t old = co_active_handle;
|
||||
co_active_handle = t;
|
||||
|
||||
CO_SWAP_ASM(t, old);
|
||||
}
|
||||
|
||||
int co_serializable() {
|
||||
return 0;
|
||||
}
|
279
libco/ppc64v2.c
Normal file
279
libco/ppc64v2.c
Normal file
|
@ -0,0 +1,279 @@
|
|||
/* author: Shawn Anastasio */
|
||||
|
||||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ppc64_context {
|
||||
//GPRs
|
||||
uint64_t gprs[32];
|
||||
uint64_t lr;
|
||||
uint64_t ccr;
|
||||
|
||||
//FPRs
|
||||
uint64_t fprs[32];
|
||||
|
||||
#ifdef __ALTIVEC__
|
||||
//Altivec (VMX)
|
||||
uint64_t vmx[12 * 2];
|
||||
uint32_t vrsave;
|
||||
#endif
|
||||
};
|
||||
|
||||
static thread_local struct ppc64_context* co_active_handle = 0;
|
||||
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
#define ALIGN(p, x) ((void*)((uintptr_t)(p) & ~((x) - 1)))
|
||||
|
||||
#define MIN_STACK 0x10000lu
|
||||
#define MIN_STACK_FRAME 0x20lu
|
||||
#define STACK_ALIGN 0x10lu
|
||||
|
||||
void swap_context(struct ppc64_context* read, struct ppc64_context* write);
|
||||
__asm__(
|
||||
".text\n"
|
||||
".align 4\n"
|
||||
".type swap_context @function\n"
|
||||
"swap_context:\n"
|
||||
".cfi_startproc\n"
|
||||
|
||||
//save GPRs
|
||||
"std 1, 8(4)\n"
|
||||
"std 2, 16(4)\n"
|
||||
"std 12, 96(4)\n"
|
||||
"std 13, 104(4)\n"
|
||||
"std 14, 112(4)\n"
|
||||
"std 15, 120(4)\n"
|
||||
"std 16, 128(4)\n"
|
||||
"std 17, 136(4)\n"
|
||||
"std 18, 144(4)\n"
|
||||
"std 19, 152(4)\n"
|
||||
"std 20, 160(4)\n"
|
||||
"std 21, 168(4)\n"
|
||||
"std 22, 176(4)\n"
|
||||
"std 23, 184(4)\n"
|
||||
"std 24, 192(4)\n"
|
||||
"std 25, 200(4)\n"
|
||||
"std 26, 208(4)\n"
|
||||
"std 27, 216(4)\n"
|
||||
"std 28, 224(4)\n"
|
||||
"std 29, 232(4)\n"
|
||||
"std 30, 240(4)\n"
|
||||
"std 31, 248(4)\n"
|
||||
|
||||
//save LR
|
||||
"mflr 5\n"
|
||||
"std 5, 256(4)\n"
|
||||
|
||||
//save CCR
|
||||
"mfcr 5\n"
|
||||
"std 5, 264(4)\n"
|
||||
|
||||
//save FPRs
|
||||
"stfd 14, 384(4)\n"
|
||||
"stfd 15, 392(4)\n"
|
||||
"stfd 16, 400(4)\n"
|
||||
"stfd 17, 408(4)\n"
|
||||
"stfd 18, 416(4)\n"
|
||||
"stfd 19, 424(4)\n"
|
||||
"stfd 20, 432(4)\n"
|
||||
"stfd 21, 440(4)\n"
|
||||
"stfd 22, 448(4)\n"
|
||||
"stfd 23, 456(4)\n"
|
||||
"stfd 24, 464(4)\n"
|
||||
"stfd 25, 472(4)\n"
|
||||
"stfd 26, 480(4)\n"
|
||||
"stfd 27, 488(4)\n"
|
||||
"stfd 28, 496(4)\n"
|
||||
"stfd 29, 504(4)\n"
|
||||
"stfd 30, 512(4)\n"
|
||||
"stfd 31, 520(4)\n"
|
||||
|
||||
#ifdef __ALTIVEC__
|
||||
//save VMX
|
||||
"li 5, 528\n"
|
||||
"stvxl 20, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 21, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 22, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 23, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 24, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 25, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 26, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 27, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 28, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 29, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 30, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"stvxl 31, 4, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
|
||||
//save VRSAVE
|
||||
"mfvrsave 5\n"
|
||||
"stw 5, 736(4)\n"
|
||||
#endif
|
||||
|
||||
//restore GPRs
|
||||
"ld 1, 8(3)\n"
|
||||
"ld 2, 16(3)\n"
|
||||
"ld 12, 96(3)\n"
|
||||
"ld 13, 104(3)\n"
|
||||
"ld 14, 112(3)\n"
|
||||
"ld 15, 120(3)\n"
|
||||
"ld 16, 128(3)\n"
|
||||
"ld 17, 136(3)\n"
|
||||
"ld 18, 144(3)\n"
|
||||
"ld 19, 152(3)\n"
|
||||
"ld 20, 160(3)\n"
|
||||
"ld 21, 168(3)\n"
|
||||
"ld 22, 176(3)\n"
|
||||
"ld 23, 184(3)\n"
|
||||
"ld 24, 192(3)\n"
|
||||
"ld 25, 200(3)\n"
|
||||
"ld 26, 208(3)\n"
|
||||
"ld 27, 216(3)\n"
|
||||
"ld 28, 224(3)\n"
|
||||
"ld 29, 232(3)\n"
|
||||
"ld 30, 240(3)\n"
|
||||
"ld 31, 248(3)\n"
|
||||
|
||||
//restore LR
|
||||
"ld 5, 256(3)\n"
|
||||
"mtlr 5\n"
|
||||
|
||||
//restore CCR
|
||||
"ld 5, 264(3)\n"
|
||||
"mtcr 5\n"
|
||||
|
||||
//restore FPRs
|
||||
"lfd 14, 384(3)\n"
|
||||
"lfd 15, 392(3)\n"
|
||||
"lfd 16, 400(3)\n"
|
||||
"lfd 17, 408(3)\n"
|
||||
"lfd 18, 416(3)\n"
|
||||
"lfd 19, 424(3)\n"
|
||||
"lfd 20, 432(3)\n"
|
||||
"lfd 21, 440(3)\n"
|
||||
"lfd 22, 448(3)\n"
|
||||
"lfd 23, 456(3)\n"
|
||||
"lfd 24, 464(3)\n"
|
||||
"lfd 25, 472(3)\n"
|
||||
"lfd 26, 480(3)\n"
|
||||
"lfd 27, 488(3)\n"
|
||||
"lfd 28, 496(3)\n"
|
||||
"lfd 29, 504(3)\n"
|
||||
"lfd 30, 512(3)\n"
|
||||
"lfd 31, 520(3)\n"
|
||||
|
||||
#ifdef __ALTIVEC__
|
||||
//restore VMX
|
||||
"li 5, 528\n"
|
||||
"lvxl 20, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 21, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 22, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 23, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 24, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 25, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 26, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 27, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 28, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 29, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 30, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
"lvxl 31, 3, 5\n"
|
||||
"addi 5, 5, 16\n"
|
||||
|
||||
//restore VRSAVE
|
||||
"lwz 5, 720(3)\n"
|
||||
"mtvrsave 5\n"
|
||||
#endif
|
||||
|
||||
//branch to LR
|
||||
"blr\n"
|
||||
|
||||
".cfi_endproc\n"
|
||||
".size swap_context, .-swap_context\n"
|
||||
);
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_handle) {
|
||||
co_active_handle = (struct ppc64_context*)malloc(MIN_STACK + sizeof(struct ppc64_context));
|
||||
}
|
||||
return (cothread_t)co_active_handle;
|
||||
}
|
||||
|
||||
cothread_t co_derive(void* memory, unsigned int size, void (*coentry)(void)) {
|
||||
uint8_t* sp;
|
||||
struct ppc64_context* context = (struct ppc64_context*)memory;
|
||||
|
||||
//save current context into new context to initialize it
|
||||
swap_context(context, context);
|
||||
|
||||
//align stack
|
||||
sp = (uint8_t*)memory + size - STACK_ALIGN;
|
||||
sp = (uint8_t*)ALIGN(sp, STACK_ALIGN);
|
||||
|
||||
//write 0 for initial backchain
|
||||
*(uint64_t*)sp = 0;
|
||||
|
||||
//create new frame with backchain
|
||||
sp -= MIN_STACK_FRAME;
|
||||
*(uint64_t*)sp = (uint64_t)(sp + MIN_STACK_FRAME);
|
||||
|
||||
//update context with new stack (r1) and entrypoint (r12, lr)
|
||||
context->gprs[ 1] = (uint64_t)sp;
|
||||
context->gprs[12] = (uint64_t)coentry;
|
||||
context->lr = (uint64_t)coentry;
|
||||
|
||||
return (cothread_t)memory;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*coentry)(void)) {
|
||||
void* memory = malloc(size);
|
||||
if(!memory) return (cothread_t)0;
|
||||
return co_derive(memory, size, coentry);
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t to) {
|
||||
struct ppc64_context* from = co_active_handle;
|
||||
co_active_handle = (struct ppc64_context*)to;
|
||||
swap_context((struct ppc64_context*)to, from);
|
||||
}
|
||||
|
||||
int co_serializable() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
38
libco/settings.h
Normal file
38
libco/settings.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#if defined(LIBCO_C)
|
||||
|
||||
/*[amd64, arm, ppc, x86]:
|
||||
by default, co_swap_function is marked as a text (code) section
|
||||
if not supported, uncomment the below line to use mprotect instead */
|
||||
/* #define LIBCO_MPROTECT */
|
||||
|
||||
/*[amd64]:
|
||||
Win64 only: provides a substantial speed-up, but will thrash XMM regs
|
||||
do not use this unless you are certain your application won't use SSE */
|
||||
/* #define LIBCO_NO_SSE */
|
||||
|
||||
#if defined(LIBCO_C)
|
||||
#if defined(LIBCO_MP)
|
||||
#define thread_local __thread
|
||||
#else
|
||||
#define thread_local
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#if !defined(_MSC_VER)
|
||||
#include <stdalign.h>
|
||||
#endif
|
||||
#else
|
||||
#define alignas(bytes)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define section(name) __declspec(allocate("." #name))
|
||||
#elif defined(__APPLE__)
|
||||
#define section(name) __attribute__((section("__TEXT,__" #name)))
|
||||
#else
|
||||
#define section(name) __attribute__((section("." #name "#")))
|
||||
#endif
|
||||
|
||||
/* if defined(LIBCO_C) */
|
||||
#endif
|
145
libco/sjlj.c
Executable file
145
libco/sjlj.c
Executable file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
note this was designed for UNIX systems. Based on ideas expressed in a paper by Ralf Engelschall.
|
||||
for SJLJ on other systems, one would want to rewrite springboard() and co_create() and hack the jmb_buf stack pointer.
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define _BSD_SOURCE
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
sigjmp_buf context;
|
||||
void (*coentry)(void);
|
||||
void* stack;
|
||||
} cothread_struct;
|
||||
|
||||
static thread_local cothread_struct co_primary;
|
||||
static thread_local cothread_struct* creating;
|
||||
static thread_local cothread_struct* co_running = 0;
|
||||
|
||||
static void springboard(int ignored) {
|
||||
if(sigsetjmp(creating->context, 0)) {
|
||||
co_running->coentry();
|
||||
}
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_running) co_running = &co_primary;
|
||||
return (cothread_t)co_running;
|
||||
}
|
||||
|
||||
cothread_t co_derive(void* memory, unsigned int size, void (*coentry)(void)) {
|
||||
if(!co_running) co_running = &co_primary;
|
||||
|
||||
cothread_struct* thread = (cothread_struct*)memory;
|
||||
memory = (unsigned char*)memory + sizeof(cothread_struct);
|
||||
size -= sizeof(cothread_struct);
|
||||
if(thread) {
|
||||
struct sigaction handler;
|
||||
struct sigaction old_handler;
|
||||
|
||||
stack_t stack;
|
||||
stack_t old_stack;
|
||||
|
||||
thread->coentry = thread->stack = 0;
|
||||
|
||||
stack.ss_flags = 0;
|
||||
stack.ss_size = size;
|
||||
thread->stack = stack.ss_sp = memory;
|
||||
if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) {
|
||||
handler.sa_handler = springboard;
|
||||
handler.sa_flags = SA_ONSTACK;
|
||||
sigemptyset(&handler.sa_mask);
|
||||
creating = thread;
|
||||
|
||||
if(!sigaction(SIGUSR1, &handler, &old_handler)) {
|
||||
if(!raise(SIGUSR1)) {
|
||||
thread->coentry = coentry;
|
||||
}
|
||||
sigaltstack(&old_stack, 0);
|
||||
sigaction(SIGUSR1, &old_handler, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(thread->coentry != coentry) {
|
||||
co_delete(thread);
|
||||
thread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (cothread_t)thread;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*coentry)(void)) {
|
||||
if(!co_running) co_running = &co_primary;
|
||||
|
||||
cothread_struct* thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
if(thread) {
|
||||
struct sigaction handler;
|
||||
struct sigaction old_handler;
|
||||
|
||||
stack_t stack;
|
||||
stack_t old_stack;
|
||||
|
||||
thread->coentry = thread->stack = 0;
|
||||
|
||||
stack.ss_flags = 0;
|
||||
stack.ss_size = size;
|
||||
thread->stack = stack.ss_sp = malloc(size);
|
||||
if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) {
|
||||
handler.sa_handler = springboard;
|
||||
handler.sa_flags = SA_ONSTACK;
|
||||
sigemptyset(&handler.sa_mask);
|
||||
creating = thread;
|
||||
|
||||
if(!sigaction(SIGUSR1, &handler, &old_handler)) {
|
||||
if(!raise(SIGUSR1)) {
|
||||
thread->coentry = coentry;
|
||||
}
|
||||
sigaltstack(&old_stack, 0);
|
||||
sigaction(SIGUSR1, &old_handler, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(thread->coentry != coentry) {
|
||||
co_delete(thread);
|
||||
thread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (cothread_t)thread;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
if(cothread) {
|
||||
if(((cothread_struct*)cothread)->stack) {
|
||||
free(((cothread_struct*)cothread)->stack);
|
||||
}
|
||||
free(cothread);
|
||||
}
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
if(!sigsetjmp(co_running->context, 0)) {
|
||||
co_running = (cothread_struct*)cothread;
|
||||
siglongjmp(co_running->context, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int co_serializable() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
86
libco/ucontext.c
Executable file
86
libco/ucontext.c
Executable file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
WARNING: the overhead of POSIX ucontext is very high,
|
||||
assembly versions of libco or libco_sjlj should be much faster
|
||||
|
||||
this library only exists for two reasons:
|
||||
1: as an initial test for the viability of a ucontext implementation
|
||||
2: to demonstrate the power and speed of libco over existing implementations,
|
||||
such as pth (which defaults to wrapping ucontext on unix targets)
|
||||
|
||||
use this library only as a *last resort*
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define _BSD_SOURCE
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <stdlib.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local ucontext_t co_primary;
|
||||
static thread_local ucontext_t* co_running = 0;
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_running) co_running = &co_primary;
|
||||
return (cothread_t)co_running;
|
||||
}
|
||||
|
||||
cothread_t co_derive(void* memory, unsigned int heapsize, void (*coentry)(void)) {
|
||||
if(!co_running) co_running = &co_primary;
|
||||
ucontext_t* thread = (ucontext_t*)memory;
|
||||
memory = (unsigned char*)memory + sizeof(ucontext_t);
|
||||
heapsize -= sizeof(ucontext_t);
|
||||
if(thread) {
|
||||
if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = memory)) {
|
||||
thread->uc_link = co_running;
|
||||
thread->uc_stack.ss_size = heapsize;
|
||||
makecontext(thread, coentry, 0);
|
||||
} else {
|
||||
thread = 0;
|
||||
}
|
||||
}
|
||||
return (cothread_t)thread;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {
|
||||
if(!co_running) co_running = &co_primary;
|
||||
ucontext_t* thread = (ucontext_t*)malloc(sizeof(ucontext_t));
|
||||
if(thread) {
|
||||
if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize))) {
|
||||
thread->uc_link = co_running;
|
||||
thread->uc_stack.ss_size = heapsize;
|
||||
makecontext(thread, coentry, 0);
|
||||
} else {
|
||||
co_delete((cothread_t)thread);
|
||||
thread = 0;
|
||||
}
|
||||
}
|
||||
return (cothread_t)thread;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
if(cothread) {
|
||||
if(((ucontext_t*)cothread)->uc_stack.ss_sp) { free(((ucontext_t*)cothread)->uc_stack.ss_sp); }
|
||||
free(cothread);
|
||||
}
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
ucontext_t* old_thread = co_running;
|
||||
co_running = (ucontext_t*)cothread;
|
||||
swapcontext(old_thread, co_running);
|
||||
}
|
||||
|
||||
int co_serializable() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
117
libco/x86.c
Executable file
117
libco/x86.c
Executable file
|
@ -0,0 +1,117 @@
|
|||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define fastcall __attribute__((fastcall))
|
||||
#elif defined(_MSC_VER)
|
||||
#define fastcall __fastcall
|
||||
#else
|
||||
#error "libco: please define fastcall macro"
|
||||
#endif
|
||||
|
||||
static thread_local long co_active_buffer[64];
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;
|
||||
|
||||
#ifdef LIBCO_MPROTECT
|
||||
alignas(4096)
|
||||
#else
|
||||
section(text)
|
||||
#endif
|
||||
/* ABI: fastcall */
|
||||
static const unsigned char co_swap_function[4096] = {
|
||||
0x89, 0x22, /* mov [edx],esp */
|
||||
0x8b, 0x21, /* mov esp,[ecx] */
|
||||
0x58, /* pop eax */
|
||||
0x89, 0x6a, 0x04, /* mov [edx+ 4],ebp */
|
||||
0x89, 0x72, 0x08, /* mov [edx+ 8],esi */
|
||||
0x89, 0x7a, 0x0c, /* mov [edx+12],edi */
|
||||
0x89, 0x5a, 0x10, /* mov [edx+16],ebx */
|
||||
0x8b, 0x69, 0x04, /* mov ebp,[ecx+ 4] */
|
||||
0x8b, 0x71, 0x08, /* mov esi,[ecx+ 8] */
|
||||
0x8b, 0x79, 0x0c, /* mov edi,[ecx+12] */
|
||||
0x8b, 0x59, 0x10, /* mov ebx,[ecx+16] */
|
||||
0xff, 0xe0, /* jmp eax */
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
static void co_init() {
|
||||
#ifdef LIBCO_MPROTECT
|
||||
DWORD old_privileges;
|
||||
VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
static void co_init() {
|
||||
#ifdef LIBCO_MPROTECT
|
||||
unsigned long addr = (unsigned long)co_swap_function;
|
||||
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
|
||||
unsigned long size = (addr - base) + sizeof co_swap_function;
|
||||
mprotect((void*)base, size, PROT_READ | PROT_EXEC);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void crash() {
|
||||
assert(0); /* called only if cothread_t entrypoint returns */
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) {
|
||||
cothread_t handle;
|
||||
if(!co_swap) {
|
||||
co_init();
|
||||
co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
|
||||
}
|
||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
|
||||
if(handle = (cothread_t)memory) {
|
||||
unsigned int offset = (size & ~15) - 32;
|
||||
long *p = (long*)((char*)handle + offset); /* seek to top of stack */
|
||||
*--p = (long)crash; /* crash if entrypoint returns */
|
||||
*--p = (long)entrypoint; /* start of function */
|
||||
*(long*)handle = (long)p; /* stack pointer */
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
|
||||
void* memory = malloc(size);
|
||||
if(!memory) return (cothread_t)0;
|
||||
return co_derive(memory, size, entrypoint);
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle) {
|
||||
register cothread_t co_previous_handle = co_active_handle;
|
||||
co_swap(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
|
||||
int co_serializable() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
40
testdelay.c
Normal file
40
testdelay.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Moritz Bitsch <moritzbitsch@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "coio.h"
|
||||
|
||||
void
|
||||
_t1(void* arg)
|
||||
{
|
||||
printf("going to sleep 1000ms (1s)\n");
|
||||
coio_delay(1000);
|
||||
printf("woken up\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
coio_create("t1", _t1, NULL, 0x8000);
|
||||
|
||||
if (coio_main() < 0) {
|
||||
printf("Deadlocked\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
49
testyield.c
Normal file
49
testyield.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Moritz Bitsch <moritzbitsch@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "coio.h"
|
||||
|
||||
void
|
||||
_t1(void* arg)
|
||||
{
|
||||
printf("Hello 1 from _t1\n");
|
||||
coio_yield();
|
||||
printf("Hello 2 from _t1\n");
|
||||
}
|
||||
|
||||
void
|
||||
_t2(void* arg)
|
||||
{
|
||||
printf("Hello 1 from _t2\n");
|
||||
coio_yield();
|
||||
printf("Hello 2 from _t2\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
coio_create("t1", _t1, NULL, 0x8000);
|
||||
coio_create("t2", _t2, NULL, 0x8000);
|
||||
|
||||
if (coio_main() < 0) {
|
||||
printf("Deadlocked\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue