#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;
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;
}
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
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);
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) {
* 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*))
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
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;
+}
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);
#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**);
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);
}
}
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
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
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
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);
#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];
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;
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);
- printf ("0: creating the gthreads\n");
+#ifdef USE_GTHREADS
+ cothread_create (NULL, 0, NULL); /* just to see where the stack is */
+#endif
- for (i=0; i<NTHREADS; i++) {
+#ifdef USE_GTHREADS
+ printf ("0: creating the gthreads\n");
+ 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");
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);
pth_mctx_restore (&main_context);
}
-void pthread (void* unused)
+void *pthread (void* unused)
{
pth_mctx_t ctx;
char *skaddr;
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");
pth_mctx_t main_context;
-void thread_1 (char *str)
+void thread_1 (void)
{
printf ("sleeping 5s in thread 1...\n");
sleep (5);
#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
{
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);
}