mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-22 07:08:23 +00:00
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:
parent
aae5e50662
commit
259c8c394c
8 changed files with 147 additions and 82 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue