RTEMS specific thread support for G++. This implementation

includes RTEMS wrappers invoked by gcc.  The beauty of this
is that it puts the implementation in our hands. :)

It uses a mutex ( semaphore ), and task variables simulating
the "keys" for each task.

Thanks to Rosimildo da Silva <rdasilva@connectel.com> for
submitting this.
This commit is contained in:
Joel Sherrill
2000-05-08 21:21:29 +00:00
parent b76a825478
commit b12d10b4e0
4 changed files with 223 additions and 511 deletions

View File

@@ -7,7 +7,9 @@ AUTOMAKE_OPTIONS = foreign 1.4
## RTEMS unistd.h needs to be checked against newlib's and removed ## RTEMS unistd.h needs to be checked against newlib's and removed
UNUSED_H_FILES = devctl.h intr.h unistd.h UNUSED_H_FILES = devctl.h intr.h unistd.h
H_FILES = pthread.h sched.h aio.h mqueue.h semaphore.h H_FILES = sched.h aio.h mqueue.h semaphore.h
# H_FILES = pthread.h sched.h aio.h mqueue.h semaphore.h
noinst_HEADERS = $(H_FILES) noinst_HEADERS = $(H_FILES)

View File

@@ -1,509 +0,0 @@
/* pthread.h
*
* $Id$
*/
#ifndef __PTHREAD_h
#define __PTHREAD_h
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/features.h>
#if defined(_POSIX_THREADS)
#include <sys/types.h>
#include <time.h>
#include <sys/sched.h>
/*
* 3.1.3 Register Fork Handlers, P1003.1c/Draft 10, P1003.1c/Draft 10, p. 27
*
* RTEMS does not support processes, so we fall under this and do not
* provide this routine:
*
* "Either the implementation shall support the pthread_atfork() function
* as described above or the pthread_atfork() funciton shall not be
* provided."
*/
/*
* 11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81
*/
int pthread_mutexattr_init(
pthread_mutexattr_t *attr
);
int pthread_mutexattr_destroy(
pthread_mutexattr_t *attr
);
int pthread_mutexattr_getpshared(
const pthread_mutexattr_t *attr,
int *pshared
);
int pthread_mutexattr_setpshared(
pthread_mutexattr_t *attr,
int pshared
);
/*
* 11.3.2 Initializing and Destroying a Mutex, P1003.1c/Draft 10, p. 87
*/
int pthread_mutex_init(
pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr
);
int pthread_mutex_destroy(
pthread_mutex_t *mutex
);
/*
* This is used to statically initialize a pthread_mutex_t. Example:
*
* pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
*/
#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) 0xFFFFFFFF)
/*
* 11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93
*
* NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29
*/
int pthread_mutex_lock(
pthread_mutex_t *mutex
);
int pthread_mutex_trylock(
pthread_mutex_t *mutex
);
int pthread_mutex_unlock(
pthread_mutex_t *mutex
);
#if defined(_POSIX_TIMEOUTS)
int pthread_mutex_timedlock(
pthread_mutex_t *mutex,
const struct timespec *timeout
);
#endif /* _POSIX_TIMEOUTS */
/*
* 11.4.1 Condition Variable Initialization Attributes,
* P1003.1c/Draft 10, p. 96
*/
int pthread_condattr_init(
pthread_condattr_t *attr
);
int pthread_condattr_destroy(
pthread_condattr_t *attr
);
int pthread_condattr_getpshared(
const pthread_condattr_t *attr,
int *pshared
);
int pthread_condattr_setpshared(
pthread_condattr_t *attr,
int pshared
);
/*
* 11.4.2 Initializing and Destroying a Condition Variable,
* P1003.1c/Draft 10, p. 87
*/
int pthread_cond_init(
pthread_cond_t *cond,
const pthread_condattr_t *attr
);
int pthread_cond_destroy(
pthread_cond_t *mutex
);
/*
* This is used to statically initialize a pthread_cond_t. Example:
*
* pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
*/
#define PTHREAD_COND_INITIALIZER ((pthread_mutex_t) 0xFFFFFFFF)
/*
* 11.4.3 Broadcasting and Signaling a Condition, P1003.1c/Draft 10, p. 101
*/
int pthread_cond_signal(
pthread_cond_t *cond
);
int pthread_cond_broadcast(
pthread_cond_t *cond
);
/*
* 11.4.4 Waiting on a Condition, P1003.1c/Draft 10, p. 105
*/
int pthread_cond_wait(
pthread_cond_t *cond,
pthread_mutex_t *mutex
);
int pthread_cond_timedwait(
pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec *abstime
);
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
/*
* 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120
*/
int pthread_attr_setscope(
pthread_attr_t *attr,
int contentionscope
);
int pthread_attr_getscope(
const pthread_attr_t *attr,
int *contentionscope
);
int pthread_attr_setinheritsched(
pthread_attr_t *attr,
int inheritsched
);
int pthread_attr_getinheritsched(
const pthread_attr_t *attr,
int *inheritsched
);
int pthread_attr_setschedpolicy(
pthread_attr_t *attr,
int policy
);
int pthread_attr_getschedpolicy(
const pthread_attr_t *attr,
int *policy
);
#endif /* defined(_POSIX_THREAD_PRIORITY_SCHEDULING) */
int pthread_attr_setschedparam(
pthread_attr_t *attr,
const struct sched_param *param
);
int pthread_attr_getschedparam(
const pthread_attr_t *attr,
struct sched_param *param
);
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
/*
* 13.5.2 Dynamic Thread Scheduling Parameters Access,
* P1003.1c/Draft 10, p. 124
*/
int pthread_getschedparam(
pthread_t thread,
int *policy,
struct sched_param *param
);
int pthread_setschedparam(
pthread_t thread,
int policy,
struct sched_param *param
);
#endif /* defined(_POSIX_THREAD_PRIORITY_SCHEDULING) */
#if defined(_POSIX_THREAD_PRIO_INHERIT) || defined(_POSIX_THREAD_PRIO_PROTECT)
/*
* 13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128
*/
int pthread_mutexattr_setprotocol(
pthread_mutexattr_t *attr,
int protocol
);
int pthread_mutexattr_getprotocol(
const pthread_mutexattr_t *attr,
int *protocol
);
int pthread_mutexattr_setprioceiling(
pthread_mutexattr_t *attr,
int prioceiling
);
int pthread_mutexattr_getprioceiling(
const pthread_mutexattr_t *attr,
int *prioceiling
);
#endif /* _POSIX_THREAD_PRIO_INHERIT || _POSIX_THREAD_PRIO_PROTECT */
#if defined(_POSIX_THREAD_PRIO_PROTECT)
/*
* 13.6.2 Change the Priority Ceiling of a Mutex, P1003.1c/Draft 10, p. 131
*/
int pthread_mutex_setprioceiling(
pthread_mutex_t *mutex,
int prioceiling,
int *old_ceiling
);
int pthread_mutex_getprioceiling(
pthread_mutex_t *mutex,
int *prioceiling
);
#endif /* _POSIX_THREAD_PRIO_PROTECT */
/*
* 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140
*/
int pthread_attr_init(
pthread_attr_t *attr
);
int pthread_attr_destroy(
pthread_attr_t *attr
);
int pthread_attr_getstacksize(
const pthread_attr_t *attr,
size_t *stacksize
);
int pthread_attr_setstacksize(
pthread_attr_t *attr,
size_t stacksize
);
int pthread_attr_getstackaddr(
const pthread_attr_t *attr,
void **stackaddr
);
int pthread_attr_setstackaddr(
pthread_attr_t *attr,
void *stackaddr
);
int pthread_attr_getdetachstate(
const pthread_attr_t *attr,
int *detachstate
);
int pthread_attr_setdetachstate(
pthread_attr_t *attr,
int detachstate
);
/*
* 16.1.2 Thread Creation, P1003.1c/Draft 10, p. 144
*/
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)( void * ),
void *arg
);
/*
* 16.1.3 Wait for Thread Termination, P1003.1c/Draft 10, p. 147
*/
int pthread_join(
pthread_t thread,
void **value_ptr
);
/*
* 16.1.4 Detaching a Thread, P1003.1c/Draft 10, p. 149
*/
int pthread_detach(
pthread_t thread
);
/*
* 16.1.5.1 Thread Termination, p1003.1c/Draft 10, p. 150
*/
void pthread_exit(
void *value_ptr
);
/*
* 16.1.6 Get Calling Thread's ID, p1003.1c/Draft 10, p. XXX
*/
pthread_t pthread_self( void );
/*
* 16.1.7 Compare Thread IDs, p1003.1c/Draft 10, p. 153
*/
int pthread_equal(
pthread_t t1,
pthread_t t2
);
/*
* 16.1.8 Dynamic Package Initialization
*/
/*
* This is used to statically initialize a pthread_once_t. Example:
*
* pthread_once_t once = PTHREAD_ONCE_INIT;
*
* NOTE: This is named inconsistently -- it should be INITIALIZER.
*/
#define PTHREAD_ONCE_INIT { 1, 0 } /* is initialized and not run */
int pthread_once(
pthread_once_t *once_control,
void (*init_routine)(void)
);
/*
* 17.1.1 Thread-Specific Data Key Create, P1003.1c/Draft 10, p. 163
*/
int pthread_key_create(
pthread_key_t *key,
void (*destructor)( void * )
);
/*
* 17.1.2 Thread-Specific Data Management, P1003.1c/Draft 10, p. 165
*/
int pthread_setspecific(
pthread_key_t key,
const void *value
);
void *pthread_getspecific(
pthread_key_t key
);
/*
* 17.1.3 Thread-Specific Data Key Deletion, P1003.1c/Draft 10, p. 167
*/
int pthread_key_delete(
pthread_key_t key
);
/*
* 18.2.1 Canceling Execution of a Thread, P1003.1c/Draft 10, p. 181
*/
#define PTHREAD_CANCEL_ENABLE 0
#define PTHREAD_CANCEL_DISABLE 1
#define PTHREAD_CANCEL_DEFERRED 0
#define PTHREAD_CANCEL_ASYNCHRONOUS 1
int pthread_cancel(
pthread_t thread
);
/*
* 18.2.2 Setting Cancelability State, P1003.1c/Draft 10, p. 183
*/
int pthread_setcancelstate(
int state,
int *oldstate
);
int pthread_setcanceltype(
int type,
int *oldtype
);
void pthread_testcancel( void );
/*
* 18.2.3.1 Establishing Cancellation Handlers, P1003.1c/Draft 10, p. 184
*/
void pthread_cleanup_push(
void (*routine)( void * ),
void *arg
);
void pthread_cleanup_pop(
int execute
);
#if defined(_POSIX_THREAD_CPUTIME)
/*
* 20.1.6 Accessing a Thread CPU-time Clock, P1003.4b/D8, p. 58
*/
int pthread_getcpuclockid(
pthread_t thread_id,
clockid_t *clock_id
);
/*
* 20.1.7 CPU-time Clock Thread Creation Attribute, P1003.4b/D8, p. 59
*/
int pthread_attr_setcputime(
pthread_attr_t *attr,
int clock_allowed
);
int pthread_attr_getcputime(
pthread_attr_t *attr,
int *clock_allowed
);
#endif /* defined(_POSIX_THREAD_CPUTIME) */
#endif /* defined(_POSIX_THREADS) */
#ifdef __cplusplus
}
#endif
#endif
/* end of include file */

