some compile fixes, api changes, and i added the ability to create new chunks on...
authorAndy Wingo <wingo@pobox.com>
Sat, 2 Feb 2002 19:07:10 +0000 (19:07 +0000)
committerAndy Wingo <wingo@pobox.com>
Sat, 2 Feb 2002 19:07:10 +0000 (19:07 +0000)
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.

gst/cothreads/cothread-stack.c
gst/cothreads/cothreads-private.h
gst/cothreads/cothreads.c
gst/cothreads/cothreads.h
gst/cothreads/test-cothreads.c
gst/cothreads/test-pth-pthreads.c
gst/cothreads/test-pth.c
gst/cothreads/test-pthreads.c

index 10a822a..cf3f13d 100644 (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;
+}
index 5425f76..2cd6202 100644 (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);
index ead9ce2..e9744fb 100644 (file)
 #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
   
index acdb268..2b50632 100644 (file)
 
 
 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);
index d734d88..b93126d 100644 (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);
   
-  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");
   
index 8941a03..fa1e8b9 100644 (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");
index 1b91f89..68b2e3f 100644 (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);
index beb34a8..817688b 100644 (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);
 }