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