From bf81ebae7c5186a4bf82b1401916a1e7ecf2a3f6 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Sun, 27 Jan 2002 20:03:54 +0000 Subject: [PATCH] a first pass at cleaning up the configure stuff new cothread library started, some experimental stack allocation code... Original commit message from CVS: * a first pass at cleaning up the configure stuff * new cothread library started, some experimental stack allocation code is in place --- gst/cothreads/acconfig.h | 2 + gst/cothreads/acinclude.m4 | 15 ++ gst/cothreads/configure.ac | 140 +---------------- gst/cothreads/cothread-stack.c | 207 +++++++++++++++++++++++++ gst/cothreads/linuxthreads-internals.h | 35 +---- gst/cothreads/pth.h.in | 1 - gst/cothreads/pth_p.h.in | 47 +----- gst/cothreads/test-pth-pthreads2.c | 34 +--- 8 files changed, 237 insertions(+), 244 deletions(-) create mode 100644 gst/cothreads/cothread-stack.c diff --git a/gst/cothreads/acconfig.h b/gst/cothreads/acconfig.h index e4d793b134..61cad0760a 100644 --- a/gst/cothreads/acconfig.h +++ b/gst/cothreads/acconfig.h @@ -54,6 +54,8 @@ #undef PTH_DMALLOC #undef PTH_NEED_SEPARATE_REGISTER_STACK +#undef HAVE_LINUXTHREADS + @BOTTOM@ #endif /* _PTH_ACDEF_H_ */ diff --git a/gst/cothreads/acinclude.m4 b/gst/cothreads/acinclude.m4 index b326db776e..f54cb34836 100644 --- a/gst/cothreads/acinclude.m4 +++ b/gst/cothreads/acinclude.m4 @@ -1764,3 +1764,18 @@ AC_MSG_VERBOSE([$]$2) AC_MSG_VERBOSE([$]$3) ]) +dnl Check for LinuxThreads +dnl COTHREADS_CHECK_LINUXTHREADS +dnl no arguments +AC_DEFUN([COTHREADS_CHECK_LINUXTHREADS], [ + AC_CACHE_CHECK([for LinuxThreads], + [cothreads_cv_linuxthreads], + [AC_EGREP_CPP(pthread_kill_other_threads_np, + [#include ], + [cothreads_cv_linuxthreads=yes], + [cothreads_cv_linuxthreads=no]) + ]) + if test $cothreads_cv_linuxthreads = yes; then + AC_DEFINE(HAVE_LINUXTHREADS,1,[if you have LinuxThreads]) + fi +]) diff --git a/gst/cothreads/configure.ac b/gst/cothreads/configure.ac index 33b5783695..7cc6c278c5 100644 --- a/gst/cothreads/configure.ac +++ b/gst/cothreads/configure.ac @@ -93,157 +93,28 @@ AC_MSG_PART(Mandatory Platform Environment) dnl # check for standard headers AC_HEADER_STDC +# FIXME AC_HAVE_HEADERS(dnl stdio.h stdlib.h stdarg.h string.h signal.h unistd.h setjmp.h fcntl.h dnl - errno.h sys/types.h sys/time.h sys/wait.h sys/socket.h sys/socketcall.h) + errno.h sys/types.h) AC_CHECK_FUNCTIONS(dnl - gettimeofday select sigaction sigprocmask sigpending sigsuspend) + sigaction sigprocmask sigpending sigsuspend) AC_BEGIN_DECISION([mandatory system headers and functions]) AC_IFALLYES(dnl header:stdio.h header:stdlib.h header:stdarg.h header:string.h dnl header:signal.h header:unistd.h header:setjmp.h header:fcntl.h header:errno.h dnl - header:sys/types.h header:sys/time.h header:sys/wait.h header:sys/socket.h dnl - func:gettimeofday func:select func:sigaction func:sigprocmask dnl + header:sys/types.h dnl + func:sigaction func:sigprocmask dnl func:sigpending func:sigsuspend, AC_DECIDE(fine, [all fine])) AC_END_DECISION AC_MSG_PART(Optional Platform Environment) -dnl # check for the number of signals -dnl AC_CHECK_NSIG(PTH_NSIG) - -dnl # check whether poll(2)'s input stuff has to be faked -AC_CHECK_FUNCTIONS(poll) -AC_CHECK_DEFINE(POLLIN, poll.h) -AC_MSG_CHECKING(whether poll(2) facility has to be faked) -AC_IFALLYES(func:poll define:POLLIN, PTH_FAKE_POLL=0, PTH_FAKE_POLL=1) -if test .$PTH_FAKE_POLL = .1; then - msg="yes" -else - msg="no" -fi -AC_SUBST(PTH_FAKE_POLL) -AC_MSG_RESULT([$msg]) - -dnl # check for readv/writev environment -AC_HAVE_HEADERS(sys/uio.h) -AC_CHECK_FUNCTIONS(readv writev) -AC_MSG_CHECKING(whether readv(2)/writev(2) facility has to be faked) -AC_IFALLYES(func:readv func:writev header:sys/uio.h, PTH_FAKE_RWV=0, PTH_FAKE_RWV=1) -if test .$PTH_FAKE_RWV = .1; then - msg="yes" -else - msg="no" -fi -AC_SUBST(PTH_FAKE_RWV) -AC_MSG_RESULT([$msg]) - -dnl # check for various other functions which would be nice to have -AC_CHECK_FUNCTIONS(usleep strerror) - -dnl # check for various other headers which we might need -AC_HAVE_HEADERS(sys/resource.h net/errno.h) - -dnl # check whether we've to use a non-standard #include to get -dnl # the definition for fd_set under AIX and other brain-dead platforms. -AC_HAVE_HEADERS(sys/select.h) -EXTRA_INCLUDE_SYS_SELECT_H="#include " -if test ".$ac_cv_header_sys_select_h" != .yes; then - EXTRA_INCLUDE_SYS_SELECT_H="/* $EXTRA_INCLUDE_SYS_SELECT_H */" -fi -AC_SUBST(EXTRA_INCLUDE_SYS_SELECT_H) - -dnl # check whether we've to define sig_atomic_t -AC_CHECK_TYPEDEF(sig_atomic_t, signal.h) -FALLBACK_SIG_ATOMIC_T="typedef int sig_atomic_t;" -if test ".$ac_cv_typedef_sig_atomic_t" = .yes; then - FALLBACK_SIG_ATOMIC_T="/* $FALLBACK_SIG_ATOMIC_T */" -fi -AC_SUBST(FALLBACK_SIG_ATOMIC_T) - -dnl # check whether we've to define pid_t -AC_CHECK_TYPEDEF(pid_t, sys/types.h) -FALLBACK_PID_T="typedef int pid_t;" -if test ".$ac_cv_typedef_pid_t" = .yes; then - FALLBACK_PID_T="/* $FALLBACK_PID_T */" -fi -AC_SUBST(FALLBACK_PID_T) - -dnl # check whether we've to define size_t -AC_CHECK_TYPEDEF(size_t, stdlib.h) -FALLBACK_SIZE_T="typedef unsigned int size_t;" -if test ".$ac_cv_typedef_size_t" = .yes; then - FALLBACK_SIZE_T="/* $FALLBACK_SIZE_T */" -fi -AC_SUBST(FALLBACK_SIZE_T) - -dnl # check whether we've to define ssize_t -AC_CHECK_TYPEDEF(ssize_t, sys/types.h) -FALLBACK_SSIZE_T="typedef unsigned int ssize_t;" -if test ".$ac_cv_typedef_ssize_t" = .yes; then - FALLBACK_SSIZE_T="/* $FALLBACK_SSIZE_T */" -fi -AC_SUBST(FALLBACK_SSIZE_T) - -dnl # check whether we've to define off_t -AC_CHECK_TYPEDEF(off_t, sys/types.h) -FALLBACK_OFF_T="typedef int off_t;" -if test ".$ac_cv_typedef_off_t" = .yes; then - FALLBACK_OFF_T="/* $FALLBACK_OFF_T */" -fi -AC_SUBST(FALLBACK_OFF_T) - -dnl # check whether stack_t exists instead of sigaltstack -AC_CHECK_TYPEDEF(stack_t, signal.h) - dnl # check whether ss_base instead of ss_sp attribute exists AC_CHECK_STRUCTATTR(ss_base, sigaltstack, sys/signal.h) AC_CHECK_STRUCTATTR(ss_sp, sigaltstack, sys/signal.h) -dnl # check for gettimeofday() variant -AC_MSG_CHECKING(for a single-argument based gettimeofday) -cross_compile=no -AC_TRY_COMPILE([ -#include -#include -#include -],[ -struct timeval tv; -(void)gettimeofday(&tv); -], -msg="yes" -, -msg="no" -) -case $PLATFORM in - *-*-mvs* ) msg="no" ;; # on OS/390 the compiler test doesn't work - *-*-aix4* ) msg="no" ;; # on AIX the compiler test doesn't work - *-*-isc* ) msg="no" ;; # on ISC the compiler test doesn't work -esac -if test ".$msg" = .yes; then - AC_DEFINE(HAVE_GETTIMEOFDAY_ARGS1) -fi -AC_MSG_RESULT([$msg]) - -dnl # check for struct timespec -AC_MSG_CHECKING(for struct timespec) -cross_compile=no -AC_TRY_COMPILE([ -#include -#include -],[ -struct timespec ts; -], -msg="yes" -, -msg="no" -) -if test ".$msg" = .yes; then - AC_DEFINE(HAVE_STRUCT_TIMESPEC) -fi -AC_MSG_RESULT([$msg]) - dnl ## dnl ## MACHINE CONTEXT IMPLEMENTATION dnl ## @@ -406,4 +277,3 @@ Makefile pth.h pth_acmac.h ) - diff --git a/gst/cothreads/cothread-stack.c b/gst/cothreads/cothread-stack.c new file mode 100644 index 0000000000..efe6a4d89e --- /dev/null +++ b/gst/cothreads/cothread-stack.c @@ -0,0 +1,207 @@ +/* Pthread-friendly coroutines with pth + * Copyright (C) 2001 Andy Wingo + * + * cothread-stack.c: various methods of allocating cothread stacks + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* chunks can contain 1 or more blocks, each block contains one cothread stack */ + +enum cothread_attr_method +{ + COTHREAD_ATTR_METHOD_MALLOC, /* cothread stacks on the heap, one block per chunk */ + COTHREAD_ATTR_METHOD_GTHREAD_STACK, /* cothread stacks within the current gthread's stack */ + COTHREAD_ATTR_METHOD_LINUXTHREADS, /* a hack that allows for linuxthreads compatibility */ +} + +struct cothread_attr { + enum cothread_attr_method method; + int chunk_size; + int blocks_per_chunk; +} + +#ifdef HAVE_LINUXTHREADS +static struct cothread_attr cothread_attr_default = +{ + COTHREAD_ATTR_METHOD_LINUXTHREADS, /* use the linuxthreads hack */ + 0x20000, /* 2 MB */ + 8 /* for a stack size of 256 KB */ +} +#else +static struct cothread_attr cothread_attr_default = +{ + COTHREAD_ATTR_METHOD_GTHREAD_STACK, /* this is what the old cothreads code does */ + 0x10000, /* only 1 MB due the the FreeBSD defaults */ + 8 /* for a stack size of 128 KB */ +} +#endif + +static struct cothread_attr *_attr = NULL; /* set in cothread_init() */ + +enum cothread_block_state +{ + COTHREAD_BLOCK_STATE_UNUSED=0, + COTHREAD_BLOCK_STATE_IN_USE +} + +struct cothread_chunk { + struct cothread_chunk *next; + enum cothread_block_state *block_states; + char *chunk; + int size; + int reserved_bottom; + gboolean needs_free; +} + +/* size must be a power of two. */ +struct cothread_chunk* +cothread_chunk_new (unsigned long size, gboolean allocate) +{ + struct cothread_chunk *ret; + char *sp = CURRENT_STACK_FRAME; + + ret = g_new0 (struct cothread_chunk, 1); + ret->block_states = g_new0 (enum cothread_block_state, _attr->blocks_per_chunk); + + if (allocate) { + if (!posix_memalign(&ret->chunk, size, size)) + g_error ("memalign operation failed"); + } else { + /* if we don't allocate the chunk, we must already be in it. */ + + ret->chunk = (unsigned long) sp &~ (size - 1); +#if PTH_STACK_GROWTH > 0 + ret->reserved_bottom = sp - ret->chunk; +#else + ret->reserved_bottom = sp + size - ret->chunk; +#endif + } + + ret->size = size; + ret->needs_free = allocate; + + return ret; +} + +gboolean +cothread_stack_alloc_on_heap (char **low, char **high) +{ + *low = g_malloc (_attr->chunk_size / _attr->blocks_per_chunk); + *high = *low + sizeof (*low); + return TRUE; +} + +/** + * cothread_stack_alloc_chunked: + * @chunk: the chunk for the + * Make a new cothread stack out of a chunk. Chunks are assumed to be aligned on + * boundaries of _attr->chunk_size. + * + * Returns: the new cothread context + */ + /* we assume that the stack is aligned on _attr->chunk_size boundaries */ +static gboolean +cothread_stack_alloc_chunked (struct cothread_chunk *chunk, char **low, char **high, + (struct cothread_chunk*)(*chunk_new)(struct cothread_chunk*)) +{ + int block; + struct cothread_chunk *walk, *last; + + for (walk=chunk; walk; last=walk, walk=walk->next) { + if (chunk->block_states[0] == COTHREAD_BLOCK_STATE_UNUSED) { + chunk->block_states[0] = COTHREAD_BLOCK_STATE_IN_USE; +#if PTH_STACK_GROWTH > 0 + *low = chunk->chunk + chunk->reserved_bottom; + *high = chunk->chunk + chunk->chunk_size / _attr->blocks_per_chunk; +#else + *low = chunk->chunk + chunk->size * (chunk->nblocks - 1) / chunk->nblocks; + *high = chunk->chunk + chunk->size - chunk->reserved_bottom; +#endif + return TRUE; + } + + for (block = 1; block < _attr->blocks_per_chunk; block++) { + if (chunk->block_states[block] == COTHREAD_BLOCK_STATE_UNUSED) { +#if PTH_STACK_GROWTH > 0 + *low = chunk->chunk + chunk->size * (chunk->nblocks - block - 1) / chunk->nblocks; +#else + *low = chunk->chunk + chunk->size * (block - 1) / chunk->nblocks; +#endif + *high = *low + chunk->size / chunk->nblocks; + return TRUE; + } + } + } + + if (!chunk_new) + return FALSE; + else + return cothread_stack_alloc_chunked (chunk_new (last), low, high, NULL); +} + +gboolean +cothread_stack_alloc_on_gthread_stack (char **low, char **high) +{ + struct cothread_chunk *chunk = NULL; + static GStaticPrivate chunk_key = G_STATIC_PRIVATE_INIT; + + if (!(chunk = g_static_private_get(&chunk_key))) { + chunk = cothread_chunk_new (_attr->size, FALSE); + g_static_private_set (&chunk_key, chunk, cothread_chunk_free); + } + + return cothread_stack_alloc_chunked (chunk, low, high, NULL); +} + +gboolean +cothread_stack_alloc_linuxthreads (char **low, char **high) +{ + struct cothread_chunk *chunk = NULL; + static GStaticPrivate chunk_key = G_STATIC_PRIVATE_INIT; + + if (!(chunk = g_static_private_get(&chunk_key))) { + chunk = cothread_chunk_new (_attr->size, FALSE); + g_static_private_set (&chunk_key, chunk, cothread_chunk_free); + } + + return cothread_stack_alloc_chunked (chunk, low, high, cothread_chunk_new_linuxthreads); +} + +struct cothread_chunk* +cothread_chunk_new_linuxthreads (struct cothread_chunk* old) +{ + struct cothread_chunk *new; + void *pthread_descr; + + new = cothread_chunk_new (_attr->chunk_size, TRUE); + pthread_descr = __linuxthreads_self(); +#if PTH_STACK_GROWTH > 0 + /* we don't really know pthread_descr's size in this case, but we can be + * conservative. it's normally 1K in the down-growing case, so we allocate 2K. + */ + new->reserved_bottom = 2048; + memcpy(new->chunk, pthread_descr, 2048); +#else + new->reserved_bottom = ((unsigned long) pthread_descr | (_attr->chunk_size - 1)) - (unsigned long) pthread_descr; + memcpy(new->chunk + new->size - new->reserved_bottom - 1, pthread_descr, new->reserved_bottom); +#endif + + old->next = new; + return new; +} + + diff --git a/gst/cothreads/linuxthreads-internals.h b/gst/cothreads/linuxthreads-internals.h index b1419a7788..ccf07d700c 100644 --- a/gst/cothreads/linuxthreads-internals.h +++ b/gst/cothreads/linuxthreads-internals.h @@ -1,38 +1,5 @@ -/* LinuxThreads internal data structures */ -/* hacked for use with gstreamer by andy wingo */ - -#include /* PTHREAD_THREADS_MAX */ -#include /* _pthread_fastlock */ - #ifndef CURRENT_STACK_FRAME #define CURRENT_STACK_FRAME ({ char __csf; &__csf; }) #endif /* CURRENT_STACK_FRAME */ -#ifndef STACK_SIZE -#define STACK_SIZE 0x200000 /* 2 M linuxthreads default stack size */ -#endif - -typedef void * pthread_descr; - -/* Global array of thread handles, used for validating a thread id - and retrieving the corresponding thread descriptor. Also used for - mapping the available stack segments. */ - -#pragma weak __pthread_handles -extern struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX]; - -struct pthread_handle_struct { - struct _pthread_fastlock h_lock; /* Fast lock for sychronized access */ - pthread_descr h_descr; /* Thread descriptor or NULL if invalid */ - char * h_bottom; /* Lowest address in the stack thread */ -}; - -typedef struct pthread_handle_struct * pthread_handle; - -/* Return the handle corresponding to a thread id */ - -static inline pthread_handle thread_handle(pthread_t id) -{ - return &__pthread_handles[id % PTHREAD_THREADS_MAX]; -} - +#define STACK_SIZE 0x200000 diff --git a/gst/cothreads/pth.h.in b/gst/cothreads/pth.h.in index 2229d993ff..eaf7072592 100644 --- a/gst/cothreads/pth.h.in +++ b/gst/cothreads/pth.h.in @@ -43,7 +43,6 @@ /* essential headers */ #include /* for ssize_t, off_t */ #include /* for sigset_t */ -@EXTRA_INCLUDE_SYS_SELECT_H@ /* essential values */ #ifndef FALSE diff --git a/gst/cothreads/pth_p.h.in b/gst/cothreads/pth_p.h.in index 76a51e95f6..124a15bf60 100644 --- a/gst/cothreads/pth_p.h.in +++ b/gst/cothreads/pth_p.h.in @@ -27,6 +27,9 @@ #define _PTH_P_H_ /* mandatory system headers */ + +#include +/* #include #include #include @@ -35,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +45,7 @@ #include #include #include +*/ /* library version */ #define _PTH_VERS_C_AS_HEADER_ @@ -58,48 +61,6 @@ #include "pth_acdef.h" #include "pth_acmac.h" -/* optional system headers */ -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif -#ifdef HAVE_NET_ERRNO_H -#include -#endif - -/* dmalloc support */ -#ifdef PTH_DMALLOC -#include -#endif - -/* paths */ -#ifdef HAVE_PATHS_H -#include -#endif -#ifdef _PATH_BSHELL -#define PTH_PATH_BINSH _PATH_BSHELL -#else -#define PTH_PATH_BINSH "/bin/sh" -#endif - -/* non-blocking flags */ -#ifdef O_NONBLOCK -#define O_NONBLOCKING O_NONBLOCK -#else -#ifdef O_NDELAY -#define O_NONBLOCKING O_NDELAY -#else -#ifdef FNDELAY -#define O_NONBLOCKING FNDELAY -#else -#error "No O_NONBLOCK, O_NDELAY or FNDELAY flag available!" -#endif -#endif -#endif - -/* compiler happyness: avoid ``empty compilation unit'' problem */ -#define COMPILER_HAPPYNESS(name) \ - int __##name##_unit = 0; - /* generated contents */ BEGIN_DECLARATION ==#== diff --git a/gst/cothreads/test-pth-pthreads2.c b/gst/cothreads/test-pth-pthreads2.c index ba55821569..6a98303ae5 100644 --- a/gst/cothreads/test-pth-pthreads2.c +++ b/gst/cothreads/test-pth-pthreads2.c @@ -1,35 +1,7 @@ -#define __USE_GNU /* non-posix functions */ -#include -#undef __USE_GNU #include -#include "linuxthreads-internals.h" +#include "linuxthreads.h" #include "pth_p.h" -/* this function is only really necessary to get the main thread's - * pthread_descr, as the other threads store the pthread_descr (actually the - * first member of struct _pthread_descr_struct, which points to itself for the - * default (non-indirected) case) at the top of the stack. */ -static _pthread_descr linuxthreads_self() -{ - pthread_mutexattr_t mutexattr; - pthread_mutex_t mutex; - _pthread_descr self; - - pthread_mutexattr_init (&mutexattr); - pthread_mutexattr_setkind_np (&mutexattr, PTHREAD_MUTEX_ERRORCHECK_NP); - pthread_mutex_init (&mutex, &mutexattr); - - pthread_mutex_lock (&mutex); - self = mutex.__m_owner; - pthread_mutex_unlock (&mutex); - - printf ("pthread_self: %d\n", pthread_self()); - printf ("descr: %p\n", self); - printf ("*descr: %p\n", *(int*)self); - - return self; -} - pth_mctx_t main_context; int threadnum = 0; @@ -49,7 +21,7 @@ void *pthread (void *unused) pth_mctx_t ctx; _pthread_descr descr; - descr = linuxthreads_self(); + descr = __linuxthreads_self(); printf ("sp: %p\n", sp); printf ("STACK_SIZE: %p\n", STACK_SIZE); printf ("sp | STACK_SIZE: 0x%x\n", (int) sp | STACK_SIZE ); @@ -84,7 +56,7 @@ int main (int argc, char *argv[]) pthread_create (&tid, NULL, pthread, NULL); pthread_join (tid, NULL); - linuxthreads_self(); + __linuxthreads_self(); exit (0); }