forked from Imagelibrary/binutils-gdb
2003-07-22 Elena Zannoni <ezannoni@redhat.com>
* gdb.threads/tls.c : New file.
* gdb.threads/tls.exp : New file.
* gdb.threads/tls-main.c : New file.
* gdb.threads/tls-shared.c : New file.
* gdb.threads/tls-shared.exp : New file.
This commit is contained in:
222
gdb/testsuite/gdb.threads/tls.c
Normal file
222
gdb/testsuite/gdb.threads/tls.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/* BeginSourceFile tls.c
|
||||
|
||||
This file creates and deletes threads. It uses thread local storage
|
||||
variables too. */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define N_THREADS 3
|
||||
|
||||
/* Uncomment to turn on debugging output */
|
||||
/*#define START_DEBUG*/
|
||||
|
||||
/* Thread-local storage. */
|
||||
__thread int a_thread_local;
|
||||
__thread int another_thread_local;
|
||||
|
||||
/* Global variable just for info addr in gdb. */
|
||||
int a_global;
|
||||
|
||||
/* Print the results of thread-local storage. */
|
||||
int thread_local_val[ N_THREADS ];
|
||||
int another_thread_local_val[ N_THREADS ];
|
||||
|
||||
/* Semaphores to make sure the threads are alive when we print the TLS
|
||||
variables from gdb. */
|
||||
sem_t tell_main, tell_thread;
|
||||
|
||||
|
||||
void print_error ()
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
fprintf (stderr, "EAGAIN\n");
|
||||
break;
|
||||
case EINTR:
|
||||
fprintf (stderr, "EINTR\n");
|
||||
break;
|
||||
case EINVAL:
|
||||
fprintf (stderr, "EINVAL\n");
|
||||
break;
|
||||
case ENOSYS:
|
||||
fprintf (stderr, "ENOSYS\n");
|
||||
break;
|
||||
case ENOENT:
|
||||
fprintf (stderr, "ENOENT\n");
|
||||
break;
|
||||
case EDEADLK:
|
||||
fprintf (stderr, "EDEADLK\n");
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "Unknown error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Routine for each thread to run, does nothing. */
|
||||
void *spin( vp )
|
||||
void * vp;
|
||||
{
|
||||
int me = (long) vp;
|
||||
int i;
|
||||
|
||||
/* Use a_global. */
|
||||
a_global++;
|
||||
|
||||
a_thread_local = 0;
|
||||
another_thread_local = me;
|
||||
for( i = 0; i <= me; i++ ) {
|
||||
a_thread_local += i;
|
||||
}
|
||||
|
||||
another_thread_local_val[me] = another_thread_local;
|
||||
thread_local_val[ me ] = a_thread_local; /* here we know tls value */
|
||||
|
||||
if (sem_post (&tell_main) == -1)
|
||||
{
|
||||
fprintf (stderr, "th %d post on sem tell_main failed\n", me);
|
||||
print_error ();
|
||||
return;
|
||||
}
|
||||
#ifdef START_DEBUG
|
||||
fprintf (stderr, "th %d post on tell main\n", me);
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
errno = 0;
|
||||
#ifdef START_DEBUG
|
||||
fprintf (stderr, "th %d start wait on tell_thread\n", me);
|
||||
#endif
|
||||
if (sem_wait (&tell_thread) == -1)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
fprintf (stderr, "th %d wait on sem tell_thread failed\n", me);
|
||||
print_error ();
|
||||
return;
|
||||
}
|
||||
#ifdef START_DEBUG
|
||||
fprintf (stderr, "th %d wait tell_thread got EINTR, rewaiting\n", me);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
while (errno == EINTR);
|
||||
|
||||
#ifdef START_DEBUG
|
||||
fprintf (stderr, "th %d Wait on tell_thread\n", me);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
do_pass()
|
||||
{
|
||||
int i;
|
||||
pthread_t t[ N_THREADS ];
|
||||
int err;
|
||||
|
||||
for( i = 0; i < N_THREADS; i++)
|
||||
{
|
||||
thread_local_val[i] = 0;
|
||||
another_thread_local_val[i] = 0;
|
||||
}
|
||||
|
||||
if (sem_init (&tell_main, 0, 0) == -1)
|
||||
{
|
||||
fprintf (stderr, "tell_main semaphore init failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sem_init (&tell_thread, 0, 0) == -1)
|
||||
{
|
||||
fprintf (stderr, "tell_thread semaphore init failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start N_THREADS threads, then join them so that they are terminated. */
|
||||
for( i = 0; i < N_THREADS; i++ )
|
||||
{
|
||||
err = pthread_create( &t[i], NULL, spin, (void *) (long) i );
|
||||
if( err != 0 ) {
|
||||
fprintf(stderr, "Error in thread %d create\n", i );
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0; i < N_THREADS; i++ )
|
||||
{
|
||||
do
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
#ifdef START_DEBUG
|
||||
fprintf (stderr, "main %d start wait on tell_main\n", i);
|
||||
#endif
|
||||
if (sem_wait (&tell_main) == -1)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
fprintf (stderr, "main %d wait on sem tell_main failed\n", i);
|
||||
print_error ();
|
||||
return;
|
||||
}
|
||||
#ifdef START_DEBUG
|
||||
fprintf (stderr, "main %d wait tell_main got EINTR, rewaiting\n", i);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
while (errno == EINTR);
|
||||
|
||||
#ifdef START_DEBUG
|
||||
fprintf (stderr, "main %d wait on tell_main\n",i);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef START_DEBUG
|
||||
fprintf (stderr, "main done waiting on tell_main\n");
|
||||
#endif
|
||||
|
||||
i = 10; /* Here all threads should be still alive. */
|
||||
|
||||
for( i = 0; i < N_THREADS; i++ )
|
||||
{
|
||||
if (sem_post (&tell_thread) == -1)
|
||||
{
|
||||
fprintf (stderr, "main %d post on sem tell_thread failed\n", i);
|
||||
print_error ();
|
||||
return;
|
||||
}
|
||||
#ifdef START_DEBUG
|
||||
fprintf (stderr, "main %d post on tell_thread\n", i);
|
||||
#endif
|
||||
}
|
||||
|
||||
for( i = 0; i < N_THREADS; i++ )
|
||||
{
|
||||
err = pthread_join(t[i], NULL );
|
||||
if( err != 0 )
|
||||
{
|
||||
fprintf (stderr, "error in thread %d join\n", i );
|
||||
}
|
||||
}
|
||||
|
||||
i = 10; /* Null line for setting bpts on. */
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
do_pass ();
|
||||
|
||||
return 0; /* Set breakpoint here before exit. */
|
||||
}
|
||||
|
||||
/* EndSourceFile */
|
||||
Reference in New Issue
Block a user