Allow compilation without the PCL library

This commit is contained in:
Nikos Mavrogiannopoulos
2013-06-26 17:20:07 +02:00
parent 4f202afefc
commit 88fcfaae7a
11 changed files with 977 additions and 2 deletions

1
.gitignore vendored
View File

@@ -38,3 +38,4 @@ src/ocpasswd
src/stamp-man
doc/stamp-man
doc/ocpasswd.8
src/pcl/libpcl.a

View File

@@ -187,6 +187,9 @@
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
/* Define to 1 if you have the `free' function. */
#undef HAVE_FREE
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
#undef HAVE_FSEEKO
@@ -199,6 +202,9 @@
/* Enable the GDBM library */
#undef HAVE_GDBM
/* Define to 1 if you have the `getcontext' function. */
#undef HAVE_GETCONTEXT
/* Define to 1 if you have the `getdelim' function. */
#undef HAVE_GETDELIM
@@ -247,9 +253,18 @@
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the `longjmp' function. */
#undef HAVE_LONGJMP
/* Define to 1 if the system has the type 'long long int'. */
#undef HAVE_LONG_LONG_INT
/* Define to 1 if you have the `makecontext' function. */
#undef HAVE_MAKECONTEXT
/* Define to 1 if you have the `malloc' function. */
#undef HAVE_MALLOC
/* Define if the 'malloc' function is POSIX compliant. */
#undef HAVE_MALLOC_POSIX
@@ -263,6 +278,9 @@
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#undef HAVE_MEMSET
/* Define to 1 if <limits.h> defines the MIN and MAX macros. */
#undef HAVE_MINMAX_IN_LIMITS_H
@@ -682,12 +700,21 @@
/* Define to 1 if you have the <runetype.h> header file. */
#undef HAVE_RUNETYPE_H
/* Define to 1 if you have the `setjmp' function. */
#undef HAVE_SETJMP
/* Define to 1 if you have the <setjmp.h> header file. */
#undef HAVE_SETJMP_H
/* Define to 1 if you have the `setproctitle' function. */
#undef HAVE_SETPROCTITLE
/* Define to 1 if you have the `sigaction' function. */
#undef HAVE_SIGACTION
/* Define to 1 if you have the `sigaltstack' function. */
#undef HAVE_SIGALTSTACK
/* Define to 1 if 'sig_atomic_t' is a signed integer type. */
#undef HAVE_SIGNED_SIG_ATOMIC_T
@@ -742,6 +769,9 @@
/* Define to 1 if you have the `strsignal' function. */
#undef HAVE_STRSIGNAL
/* Define to 1 if you have the `swapcontext' function. */
#undef HAVE_SWAPCONTEXT
/* Define to 1 if you have the `symlink' function. */
#undef HAVE_SYMLINK
@@ -1055,6 +1085,9 @@
/* Define to 1 if you need to in order for 'stat' and other things to work. */
#undef _POSIX_SOURCE
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* _GL_INLINE is a portable alternative to ISO C99 plain 'inline'.
_GL_EXTERN_INLINE is a portable alternative to 'extern inline'.
_GL_INLINE_HEADER_BEGIN contains useful stuff to put
@@ -1183,3 +1216,7 @@
/* Define as `fork' if `vfork' does not work. */
#undef vfork
/* Define to empty if the keyword `volatile' does not work. Warning: valid
code using `volatile' can become incorrect without. Disable with care. */
#undef volatile

View File

