question re: questions

H. J. Lu hjl@lucon.org
Fri Jul 5 14:21:00 GMT 2002


On Fri, Jul 05, 2002 at 08:07:00PM +0200, Thomas Vander Stichele wrote:
> 
> > The second problem is the testcase reuses the stack memory. It seems
> > to really confuse the glibc. I will see if I can create a different
> > testcase.
> 
> Do you mean, that different threads are trying to use the same piece of 
> stack memory ? I will look over it some more now that you have provided 
> some help.

Linuxthreads is pretty much broken when you call pthread_create after
pthread_join and stack memory is reused for whatever reason. The
problem is the corrupted doubly linked list of active threads. The
linked list is maitained by pthread_handle_create and pthread_exited.
However, memset in pthread_allocate_stack can trash the doubly linked
list before the dead threads are removed from the active thread list.
I don't know what is the best fix. It can be very tricky.

I am enclosing the testcase here.


H.J.
-------------- next part --------------
/*
 * Testcase for pthread_join() with user-defined stacks
 * by Wolfram Gloger <wg@malloc.de> 2000
 * http://sources.redhat.com/ml/libc-alpha/2000-12/msg00100.html
 * adapted to use  pthread_attr_setstack () and efence
 */
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <malloc.h>
#include <error.h>

#define NT_MAX   100
#define NT_TOTAL 200
#define MAX_USEC 400
#define STACKSIZE 65536
#ifndef USERSTACKS
#define USERSTACKS 1
#endif

struct thread_t {
    char* sp;
    pthread_t pt;
    int done;
    int i;
};

pthread_cond_t finish_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t finish_mutex = PTHREAD_MUTEX_INITIALIZER;

static void*
t_entry(void* ptr)
{
    struct thread_t* tt = (struct thread_t*)ptr;
    long r;
    struct timeval tv;

#if 1
    r = random()%1000;
#else
    r = (tt->i + 1) * 100;
#endif
    printf("start: %d, %d, %p\n", getpid (), r, tt->sp);
    tv.tv_sec = 0;
    tv.tv_usec = r*MAX_USEC;
    select(0, 0, 0, 0, &tv);
    pthread_mutex_lock(&finish_mutex);
    tt->done = 1;
    pthread_mutex_unlock(&finish_mutex);
    pthread_cond_signal(&finish_cond);
    return 0;
}

int
main(int argc, char* argv[])
{
    int completed, running = 0;
    int i, nt = 8, nt_total = NT_TOTAL;
    struct thread_t tt[NT_MAX];
    pthread_attr_t pa;
    int err;
    int done;

    /* free (malloc (8));*/ /* -lefence */
    if(argc > 1) {
	nt = atoi(argv[1]);
	if(argc > 2)
	    nt_total = atoi(argv[2]);
    }
    if(nt > NT_MAX)
	nt = NT_MAX;

    for(i=0; i<nt; i++) {
	tt[i].sp = valloc (STACKSIZE);
	tt[i].i = i;
	tt[i].done = 0;
	pthread_attr_init(&pa);
	err = pthread_attr_setstack(&pa, tt[i].sp, STACKSIZE);
	if (err)
	  {
	    fprintf(stderr, "pthread_attr_setstack: %s\n",
		    strerror (err));
	    break;
	  }

	if(pthread_create(&tt[i].pt, USERSTACKS ? &pa : 0, t_entry, &tt[i])) {
	    fprintf(stderr, "can't create\n");
	    pthread_attr_destroy(&pa);
	    break;
	}
	pthread_attr_destroy(&pa);
	++running;
    }
    nt = i;
    for(completed=0; running>0;) {
	done = 0;
	pthread_mutex_lock(&finish_mutex);
	for(i=0; i<nt; i++) {
	    if(tt[i].done) {
		done = 1;
		break;
	    }
	}
	if (!done)
	    pthread_cond_wait(&finish_cond, &finish_mutex);
	for(i=0; i<nt; i++) {
	    if(tt[i].done) {
		printf("join %p\n", tt[i].sp);
		pthread_join(tt[i].pt, NULL);
		printf("done %p (%d)\n", tt[i].sp, i);
		++completed;
		printf("comp=%d run=%d\n", completed, running);
		tt[i].done = 0;
		if(completed+running < nt_total) {
		    pthread_attr_init(&pa);
	            pthread_attr_setstack(&pa, tt[i].sp, STACKSIZE);

		    if(pthread_create(&tt[i].pt, USERSTACKS ? &pa : 0, t_entry,
				      &tt[i])) {
			fprintf(stderr, "can't create\n");
			pthread_attr_destroy(&pa);
			--running;
			break;
		    }
		    pthread_attr_destroy(&pa);
		} else
		    --running;
	    }
	}
	pthread_mutex_unlock(&finish_mutex);
    }
    fprintf(stderr, "Done\n");
    for(i=0; i<nt; i++) {
	free(tt[i].sp);
    }
    return 0;
}




More information about the Libc-alpha mailing list