some compile fixes, api changes, and i added the ability to create new chunks on the stack, which can extend the main...

Original commit message from CVS:
some compile fixes, api changes, and i added the ability to create new chunks on the
stack, which can extend the main thread's stack up to 8M under linuxthreads. thanks
to billh for the {set,get}rlimit tip.

on the other hand, there's a nasty bug in cothreads when they are run without gthreads
that i'm still tracking down. that's the last bug though, at this point.

the commit is to syn the repository with my working copy before moving cothreads to a
separate module.
This commit is contained in:
Andy Wingo 2002-02-02 19:07:10 +00:00
parent aae5e50662
commit 259c8c394c
8 changed files with 147 additions and 82 deletions

View file

@ -21,6 +21,8 @@
#include "cothreads-private.h"
#include "linuxthreads.h"
#include <unistd.h>
#include <sys/resource.h>
typedef enum _cothread_block_state cothread_block_state;
typedef struct _cothread_chunk cothread_chunk;
@ -47,13 +49,14 @@ static void cothread_chunk_free (cothread_chunk *chunk);
static gboolean cothread_stack_alloc_chunked (cothread_chunk *chunk, char **low, char **high,
cothread_chunk *(*chunk_new)(cothread_chunk*));
static cothread_chunk* cothread_chunk_new_linuxthreads (cothread_chunk* old);
static cothread_chunk* cothread_chunk_new_on_stack (cothread_chunk* old);
gboolean
cothread_stack_alloc_on_heap (char **low, char **high)
{
if (posix_memalign (low, _cothread_attr_global->chunk_size / _cothread_attr_global->blocks_per_chunk,
_cothread_attr_global->chunk_size / _cothread_attr_global->blocks_per_chunk) != NULL) {
if (posix_memalign (low, _cothreads_config_global->chunk_size / _cothreads_config_global->blocks_per_chunk,
_cothreads_config_global->chunk_size / _cothreads_config_global->blocks_per_chunk)) {
g_error ("could not memalign stack");
return FALSE;
}
@ -69,11 +72,11 @@ cothread_stack_alloc_on_gthread_stack (char **low, char **high)
static GStaticPrivate chunk_key = G_STATIC_PRIVATE_INIT;
if (!(chunk = g_static_private_get(&chunk_key))) {
chunk = cothread_chunk_new (_cothread_attr_global->chunk_size, FALSE);
g_static_private_set (&chunk_key, chunk, cothread_chunk_free);
chunk = cothread_chunk_new (_cothreads_config_global->chunk_size, FALSE);
g_static_private_set (&chunk_key, chunk, (GDestroyNotify) cothread_chunk_free);
}
return cothread_stack_alloc_chunked (chunk, low, high, NULL);
return cothread_stack_alloc_chunked (chunk, low, high, cothread_chunk_new_on_stack);
}
gboolean
@ -83,9 +86,9 @@ cothread_stack_alloc_linuxthreads (char **low, char **high)
static GStaticPrivate chunk_key = G_STATIC_PRIVATE_INIT;
if (!(chunk = g_static_private_get(&chunk_key))) {
chunk = cothread_chunk_new (_cothread_attr_global->chunk_size, FALSE);
chunk = cothread_chunk_new (_cothreads_config_global->chunk_size, FALSE);
g_message ("created new chunk, %p, size=0x%x", chunk->chunk, chunk->size);
g_static_private_set (&chunk_key, chunk, cothread_chunk_free);
g_static_private_set (&chunk_key, chunk, (GDestroyNotify) cothread_chunk_free);
}
return cothread_stack_alloc_chunked (chunk, low, high, cothread_chunk_new_linuxthreads);
@ -100,7 +103,7 @@ cothread_chunk_new (unsigned long size, gboolean allocate)
char *sp = CURRENT_STACK_FRAME;
ret = g_new0 (cothread_chunk, 1);
ret->nblocks = _cothread_attr_global->blocks_per_chunk;
ret->nblocks = _cothreads_config_global->blocks_per_chunk;
ret->block_states = g_new0 (cothread_block_state, ret->nblocks);
if (allocate) {
@ -127,11 +130,11 @@ cothread_chunk_new (unsigned long size, gboolean allocate)
* 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 _cothread_attr_global->chunk_size.
* boundaries of _cothreads_config_global->chunk_size.
*
* Returns: the new cothread context
*/
/* we assume that the stack is aligned on _cothread_attr_global->chunk_size boundaries */
/* we assume that the stack is aligned on _cothreads_config_global->chunk_size boundaries */
static gboolean
cothread_stack_alloc_chunked (cothread_chunk *chunk, char **low, char **high,
cothread_chunk *(*chunk_new)(cothread_chunk*))
@ -184,7 +187,7 @@ cothread_chunk_new_linuxthreads (cothread_chunk* old)
cothread_chunk *new;
void *pthread_descr;
new = cothread_chunk_new (_cothread_attr_global->chunk_size, TRUE);
new = cothread_chunk_new (_cothreads_config_global->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
@ -200,3 +203,34 @@ cothread_chunk_new_linuxthreads (cothread_chunk* old)
old->next = new;
return new;
}
static cothread_chunk*
cothread_chunk_new_on_stack (cothread_chunk* old)
{
cothread_chunk *new;
void *pthread_descr;
struct rlimit limit;
getrlimit (RLIMIT_STACK, &limit);
g_print ("stack limit: %d\nstack max: %d\n", limit.rlim_cur, limit.rlim_max);
limit.rlim_cur += old->size;
if (setrlimit (RLIMIT_STACK, &limit)) {
perror ("Could not increase the stack size, aborting...");
return NULL;
}
new = cothread_chunk_new (old->size, FALSE);
new->reserved_bottom = 0;
#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->chunk += new->size;
#else
new->chunk -= new->size;
#endif
old->next = new;
return new;
}

View file

@ -28,11 +28,11 @@ typedef struct _cothread_private cothread_private;
struct _cothread_private {
int argc;
char **argv;
void (*func) (int argc, char **argv);
void **argv;
void (*func) (int argc, void **argv);
};
extern cothread_attr *_cothread_attr_global;
extern cothreads_config *_cothreads_config_global;
gboolean cothread_stack_alloc_on_gthread_stack (char **low, char **high);

View file

@ -24,24 +24,12 @@
#define HAVE_LINUXTHREADS
#ifdef HAVE_LINUXTHREADS
static cothread_attr cothread_attr_default =
{
COTHREAD_ATTR_METHOD_LINUXTHREADS, /* use the linuxthreads hack */
0x200000, /* 2 MB */
8, /* for a stack size of 256 KB */
TRUE /* set up the first chunk */
};
static cothreads_config cothreads_config_default = COTHREADS_CONFIG_LINUXTHREADS_INITIALIZER;
#else
static cothread_attr cothread_attr_default =
{
COTHREAD_ATTR_METHOD_GTHREAD_STACK, /* this is what the old cothreads code does */
0x100000, /* only 1 MB due the the FreeBSD defaults */
8, /* for a stack size of 128 KB */
TRUE /* set up the first chunk */
};
static cothreads_config cothreads_config_default = COTHREADS_CONFIG_GTHREAD_INITIALIZER;
#endif
cothread_attr *_cothread_attr_global = NULL;
cothreads_config *_cothreads_config_global = NULL;
static gboolean (*stack_alloc_func) (char**, char**);
@ -60,45 +48,46 @@ static void cothread_stub (void);
gboolean
cothreads_initialized (void)
{
return (_cothread_attr_global != NULL);
return (_cothreads_config_global != NULL);
}
/**
* cothreads_init:
* @attr: attributes for creation of cothread stacks
* @config: attributes for creation of cothread stacks
*
* Initialize the cothreads system. If @attr is NULL, use the default parameters
* Initialize the cothreads system. If @config is NULL, use the default parameters
* detected at compile-time.
*/
void
cothreads_init (cothread_attr *attr)
cothreads_init (cothreads_config *config)
{
static cothread_attr _attr;
static cothreads_config _config;
if (cothreads_initialized()) {
g_warning ("cothread system has already been initialized");
return;
}
if (!attr)
_attr = cothread_attr_default;
/* we don't hold on to *config, we copy it (if it's supplied) */
if (!config)
_config = cothreads_config_default;
else
_attr = *attr;
_config = *config;
_cothread_attr_global = &_attr;
_cothreads_config_global = &_config;
switch (_cothread_attr_global->method) {
case COTHREAD_ATTR_METHOD_MALLOC:
switch (_cothreads_config_global->method) {
case COTHREADS_ALLOC_METHOD_MALLOC:
stack_alloc_func = cothread_stack_alloc_on_heap;
break;
case COTHREAD_ATTR_METHOD_GTHREAD_STACK:
case COTHREADS_ALLOC_METHOD_GTHREAD_STACK:
stack_alloc_func = cothread_stack_alloc_on_gthread_stack;
break;
case COTHREAD_ATTR_METHOD_LINUXTHREADS:
case COTHREADS_ALLOC_METHOD_LINUXTHREADS:
stack_alloc_func = cothread_stack_alloc_linuxthreads;
break;
default:
g_error ("unexpected value for attr method %d", _cothread_attr_global->method);
g_error ("unexpected value for config method %d", _cothreads_config_global->method);
}
}
@ -124,7 +113,7 @@ cothread_create (void (*func)(int, void **), int argc, void **argv)
if (!func) {
/* we are being asked to save the current thread into a new cothread. this
* only happens for the first cothread. */
if (_cothread_attr_global->alloc_cothread_0)
if (_cothreads_config_global->alloc_cothread_0)
if (!stack_alloc_func (&low, &high))
g_error ("couldn't create cothread 0");
else
@ -174,10 +163,10 @@ cothread_private_set (char *sp, void *priv, size_t size)
char *dest;
#if PTH_STACK_GROWTH > 0
dest = ((gulong)sp | (_cothread_attr_global->chunk_size / _cothread_attr_global->blocks_per_chunk - 1))
dest = (char*) ((gulong)sp | (_cothreads_config_global->chunk_size / _cothreads_config_global->blocks_per_chunk - 1))
- size + 1 - getpagesize();
#else
dest = ((gulong)sp &~ (_cothread_attr_global->chunk_size / _cothread_attr_global->blocks_per_chunk - 1))
dest = (char*) ((gulong)sp &~ (_cothreads_config_global->chunk_size / _cothreads_config_global->blocks_per_chunk - 1))
+ getpagesize();
#endif
@ -190,10 +179,10 @@ cothread_private_get (char *sp, void *priv, size_t size)
char *src;
#if PTH_STACK_GROWTH > 0
src = ((gulong)sp | (_cothread_attr_global->chunk_size / _cothread_attr_global->blocks_per_chunk - 1))
src = (char*) ((gulong)sp | (_cothreads_config_global->chunk_size / _cothreads_config_global->blocks_per_chunk - 1))
- size + 1 - getpagesize();
#else
src = ((gulong)sp &~ (_cothread_attr_global->chunk_size / _cothread_attr_global->blocks_per_chunk - 1))
src = (char*) ((gulong)sp &~ (_cothreads_config_global->chunk_size / _cothreads_config_global->blocks_per_chunk - 1))
+ getpagesize();
#endif

View file

@ -32,27 +32,47 @@
typedef pth_mctx_t cothread;
typedef enum _cothread_attr_method cothread_attr_method;
typedef struct _cothread_attr cothread_attr;
typedef enum _cothreads_alloc_method cothreads_alloc_method;
typedef struct _cothreads_config cothreads_config;
enum _cothread_attr_method
enum _cothreads_alloc_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 */
COTHREADS_ALLOC_METHOD_MALLOC, /* cothread stacks on the heap, one block per chunk */
COTHREADS_ALLOC_METHOD_GTHREAD_STACK, /* cothread stacks within the current gthread's stack */
COTHREADS_ALLOC_METHOD_LINUXTHREADS, /* a hack that allows for linuxthreads compatibility */
};
struct _cothread_attr {
cothread_attr_method method; /* the method of allocating new cothread stacks */
int chunk_size; /* size of contiguous chunk of memory for cothread stacks */
int blocks_per_chunk; /* cothreads per chunk */
gboolean alloc_cothread_0; /* if the first cothread needs to be allocated */
struct _cothreads_config {
cothreads_alloc_method method; /* the method of allocating new cothread stacks */
int chunk_size; /* size of contiguous chunk of memory for cothread stacks */
int blocks_per_chunk; /* cothreads per chunk */
gboolean alloc_cothread_0; /* if the first cothread needs to be allocated */
};
#define COTHREADS_CONFIG_HEAP_INITIALIZER { \
COTHREADS_ALLOC_METHOD_MALLOC, /* each cothread on the heap */ \
0x20000, /* stack size of 128 kB */ \
1, /* we aren't chunked */ \
FALSE /* nothing special for cothread 0 */ \
}
#define COTHREADS_CONFIG_GTHREAD_INITIALIZER { \
COTHREADS_ALLOC_METHOD_GTHREAD_STACK, /* this is what the old cothreads code does */ \
0x100000, /* only 1 MB due the the FreeBSD defaults */ \
8, /* for a stack size of 128 KB */ \
TRUE /* set up the first chunk */ \
}
#define COTHREADS_CONFIG_LINUXTHREADS_INITIALIZER { \
COTHREADS_ALLOC_METHOD_LINUXTHREADS, /* use the linuxthreads hack */ \
0x200000, /* 2 MB */ \
8, /* for a stack size of 256 KB */ \
TRUE /* set up the first chunk */ \
}
gboolean cothreads_initialized (void);
void cothreads_init (cothread_attr *attr);
void cothreads_init (cothreads_config *config);
cothread* cothread_create (void (*func)(int, void**), int argc, void **argv);
void cothread_destroy (cothread *thread);

View file

@ -1,5 +1,12 @@
#include <cothreads.h>
#define METHOD COTHREADS_CONFIG_GTHREAD_INITIALIZER
#define NGTHREADS 2
#define NCOTHREADS 5
//#define USE_GTHREADS
void co_thread (int argc, void **argv)
{
int pthreadnum = *(int*)argv[0];
@ -14,16 +21,16 @@ void co_thread (int argc, void **argv)
cothread_switch (self, main);
}
void pthread (void* _pthreadnum)
void *pthread (void* _pthreadnum)
{
int pthreadnum = *(int*) _pthreadnum;
int cothreadnum = 0;
cothread *main, *new;
char *argv[4];
void *argv[4];
main = cothread_create (NULL, 0, NULL);
while (cothreadnum++ < 25) {
while (cothreadnum++ < NCOTHREADS) {
printf ("%d: spawning a new cothread\n", pthreadnum);
argv[0] = &pthreadnum;
@ -34,32 +41,40 @@ void pthread (void* _pthreadnum)
printf ("%d: switching to cothread %d...\n", pthreadnum, cothreadnum);
cothread_switch (main, new);
printf ("%d: back now, looping\n", pthreadnum);
}
return NULL;
}
#define NTHREADS 2
int main (int argc, char *argv[])
{
GThread *thread[NTHREADS];
GThread *thread[NGTHREADS];
int pthreadnum[4], i;
cothreads_config config = METHOD;
g_thread_init(NULL);
cothreads_init(NULL);
cothreads_init(&config);
#ifdef USE_GTHREADS
cothread_create (NULL, 0, NULL); /* just to see where the stack is */
#endif
#ifdef USE_GTHREADS
printf ("0: creating the gthreads\n");
for (i=0; i<NTHREADS; i++) {
for (i=0; i<NGTHREADS; i++) {
pthreadnum[i] = i+1;
thread[i] = g_thread_create (pthread, &pthreadnum[i], TRUE, NULL);
}
printf ("0: joining the gthreads\n");
for (i=0; i<NTHREADS; i++) {
for (i=0; i<NGTHREADS; i++) {
g_thread_join (thread[i]);
}
#else
printf ("0: calling the pthread function directly\n");
pthreadnum[0] = 1;
pthread (&pthreadnum[0]);
#endif
printf ("exiting\n");

View file

@ -7,7 +7,7 @@
pth_mctx_t main_context;
int threadnum = 0;
void cothread (void *unused)
void cothread (void)
{
printf ("1.1: current stack frame: %p\n", CURRENT_STACK_FRAME);
printf ("1.1: sleeping 2s in thread %d...\n", threadnum);
@ -17,7 +17,7 @@ void cothread (void *unused)
pth_mctx_restore (&main_context);
}
void pthread (void* unused)
void *pthread (void* unused)
{
pth_mctx_t ctx;
char *skaddr;
@ -52,11 +52,11 @@ int main (int argc, char *argv[])
printf ("0: current stack frame: %p\n", CURRENT_STACK_FRAME);
printf ("0: creating the pthread\n");
pthread_create (&tid, NULL, pthread, NULL);
printf ("0: %d\n", pthread_self());
// pthread(NULL);
// pthread_create (&tid, NULL, pthread, NULL);
// printf ("0: %d\n", pthread_self());
pthread(NULL);
// printf ("joining the pthread\n");
pthread_join (tid, NULL);
// pthread_join (tid, NULL);
printf ("0: current stack frame: %p\n", CURRENT_STACK_FRAME);
printf ("0: take five...\n");

View file

@ -6,7 +6,7 @@
pth_mctx_t main_context;
void thread_1 (char *str)
void thread_1 (void)
{
printf ("sleeping 5s in thread 1...\n");
sleep (5);

View file

@ -1,5 +1,7 @@
#include <stdio.h>
#include "linuxthreads.h"
#include <sys/resource.h>
#include <unistd.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
@ -43,12 +45,17 @@ int main (int argc, char *argv[])
{
pthread_t tid;
int i;
struct rlimit limit;
for (i=0; i<10; i++) {
for (i=0; i<5; i++) {
pthread_create (&tid, NULL, pthread, NULL);
sleep(2);
sleep(1);
}
linuxthreads_self();
getrlimit (RLIMIT_STACK, &limit);
printf ("\nstack size: %d\nmax stack sizeL %d\n", limit.rlim_cur, limit.rlim_max);
exit (0);
}