@@ -112,6 +112,15 @@ if [ test "$anyconnect_enabled" = "yes" ];then
AC_DEFINE([ANYCONNECT_CLIENT_COMPAT], [], [Enable Anyconnect compatibility])
fi
dnl needed in the included PCL
AC_C_VOLATILE
AC_C_CONST
AC_CHECK_FUNCS(memset malloc free)
AC_CHECK_FUNCS(makecontext getcontext swapcontext)
AC_CHECK_FUNCS(sigaction)
AC_CHECK_FUNCS(longjmp setjmp)
AC_CHECK_FUNCS(sigaltstack)
pcl_enabled=no
LIBS="$oldlibs -lpcl"
AC_MSG_CHECKING([for pcl library])
@@ -123,12 +132,15 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([
AC_SUBST([PCL_CFLAGS], [])
pcl_enabled=yes],
[AC_MSG_RESULT(no)
AC_MSG_ERROR([[
AC_MSG_WARN([[
***
*** libpcl (portable co-routines) was not found.
*** An included version of the library will be used.
*** ]])])
LIBS="$oldlibs"
AM_CONDITIONAL(PCL, test "$pcl_enabled" = yes)
enable_local_libopts=yes
NEED_LIBOPTS_DIR=true
LIBOPTS_CHECK([libopts])
@@ -137,6 +149,7 @@ AC_CONFIG_FILES([
Makefile
src/version.def
src/Makefile
src/pcl/Makefile
doc/Makefile
gl/Makefile
])
@@ -153,6 +166,7 @@ Summary of build options:
GDBM storage backend: ${gdbm_enabled}
PAM auth backend: ${pam_enabled}
TCP wrappers: ${libwrap_enabled}
PCL library: ${pcl_enabled}
Experimental options:
seccomp: ${seccomp_enabled}

View File

@@ -1,3 +1,5 @@
SUBDIRS =
AM_CPPFLAGS = -I$(srcdir)/../gl/ -I$(builddir)/../gl/ \
-I$(srcdir)/ -I$(builddir)/../ -I$(srcdir)/../libopts
@@ -26,7 +28,15 @@ ocserv_SOURCES += ocserv-args.def ocserv-args.c ocserv-args.h
ocserv_LDADD = ../gl/libgnu.a ../libopts/libopts.a
ocserv_LDADD += $(LIBGNUTLS_LIBS) $(GDBM_LIBS) $(PAM_LIBS) $(LIBUTIL) \
$(LIBSECCOMP) $(LIBWRAP) $(LIBCRYPT) $(PCL_LIBS)
$(LIBSECCOMP) $(LIBWRAP) $(LIBCRYPT)
if PCL
ocserv_LDADD += $(PCL_LIBS)
else
ocserv_LDADD += pcl/libpcl.a
SUBDIRS += pcl
AM_CPPFLAGS += -I$(srcdir)/pcl/
endif
ocserv-args.c ocserv-args.h: $(srcdir)/ocserv-args.def
@AUTOGEN@ $<

7
src/pcl/Makefile.am Normal file
View File

@@ -0,0 +1,7 @@
AM_CPPFLAGS = -I$(srcdir)/../gl/ -I$(builddir)/../gl/ \
-I$(srcdir)/ -I$(builddir)/../../
noinst_LIBRARIES = libpcl.a
libpcl_a_SOURCES = pcl.c pcl_version.c pcl_private.c \
pcl_config.h pcl.h pcl_private.h

514
src/pcl/pcl.c Normal file
View File

@@ -0,0 +1,514 @@
/*
* PCL by Davide Libenzi (Portable Coroutine Library)
* Copyright (C) 2003..2010 Davide Libenzi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "pcl_config.h"
#include "pcl.h"
#include "pcl_private.h"
#if defined(CO_USE_SIGCONTEXT)
#include <signal.h>
#endif
#if defined(CO_USE_SIGCONTEXT)
/*
* Multi thread and CO_USE_SIGCONTEXT are a NO GO!
*/
#if defined(CO_MULTI_THREAD)
#error "Sorry, it is not possible to use MT libpcl with CO_USE_SIGCONTEXT"
#endif
static volatile int ctx_called;
static co_ctx_t *ctx_creating;
static void *ctx_creating_func;
static sigset_t ctx_creating_sigs;
static co_ctx_t ctx_trampoline;
static co_ctx_t ctx_caller;
#endif /* #if defined(CO_USE_SIGCONTEXT) */
static int co_ctx_sdir(unsigned long psp)
{
int nav = 0;
unsigned long csp = (unsigned long) &nav;
return psp > csp ? -1: +1;
}
static int co_ctx_stackdir(void)
{
int cav = 0;
return co_ctx_sdir((unsigned long) &cav);
}
#if defined(CO_USE_UCONEXT)
static int co_set_context(co_ctx_t *ctx, void *func, char *stkbase, long stksiz)
{
if (getcontext(&ctx->cc))
return -1;
ctx->cc.uc_link = NULL;
ctx->cc.uc_stack.ss_sp = stkbase;
ctx->cc.uc_stack.ss_size = stksiz - sizeof(long);
ctx->cc.uc_stack.ss_flags = 0;
makecontext(&ctx->cc, func, 1);
return 0;
}
static void co_switch_context(co_ctx_t *octx, co_ctx_t *nctx)
{
cothread_ctx *tctx = co_get_thread_ctx();
if (swapcontext(&octx->cc, &nctx->cc) < 0) {
fprintf(stderr, "[PCL] Context switch failed: curr=%p\n",
tctx->co_curr);
exit(1);
}
}
#else /* #if defined(CO_USE_UCONEXT) */
#if defined(CO_USE_SIGCONTEXT)
/*
* This code comes from the GNU Pth implementation and uses the
* sigstack/sigaltstack() trick.
*
* The ingenious fact is that this variant runs really on _all_ POSIX
* compliant systems without special platform kludges. But be _VERY_
* carefully when you change something in the following code. The slightest
* change or reordering can lead to horribly broken code. Really every
* function call in the following case is intended to be how it is, doubt
* me...
*
* For more details we strongly recommend you to read the companion
* paper ``Portable Multithreading -- The Signal Stack Trick for
* User-Space Thread Creation'' from Ralf S. Engelschall.
*/
static void co_ctx_bootstrap(void)
{
cothread_ctx *tctx = co_get_thread_ctx();
co_ctx_t * volatile ctx_starting;
void (* volatile ctx_starting_func)(void);
/*
* Switch to the final signal mask (inherited from parent)
*/
sigprocmask(SIG_SETMASK, &ctx_creating_sigs, NULL);
/*
* Move startup details from static storage to local auto
* variables which is necessary because it has to survive in
* a local context until the thread is scheduled for real.
*/
ctx_starting = ctx_creating;
ctx_starting_func = (void (*)(void)) ctx_creating_func;
/*
* Save current machine state (on new stack) and
* go back to caller until we're scheduled for real...
*/
if (!setjmp(ctx_starting->cc))
longjmp(ctx_caller.cc, 1);
/*
* The new thread is now running: GREAT!
* Now we just invoke its init function....
*/
ctx_starting_func();
fprintf(stderr, "[PCL] Hmm, you really shouldn't reach this point: curr=%p\n",
tctx->co_curr);
exit(1);
}
static void co_ctx_trampoline(int sig)
{
/*
* Save current machine state and _immediately_ go back with
* a standard "return" (to stop the signal handler situation)
* to let him remove the stack again. Notice that we really
* have do a normal "return" here, or the OS would consider
* the thread to be running on a signal stack which isn't
* good (for instance it wouldn't allow us to spawn a thread
* from within a thread, etc.)
*/
if (setjmp(ctx_trampoline.cc) == 0) {
ctx_called = 1;
return;
}
/*
* Ok, the caller has longjmp'ed back to us, so now prepare
* us for the real machine state switching. We have to jump
* into another function here to get a new stack context for
* the auto variables (which have to be auto-variables
* because the start of the thread happens later).
*/
co_ctx_bootstrap();
}
static int co_set_context(co_ctx_t *ctx, void *func, char *stkbase, long stksiz)
{
struct sigaction sa;
struct sigaction osa;
sigset_t osigs;
sigset_t sigs;
#if defined(CO_HAS_SIGSTACK)
struct sigstack ss;
struct sigstack oss;
#elif defined(CO_HAS_SIGALTSTACK)
struct sigaltstack ss;
struct sigaltstack oss;
#else
#error "PCL: Unknown context stack type"
#endif
/*
* Preserve the SIGUSR1 signal state, block SIGUSR1,
* and establish our signal handler. The signal will
* later transfer control onto the signal stack.
*/
sigemptyset(&sigs);
sigaddset(&sigs, SIGUSR1);
sigprocmask(SIG_BLOCK, &sigs, &osigs);
sa.sa_handler = co_ctx_trampoline;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK;
if (sigaction(SIGUSR1, &sa, &osa) != 0)
return -1;
/*
* Set the new stack.
*
* For sigaltstack we're lucky [from sigaltstack(2) on
* FreeBSD 3.1]: ``Signal stacks are automatically adjusted
* for the direction of stack growth and alignment
* requirements''
*
* For sigstack we have to decide ourself [from sigstack(2)
* on Solaris 2.6]: ``The direction of stack growth is not
* indicated in the historical definition of struct sigstack.
* The only way to portably establish a stack pointer is for
* the application to determine stack growth direction.''
*/
#if defined(CO_HAS_SIGALTSTACK)
ss.ss_sp = stkbase;
ss.ss_size = stksiz - sizeof(long);
ss.ss_flags = 0;
if (sigaltstack(&ss, &oss) < 0)
return -1;
#elif defined(CO_HAS_SIGSTACK)
if (co_ctx_stackdir() < 0)
ss.ss_sp = (stkbase + stksiz - sizeof(long));
else
ss.ss_sp = stkbase;
ss.ss_onstack = 0;
if (sigstack(&ss, &oss) < 0)
return -1;
#else
#error "PCL: Unknown context stack type"
#endif
/*
* Now transfer control onto the signal stack and set it up.
* It will return immediately via "return" after the setjmp()
* was performed. Be careful here with race conditions. The
* signal can be delivered the first time sigsuspend() is
* called.
*/
ctx_called = 0;
kill(getpid(), SIGUSR1);
sigfillset(&sigs);
sigdelset(&sigs, SIGUSR1);
while (!ctx_called)
sigsuspend(&sigs);
/*
* Inform the system that we are back off the signal stack by
* removing the alternative signal stack. Be careful here: It
* first has to be disabled, before it can be removed.
*/
#if defined(CO_HAS_SIGALTSTACK)
sigaltstack(NULL, &ss);
ss.ss_flags = SS_DISABLE;
if (sigaltstack(&ss, NULL) < 0)
return -1;
sigaltstack(NULL, &ss);
if (!(ss.ss_flags & SS_DISABLE))
return -1;
if (!(oss.ss_flags & SS_DISABLE))
sigaltstack(&oss, NULL);
#elif defined(CO_HAS_SIGSTACK)
if (sigstack(&oss, NULL))
return -1;
#else
#error "PCL: Unknown context stack type"
#endif
/*
* Restore the old SIGUSR1 signal handler and mask
*/
sigaction(SIGUSR1, &osa, NULL);
sigprocmask(SIG_SETMASK, &osigs, NULL);
/*
* Set creation information.
*/
ctx_creating = ctx;
ctx_creating_func = func;
memcpy(&ctx_creating_sigs, &osigs, sizeof(sigset_t));
/*
* Now enter the trampoline again, but this time not as a signal
* handler. Instead we jump into it directly.
*/
if (setjmp(ctx_caller.cc) == 0)
longjmp(ctx_trampoline.cc, 1);
return 0;
}
#else /* #if defined(CO_USE_SIGCONTEXT) */
static int co_set_context(co_ctx_t *ctx, void *func, char *stkbase, long stksiz)
{
char *stack;
stack = stkbase + stksiz - sizeof(long);
setjmp(ctx->cc);
#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) \
&& __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined(JB_PC) && defined(JB_SP)
ctx->cc[0].__jmpbuf[JB_PC] = (int) func;
ctx->cc[0].__jmpbuf[JB_SP] = (int) stack;
#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) \
&& __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined(__mc68000__)
ctx->cc[0].__jmpbuf[0].__aregs[0] = (long) func;
ctx->cc[0].__jmpbuf[0].__sp = (int *) stack;
#elif defined(__GNU_LIBRARY__) && defined(__i386__)
ctx->cc[0].__jmpbuf[0].__pc = func;
ctx->cc[0].__jmpbuf[0].__sp = stack;
#elif defined(__MINGW32__)
ctx->cc[5] = (long) func;
ctx->cc[4] = (long) stack;
#elif defined(__APPLE__)
/* START Apple */
#if defined(__x86_64__)
*(long *) ((char *) &ctx->cc + 56) = (long) func;
*(long *) ((char *) &ctx->cc + 16) = (long) stack;
#elif defined(__i386__)
*(long *) ((char *) &ctx->cc + 48) = (long) func;
*(long *) ((char *) &ctx->cc + 36) = (long) stack;
#elif defined(__arm__)
*(long *) ((char *) &ctx->cc + 32) = (long) func;
*(long *) ((char *) &ctx->cc + 28) = (long) stack;
#else
#error "PCL: Unsupported setjmp/longjmp OSX CPU. Please report to <davidel@xmailserver.org>"
#endif
/* END Apple */
#elif defined(_WIN32) && defined(_MSC_VER)
/* START Windows */
#if defined(_M_IX86)
((_JUMP_BUFFER *) &ctx->cc)->Eip = (long) func;
((_JUMP_BUFFER *) &ctx->cc)->Esp = (long) stack;
#elif defined(_M_AMD64)
((_JUMP_BUFFER *) &ctx->cc)->Rip = (long) func;
((_JUMP_BUFFER *) &ctx->cc)->Rsp = (long) stack;
#else
#error "PCL: Unsupported setjmp/longjmp Windows CPU. Please report to <davidel@xmailserver.org>"
#endif
/* END Windows */
#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) \
&& __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && (defined(__powerpc64__) || defined(__powerpc__))
ctx->cc[0].__jmpbuf[JB_LR] = (int) func;
ctx->cc[0].__jmpbuf[JB_GPR1] = (int) stack;
#else
#error "PCL: Unsupported setjmp/longjmp platform. Please report to <davidel@xmailserver.org>"
#endif
return 0;
}
#endif /* #if defined(CO_USE_SIGCONTEXT) */
static void co_switch_context(co_ctx_t *octx, co_ctx_t *nctx)
{
if (setjmp(octx->cc) == 0)
longjmp(nctx->cc, 1);
}
#endif /* #if defined(CO_USE_UCONEXT) */
static void co_runner(void)
{
cothread_ctx *tctx = co_get_thread_ctx();
coroutine *co = tctx->co_curr;
co->restarget = co->caller;
co->func(co->data);
co_exit();
}
coroutine_t co_create(void (*func)(void *), void *data, void *stack, int size)
{
int alloc = 0, r = CO_STK_COROSIZE;
coroutine *co;
if ((size &= ~(sizeof(long) - 1)) < CO_MIN_SIZE)
return NULL;
if (stack == NULL) {
size = (size + sizeof(coroutine) + CO_STK_ALIGN - 1) & ~(CO_STK_ALIGN - 1);
stack = malloc(size);
if (stack == NULL)
return NULL;
alloc = size;
}
co = stack;
stack = (char *) stack + CO_STK_COROSIZE;
co->alloc = alloc;
co->func = func;
co->data = data;
if (co_set_context(&co->ctx, co_runner, stack, size - CO_STK_COROSIZE) < 0) {
if (alloc)
free(co);
return NULL;
}
return (coroutine_t) co;
}
void co_delete(coroutine_t coro)
{
cothread_ctx *tctx = co_get_thread_ctx();
coroutine *co = (coroutine *) coro;
if (co == tctx->co_curr) {
fprintf(stderr, "[PCL] Cannot delete itself: curr=%p\n",
tctx->co_curr);
exit(1);
}
if (co->alloc)
free(co);
}
void co_call(coroutine_t coro)
{
cothread_ctx *tctx = co_get_thread_ctx();
coroutine *co = (coroutine *) coro, *oldco = tctx->co_curr;
co->caller = tctx->co_curr;
tctx->co_curr = co;
co_switch_context(&oldco->ctx, &co->ctx);
}
void co_resume(void)
{
cothread_ctx *tctx = co_get_thread_ctx();
co_call(tctx->co_curr->restarget);
tctx->co_curr->restarget = tctx->co_curr->caller;
}
static void co_del_helper(void *data)
{
cothread_ctx *tctx;
coroutine *cdh;
for (;;) {
tctx = co_get_thread_ctx();
cdh = tctx->co_dhelper;
tctx->co_dhelper = NULL;
co_delete(tctx->co_curr->caller);
co_call((coroutine_t) cdh);
if (tctx->co_dhelper == NULL) {
fprintf(stderr,
"[PCL] Resume to delete helper coroutine: curr=%p caller=%p\n",
tctx->co_curr, tctx->co_curr->caller);
exit(1);
}
}
}
void co_exit_to(coroutine_t coro)
{
cothread_ctx *tctx = co_get_thread_ctx();
coroutine *co = (coroutine *) coro;
if (tctx->dchelper == NULL &&
(tctx->dchelper = co_create(co_del_helper, NULL,
tctx->stk, sizeof(tctx->stk))) == NULL) {
fprintf(stderr, "[PCL] Unable to create delete helper coroutine: curr=%p\n",
tctx->co_curr);
exit(1);
}
tctx->co_dhelper = co;
co_call((coroutine_t) tctx->dchelper);
fprintf(stderr, "[PCL] Stale coroutine called: curr=%p exitto=%p caller=%p\n",
tctx->co_curr, co, tctx->co_curr->caller);
exit(1);
}
void co_exit(void)
{
cothread_ctx *tctx = co_get_thread_ctx();
co_exit_to((coroutine_t) tctx->co_curr->restarget);
}
coroutine_t co_current(void)
{
cothread_ctx *tctx = co_get_thread_ctx();
return (coroutine_t) tctx->co_curr;
}
void *co_get_data(coroutine_t coro)
{
coroutine *co = (coroutine *) coro;
return co->data;
}
void *co_set_data(coroutine_t coro, void *data)
{
coroutine *co = (coroutine *) coro;
void *odata;
odata = co->data;
co->data = data;
return odata;
}

49
src/pcl/pcl.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* PCL by Davide Libenzi (Portable Coroutine Library)
* Copyright (C) 2003..2010 Davide Libenzi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#if !defined(PCL_H)
#define PCL_H
#ifdef __cplusplus
#define PCLXC extern "C"
#else
#define PCLXC
#endif
typedef void *coroutine_t;
PCLXC int co_thread_init(void);
PCLXC void co_thread_cleanup(void);
PCLXC coroutine_t co_create(void (*func)(void *), void *data, void *stack,
int size);
PCLXC void co_delete(coroutine_t coro);
PCLXC void co_call(coroutine_t coro);
PCLXC void co_resume(void);
PCLXC void co_exit_to(coroutine_t coro);
PCLXC void co_exit(void);
PCLXC coroutine_t co_current(void);
PCLXC void *co_get_data(coroutine_t coro);
PCLXC void *co_set_data(coroutine_t coro, void *data);
#endif

81
src/pcl/pcl_config.h Normal file
View File

@@ -0,0 +1,81 @@
/*
* PCL by Davide Libenzi (Portable Coroutine Library)
* Copyright (C) 2003..2010 Davide Libenzi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#if !defined(PCL_CONFIG_H)
#define PCL_CONFIG_H
#if defined(HAVE_CONFIG_H)
#include "config.h"
#elif defined(HAVE_WINCONFIG_H)
#include "winconfig.h"
#endif /* #if defined(HAVE_CONFIG_H) */
#if defined(__APPLE__)
/*
* Need to use setjmp/longjmp on OSX, since the ucontext bits are
* both broken and deprecated.
*/
#define CO_MULTI_THREAD
#elif defined(HAVE_GETCONTEXT) && defined(HAVE_MAKECONTEXT) && defined(HAVE_SWAPCONTEXT)
/*
* Use this if the system has a working getcontext/makecontext/swapcontext
* implementation.
*/
#define CO_USE_UCONEXT
/*
* Use threads.
*/
#define CO_MULTI_THREAD
#elif defined(HAVE_SIGACTION)
/*
* Use this to have the generic signal implementation (not working on
* Windows). Suggested on generic Unix implementations or on Linux with
* CPU different from x86 family.
*/
#define CO_USE_SIGCONTEXT
/*
* Use this in conjuction with CO_USE_SIGCONTEXT to use the sigaltstack
* environment (suggested when CO_USE_SIGCONTEXT is defined).
*/
#if defined(HAVE_SIGALTSTACK)
#define CO_HAS_SIGALTSTACK
#endif
#else
/*
* This will be using setjmp/longjmp
*/
/*
* Use threads.
*/
#define CO_MULTI_THREAD
#endif
#endif

159
src/pcl/pcl_private.c Normal file
View File

@@ -0,0 +1,159 @@
/*
* PCL by Davide Libenzi (Portable Coroutine Library)
* Copyright (C) 2003..2010 Davide Libenzi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pcl_config.h"
#include "pcl.h"
#include "pcl_private.h"
static cothread_ctx *co_get_global_ctx(void)
{
static cothread_ctx tctx;
if (tctx.co_curr == NULL)
tctx.co_curr = &tctx.co_main;
return &tctx;
}
#if !defined(CO_MULTI_THREAD)
/*
* Simple case, the single thread one ...
*/
int co_thread_init(void)
{
return 0;
}
void co_thread_cleanup(void)
{
}
cothread_ctx *co_get_thread_ctx(void)
{
return co_get_global_ctx();
}
#else
/*
* MultiThread cases ...
*/
#if defined(_WIN32) && defined(_MSC_VER)
/*
* On Windows, we can use the native TLS capabilities. Pretty easy ...
*/
static __declspec(thread) cothread_ctx *tctx;
int co_thread_init(void)
{
if ((tctx = (cothread_ctx *)
malloc(sizeof(cothread_ctx))) == NULL) {
perror("allocating context");
return -1;
}
memset(tctx, 0, sizeof(*tctx));
tctx->co_curr = &tctx->co_main;
return 0;
}
void co_thread_cleanup(void)
{
free(tctx);
}
cothread_ctx *co_get_thread_ctx(void)
{
/*
* Even in MT mode, allows for the main thread to not call
* the co_thread_init()/co_thread_cleanup() functions.
*/
return tctx != NULL ? tctx: co_get_global_ctx();
}
#else
/*
* On Unix, we use pthread. Sligthly more complicated ...
*/
#include <pthread.h>
static int valid_key;
static pthread_key_t key;
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
static void co_once_init(void)
{
if (pthread_key_create(&key, free))
perror("creating TLS key");
else
valid_key++;
}
int co_thread_init(void)
{
cothread_ctx *tctx;
pthread_once(&once_control, co_once_init);
if (!valid_key)
return -1;
if ((tctx = (cothread_ctx *)
malloc(sizeof(cothread_ctx))) == NULL) {
perror("allocating context");
return -1;
}
memset(tctx, 0, sizeof(*tctx));
tctx->co_curr = &tctx->co_main;
if (pthread_setspecific(key, tctx)) {
perror("setting thread context");
free(tctx);
return -1;
}
return 0;
}
void co_thread_cleanup(void)
{
}
cothread_ctx *co_get_thread_ctx(void)
{
cothread_ctx *tctx = (cothread_ctx *)
(valid_key ? pthread_getspecific(key): NULL);
/*
* Even in MT mode, allows for the main thread to not call
* the co_thread_init()/co_thread_cleanup() functions.
*/
return tctx != NULL ? tctx: co_get_global_ctx();
}
#endif
#endif

72
src/pcl/pcl_private.h Normal file
View File

@@ -0,0 +1,72 @@
/*
* PCL by Davide Libenzi (Portable Coroutine Library)
* Copyright (C) 2003..2010 Davide Libenzi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#if !defined(PCL_PRIVATE_H)
#define PCL_PRIVATE_H
#include <stdio.h>
#include <stdlib.h>
#include "pcl_config.h"
#include "pcl.h"
#if defined(CO_USE_UCONEXT)
#include <ucontext.h>
typedef ucontext_t co_core_ctx_t;
#else
#include <setjmp.h>
typedef jmp_buf co_core_ctx_t;
#endif
/*
* The following value must be power of two (N^2).
*/
#define CO_STK_ALIGN 256
#define CO_STK_COROSIZE ((sizeof(coroutine) + CO_STK_ALIGN - 1) & ~(CO_STK_ALIGN - 1))
#define CO_MIN_SIZE (4 * 1024)
typedef struct s_co_ctx {
co_core_ctx_t cc;
} co_ctx_t;
typedef struct s_coroutine {
co_ctx_t ctx;
int alloc;
struct s_coroutine *caller;
struct s_coroutine *restarget;
void (*func)(void *);
void *data;
} coroutine;
typedef struct s_cothread_ctx {
coroutine co_main;
coroutine *co_curr;
coroutine *co_dhelper;
coroutine *dchelper;
char stk[CO_MIN_SIZE];
} cothread_ctx;
cothread_ctx *co_get_thread_ctx(void);
#endif

31
src/pcl/pcl_version.c Normal file
View File

@@ -0,0 +1,31 @@
/*
* PCL by Davide Libenzi (Portable Coroutine Library)
* Copyright (C) 2003..2010 Davide Libenzi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Davide Libenzi <davidel@xmailserver.org>
*
*/
#include "pcl_config.h"
#define PCL_VERSION VERSION
char const *pcl_version[] = {
"Portable Coroutine Library (PCL) - Version " PCL_VERSION "\n"
"Copyright (C) 2003..2010 Davide Libenzi <davidel@xmailserver.org>\n"
};