View File

@@ -48,7 +48,7 @@ LIBC_GLUE_C_FILES = __getpid.c __gettod.c __times.c truncate.c access.c \
UNIX_LIBC_C_FILES = unixlibc.c hosterr.c UNIX_LIBC_C_FILES = unixlibc.c hosterr.c
COMMON_C_FILES = $(BASE_FS_C_FILES) $(MALLOC_C_FILES) $(TERMIOS_C_FILES) \ COMMON_C_FILES = gxx_wrappers.c $(BASE_FS_C_FILES) $(MALLOC_C_FILES) $(TERMIOS_C_FILES) \
$(ERROR_C_FILES) $(ASSOCIATION_C_FILES) $(ERROR_C_FILES) $(ASSOCIATION_C_FILES)
UNIX_C_FILES = $(UNIX_LIBC_C_FILES) imfs_unixstub.c UNIX_C_FILES = $(UNIX_LIBC_C_FILES) imfs_unixstub.c

View File

@@ -0,0 +1,219 @@
/*
* RTEMS threads compatibily routines for libgcc2.
*
* by: Rosimildo da Silva ( rdasilva@connecttel.com
*
* Used ideas from:
* W. Eric Norum
* Canadian Light Source
* University of Saskatchewan
* Saskatoon, Saskatchewan, CANADA
* eric@cls.usask.ca
*
* Eric sent some e-mail in the rtems-list as a start point for this
* module implementation.
*
*
*/
/* We might not need, defined just in case */
#define __RTEMS_INSIDE__ 1
#include <stdlib.h>
#include <stdio.h>
#include <rtems.h>
#include <rtems/system.h>
#include <rtems/rtems/tasks.h>
/*
* These typedefs should match with the ones defined in the file
* gcc/gthr-rtems.h in the gcc distribution.
*/
typedef void *__gthread_key_t;
typedef int __gthread_once_t;
typedef void *__gthread_mutex_t;
/* uncomment this if you need to debug this interface */
/*
#define DEBUG_GXX_WRAPPERS 1
*/
/* prototype for the terminate() */
extern void __terminate( void );
#ifdef DEBUG_GXX_WRAPPERS
/* local function to return the ID of the calling thread */
static rtems_id get_tid( void )
{
rtems_id id = 0;
rtems_task_ident( RTEMS_SELF, 0, &id );
return id;
}
#endif
int rtems_gxx_once(__gthread_once_t *once, void (*func) ())
{
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: once=%x, func=%x\n", *once, func );
#endif
if( *once == 0 )
{
/*
* NOTE: could not use the call to disable "preemption", it causes
* one exception. Somebody might want to investiage it further
* sometime later.
*/
_Thread_Disable_dispatch();
*once = 1;
(*func)();
_Thread_Enable_dispatch();
}
return 0;
}
int rtems_gxx_key_create (__gthread_key_t *key, void (*dtor) (void *))
{
/* Ok, this can be a bit tricky. We are going to return a "key" as a
* pointer to the buffer that will hold the value of the key itself.
* We have to to this, becuase the others functions on this interface
* deal with the value of the key, as used with the POSIX API.
*/
/* Do not pull your hair, trust me this works. :-) */
__gthread_key_t *new_key = ( __gthread_key_t * )malloc( sizeof( __gthread_key_t ) );
*key = ( __gthread_key_t )new_key;
*new_key = NULL;
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: create key=%x, dtor=%x, new_key=%x\n", key, dtor, new_key );
#endif
/* register with RTEMS the buffer that will hold the key values */
if( rtems_task_variable_add( RTEMS_SELF, (void **)new_key, NULL ) == RTEMS_SUCCESSFUL )
return 0;
return -1;
}
int rtems_gxx_key_dtor (__gthread_key_t key, void *ptr)
{
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: dtor key=%x, ptr=%x\n", key, ptr );
#endif
*(void **)key = 0;
return 0;
}
int rtems_gxx_key_delete (__gthread_key_t key)
{
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: delete key=%x\n", key );
#endif
/* register with RTEMS the buffer that will hold the key values */
if( rtems_task_variable_delete( RTEMS_SELF, (void **)key ) == RTEMS_SUCCESSFUL )
{
if( key ) free( (void *)key );
return 0;
}
return 0;
}
void *rtems_gxx_getspecific(__gthread_key_t key)
{
void *p= 0;
/* register with RTEMS the buffer that will hold the key values */
if( rtems_task_variable_get( RTEMS_SELF, (void **)key, &p ) == RTEMS_SUCCESSFUL )
{
/* We do not have to do this, but what the heck ! */
p= *( void **)key;
}
else
{
/* fisrt time, always set to zero, it is unknown the value that the others
* threads are using at the moment of this call
*/
if( rtems_task_variable_add( RTEMS_SELF, (void **)key, NULL ) != RTEMS_SUCCESSFUL )
{
__terminate ();
}
*( void ** )key = (void *)0;
}
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: getspecific key=%x, ptr=%x, id=%x\n", key, p, get_tid() );
#endif
return p;
}
int rtems_gxx_setspecific(__gthread_key_t key, const void *ptr)
{
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: setspecific key=%x, ptr=%x, id=%x\n", key, ptr, get_tid() );
#endif
/* register with RTEMS the buffer that will hold the key values */
if( rtems_task_variable_add( RTEMS_SELF, (void **)key, NULL ) == RTEMS_SUCCESSFUL )
{
/* now let's set the proper value */
*( void ** )key = (void *)ptr;
return 0;
}
return -1;
}
/*
* MUTEX support
*/
void rtems_gxx_mutex_init (__gthread_mutex_t *mutex)
{
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: mutex init =%X\n", *mutex );
#endif
if( rtems_semaphore_create( rtems_build_name ('G', 'C', 'C', '2'),
1,
RTEMS_PRIORITY|RTEMS_BINARY_SEMAPHORE
|RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING|RTEMS_LOCAL,
0,
(rtems_id *)mutex ) != RTEMS_SUCCESSFUL )
{
__terminate ();
}
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: mutex init complete =%X\n", *mutex );
#endif
}
int rtems_gxx_mutex_lock (__gthread_mutex_t *mutex)
{
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: lock mutex=%X\n", *mutex );
#endif
return ( rtems_semaphore_obtain( (rtems_id)*mutex,
RTEMS_WAIT, RTEMS_NO_TIMEOUT ) == RTEMS_SUCCESSFUL) ? 0 : -1;
}
int rtems_gxx_mutex_trylock (__gthread_mutex_t *mutex)
{
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: trylock mutex=%X\n", *mutex );
#endif
return (rtems_semaphore_obtain ((rtems_id)*mutex,
RTEMS_NO_WAIT, 0) == RTEMS_SUCCESSFUL) ? 0 : -1;
}
int rtems_gxx_mutex_unlock (__gthread_mutex_t *mutex)
{
#ifdef DEBUG_GXX_WRAPPERS
printk( "gxx_wrappers: unlock mutex=%X\n", *mutex );
#endif
return (rtems_semaphore_release( (rtems_id)*mutex ) == RTEMS_SUCCESSFUL) ? 0 :-1;
}