diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c96160a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,58 @@ +name: windows & linux + +on: [push, pull_request] + +jobs: + build: + name: ${{ matrix.target }} + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + include: + - target: amd64 + flags: -O3 -fomit-frame-pointer + - target: x86 + flags: -m32 -O3 -fomit-frame-pointer + steps: + - uses: actions/checkout@v3 + - name: Prepare + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update -q -y + sudo apt-get install -y gcc-multilib g++-multilib valgrind libc6-dbg libc6-dbg:i386 + - name: cmake build & test example + run: | + mkdir build + cd build + cmake .. + cmake --build . + cd bin + ./chan_3 + ./primes + ./testdelay 2 + + build-windows: + name: Windows (${{ matrix.arch }}) + runs-on: windows-2019 + strategy: + fail-fast: false + matrix: + arch: [amd64, x86] + steps: + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.arch }} + - uses: actions/checkout@v3 + - name: cmake build & test examples + run: | + mkdir build + cd build + cmake .. -D CMAKE_GENERATOR_PLATFORM=Win32 + cmake --build . + cd bin/Debug + .\chan_1.exe + .\chan_2.exe + .\chan_3.exe + .\primes.exe + .\testdelay.exe 2 diff --git a/.github/workflows/ci_qemu.yml b/.github/workflows/ci_qemu.yml new file mode 100644 index 0000000..37b299f --- /dev/null +++ b/.github/workflows/ci_qemu.yml @@ -0,0 +1,42 @@ +name: arch64 & others by qemu + +on: [push, pull_request] + +jobs: + build-qemu: + name: ${{ matrix.target }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - target: aarch64 + arch: aarch64 + - target: ppc64v2 + arch: ppc64le + - target: riscv64 + arch: riscv64 + - target: s390x + arch: s390x + steps: + - uses: actions/checkout@v3 + - uses: uraimo/run-on-arch-action@v2 + with: + arch: ${{ matrix.arch }} + distro: ubuntu_latest + install: | + apt-get update -q -y + apt-get install -q -y --no-install-recommends cmake build-essential + env: | + # Valgrind on arm will fail if the stack size is larger than 8MB. + # Set QEMUs stack size to 8MB since Github runners use 16MB default. + QEMU_STACK_SIZE: 8388608 + run: | + mkdir build + cd build + cmake .. + cmake --build . + cd bin + ./chan_3 + ./primes + ./testdelay 2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 593d6c5..a54e85e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,14 @@ cmake_minimum_required(VERSION 3.10) project(LIBTASK C) -set(C_STANDARD 99) +set(C_STANDARD 89) -# -g for debugging -set(CMAKE_C_FLAGS "-g") +if(UNIX) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g ") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -fomit-frame-pointer ") +endif() + +message("Generated with config types: ${CMAKE_CONFIGURATION_TYPES}") set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BUILD_DIR}/bin) @@ -17,10 +21,9 @@ file(GLOB lib_files ) add_library(task STATIC ${lib_files}) -set(TARGET_LIST primes tcpproxy helloworld chan_1 chan_2 chan_3) +set(TARGET_LIST testdelay primes helloworld chan_1 chan_2 chan_3) foreach (TARGET ${TARGET_LIST}) add_executable(${TARGET} examples/${TARGET}.c) target_include_directories(${TARGET} PRIVATE src) target_link_libraries(${TARGET} task) endforeach() -libtask diff --git a/README.md b/README.md index 3bb6f66..602072f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ -Libtask is a simple coroutine library. It runs on Linux (ARM, MIPS, and x86), -FreeBSD (x86), OS X (PowerPC x86, and x86-64), and SunOS Solaris (Sparc), +# Libtask + +**Libtask** is a simple coroutine library. It runs on Linux (ARM, MIPS, and x86), +FreeBSD (x86), OS X (PowerPC x86, and x86-64), SunOS Solaris (Sparc), **Windows** and is easy to port to other systems. Libtask gives the programmer the illusion of threads, but @@ -12,32 +14,32 @@ the CPU. Most of the functions provided in task.h do have the possibility of going to sleep. Programs using the task functions should #include . ---- Basic task manipulation +## Basic task manipulation -int taskcreate(void (*f)(void*arg), void *arg, unsigned int stacksize); +`int taskcreate(void (*f)(void*arg), void *arg, unsigned int stacksize);` Create a new task running f(arg) on a stack of size stacksize. -void tasksystem(void); +`void tasksystem(void);` Mark the current task as a "system" task. These are ignored for the purposes of deciding the program is done running (see taskexit next). -void taskexit(int status); +`void taskexit(int status);` Exit the current task. If this is the last non-system task, exit the entire program using the given exit status. -void taskexitall(int status); +`void taskexitall(int status);` Exit the entire program, using the given exit status. -void taskmain(int argc, char *argv[]); +`void taskmain(int argc, char *argv[]);` Write this function instead of main. Libtask provides its own main. -int taskyield(void); +`int taskyield(void);` Explicitly give up the CPU. The current task will be scheduled again once all the other currently-ready tasks have a chance @@ -45,33 +47,33 @@ int taskyield(void); current task was waiting. (Zero means there are no other tasks trying to run.) -int taskdelay(unsigned int ms) +`int taskdelay(unsigned int ms);` Explicitly give up the CPU for at least ms milliseconds. Other tasks continue to run during this time. -void** taskdata(void); +`void** taskdata(void);` Return a pointer to a single per-task void* pointer. You can use this as a per-task storage place. -void needstack(int n); +`void needstack(int n);` Tell the task library that you need at least n bytes left on the stack. If you don't have it, the task library will call abort. (It's hard to figure out how big stacks should be. I usually make them really big (say 32768) and then don't worry about it.) -void taskname(char*, ...); +`void taskname(char*, ...);` Takes an argument list like printf. Sets the current task's name. -char* taskgetname(void); +`char* taskgetname(void);` Returns the current task's name. Is the actual buffer; do not free. -void taskstate(char*, ...); -char* taskgetstate(void); +`void taskstate(char*, ...);` +`char* taskgetstate(void);` Like taskname and taskgetname but for the task state. @@ -79,31 +81,31 @@ char* taskgetstate(void); it will print a list of all its tasks and their names and states. This is useful for debugging why your program isn't doing anything! -unsigned int taskid(void); +`unsigned int taskid(void);` Return the unique task id for the current task. ---- Non-blocking I/O +## Non-blocking I/O There is a small amount of runtime support for non-blocking I/O on file descriptors. -int fdnoblock(int fd); +`int fdnoblock(int fd);` Sets I/O on the given fd to be non-blocking. Should be called before any of the other fd routines. -int fdread(int, void*, int); +`int fdread(int, void*, int);` Like regular read(), but puts task to sleep while waiting for data instead of blocking the whole program. -int fdwrite(int, void*, int); +`int fdwrite(int, void*, int);` Like regular write(), but puts task to sleep while waiting to write data instead of blocking the whole program. -void fdwait(int fd, int rw); +`void fdwait(int fd, int rw);` Low-level call sitting underneath fdread and fdwrite. Puts task to sleep while waiting for I/O to be possible on fd. @@ -111,12 +113,12 @@ void fdwait(int fd, int rw); anything else means just exceptional conditions (hang up, etc.) The 'r' and 'w' also wake up for exceptional conditions. ---- Network I/O +## Network I/O These are convenient packaging of the ugly Unix socket routines. They can all put the current task to sleep during the call. -int netannounce(int proto, char *address, int port) +`int netannounce(int proto, char *address, int port);` Start a network listener running on address and port of protocol. Proto is either TCP or UDP. Port is a port number. Address is a @@ -126,7 +128,7 @@ int netannounce(int proto, char *address, int port) Examples: netannounce(TCP, "localhost", 80) or netannounce(TCP, "127.0.0.1", 80) or netannounce(TCP, 0, 80). -int netaccept(int fd, char *server, int*port) +`int netaccept(int fd, char *server, int*port);` Get the next connection that comes in to the listener fd. Returns a fd to use to talk to the guy who just connected. @@ -134,13 +136,16 @@ int netaccept(int fd, char *server, int*port) 16 bytes that is filled in with the remote IP address. If port is not null, it is filled in with the report port. Example: + +```c char server[16]; int port; if(netaccept(fd, server, &port) >= 0) printf("connect from %s:%d", server, port); +``` -int netdial(int proto, char *name, int port) +`int netdial(int proto, char *name, int port);` Create a new (outgoing) connection to a particular host. Name can be an ip address or a domain name. If it's a domain name, @@ -149,49 +154,63 @@ int netdial(int proto, char *name, int port) Example: netdial(TCP, "www.google.com", 80) or netdial(TCP, "18.26.4.9", 80) ---- Time +## Time -unsigned int taskdelay(unsigned int ms) +`unsigned int taskdelay(unsigned int ms);` Put the current task to sleep for approximately ms milliseconds. Return the actual amount of time slept, in milliseconds. ---- Example programs +## Example programs -In this directory, tcpproxy.c is a simple TCP proxy that illustrates +In this directory, `tcpproxy.c` is a simple TCP proxy that illustrates most of the above. You can run - tcpproxy 1234 www.google.com 80 +- tcpproxy 1234 80 and then you should be able to visit and see Google. Other examples are: - primes.c - simple prime sieve - httpload.c - simple HTTP load generator - testdelay.c - test taskdelay() ---- Building +- primes.c - simple prime sieve +- httpload.c - simple HTTP load generator +- testdelay.c - test taskdelay() + +## Building + +To build, run **cmake**. You can copy task.h and +libtask.a to the appropriate places in /usr/local. Then you +should be able to just link with -ltask in your programs that use it. + +```shell +mkdir build +cd build +# Windows +cmake .. -D CMAKE_GENERATOR_PLATFORM=Win32 +# Linux/Unix +cmake .. +cmake --build . +``` -To build, run make. You can run make install to copy task.h and -libtask.a to the appropriate places in /usr/local. Then you -should be able to just link with -ltask in your programs -that use it. +`libtask.a` or `libtask.lib` is in **lib** directory. On SunOS Solaris machines, run makesun instead of just make. ---- Contact Info +### Contact Info Please email me with questions or problems. Russ Cox ---- Stuff you probably won't use at first --- ---- but might want to know about eventually --- +***Stuff you probably won't use at first*** +***but might want to know about eventually*** +```c void tasksleep(Rendez*); int taskwakeup(Rendez*); int taskwakeupall(Rendez*); +``` A Rendez is a condition variable. You can declare a new one by just allocating memory for it (or putting it in another structure) @@ -202,9 +221,11 @@ int taskwakeupall(Rendez*); Taskwakeupall(r) wakes up all the tasks sleeping on r. They both return the actual number of tasks awakened. +```c void qlock(QLock*); int canqlock(QLock*); void qunlock(QLock*); +``` You probably won't need locks because of the cooperative scheduling, but if you do, here are some. You can make a new @@ -214,6 +235,7 @@ void qunlock(QLock*); Calling canqlock tries to lock the lock, but will not give up the CPU. It returns 1 if the lock was acquired, 0 if it cannot be at this time. +```C void rlock(RWLock*); int canrlock(RWLock*); void runlock(RWLock*); @@ -221,12 +243,13 @@ void runlock(RWLock*); void wlock(RWLock*); int canwlock(RWLock*); void wunlock(RWLock*); +``` RWLocks are reader-writer locks. Any number of readers can lock them at once, but only one writer at a time. If a writer is holding it, there can't be any readers. -Channel *chancreate(int, int); +`Channel *chancreate(int, int);` etc. Channels are buffered communication pipes you can @@ -234,7 +257,7 @@ etc. doing most of the inter-task communication using channels. For details on channels see the description of channels in - http://swtch.com/usr/local/plan9/man/man3/thread.html and - http://swtch.com/~rsc/thread/ + and + and also the example program primes.c, which implements a concurrent prime sieve. diff --git a/examples/tcpproxy.c b/examples/tcpproxy.c index d52ce46..10683ae 100644 --- a/examples/tcpproxy.c +++ b/examples/tcpproxy.c @@ -3,13 +3,13 @@ #include #if defined(_WIN32) || defined(_WIN64) #include "../src/compat/unistd.h" +#include "../src/compat/sys/socket.h" #else #include +#include #endif #include "../src/task.h" #include -#include - enum { STACK = 32768 diff --git a/src/arm-ucontext.h b/src/arm-ucontext.h new file mode 100644 index 0000000..791886e --- /dev/null +++ b/src/arm-ucontext.h @@ -0,0 +1,30 @@ +#define setcontext(u) setmcontext(&(u)->uc_mcontext) +#define getcontext(u) getmcontext(&(u)->uc_mcontext) +typedef struct mcontext mcontext_t; +typedef struct ucontext ucontext_t; + +extern int swapcontext(ucontext_t*, const ucontext_t*); +extern void makecontext(ucontext_t*, void(*)(), int, ...); +extern int getmcontext(mcontext_t*); +extern void setmcontext(const mcontext_t*); + +struct mcontext { + int gregs[16]; +}; + +struct ucontext { + /* + * Keep the order of the first two fields. Also, + * keep them the first two fields in the structure. + * This way we can have a union with struct + * sigcontext and ucontext_t. This allows us to + * support them both at the same time. + * note: the union is not defined, though. + */ + sigset_t uc_sigmask; + mcontext_t uc_mcontext; + + struct __ucontext *uc_link; + stack_t uc_stack; + int __spare__[8]; +}; diff --git a/src/cl_32.bat b/src/cl_32.bat index 2878f06..faa572a 100644 --- a/src/cl_32.bat +++ b/src/cl_32.bat @@ -2,5 +2,5 @@ if EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools" ( %comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars32.bat" ) else if EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community" ( - %comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsamd64_x86.bat" + %comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat" ) diff --git a/src/cl_64.bat b/src/cl_64.bat index cd4db3d..7e7b60a 100644 --- a/src/cl_64.bat +++ b/src/cl_64.bat @@ -2,5 +2,5 @@ if EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools" ( %comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat" ) else if EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community" ( - %comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsx86_amd64.bat" + %comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" ) diff --git a/src/compat/netdb.h b/src/compat/netdb.h index d36b91d..6c1fca6 100644 --- a/src/compat/netdb.h +++ b/src/compat/netdb.h @@ -6,5 +6,5 @@ #ifndef _WIN32 #include_next #else -#include +#include "win32netcompat.h" #endif diff --git a/src/compat/netinet/in.h b/src/compat/netinet/in.h index d1afb27..7d10b23 100644 --- a/src/compat/netinet/in.h +++ b/src/compat/netinet/in.h @@ -6,7 +6,7 @@ #ifndef _WIN32 #include_next #else -#include +#include "../win32netcompat.h" #endif #ifndef LIBCRYPTOCOMPAT_NETINET_IN_H diff --git a/src/compat/netinet/tcp.h b/src/compat/netinet/tcp.h index c98cf74..2f346a3 100644 --- a/src/compat/netinet/tcp.h +++ b/src/compat/netinet/tcp.h @@ -6,5 +6,5 @@ #ifndef _WIN32 #include_next #else -#include +#include "../win32netcompat.h" #endif diff --git a/src/compat/poll.h b/src/compat/poll.h index d81a4f7..7c4a552 100644 --- a/src/compat/poll.h +++ b/src/compat/poll.h @@ -22,12 +22,6 @@ /* Type used for the number of file descriptors. */ typedef unsigned long int nfds_t; -/* Data structure describing a polling request. */ -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ -}; /* Event types that can be polled */ #define POLLIN 0x001 /* There is data to read. */ diff --git a/src/context.c b/src/context.c index 4699f88..8f21c4e 100644 --- a/src/context.c +++ b/src/context.c @@ -9,6 +9,9 @@ #elif defined(__x86_64__) #define NEEDAMD64MAKECONTEXT #define NEEDSWAPCONTEXT +#elif defined(__arm__) +#define NEEDARMMAKECONTEXT +#define NEEDSWAPCONTEXT #else #define NEEDPOWERMAKECONTEXT #define NEEDSWAPCONTEXT @@ -43,7 +46,7 @@ makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) va_list arg; tos = (ulong*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(ulong); - sp = tos - 16; + sp = tos - 16; ucp->mc.pc = (long)func; ucp->mc.sp = (long)sp; va_start(arg, argc); @@ -98,14 +101,17 @@ makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) { int i, *sp; va_list arg; - + sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4; va_start(arg, argc); - for(i=0; i<4 && iuc_mcontext.gregs[i] = va_arg(arg, uint); - va_end(arg); - uc->uc_mcontext.gregs[13] = (uint)sp; - uc->uc_mcontext.gregs[14] = (uint)fn; + if (argc-- > 0) uc->uc_mcontext.arm_r0 = va_arg(arg, uint); + if (argc-- > 0) uc->uc_mcontext.arm_r1 = va_arg(arg, uint); + if (argc-- > 0) uc->uc_mcontext.arm_r2 = va_arg(arg, uint); + if (argc-- > 0) uc->uc_mcontext.arm_r3 = va_arg(arg, uint); + va_end(arg); + + uc->uc_mcontext.arm_sp = (uint)sp; + uc->uc_mcontext.arm_lr = (uint)fn; } #endif @@ -115,7 +121,7 @@ makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) { int i, *sp; va_list arg; - + va_start(arg, argc); sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4; for(i=0; i<4 && i= t->alarmtime) { diff --git a/mips-ucontext.h b/src/mips-ucontext.h similarity index 100% rename from mips-ucontext.h rename to src/mips-ucontext.h diff --git a/src/net.c b/src/net.c index bd05778..7417930 100644 --- a/src/net.c +++ b/src/net.c @@ -1,10 +1,18 @@ #include "taskimpl.h" #include -#include +#if defined(_WIN32) || defined(_WIN64) +#include "compat/netdb.h" +#include "compat/sys/socket.h" +#include "compat/netinet/in.h" +#include "compat/netinet/tcp.h" +#include "compat/poll.h" +#else #include +#include #include #include #include +#endif int netannounce(int istcp, char *server, int port) @@ -30,7 +38,7 @@ netannounce(int istcp, char *server, int port) taskstate("socket failed"); return -1; } - + /* set reuse flag for tcp */ if(istcp && getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0){ n = 1; @@ -58,7 +66,7 @@ netaccept(int fd, char *server, int *port) struct sockaddr_in sa; uchar *ip; socklen_t len; - + fdwait(fd, 'r'); taskstate("netaccept"); @@ -133,7 +141,7 @@ netlookup(char *name, uint32_t *ip) if(parseip(name, ip) >= 0) return 0; - + /* BUG - Name resolution blocks. Need a non-blocking DNS. */ taskstate("netlookup"); if((he = gethostbyname(name)) != 0){ @@ -141,7 +149,7 @@ netlookup(char *name, uint32_t *ip) taskstate("netlookup succeeded"); return 0; } - + taskstate("netlookup failed"); return -1; } @@ -153,7 +161,7 @@ netdial(int istcp, char *server, int port) uint32_t ip; struct sockaddr_in sa; socklen_t sn; - + if(netlookup(server, &ip) < 0) return -1; @@ -170,7 +178,7 @@ netdial(int istcp, char *server, int port) n = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &n, sizeof n); } - + /* start connecting */ memset(&sa, 0, sizeof sa); memmove(&sa.sin_addr, &ip, 4); @@ -182,14 +190,14 @@ netdial(int istcp, char *server, int port) return -1; } - /* wait for finish */ + /* wait for finish */ fdwait(fd, 'w'); sn = sizeof sa; if(getpeername(fd, (struct sockaddr*)&sa, &sn) >= 0){ taskstate("connect succeeded"); return fd; } - + /* report error */ sn = sizeof n; getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&n, &sn); @@ -200,4 +208,3 @@ netdial(int istcp, char *server, int port) errno = n; return -1; } - diff --git a/src/task.c b/src/task.c index 81c83ed..fe385ff 100644 --- a/src/task.c +++ b/src/task.c @@ -367,6 +367,15 @@ taskmainstart(void *v) int main(int argc, char **argv) { +#if !defined(_WIN32) + struct sigaction sa, osa; + + memset(&sa, 0, sizeof sa); + sa.sa_handler = taskinfo; + sa.sa_flags = SA_RESTART; + sigaction(SIGQUIT, &sa, &osa); +#endif + #ifdef SIGINFO sigaction(SIGINFO, &sa, &osa); #endif diff --git a/src/taskimpl.h b/src/taskimpl.h index 2394f2f..53b5fca 100644 --- a/src/taskimpl.h +++ b/src/taskimpl.h @@ -26,36 +26,29 @@ #include #include + #if defined(_WIN32) || defined(_WIN64) #include "compat/unistd.h" +#include "compat/sys/time.h" +#include "compat/wait.h" #else #include +#include +#include #endif + #include #include #include -#if defined(_WIN32) || defined(_WIN64) -#include "compat/sys/time.h" -#else -#include -#endif #include -#if defined(_WIN32) || defined(_WIN64) -#include "compat/wait.h" -#else -#include -#endif - #include #if USE_UCONTEXT - #if defined(_WIN32) || defined(_WIN64) -#include "ucontext.h" + #include "ucontext.h" #else -#include + #include #endif - #endif #if defined(_WIN32) || defined(_WIN64) @@ -121,6 +114,8 @@ extern void makecontext(ucontext_t*, void(*)(), int, ...); # include "386-ucontext.h" # elif defined(__x86_64__) # include "amd64-ucontext.h" +# elif defined(__arm__) +# include "arm-ucontext.h" # else # include "power-ucontext.h" # endif @@ -147,11 +142,12 @@ extern pid_t rfork_thread(int, void*, int(*)(void*), void*); # include "sparc-ucontext.h" #endif -#if defined(__arm__) -int getmcontext(mcontext_t*); -void setmcontext(const mcontext_t*); -#define setcontext(u) setmcontext(&(u)->uc_mcontext) -#define getcontext(u) getmcontext(&(u)->uc_mcontext) +#if defined(__arm__) && defined(__linux__) +extern int getmcontext(mcontext_t *); +extern void setmcontext(const mcontext_t *); + +#define setcontext(u) setmcontext((void *)&((u)->uc_mcontext.arm_r0)) +#define getcontext(u) getmcontext((void *)&((u)->uc_mcontext.arm_r0)) #endif #if defined(__mips__) diff --git a/src/ucontext.c b/src/ucontext.c index f9dd621..5f649c5 100644 --- a/src/ucontext.c +++ b/src/ucontext.c @@ -24,6 +24,7 @@ #include #include +#if defined(_WIN32) || defined(_WIN64) int getcontext(ucontext_t *ucp) { int ret; @@ -99,3 +100,4 @@ int swapcontext(ucontext_t *oucp, const ucontext_t *ucp) } return ret; } +#endif diff --git a/src/ucontext.h b/src/ucontext.h index 49093cf..f40cb46 100644 --- a/src/ucontext.h +++ b/src/ucontext.h @@ -23,6 +23,7 @@ #ifndef UCONTEXT_H #define UCONTEXT_H +#if defined(_WIN32) || defined(_WIN64) #include #ifdef __cplusplus @@ -62,4 +63,5 @@ int swapcontext(ucontext_t *, const ucontext_t *); } #endif +#endif #endif /* UCONTEXT_H */