mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-11 01:06:59 +08:00
Allow compilation without the PCL library
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -38,3 +38,4 @@ src/ocpasswd
|
||||
src/stamp-man
|
||||
doc/stamp-man
|
||||
doc/ocpasswd.8
|
||||
src/pcl/libpcl.a
|
||||
|
||||
37
config.h.in
37
config.h.in
@@ -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
|
||||
|
||||
16
configure.ac
16
configure.ac
@@ -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}
|
||||
|
||||
@@ -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
7
src/pcl/Makefile.am
Normal 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
514
src/pcl/pcl.c
Normal 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
49
src/pcl/pcl.h
Normal 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
81
src/pcl/pcl_config.h
Normal 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
159
src/pcl/pcl_private.c
Normal 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
72
src/pcl/pcl_private.h
Normal 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
31
src/pcl/pcl_version.c
Normal 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"
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user