diff options
Diffstat (limited to 'cpukit/posix/src')
175 files changed, 11918 insertions, 0 deletions
diff --git a/cpukit/posix/src/.cvsignore b/cpukit/posix/src/.cvsignore new file mode 100644 index 0000000000..000074c626 --- /dev/null +++ b/cpukit/posix/src/.cvsignore @@ -0,0 +1,4 @@ +stamp-h +stamp-h.in +config.h +config.h.in diff --git a/cpukit/posix/src/README.mqueue b/cpukit/posix/src/README.mqueue new file mode 100644 index 0000000000..12c8afc03e --- /dev/null +++ b/cpukit/posix/src/README.mqueue @@ -0,0 +1,38 @@ +# +# $Id$ +# + +This program should print out the default attribute settings for a +POSIX message queue. + +#include <mqueue.h> +#include <stdio.h> + +main() +{ + mqd_t mqfd; + struct mq_attr mqstat; + int status; + + /* this should create it */ + mqfd = mq_open("myipc",O_WRONLY|O_CREAT,NULL); + if ( (int)mqfd == -1 ) { + perror( "Unable to open message queue" ); + exit( 1 ); + } + + status = mq_getattr(mqfd, &mqstat); + if ( !status ) { + printf( "mq_maxmsg: %d\n", mqstat.mq_maxmsg ); + printf( "mq_msgsize: %d\n", mqstat.mq_msgsize ); + printf( "mq_curmsgs: %d\n", mqstat.mq_curmsgs ); + } else { + perror( "Unable to get attributes on message queue" ); + exit( 1 ); + } + + /* this should delete it */ + (void) mq_close( mqfd ); + exit( 0 ); +} + diff --git a/cpukit/posix/src/adasupp.c b/cpukit/posix/src/adasupp.c new file mode 100644 index 0000000000..535ff669c2 --- /dev/null +++ b/cpukit/posix/src/adasupp.c @@ -0,0 +1,32 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> + +/*PAGE + * + * _ada_pthread_minimum_stack_size + * + * This routine returns the minimum stack size so the GNAT RTS can + * allocate enough stack for Ada tasks. + */ + +size_t _ada_pthread_minimum_stack_size( void ) +{ + /* + * Eventually this may need to include a per cpu family calculation + * but for now, this will do. + */ + + return PTHREAD_MINIMUM_STACK_SIZE * 2; +} diff --git a/cpukit/posix/src/adjtime.c b/cpukit/posix/src/adjtime.c new file mode 100644 index 0000000000..1e06dab608 --- /dev/null +++ b/cpukit/posix/src/adjtime.c @@ -0,0 +1,60 @@ +/* + * adjustime() function - required by NTP + * + * I am unaware of the history behind the definition of this service + * and don't know if its behavior is covered by any standard. --joel + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <time.h> +#include <sys/time.h> + +#include <rtems/system.h> +#include <rtems/score/tod.h> +#include <rtems/posix/time.h> + +static long __adjustment = 0; + +int adjtime ( struct timeval *delta, struct timeval *olddelta ) +{ + struct timespec ts; + + if ( olddelta ) { + olddelta->tv_sec = __adjustment / TOD_MICROSECONDS_PER_SECOND; + olddelta->tv_usec = __adjustment / TOD_MICROSECONDS_PER_SECOND; + } + + if ( !delta ) + return -1; + + __adjustment = (delta->tv_sec * TOD_MICROSECONDS_PER_SECOND) + delta->tv_usec; + /* too small to account for */ + if ( __adjustment < _TOD_Microseconds_per_tick ) + return 0; + + clock_gettime( CLOCK_REALTIME, &ts ); + + ts.tv_sec += (__adjustment / TOD_MICROSECONDS_PER_SECOND); + ts.tv_nsec += (__adjustment % TOD_MICROSECONDS_PER_SECOND) * + TOD_NANOSECONDS_PER_MICROSECOND; + + /* if adjustment is too much positive */ + while ( ts.tv_nsec >= TOD_NANOSECONDS_PER_SECOND ) { + ts.tv_nsec -= TOD_NANOSECONDS_PER_SECOND; + ts.tv_sec++; + } + + /* if adjustment is too much negative */ + while ( ts.tv_nsec <= (-1 * TOD_NANOSECONDS_PER_SECOND) ) { + ts.tv_nsec += TOD_NANOSECONDS_PER_SECOND; + ts.tv_sec--; + } + + clock_settime( CLOCK_REALTIME, &ts ); + return 0; +} diff --git a/cpukit/posix/src/aio.c b/cpukit/posix/src/aio.c new file mode 100644 index 0000000000..f993a5f2d5 --- /dev/null +++ b/cpukit/posix/src/aio.c @@ -0,0 +1,118 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <aio.h> + +#include <rtems/system.h> +#include <rtems/seterr.h> + +int POSIX_NOT_IMPLEMENTED(); + +/*PAGE + * + * 6.7.2 Asynchronous Read, P1003.1b-1993, p. 154 + */ + +int aio_read( + struct aiocb *aiocbp +) +{ + return POSIX_NOT_IMPLEMENTED(); +} + +/*PAGE + * + * 6.7.3 Asynchronous Write, P1003.1b-1993, p. 155 + */ + +int aio_write( + struct aiocb *aiocbp +) +{ + return POSIX_NOT_IMPLEMENTED(); +} + +/*PAGE + * + * 6.7.4 List Directed I/O, P1003.1b-1993, p. 158 + */ + +int lio_listio( + int mode, + struct aiocb * const list[], + int nent, + struct sigevent *sig +) +{ + return POSIX_NOT_IMPLEMENTED(); +} + +/*PAGE + * + * 6.7.5 Retrieve Error of Asynchronous I/O Operation, P1003.1b-1993, p. 161 + */ + +int aio_error( + const struct aiocb *aiocbp +) +{ + return POSIX_NOT_IMPLEMENTED(); +} + +/*PAGE + * + * 6.7.6 Retrieve Return Status of Asynchronous I/O Operation, + * P1003.1b-1993, p. 162 + */ + +int aio_return( + const struct aiocb *aiocbp +) +{ + return POSIX_NOT_IMPLEMENTED(); +} + +/*PAGE + * + * 6.7.7 Cancel Asynchronous I/O Operation, P1003.1b-1993, p. 163 + */ + +int aio_cancel( + int filedes, + struct aiocb *aiocbp +) +{ + return POSIX_NOT_IMPLEMENTED(); +} + +/*PAGE + * + * 6.7.7 Wait for Asynchronous I/O Request, P1003.1b-1993, p. 164 + */ + +int aio_suspend( + struct aiocb * const list[], + int nent, + const struct timespec *timeout +) +{ + return POSIX_NOT_IMPLEMENTED(); +} + +/*PAGE + * + * 6.7.9 Asynchronous File Synchronization, P1003.1b-1993, p. 166 + */ + +int aio_fsync( + int op, + struct aiocb *aiocbp +) +{ + return POSIX_NOT_IMPLEMENTED(); +} diff --git a/cpukit/posix/src/alarm.c b/cpukit/posix/src/alarm.c new file mode 100644 index 0000000000..c061b97e48 --- /dev/null +++ b/cpukit/posix/src/alarm.c @@ -0,0 +1,82 @@ +/* + * 3.4.1 Schedule Alarm, P1003.1b-1993, p. 79 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +/* #include <errno.h> */ + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> + +Watchdog_Control _POSIX_signals_Alarm_timer; + +/*PAGE + * + * _POSIX_signals_Alarm_TSR + */ + +void _POSIX_signals_Alarm_TSR( + Objects_Id id, + void *argument +) +{ + int status; + + status = kill( getpid(), SIGALRM ); + /* XXX can't print from an ISR, should this be fatal? */ +} + +unsigned int alarm( + unsigned int seconds +) +{ + unsigned int remaining = 0; + Watchdog_Control *the_timer; + + the_timer = &_POSIX_signals_Alarm_timer; + + /* + * Initialize the timer used to implement alarm(). + */ + + if ( !the_timer->routine ) { + _Watchdog_Initialize( the_timer, _POSIX_signals_Alarm_TSR, 0, NULL ); + } else { + switch ( _Watchdog_Remove( the_timer ) ) { + case WATCHDOG_INACTIVE: + case WATCHDOG_BEING_INSERTED: + break; + + case WATCHDOG_ACTIVE: + case WATCHDOG_REMOVE_IT: + /* + * The stop_time and start_time fields are snapshots of ticks since + * boot. Since alarm() is dealing in seconds, we must account for + * this. + */ + + remaining = the_timer->initial - + ((the_timer->stop_time - the_timer->start_time) / + _TOD_Ticks_per_second); + break; + } + } + + _Watchdog_Insert_seconds( the_timer, seconds ); + + return remaining; +} diff --git a/cpukit/posix/src/cancel.c b/cpukit/posix/src/cancel.c new file mode 100644 index 0000000000..2b72be4aef --- /dev/null +++ b/cpukit/posix/src/cancel.c @@ -0,0 +1,62 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/cancel.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/threadsup.h> + +/*PAGE + * + * 18.2.1 Canceling Execution of a Thread, P1003.1c/Draft 10, p. 181 + */ + +int pthread_cancel( + pthread_t thread +) +{ + Thread_Control *the_thread; + POSIX_API_Control *thread_support; + Objects_Locations location; + + /* + * Don't even think about deleting a resource from an ISR. + */ + + if ( _ISR_Is_in_progress() ) + return EPROTO; + + the_thread = _POSIX_Threads_Get( thread, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return EINVAL; + case OBJECTS_REMOTE: + return POSIX_MP_NOT_IMPLEMENTED(); + case OBJECTS_LOCAL: + thread_support = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + thread_support->cancelation_requested = 1; + + if ( thread_support->cancelability_state == PTHREAD_CANCEL_ENABLE && + thread_support->cancelability_type == PTHREAD_CANCEL_ASYNCHRONOUS ) { + _POSIX_Threads_cancel_run( the_thread ); + } + + _Thread_Enable_dispatch(); + return 0; + } + + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/cancelrun.c b/cpukit/posix/src/cancelrun.c new file mode 100644 index 0000000000..17fa55bdc6 --- /dev/null +++ b/cpukit/posix/src/cancelrun.c @@ -0,0 +1,63 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/cancel.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/threadsup.h> + +/*PAGE + * + * _POSIX_Threads_cancel_run + * + */ + +void _POSIX_Threads_cancel_run( + Thread_Control *the_thread +) +{ + POSIX_Cancel_Handler_control *handler; + Chain_Control *handler_stack; + POSIX_API_Control *thread_support; + ISR_Level level; + + thread_support = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + handler_stack = &thread_support->Cancellation_Handlers; + + thread_support->cancelability_state = PTHREAD_CANCEL_DISABLE; + + while ( !_Chain_Is_empty( handler_stack ) ) { + _ISR_Disable( level ); + handler = (POSIX_Cancel_Handler_control *) + _Chain_Tail( handler_stack )->previous; + _Chain_Extract_unprotected( &handler->Node ); + _ISR_Enable( level ); + + (*handler->routine)( handler->arg ); + + _Workspace_Free( handler ); + } + + /* Now we can delete the thread */ + + the_thread->Wait.return_argument = PTHREAD_CANCELED; + _Thread_Close( + _Objects_Get_information( the_thread->Object.id ), + the_thread + ); + _POSIX_Threads_Free( the_thread ); + +} diff --git a/cpukit/posix/src/cleanuppop.c b/cpukit/posix/src/cleanuppop.c new file mode 100644 index 0000000000..49c35dff41 --- /dev/null +++ b/cpukit/posix/src/cleanuppop.c @@ -0,0 +1,60 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/cancel.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/threadsup.h> + +/*PAGE + * + * 18.2.3.1 Establishing Cancellation Handlers, P1003.1c/Draft 10, p. 184 + */ + +void pthread_cleanup_pop( + int execute +) +{ + POSIX_Cancel_Handler_control *handler; + POSIX_Cancel_Handler_control tmp_handler; + Chain_Control *handler_stack; + POSIX_API_Control *thread_support; + ISR_Level level; + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + handler_stack = &thread_support->Cancellation_Handlers; + + _ISR_Disable( level ); + if ( _Chain_Is_empty( handler_stack ) ) { + _ISR_Enable( level ); + return; + } + + handler = (POSIX_Cancel_Handler_control *) + _Chain_Tail( handler_stack )->previous; + _Chain_Extract_unprotected( &handler->Node ); + + _ISR_Enable( level ); + + tmp_handler = *handler; + + _Thread_Disable_dispatch(); + _Workspace_Free( handler ); + _Thread_Enable_dispatch(); + + if ( execute ) + (*tmp_handler.routine)( tmp_handler.arg ); +} diff --git a/cpukit/posix/src/cleanuppush.c b/cpukit/posix/src/cleanuppush.c new file mode 100644 index 0000000000..6efc7f9c45 --- /dev/null +++ b/cpukit/posix/src/cleanuppush.c @@ -0,0 +1,56 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/cancel.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/threadsup.h> + +/*PAGE + * + * 18.2.3.1 Establishing Cancellation Handlers, P1003.1c/Draft 10, p. 184 + */ + +void pthread_cleanup_push( + void (*routine)( void * ), + void *arg +) +{ + POSIX_Cancel_Handler_control *handler; + Chain_Control *handler_stack; + POSIX_API_Control *thread_support; + + if ( !routine ) + return; /* XXX what to do really? */ + + _Thread_Disable_dispatch(); + handler = _Workspace_Allocate( sizeof( POSIX_Cancel_Handler_control ) ); + + if ( !handler ) { + _Thread_Enable_dispatch(); + return; /* XXX what to do really? */ + } + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + handler_stack = &thread_support->Cancellation_Handlers; + + handler->routine = routine; + handler->arg = arg; + + _Chain_Append( handler_stack, &handler->Node ); + + _Thread_Enable_dispatch(); +} diff --git a/cpukit/posix/src/clockgetcpuclockid.c b/cpukit/posix/src/clockgetcpuclockid.c new file mode 100644 index 0000000000..96e554c1f5 --- /dev/null +++ b/cpukit/posix/src/clockgetcpuclockid.c @@ -0,0 +1,32 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 20.1.3 Accessing a Process CPU-time CLock, P1003.4b/D8, p. 55 + */ + +int clock_getcpuclockid( + pid_t pid, + clockid_t *clock_id +) +{ + return POSIX_NOT_IMPLEMENTED(); +} diff --git a/cpukit/posix/src/clockgetenableattr.c b/cpukit/posix/src/clockgetenableattr.c new file mode 100644 index 0000000000..0d3fbebfb4 --- /dev/null +++ b/cpukit/posix/src/clockgetenableattr.c @@ -0,0 +1,32 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 20.1.5 CPU-time Clock Attribute Access, P1003.4b/D8, p. 58 + */ + +int clock_getenable_attr( + clockid_t clock_id, + int *attr +) +{ + return POSIX_NOT_IMPLEMENTED(); +} diff --git a/cpukit/posix/src/clockgetres.c b/cpukit/posix/src/clockgetres.c new file mode 100644 index 0000000000..423759c8d8 --- /dev/null +++ b/cpukit/posix/src/clockgetres.c @@ -0,0 +1,55 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 14.2.1 Clocks, P1003.1b-1993, p. 263 + */ + +int clock_getres( + clockid_t clock_id, + struct timespec *res +) +{ + if ( !res ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + switch ( clock_id ) { + + /* + * All time in rtems is based on the same clock tick. + */ + + case CLOCK_REALTIME: + case CLOCK_PROCESS_CPUTIME: + case CLOCK_THREAD_CPUTIME: + if ( res ) { + res->tv_sec = _TOD_Microseconds_per_tick / 1000000; + res->tv_nsec = _TOD_Microseconds_per_tick * 1000; + /* _POSIX_Interval_to_timespec( _TOD_Microseconds_per_tick, res ); */ + } + break; + + default: + rtems_set_errno_and_return_minus_one( EINVAL ); + + } + return 0; +} diff --git a/cpukit/posix/src/clockgettime.c b/cpukit/posix/src/clockgettime.c new file mode 100644 index 0000000000..97a6f607e5 --- /dev/null +++ b/cpukit/posix/src/clockgettime.c @@ -0,0 +1,69 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 14.2.1 Clocks, P1003.1b-1993, p. 263 + */ + +int clock_gettime( + clockid_t clock_id, + struct timespec *tp +) +{ + ISR_Level level; + time_t seconds; + long ticks; + + if ( !tp ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + switch ( clock_id ) { + + case CLOCK_REALTIME: + + _ISR_Disable( level ); + seconds = _TOD_Seconds_since_epoch; + ticks = _TOD_Current.ticks; + _ISR_Enable( level ); + + tp->tv_sec = seconds + POSIX_TIME_SECONDS_1970_THROUGH_1988; + tp->tv_nsec = ticks * _TOD_Microseconds_per_tick * + TOD_NANOSECONDS_PER_MICROSECOND; + break; + +#ifdef _POSIX_CPUTIME + case CLOCK_PROCESS_CPUTIME: + /* don't base this on _Watchdog_Ticks_since_boot--duration is too short*/ + return POSIX_NOT_IMPLEMENTED(); + break; +#endif + +#ifdef _POSIX_THREAD_CPUTIME + case CLOCK_THREAD_CPUTIME: + return POSIX_NOT_IMPLEMENTED(); + break; +#endif + default: + rtems_set_errno_and_return_minus_one( EINVAL ); + + } + return 0; +} diff --git a/cpukit/posix/src/clocksetenableattr.c b/cpukit/posix/src/clocksetenableattr.c new file mode 100644 index 0000000000..f5a29920d1 --- /dev/null +++ b/cpukit/posix/src/clocksetenableattr.c @@ -0,0 +1,32 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 20.1.5 CPU-time Clock Attribute Access, P1003.4b/D8, p. 58 + */ + +int clock_setenable_attr( + clockid_t clock_id, + int attr +) +{ + return POSIX_NOT_IMPLEMENTED(); +} diff --git a/cpukit/posix/src/clocksettime.c b/cpukit/posix/src/clocksettime.c new file mode 100644 index 0000000000..c85e90de61 --- /dev/null +++ b/cpukit/posix/src/clocksettime.c @@ -0,0 +1,88 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 14.2.1 Clocks, P1003.1b-1993, p. 263 + */ + +int clock_settime( + clockid_t clock_id, + const struct timespec *tp +) +{ + struct tm split_time; + TOD_Control tod; + Watchdog_Interval seconds; + + assert( tp ); + + switch ( clock_id ) { + + case CLOCK_REALTIME: + (void) gmtime_r( &tp->tv_sec, &split_time ); + + /* + * Convert the tm structure format to that used by the TOD Handler + * + * NOTE: TOD Handler does not honor leap seconds. + */ + + tod.year = split_time.tm_year + 1900; /* RHS is years since 1900 */ + tod.month = split_time.tm_mon + 1; /* RHS uses 0-11 */ + tod.day = split_time.tm_mday; + tod.hour = split_time.tm_hour; + tod.minute = split_time.tm_min; + tod.second = split_time.tm_sec; /* RHS allows 0-61 for leap seconds */ + + tod.ticks = (tp->tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND) / + _TOD_Microseconds_per_tick; + + if ( !_TOD_Validate( &tod ) ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + /* + * We can't use the tp->tv_sec field because it is based on + * a different EPOCH. + */ + + seconds = _TOD_To_seconds( &tod ); + _Thread_Disable_dispatch(); + _TOD_Set( &tod, seconds ); + _Thread_Enable_dispatch(); + break; + +#ifdef _POSIX_CPUTIME + case CLOCK_PROCESS_CPUTIME: + return POSIX_NOT_IMPLEMENTED(); + break; +#endif + +#ifdef _POSIX_THREAD_CPUTIME + case CLOCK_THREAD_CPUTIME: + return POSIX_NOT_IMPLEMENTED(); + break; +#endif + default: + rtems_set_errno_and_return_minus_one( EINVAL ); + + } + return 0; +} diff --git a/cpukit/posix/src/cond.c b/cpukit/posix/src/cond.c new file mode 100644 index 0000000000..b2d0fcd8d1 --- /dev/null +++ b/cpukit/posix/src/cond.c @@ -0,0 +1,52 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * _POSIX_Condition_variables_Manager_initialization + * + * This routine initializes all condition variable manager related data + * structures. + * + * Input parameters: + * maximum_condition_variables - maximum configured condition_variables + * + * Output parameters: NONE + */ + +void _POSIX_Condition_variables_Manager_initialization( + uint32_t maximum_condition_variables +) +{ + _Objects_Initialize_information( + &_POSIX_Condition_variables_Information, /* object information table */ + OBJECTS_POSIX_API, /* object API */ + OBJECTS_POSIX_CONDITION_VARIABLES, /* object class */ + maximum_condition_variables, /* maximum objects of this class */ + sizeof( POSIX_Condition_variables_Control ), + /* size of this object's control block */ + FALSE, /* TRUE if names for this object are strings */ + 0 /* maximum length of each object's name */ +#if defined(RTEMS_MULTIPROCESSING) + , + FALSE, /* TRUE if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); +} diff --git a/cpukit/posix/src/condattrdestroy.c b/cpukit/posix/src/condattrdestroy.c new file mode 100644 index 0000000000..3d818e9fef --- /dev/null +++ b/cpukit/posix/src/condattrdestroy.c @@ -0,0 +1,35 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 11.4.1 Condition Variable Initialization Attributes, + * P1003.1c/Draft 10, p. 96 + */ + +int pthread_condattr_destroy( + pthread_condattr_t *attr +) +{ + if ( !attr || attr->is_initialized == FALSE ) + return EINVAL; + + attr->is_initialized = FALSE; + return 0; +} diff --git a/cpukit/posix/src/condattrgetpshared.c b/cpukit/posix/src/condattrgetpshared.c new file mode 100644 index 0000000000..479fb61cfb --- /dev/null +++ b/cpukit/posix/src/condattrgetpshared.c @@ -0,0 +1,36 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 11.4.1 Condition Variable Initialization Attributes, + * P1003.1c/Draft 10, p. 96 + */ + +int pthread_condattr_getpshared( + const pthread_condattr_t *attr, + int *pshared +) +{ + if ( !attr ) + return EINVAL; + + *pshared = attr->process_shared; + return 0; +} diff --git a/cpukit/posix/src/condattrinit.c b/cpukit/posix/src/condattrinit.c new file mode 100644 index 0000000000..3cd620a312 --- /dev/null +++ b/cpukit/posix/src/condattrinit.c @@ -0,0 +1,35 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 11.4.1 Condition Variable Initialization Attributes, + * P1003.1c/Draft 10, p. 96 + */ + +int pthread_condattr_init( + pthread_condattr_t *attr +) +{ + if ( !attr ) + return EINVAL; + + *attr = _POSIX_Condition_variables_Default_attributes; + return 0; +} diff --git a/cpukit/posix/src/condattrsetpshared.c b/cpukit/posix/src/condattrsetpshared.c new file mode 100644 index 0000000000..05539b2866 --- /dev/null +++ b/cpukit/posix/src/condattrsetpshared.c @@ -0,0 +1,43 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 11.4.1 Condition Variable Initialization Attributes, + * P1003.1c/Draft 10, p. 96 + */ + +int pthread_condattr_setpshared( + pthread_condattr_t *attr, + int pshared +) +{ + if ( !attr ) + return EINVAL; + + switch ( pshared ) { + case PTHREAD_PROCESS_SHARED: + case PTHREAD_PROCESS_PRIVATE: + attr->process_shared = pshared; + return 0; + + default: + return EINVAL; + } +} diff --git a/cpukit/posix/src/condbroadcast.c b/cpukit/posix/src/condbroadcast.c new file mode 100644 index 0000000000..b1efbceb96 --- /dev/null +++ b/cpukit/posix/src/condbroadcast.c @@ -0,0 +1,30 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 11.4.3 Broadcasting and Signaling a Condition, P1003.1c/Draft 10, p. 101 + */ + +int pthread_cond_broadcast( + pthread_cond_t *cond +) +{ + return _POSIX_Condition_variables_Signal_support( cond, TRUE ); +} diff --git a/cpukit/posix/src/conddefaultattributes.c b/cpukit/posix/src/conddefaultattributes.c new file mode 100644 index 0000000000..b8b0ae824c --- /dev/null +++ b/cpukit/posix/src/conddefaultattributes.c @@ -0,0 +1,28 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * The default condition variable attributes structure. + */ + +const pthread_condattr_t _POSIX_Condition_variables_Default_attributes = { + TRUE, /* is_initialized */ + PTHREAD_PROCESS_PRIVATE /* process_shared */ +}; diff --git a/cpukit/posix/src/conddestroy.c b/cpukit/posix/src/conddestroy.c new file mode 100644 index 0000000000..a6d2c0fc81 --- /dev/null +++ b/cpukit/posix/src/conddestroy.c @@ -0,0 +1,80 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 11.4.2 Initializing and Destroying a Condition Variable, + * P1003.1c/Draft 10, p. 87 + */ + +int pthread_cond_destroy( + pthread_cond_t *cond +) +{ + register POSIX_Condition_variables_Control *the_cond; + Objects_Locations location; + + the_cond = _POSIX_Condition_variables_Get( cond, &location ); + switch ( location ) { + case OBJECTS_REMOTE: +#if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + return EINVAL; +#endif + + case OBJECTS_ERROR: + return EINVAL; + + + case OBJECTS_LOCAL: + + if ( _Thread_queue_First( &the_cond->Wait_queue ) ) { + _Thread_Enable_dispatch(); + return EBUSY; + } + + _Objects_Close( + &_POSIX_Condition_variables_Information, + &the_cond->Object + ); + + _POSIX_Condition_variables_Free( the_cond ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( the_cond->process_shared == PTHREAD_PROCESS_SHARED ) { + + _Objects_MP_Close( + &_POSIX_Condition_variables_Information, + the_cond->Object.id + ); + + _POSIX_Condition_variables_MP_Send_process_packet( + POSIX_CONDITION_VARIABLES_MP_ANNOUNCE_DELETE, + the_cond->Object.id, + 0, /* Not used */ + 0 /* Not used */ + ); + } +#endif + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/condinit.c b/cpukit/posix/src/condinit.c new file mode 100644 index 0000000000..319cd4383a --- /dev/null +++ b/cpukit/posix/src/condinit.c @@ -0,0 +1,99 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 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 +) +{ + POSIX_Condition_variables_Control *the_cond; + const pthread_condattr_t *the_attr; + + if ( attr ) the_attr = attr; + else the_attr = &_POSIX_Condition_variables_Default_attributes; + + /* + * XXX: Be careful about attributes when global!!! + */ + + if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED ) + return POSIX_MP_NOT_IMPLEMENTED(); + + if ( !the_attr->is_initialized ) + return EINVAL; + + _Thread_Disable_dispatch(); + + the_cond = _POSIX_Condition_variables_Allocate(); + + if ( !the_cond ) { + _Thread_Enable_dispatch(); + return ENOMEM; + } + +#if defined(RTEMS_MULTIPROCESSING) + if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED && + !( _Objects_MP_Allocate_and_open( &_POSIX_Condition_variables_Information, + 0, the_cond->Object.id, FALSE ) ) ) { + _POSIX_Condition_variables_Free( the_cond ); + _Thread_Enable_dispatch(); + return EAGAIN; + } +#endif + + the_cond->process_shared = the_attr->process_shared; + + the_cond->Mutex = POSIX_CONDITION_VARIABLES_NO_MUTEX; + +/* XXX some more initialization might need to go here */ + _Thread_queue_Initialize( + &the_cond->Wait_queue, + THREAD_QUEUE_DISCIPLINE_FIFO, + STATES_WAITING_FOR_CONDITION_VARIABLE, + ETIMEDOUT + ); + + _Objects_Open( + &_POSIX_Condition_variables_Information, + &the_cond->Object, + 0 + ); + + *cond = the_cond->Object.id; + +#if defined(RTEMS_MULTIPROCESSING) + if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED ) + _POSIX_Condition_variables_MP_Send_process_packet( + POSIX_CONDITION_VARIABLES_MP_ANNOUNCE_CREATE, + the_cond->Object.id, + 0, /* Name not used */ + 0 /* Not used */ + ); +#endif + + _Thread_Enable_dispatch(); + + return 0; +} diff --git a/cpukit/posix/src/condmp.c b/cpukit/posix/src/condmp.c new file mode 100644 index 0000000000..8b5054d264 --- /dev/null +++ b/cpukit/posix/src/condmp.c @@ -0,0 +1,45 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/* + * TEMPORARY + */ + +#if defined(RTEMS_MULTIPROCESSING) +void _POSIX_Condition_variables_MP_Send_process_packet ( + POSIX_Condition_variables_MP_Remote_operations operation, + Objects_Id condition_variables_id, + Objects_Name name, + Objects_Id proxy_id +) +{ + (void) POSIX_MP_NOT_IMPLEMENTED(); +} + +void _POSIX_Condition_variables_MP_Send_extract_proxy( + Thread_Control *the_thread +) +{ + (void) POSIX_MP_NOT_IMPLEMENTED(); +} +#endif + +/* + * END OF TEMPORARY + */ diff --git a/cpukit/posix/src/condsignal.c b/cpukit/posix/src/condsignal.c new file mode 100644 index 0000000000..bd9d4b3b07 --- /dev/null +++ b/cpukit/posix/src/condsignal.c @@ -0,0 +1,30 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 11.4.3 Broadcasting and Signaling a Condition, P1003.1c/Draft 10, p. 101 + */ + +int pthread_cond_signal( + pthread_cond_t *cond +) +{ + return _POSIX_Condition_variables_Signal_support( cond, FALSE ); +} diff --git a/cpukit/posix/src/condsignalsupp.c b/cpukit/posix/src/condsignalsupp.c new file mode 100644 index 0000000000..5fad8e0ead --- /dev/null +++ b/cpukit/posix/src/condsignalsupp.c @@ -0,0 +1,61 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * _POSIX_Condition_variables_Signal_support + * + * A support routine which implements guts of the broadcast and single task + * wake up version of the "signal" operation. + */ + +int _POSIX_Condition_variables_Signal_support( + pthread_cond_t *cond, + boolean is_broadcast +) +{ + register POSIX_Condition_variables_Control *the_cond; + Objects_Locations location; + Thread_Control *the_thread; + + the_cond = _POSIX_Condition_variables_Get( cond, &location ); + switch ( location ) { + case OBJECTS_REMOTE: +#if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + return EINVAL; +#endif + + case OBJECTS_ERROR: + return EINVAL; + case OBJECTS_LOCAL: + + do { + the_thread = _Thread_queue_Dequeue( &the_cond->Wait_queue ); + if ( !the_thread ) + the_cond->Mutex = POSIX_CONDITION_VARIABLES_NO_MUTEX; + } while ( is_broadcast && the_thread ); + + _Thread_Enable_dispatch(); + + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/condtimedwait.c b/cpukit/posix/src/condtimedwait.c new file mode 100644 index 0000000000..32ce1d4a05 --- /dev/null +++ b/cpukit/posix/src/condtimedwait.c @@ -0,0 +1,61 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 11.4.4 Waiting on a Condition, P1003.1c/Draft 10, p. 105 + */ + +int pthread_cond_timedwait( + pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime +) +{ + Watchdog_Interval timeout; + struct timespec current_time; + struct timespec difference; + boolean already_timedout = FALSE; + + if ( !abstime ) + return EINVAL; + + /* + * The abstime is a walltime. We turn it into an interval. + */ + + (void) clock_gettime( CLOCK_REALTIME, ¤t_time ); + + /* XXX probably some error checking should go here */ + + _POSIX_Timespec_subtract( ¤t_time, abstime, &difference ); + + if ( ( difference.tv_sec < 0 ) || ( ( difference.tv_sec == 0 ) && + ( difference.tv_nsec < 0 ) ) ) + already_timedout = TRUE; + + timeout = _POSIX_Timespec_to_interval( &difference ); + + return _POSIX_Condition_variables_Wait_support( + cond, + mutex, + timeout, + already_timedout + ); +} diff --git a/cpukit/posix/src/condwait.c b/cpukit/posix/src/condwait.c new file mode 100644 index 0000000000..cde020fe93 --- /dev/null +++ b/cpukit/posix/src/condwait.c @@ -0,0 +1,36 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * 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 +) +{ + return _POSIX_Condition_variables_Wait_support( + cond, + mutex, + THREAD_QUEUE_WAIT_FOREVER, + FALSE + ); +} diff --git a/cpukit/posix/src/condwaitsupp.c b/cpukit/posix/src/condwaitsupp.c new file mode 100644 index 0000000000..02780779bf --- /dev/null +++ b/cpukit/posix/src/condwaitsupp.c @@ -0,0 +1,108 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/score/states.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/cond.h> +#include <rtems/posix/time.h> +#include <rtems/posix/mutex.h> + +/*PAGE + * + * _POSIX_Condition_variables_Wait_support + * + * A support routine which implements guts of the blocking, non-blocking, and + * timed wait version of condition variable wait routines. + */ + +int _POSIX_Condition_variables_Wait_support( + pthread_cond_t *cond, + pthread_mutex_t *mutex, + Watchdog_Interval timeout, + boolean already_timedout +) +{ + register POSIX_Condition_variables_Control *the_cond; + Objects_Locations location; + int status; + int mutex_status; + + if ( !_POSIX_Mutex_Get( mutex, &location ) ) { + return EINVAL; + } + + _Thread_Unnest_dispatch(); + + the_cond = _POSIX_Condition_variables_Get( cond, &location ); + switch ( location ) { + case OBJECTS_REMOTE: +#if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + return EINVAL; +#endif + case OBJECTS_ERROR: + return EINVAL; + case OBJECTS_LOCAL: + + if ( the_cond->Mutex && ( the_cond->Mutex != *mutex ) ) { + _Thread_Enable_dispatch(); + return EINVAL; + } + + (void) pthread_mutex_unlock( mutex ); +/* XXX ignore this for now since behavior is undefined + if ( mutex_status ) { + _Thread_Enable_dispatch(); + return EINVAL; + } +*/ + + if ( !already_timedout ) { + the_cond->Mutex = *mutex; + + _Thread_queue_Enter_critical_section( &the_cond->Wait_queue ); + _Thread_Executing->Wait.return_code = 0; + _Thread_Executing->Wait.queue = &the_cond->Wait_queue; + _Thread_Executing->Wait.id = *cond; + + _Thread_queue_Enqueue( &the_cond->Wait_queue, timeout ); + + _Thread_Enable_dispatch(); + + /* + * Switch ourself out because we blocked as a result of the + * _Thread_queue_Enqueue. + */ + + status = _Thread_Executing->Wait.return_code; + if ( status && status != ETIMEDOUT ) + return status; + + } else { + _Thread_Enable_dispatch(); + status = ETIMEDOUT; + } + + /* + * When we get here the dispatch disable level is 0. + */ + + mutex_status = pthread_mutex_lock( mutex ); + if ( mutex_status ) + return EINVAL; + + return status; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/devctl.c b/cpukit/posix/src/devctl.c new file mode 100644 index 0000000000..9800a109eb --- /dev/null +++ b/cpukit/posix/src/devctl.c @@ -0,0 +1,26 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <devctl.h> + +#include <rtems/system.h> + +/*PAGE + * + * 21.2.1 Control a Device, P1003.4b/D8, p. 65 + */ + +int devctl( + int filedes, + void *dev_data_ptr, + size_t nbyte, + int *dev_info_ptr +) +{ + return POSIX_NOT_IMPLEMENTED(); +} diff --git a/cpukit/posix/src/execl.c b/cpukit/posix/src/execl.c new file mode 100644 index 0000000000..fa820a268f --- /dev/null +++ b/cpukit/posix/src/execl.c @@ -0,0 +1,21 @@ +/* + * execl() - POSIX 1003.1b 3.1.2 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +int execl( + const char *path, + const char *arg, + ... +) +{ + errno = ENOSYS; + return -1; +} diff --git a/cpukit/posix/src/execle.c b/cpukit/posix/src/execle.c new file mode 100644 index 0000000000..83bd05882c --- /dev/null +++ b/cpukit/posix/src/execle.c @@ -0,0 +1,21 @@ +/* + * execle() - POSIX 1003.1b 3.1.2 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +int execle( + const char *path, + char const *arg, + ... +) +{ + errno = ENOSYS; + return -1; +} diff --git a/cpukit/posix/src/execlp.c b/cpukit/posix/src/execlp.c new file mode 100644 index 0000000000..2bc1303527 --- /dev/null +++ b/cpukit/posix/src/execlp.c @@ -0,0 +1,21 @@ +/* + * execlp() - POSIX 1003.1b 3.1.2 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +int execlp( + const char *file, + const char *arg, + ... +) +{ + errno = ENOSYS; + return -1; +} diff --git a/cpukit/posix/src/execv.c b/cpukit/posix/src/execv.c new file mode 100644 index 0000000000..c30d4939b6 --- /dev/null +++ b/cpukit/posix/src/execv.c @@ -0,0 +1,20 @@ +/* + * execv() - POSIX 1003.1b 3.1.2 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +int execv( + const char *file, + char *const argv[] +) +{ + errno = ENOSYS; + return -1; +} diff --git a/cpukit/posix/src/execve.c b/cpukit/posix/src/execve.c new file mode 100644 index 0000000000..43ec3004e6 --- /dev/null +++ b/cpukit/posix/src/execve.c @@ -0,0 +1,21 @@ +/* + * execve() - POSIX 1003.1b 3.1.2 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +int execve( + const char *path, + char *const argv[], + char *const envp[] +) +{ + errno = ENOSYS; + return -1; +} diff --git a/cpukit/posix/src/execvp.c b/cpukit/posix/src/execvp.c new file mode 100644 index 0000000000..a82db0ed32 --- /dev/null +++ b/cpukit/posix/src/execvp.c @@ -0,0 +1,20 @@ +/* + * execvp() - POSIX 1003.1b 3.1.2 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +int execvp( + const char *path, + char *const argv[] +) +{ + errno = ENOSYS; + return -1; +} diff --git a/cpukit/posix/src/fork.c b/cpukit/posix/src/fork.c new file mode 100644 index 0000000000..b06b1c9dbf --- /dev/null +++ b/cpukit/posix/src/fork.c @@ -0,0 +1,18 @@ +/* + * fork() - POSIX 1003.1b 3.1.1 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <errno.h> + +int fork( void ) +{ + errno = ENOSYS; + return -1; +} diff --git a/cpukit/posix/src/getpagesize.c b/cpukit/posix/src/getpagesize.c new file mode 100644 index 0000000000..806c500a9b --- /dev/null +++ b/cpukit/posix/src/getpagesize.c @@ -0,0 +1,23 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> + +/*PAGE + * + * Get System Page Size (from SVR4 and 4.2+ BSD) + * + * This is not a functional version but the SPARC backend for at least + * gcc 2.8.1 plus gnat 3.13p and gcc 3.0.1 require it to be there and + * return a reasonable value. + */ + +size_t getpagesize(void) +{ + return 4096; +} diff --git a/cpukit/posix/src/intr.c b/cpukit/posix/src/intr.c new file mode 100644 index 0000000000..895db3c120 --- /dev/null +++ b/cpukit/posix/src/intr.c @@ -0,0 +1,349 @@ +/* + * NOTE: Each task has an interrupt semaphore associated with it. + * No matter which interrupt occurs that it has registered, + * the same semaphore is used. + * + * This whole interrupt scheme may have been eliminated in a later draft. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <intr.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/coresem.h> +#include <rtems/score/thread.h> +#include <rtems/score/watchdog.h> +#include <rtems/posix/intr.h> +#include <rtems/posix/time.h> +#include <rtems/posix/threadsup.h> + +/* + * _POSIX_Interrupt_Manager_initialization + * + * DESCRIPTION: + * + * This routine performs the initialization necessary for this manager. + */ + +void _POSIX_Interrupt_Manager_initialization( + uint32_t maximum_interrupt_handlers +) +{ + uint32_t index; + POSIX_Interrupt_Control *the_vector; + + _Objects_Initialize_information( + &_POSIX_Interrupt_Handlers_Information, /* object information table */ + OBJECTS_POSIX_API, /* object API */ + OBJECTS_POSIX_INTERRUPTS, /* object class */ + maximum_interrupt_handlers, /* maximum objects of this class */ + sizeof( POSIX_Interrupt_Handler_control ), + /* size of this object's control block */ + FALSE, /* TRUE if names for this object are strings */ + 0 /* maximum length of each object's name */ +#if defined(RTEMS_MULTIPROCESSING) + , + FALSE, /* TRUE if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); + + for ( index=0 ; index < CPU_INTERRUPT_NUMBER_OF_VECTORS ; index++ ) { + the_vector = &_POSIX_Interrupt_Information[ index ]; + + the_vector->number_installed = 0; + the_vector->lock_count = 0; + the_vector->deferred_count = 0; + _Chain_Initialize_empty( &the_vector->Handlers ); + } +} + +/*PAGE + * + * 22.3.1 Associate a User-Written ISR with an Interrupt, P1003.4b/D8, p. 74 + */ + +int intr_capture( + intr_t intr, + int (*intr_handler)( void *area ), + volatile void *area, + size_t areasize +) +{ + POSIX_Interrupt_Handler_control *the_intr; + POSIX_Interrupt_Control *the_vector; + POSIX_API_Thread_Support_Control *thread_support; + proc_ptr old_handler; + + if ( !_ISR_Is_vector_number_valid( intr ) || + !_ISR_Is_valid_user_handler( intr_handler ) ) + return EINVAL; + + _Thread_Disable_dispatch(); + + the_intr = _POSIX_Interrupt_Allocate(); + + if ( !the_intr ) { + _Thread_Enable_dispatch(); + return ENOMEM; + } + + the_vector = &_POSIX_Interrupt_Information[ intr ]; + + the_intr->vector = intr; + the_intr->handler = intr_handler; + the_intr->user_data_area = area; + the_intr->server = _Thread_Executing; + the_intr->is_active = TRUE; + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + thread_support->interrupts_installed++; + +/* XXX should we malloc the semaphore on the fly??? if so we probably need to + release it when the thread has released all interrupts and keep + a count of how many it has installed. CURRENTLY NO.. ALLOCATED w/TCB +*/ + + /* + * This is sufficient to have the handlers invoked in the opposite + * order of installation. The loop invoking them can then go from + * the front of the list to the end. + */ + + _Chain_Prepend( &the_vector->Handlers, &the_intr->Object.Node ); + + if ( !the_vector->number_installed++ ) + _ISR_Install_vector( + intr, + (proc_ptr) _POSIX_Interrupt_Handler, + &old_handler + ); + + _Objects_Open( &_POSIX_Interrupt_Handlers_Information, &the_intr->Object, 0 ); + + /* + * Normally, an Id would be returned here. + */ + + _Thread_Enable_dispatch(); + + return 0; +} + +/*PAGE + * + * 22.3.1 Associate a User-Written ISR with an Interrupt, P1003.4b/D8, p. 74 + */ + +int intr_release( + intr_t intr, + int (*intr_handler)( void *area ) +) +{ + boolean found; + POSIX_Interrupt_Handler_control *the_intr; + POSIX_Interrupt_Control *the_vector; + POSIX_API_Thread_Support_Control *thread_support; + Chain_Node *the_node; + + if ( !_ISR_Is_valid_user_handler( intr_handler ) ) + return EINVAL; + + _Thread_Disable_dispatch(); + + /* + * Since interrupt handlers do not have a user visible id, there is + * no choice but to search the entire set of active interrupt handlers + * to find this one. + */ + + found = FALSE; + + the_vector = &_POSIX_Interrupt_Information[ intr ]; + + the_node = _Chain_Head( &the_vector->Handlers ); + + for ( ; !_Chain_Is_tail( &the_vector->Handlers, the_node ) ; ) { + the_intr = (POSIX_Interrupt_Handler_control *) the_node; + + if ( the_intr->handler == intr_handler ) { + found = TRUE; + break; + } + the_node = the_node->next; + } + + if ( !found ) { + _Thread_Enable_dispatch(); + return EINVAL; + } + + if ( !_Thread_Is_executing( the_intr->server ) ) { + _Thread_Enable_dispatch(); + return EINVAL; /* XXX should be ENOISR; */ + } + + /* + * OK now we have found the interrupt handler and can do some work. + */ + + _Chain_Extract( &the_intr->Object.Node ); + + the_intr->is_active = FALSE; + + the_vector->number_installed -= 1; + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + thread_support->interrupts_installed--; + + /* + * It is unnecessary to flush the semaphore since the handler can only + * be "removed" by the thread which installed it. Thus it cannot be + * blocked on the semaphore or it would not be executing this routine. + */ + + _Objects_Close( &_POSIX_Interrupt_Handlers_Information, &the_intr->Object ); + + _POSIX_Interrupt_Free( the_intr ); + + _Thread_Enable_dispatch(); + + return 0; +} + +/*PAGE + * + * 22.3.1 Associate a User-Written ISR with an Interrupt, P1003.4b/D8, p. 74 + */ + +int intr_lock( + intr_t intr +) +{ + POSIX_Interrupt_Control *the_vector; + + _Thread_Disable_dispatch(); + + the_vector = &_POSIX_Interrupt_Information[ intr ]; + + the_vector->lock_count++; + + _Thread_Enable_dispatch(); + + return 0; +} + +/*PAGE + * + * 22.3.1 Associate a User-Written ISR with an Interrupt, P1003.4b/D8, p. 74 + */ + +int intr_unlock( + intr_t intr +) +{ + POSIX_Interrupt_Control *the_vector; + + _Thread_Disable_dispatch(); + + the_vector = &_POSIX_Interrupt_Information[ intr ]; + + if ( !--the_vector->lock_count ) { + while ( --the_vector->deferred_count ) { + _POSIX_Interrupt_Handler( intr ); + } + } + + _Thread_Enable_dispatch(); + + return 0; +} + +/* + * 22.3.2 Await Interrupt Notification, P1003.4b/D8, p. 76 + */ + +int intr_timed_wait( + int flags, + const struct timespec *timeout +) +{ + Watchdog_Interval ticks; + POSIX_API_Thread_Support_Control *thread_support; + + ticks = _POSIX_Timespec_to_interval( timeout ); + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + _Thread_Disable_dispatch(); + + _CORE_semaphore_Seize( + &thread_support->Interrupt_Semaphore, + 0, /* XXX does id=0 hurt in this case? */ + TRUE, + ticks + ); + _Thread_Enable_dispatch(); + + return _Thread_Executing->Wait.return_code; /* XXX should be POSIX */ +} + +/*PAGE + * + * _POSIX_Interrupt_Handler + * + */ + +void _POSIX_Interrupt_Handler( + ISR_Vector_number vector +) +{ + POSIX_Interrupt_Handler_control *the_intr; + POSIX_Interrupt_Control *the_vector; + POSIX_API_Thread_Support_Control *thread_support; + Chain_Node *the_node; + int status; + + the_vector = &_POSIX_Interrupt_Information[ vector ]; + + the_node = _Chain_Head( &the_vector->Handlers ); + + for ( ; !_Chain_Is_tail( &the_vector->Handlers, the_node ) ; ) { + the_intr = (POSIX_Interrupt_Handler_control *) the_node; + + status = (*the_intr->handler)( (void *) the_intr->user_data_area ); + + switch ( status ) { + case INTR_HANDLED_NOTIFY: + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + _CORE_semaphore_Surrender( + &thread_support->Interrupt_Semaphore, + 0, /* XXX is id=0 a problem */ + 0 /* XXX is this a problem (mp support)*/ + ); + return; + + case INTR_HANDLED_DO_NOT_NOTIFY: + return; + + case INTR_NOT_HANDLED: + default: /* this should not happen */ + break; + } + the_node = the_node->next; + } + + /* XXX + * + * This is an unhandled interrupt!!! + */ +} diff --git a/cpukit/posix/src/key.c b/cpukit/posix/src/key.c new file mode 100644 index 0000000000..8723cb67a0 --- /dev/null +++ b/cpukit/posix/src/key.c @@ -0,0 +1,46 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <string.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/key.h> + +/* + * _POSIX_Key_Manager_initialization + * + * DESCRIPTION: + * + * This routine performs the initialization necessary for this manager. + */ + +void _POSIX_Key_Manager_initialization( + uint32_t maximum_keys +) +{ + _Objects_Initialize_information( + &_POSIX_Keys_Information, /* object information table */ + OBJECTS_POSIX_API, /* object API */ + OBJECTS_POSIX_KEYS, /* object class */ + maximum_keys, /* maximum objects of this class */ + sizeof( POSIX_Keys_Control ), + /* size of this object's control block */ + FALSE, /* TRUE if names for this object are strings */ + 0 /* maximum length of each object's name */ +#if defined(RTEMS_MULTIPROCESSING) + , + FALSE, /* TRUE if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); +} diff --git a/cpukit/posix/src/keycreate.c b/cpukit/posix/src/keycreate.c new file mode 100644 index 0000000000..d8ae746992 --- /dev/null +++ b/cpukit/posix/src/keycreate.c @@ -0,0 +1,90 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <string.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/key.h> + +/*PAGE + * + * 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 * ) +) +{ + POSIX_Keys_Control *the_key; + void *table; + uint32_t the_api; + uint32_t bytes_to_allocate; + + + _Thread_Disable_dispatch(); + + the_key = _POSIX_Keys_Allocate(); + + if ( !the_key ) { + _Thread_Enable_dispatch(); + return EAGAIN; + } + + the_key->destructor = destructor; + + /* + * This is a bit more complex than one might initially expect because + * APIs are optional. Thus there may be no ITRON tasks to have keys + * for. [NOTE: Currently RTEMS Classic API tasks are not always enabled.] + */ + + for ( the_api = 1; + the_api <= OBJECTS_APIS_LAST; + the_api++ ) { + + if ( _Objects_Information_table[ the_api ] && + _Objects_Information_table[ the_api ][ 1 ] ) { + bytes_to_allocate = sizeof( void * ) * + (_Objects_Information_table[ the_api ][ 1 ]->maximum + 1); + table = _Workspace_Allocate( bytes_to_allocate ); + if ( !table ) { + for ( --the_api; + the_api >= 1; + the_api-- ) + _Workspace_Free( the_key->Values[ the_api ] ); + + _POSIX_Keys_Free( the_key ); + _Thread_Enable_dispatch(); + return ENOMEM; + } + + the_key->Values[ the_api ] = table; + memset( table, '\0', bytes_to_allocate ); + } else { + the_key->Values[ the_api ] = NULL; + } + + + } + + the_key->is_active = TRUE; + + _Objects_Open( &_POSIX_Keys_Information, &the_key->Object, 0 ); + + *key = the_key->Object.id; + + _Thread_Enable_dispatch(); + + return 0; +} diff --git a/cpukit/posix/src/keydelete.c b/cpukit/posix/src/keydelete.c new file mode 100644 index 0000000000..364108046b --- /dev/null +++ b/cpukit/posix/src/keydelete.c @@ -0,0 +1,58 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <string.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/key.h> + +/*PAGE + * + * 17.1.3 Thread-Specific Data Key Deletion, P1003.1c/Draft 10, p. 167 + */ + +int pthread_key_delete( + pthread_key_t key +) +{ + register POSIX_Keys_Control *the_key; + Objects_Locations location; + uint32_t the_api; + + the_key = _POSIX_Keys_Get( key, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: /* should never happen */ + return EINVAL; + case OBJECTS_LOCAL: + _Objects_Close( &_POSIX_Keys_Information, &the_key->Object ); + + the_key->is_active = FALSE; + + for ( the_api = 1; + the_api <= OBJECTS_APIS_LAST; + the_api++ ) + if ( the_key->Values[ the_api ] ) + _Workspace_Free( the_key->Values[ the_api ] ); + + /* + * NOTE: The destructor is not called and it is the responsibility + * of the application to free the memory. + */ + + _POSIX_Keys_Free( the_key ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/keygetspecific.c b/cpukit/posix/src/keygetspecific.c new file mode 100644 index 0000000000..ee6912022c --- /dev/null +++ b/cpukit/posix/src/keygetspecific.c @@ -0,0 +1,48 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <string.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/key.h> + +/*PAGE + * + * 17.1.2 Thread-Specific Data Management, P1003.1c/Draft 10, p. 165 + */ + +void *pthread_getspecific( + pthread_key_t key +) +{ + register POSIX_Keys_Control *the_key; + uint32_t index; + uint32_t class; + Objects_Locations location; + void *key_data; + + the_key = _POSIX_Keys_Get( key, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: /* should never happen */ + return NULL; + case OBJECTS_LOCAL: + index = _Objects_Get_index( _Thread_Executing->Object.id ); + class = _Objects_Get_class( _Thread_Executing->Object.id ); + key_data = (void *) the_key->Values[ class ][ index ]; + _Thread_Enable_dispatch(); + return key_data; + } + (void) POSIX_BOTTOM_REACHED(); + return (void *)NULL; +} diff --git a/cpukit/posix/src/keyrundestructors.c b/cpukit/posix/src/keyrundestructors.c new file mode 100644 index 0000000000..f2c3b8e380 --- /dev/null +++ b/cpukit/posix/src/keyrundestructors.c @@ -0,0 +1,80 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <string.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/key.h> + +/*PAGE + * + * _POSIX_Keys_Run_destructors + * + * 17.1.1 Thread-Specific Data Key Create, P1003.1c/Draft 10, p. 163 + * + * NOTE: This is the routine executed when a thread exits to + * run through all the keys and do the destructor action. + */ + +void _POSIX_Keys_Run_destructors( + Thread_Control *thread +) +{ + uint32_t index; + uint32_t pthread_index; + uint32_t pthread_class; + uint32_t iterations; + boolean are_all_null; + POSIX_Keys_Control *the_key; + void *value; + + pthread_index = _Objects_Get_index( thread->Object.id ); + pthread_class = _Objects_Get_class( thread->Object.id ); + + iterations = 0; + + for ( ; ; ) { + + are_all_null = TRUE; + + for ( index=1 ; index <= _POSIX_Keys_Information.maximum ; index++ ) { + + the_key = (POSIX_Keys_Control *) + _POSIX_Keys_Information.local_table[ index ]; + + if ( the_key && the_key->is_active && the_key->destructor ) { + value = the_key->Values[ pthread_class ][ pthread_index ]; + if ( value ) { + (*the_key->destructor)( value ); + if ( the_key->Values[ pthread_class ][ pthread_index ] ) + are_all_null = FALSE; + } + } + } + + if ( are_all_null == TRUE ) + return; + + iterations++; + + /* + * The standard allows one to not do this and thus go into an infinite + * loop. It seems rude to unnecessarily lock up a system. + * + * Reference: 17.1.1.2 P1003.1c/Draft 10, p. 163, line 99. + */ + + if ( iterations >= PTHREAD_DESTRUCTOR_ITERATIONS ) + return; + } +} diff --git a/cpukit/posix/src/keysetspecific.c b/cpukit/posix/src/keysetspecific.c new file mode 100644 index 0000000000..30f10a06b4 --- /dev/null +++ b/cpukit/posix/src/keysetspecific.c @@ -0,0 +1,47 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <string.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/key.h> + +/*PAGE + * + * 17.1.2 Thread-Specific Data Management, P1003.1c/Draft 10, p. 165 + */ + +int pthread_setspecific( + pthread_key_t key, + const void *value +) +{ + register POSIX_Keys_Control *the_key; + uint32_t index; + uint32_t class; + Objects_Locations location; + + the_key = _POSIX_Keys_Get( key, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: /* should never happen */ + return EINVAL; + case OBJECTS_LOCAL: + index = _Objects_Get_index( _Thread_Executing->Object.id ); + class = _Objects_Get_class( _Thread_Executing->Object.id ); + the_key->Values[ class ][ index ] = (void *) value; + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/kill.c b/cpukit/posix/src/kill.c new file mode 100644 index 0000000000..b601ee1d01 --- /dev/null +++ b/cpukit/posix/src/kill.c @@ -0,0 +1,51 @@ +/* + * 3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> + +int kill( + pid_t pid, + int sig +) +{ + return killinfo( pid, sig, NULL ); +} + +/* + * _kill_r + * + * This is the Newlib dependent reentrant version of kill(). + */ + +#if defined(RTEMS_NEWLIB) + +#include <reent.h> + +int _kill_r( + struct _reent *ptr, + pid_t pid, + int sig +) +{ + return kill( pid, sig ); +} +#endif diff --git a/cpukit/posix/src/killinfo.c b/cpukit/posix/src/killinfo.c new file mode 100644 index 0000000000..b275a0b764 --- /dev/null +++ b/cpukit/posix/src/killinfo.c @@ -0,0 +1,338 @@ +/* + * kill() support routine + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <signal.h> +#include <errno.h> +#include <assert.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> +#include <rtems/score/isr.h> + +/*PAGE + * + * 3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68 + * + * NOTE: Behavior of kill() depends on _POSIX_SAVED_IDS. + */ + +#define _POSIX_signals_Is_interested( _api, _mask ) \ + ( ~(_api)->signals_blocked & (_mask) ) + +int killinfo( + pid_t pid, + int sig, + const union sigval *value +) +{ + sigset_t mask; + POSIX_API_Control *api; + uint32_t the_api; + uint32_t index; + uint32_t maximum; + Objects_Information *the_info; + Objects_Control **object_table; + Thread_Control *the_thread; + Thread_Control *interested_thread; + Priority_Control interested_priority; + Chain_Control *the_chain; + Chain_Node *the_node; + siginfo_t siginfo_struct; + siginfo_t *siginfo; + POSIX_signals_Siginfo_node *psiginfo; + + /* + * Only supported for the "calling process" (i.e. this node). + */ + + if ( pid != getpid() ) + rtems_set_errno_and_return_minus_one( ESRCH ); + + /* + * Validate the signal passed. + */ + + if ( !sig ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( !is_valid_signo(sig) ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + /* + * If the signal is being ignored, then we are out of here. + */ + + if ( _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN ) { + return 0; + } + + /* + * P1003.1c/Draft 10, p. 33 says that certain signals should always + * be directed to the executing thread such as those caused by hardware + * faults. + */ + + switch ( sig ) { + case SIGFPE: + case SIGILL: + case SIGSEGV: + return pthread_kill( pthread_self(), sig ); + default: + break; + } + + mask = signo_to_mask( sig ); + + /* + * Build up a siginfo structure + */ + + siginfo = &siginfo_struct; + siginfo->si_signo = sig; + siginfo->si_code = SI_USER; + if ( !value ) { + siginfo->si_value.sival_int = 0; + } else { + siginfo->si_value = *value; + } + + _Thread_Disable_dispatch(); + + /* + * Is the currently executing thread interested? If so then it will + * get it an execute it as soon as the dispatcher executes. + */ + + the_thread = _Thread_Executing; + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + if ( _POSIX_signals_Is_interested( api, mask ) ) { + goto process_it; + } + + /* + * Is an interested thread waiting for this signal (sigwait())? + */ + + /* XXX violation of visibility -- need to define thread queue support */ + + for( index=0 ; + index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ; + index++ ) { + + the_chain = &_POSIX_signals_Wait_queue.Queues.Priority[ index ]; + + for ( the_node = the_chain->first ; + !_Chain_Is_tail( the_chain, the_node ) ; + the_node = the_node->next ) { + + the_thread = (Thread_Control *)the_node; + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + if ((the_thread->Wait.option & mask) || (~api->signals_blocked & mask)) { + goto process_it; + } + + } + } + + /* + * Is any other thread interested? The highest priority interested + * thread is selected. In the event of a tie, then the following + * additional criteria is used: + * + * + ready thread over blocked + * + blocked on call interruptible by signal (can return EINTR) + * + blocked on call not interruptible by signal + * + * This looks at every thread in the system regardless of the creating API. + * + * NOTES: + * + * + rtems internal threads do not receive signals. + */ + + interested_thread = NULL; + interested_priority = PRIORITY_MAXIMUM + 1; + + for ( the_api = 2; + the_api <= OBJECTS_APIS_LAST; + the_api++ ) { + + if ( the_api == OBJECTS_INTERNAL_THREADS ) + continue; + + if ( !_Objects_Information_table[ the_api ] ) /* API not installed */ + continue; + + the_info = _Objects_Information_table[ the_api ][ 1 ]; + + if ( !the_info ) /* manager not installed */ + continue; + + maximum = the_info->maximum; + object_table = the_info->local_table; + + assert( object_table ); /* always at least 1 entry */ + + for ( index = 1 ; index <= maximum ; index++ ) { + the_thread = (Thread_Control *) object_table[ index ]; + + if ( !the_thread ) + continue; + + /* + * If this thread is of lower priority than the interested thread, + * go on to the next thread. + */ + + if ( the_thread->current_priority > interested_priority ) + continue; + + /* + * If this thread is not interested, then go on to the next thread. + */ + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + if ( !api || !_POSIX_signals_Is_interested( api, mask ) ) + continue; + + /* + * Now we know the thread under connsideration is interested. + * If the thread under consideration is of higher priority, then + * it becomes the interested thread. + */ + + if ( the_thread->current_priority < interested_priority ) { + interested_thread = the_thread; + interested_priority = the_thread->current_priority; + continue; + } + + /* + * Now the thread and the interested thread have the same priority. + * If the interested thread is ready, then we don't need to send it + * to a blocked thread. + */ + + if ( _States_Is_ready( interested_thread->current_state ) ) + continue; + + /* + * Now the interested thread is blocked. + * If the thread we are considering is not, the it becomes the + * interested thread. + */ + + if ( _States_Is_ready( the_thread->current_state ) ) { + interested_thread = the_thread; + interested_priority = the_thread->current_priority; + continue; + } + + /* + * Now we know both threads are blocked. + * If the interested thread is interruptible, then just use it. + */ + + /* XXX need a new states macro */ + if ( interested_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) + continue; + + /* + * Now both threads are blocked and the interested thread is not + * interruptible. + * If the thread under consideration is interruptible by a signal, + * then it becomes the interested thread. + */ + + /* XXX need a new states macro */ + if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) { + interested_thread = the_thread; + interested_priority = the_thread->current_priority; + } + } + } + + if ( interested_thread ) { + the_thread = interested_thread; + goto process_it; + } + + /* + * OK so no threads were interested right now. It will be left on the + * global pending until a thread receives it. The global set of threads + * can change interest in this signal in one of the following ways: + * + * + a thread is created with the signal unblocked, + * + pthread_sigmask() unblocks the signal, + * + sigprocmask() unblocks the signal, OR + * + sigaction() which changes the handler to SIG_IGN. + */ + + the_thread = NULL; + goto post_process_signal; + + /* + * We found a thread which was interested, so now we mark that this + * thread needs to do the post context switch extension so it can + * evaluate the signals pending. + */ + +process_it: + + the_thread->do_post_task_switch_extension = TRUE; + + /* + * Returns TRUE if the signal was synchronously given to a thread + * blocked waiting for the signal. + */ + + if ( _POSIX_signals_Unblock_thread( the_thread, sig, siginfo ) ) { + _Thread_Enable_dispatch(); + return 0; + } + +post_process_signal: + + /* + * We may have woken up a thread but we definitely need to post the + * signal to the process wide information set. + */ + + _POSIX_signals_Set_process_signals( mask ); + + if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO ) { + + psiginfo = (POSIX_signals_Siginfo_node *) + _Chain_Get( &_POSIX_signals_Inactive_siginfo ); + if ( !psiginfo ) { + rtems_set_errno_and_return_minus_one( EAGAIN ); + } + + psiginfo->Info = *siginfo; + + _Chain_Append( &_POSIX_signals_Siginfo[ sig ], &psiginfo->Node ); + } + + _Thread_Enable_dispatch(); + return 0; +} diff --git a/cpukit/posix/src/mprotect.c b/cpukit/posix/src/mprotect.c new file mode 100644 index 0000000000..60740615b5 --- /dev/null +++ b/cpukit/posix/src/mprotect.c @@ -0,0 +1,23 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> + +/*PAGE + * + * 12.2.3 Change Memory Protection, P1003.1b-1996, p. 277. + * + * This is not a functional version but the SPARC backend for at least + * gcc 2.8.1 plus gnat 3.13p and gcc 3.0.1 require it to be there and + * return 0. + */ + +int mprotect(const void *addr, size_t len, int prot) +{ + return 0; +} diff --git a/cpukit/posix/src/mqueue.c b/cpukit/posix/src/mqueue.c new file mode 100644 index 0000000000..7773626c76 --- /dev/null +++ b/cpukit/posix/src/mqueue.c @@ -0,0 +1,82 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Message_queue_Manager_initialization + * + * This routine initializes all message_queue manager related data structures. + * + * Input parameters: + * maximum_message_queues - maximum configured message_queues + * + * Output parameters: NONE + */ + +void _POSIX_Message_queue_Manager_initialization( + uint32_t maximum_message_queues +) +{ + _Objects_Initialize_information( + &_POSIX_Message_queue_Information, /* object information table */ + OBJECTS_POSIX_API, /* object API */ + OBJECTS_POSIX_MESSAGE_QUEUES, /* object class */ + maximum_message_queues, /* maximum objects of this class */ + sizeof( POSIX_Message_queue_Control ), + /* size of this object's control block */ + TRUE, /* TRUE if names for this object are strings */ + _POSIX_PATH_MAX /* maximum length of each object's name */ +#if defined(RTEMS_MULTIPROCESSING) + , + FALSE, /* TRUE if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); + _Objects_Initialize_information( + &_POSIX_Message_queue_Information_fds, + OBJECTS_POSIX_API, + OBJECTS_POSIX_MESSAGE_QUEUE_FDS, + maximum_message_queues, + sizeof( POSIX_Message_queue_Control_fd ), + /* size of this object's control block */ + TRUE, /* TRUE if names for this object are strings */ + NAME_MAX /* maximum length of each object's name */ +#if defined(RTEMS_MULTIPROCESSING) + , + FALSE, /* TRUE if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); +} diff --git a/cpukit/posix/src/mqueueclose.c b/cpukit/posix/src/mqueueclose.c new file mode 100644 index 0000000000..9254bbf25b --- /dev/null +++ b/cpukit/posix/src/mqueueclose.c @@ -0,0 +1,79 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/* + * + * 15.2.2 Close a Message Queue, P1003.1b-1993, p. 275 + */ + +int mq_close( + mqd_t mqdes +) +{ + POSIX_Message_queue_Control *the_mq; + POSIX_Message_queue_Control_fd *the_mq_fd; + Objects_Locations location; + + the_mq_fd = _POSIX_Message_queue_Get_fd( mqdes, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EBADF ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + /* + * First update the actual message queue to reflect this descriptor + * being disassociated. This may result in the queue being really + * deleted. + */ + + the_mq = the_mq_fd->Queue; + the_mq->open_count -= 1; + _POSIX_Message_queue_Delete( the_mq ); + + /* + * Now close this file descriptor. + */ + + _Objects_Close( + &_POSIX_Message_queue_Information_fds, &the_mq_fd->Object ); + _POSIX_Message_queue_Free_fd( the_mq_fd ); + + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mqueuecreatesupp.c b/cpukit/posix/src/mqueuecreatesupp.c new file mode 100644 index 0000000000..1259701124 --- /dev/null +++ b/cpukit/posix/src/mqueuecreatesupp.c @@ -0,0 +1,173 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/score/wkspace.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/* pure ANSI mode does not have this prototype */ +size_t strnlen(const char *, size_t); + +/*PAGE + * + * _POSIX_Message_queue_Create_support + * + * This routine does the actual creation and initialization of + * a poxix message queue. + */ + +int _POSIX_Message_queue_Create_support( + const char *name_arg, + int pshared, + struct mq_attr *attr_ptr, + POSIX_Message_queue_Control **message_queue +) +{ + POSIX_Message_queue_Control *the_mq; + CORE_message_queue_Attributes *the_mq_attr; + struct mq_attr attr; + char *name; + size_t n; + + n = strnlen( name_arg, NAME_MAX ); + if ( n > NAME_MAX ) + return ENAMETOOLONG; + + _Thread_Disable_dispatch(); + + /* + * There is no real basis for the default values. They will work + * but were not compared against any existing implementation for + * compatibility. See README.mqueue for an example program we + * think will print out the defaults. Report anything you find with it. + */ + + if ( attr_ptr == NULL ) { + attr.mq_maxmsg = 10; + attr.mq_msgsize = 16; + } else { + if ( attr_ptr->mq_maxmsg <= 0 ){ + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + if ( attr_ptr->mq_msgsize <= 0 ){ + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + attr = *attr_ptr; + } + +#if 0 && defined(RTEMS_MULTIPROCESSING) + if ( pshared == PTHREAD_PROCESS_SHARED && + !( _Objects_MP_Allocate_and_open( &_POSIX_Message_queue_Information, 0, + the_mq->Object.id, FALSE ) ) ) { + _POSIX_Message_queue_Free( the_mq ); + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENFILE ); + } +#endif + + the_mq = _POSIX_Message_queue_Allocate(); + if ( !the_mq ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENFILE ); + } + + the_mq->process_shared = pshared; + the_mq->named = TRUE; + the_mq->open_count = 1; + the_mq->linked = TRUE; + + /* + * Make a copy of the user's string for name just in case it was + * dynamically constructed. + */ + + name = _Workspace_Allocate(n); + if (!name) { + _POSIX_Message_queue_Free( the_mq ); + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENOMEM ); + } + strcpy( name, name_arg ); + + /* XXX + * + * Note that thread blocking discipline should be based on the + * current scheduling policy. + */ + + the_mq_attr = &the_mq->Message_queue.Attributes; + the_mq_attr->discipline = CORE_MESSAGE_QUEUE_DISCIPLINES_FIFO; + + if ( ! _CORE_message_queue_Initialize( + &the_mq->Message_queue, + the_mq_attr, + attr.mq_maxmsg, + attr.mq_msgsize + ) ) { + +#if 0 && defined(RTEMS_MULTIPROCESSING) + if ( pshared == PTHREAD_PROCESS_SHARED ) + _Objects_MP_Close( &_POSIX_Message_queue_Information, the_mq->Object.id ); +#endif + + _POSIX_Message_queue_Free( the_mq ); + _Workspace_Free(name); + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENOSPC ); + } + + _Objects_Open( + &_POSIX_Message_queue_Information, + &the_mq->Object, + (char *) name + ); + + *message_queue = the_mq; + +#if 0 && defined(RTEMS_MULTIPROCESSING) + if ( pshared == PTHREAD_PROCESS_SHARED ) + _POSIX_Message_queue_MP_Send_process_packet( + POSIX_MESSAGE_QUEUE_MP_ANNOUNCE_CREATE, + the_mq->Object.id, + (char *) name, + 0 /* Not used */ + ); +#endif + + _Thread_Enable_dispatch(); + return 0; +} diff --git a/cpukit/posix/src/mqueuedeletesupp.c b/cpukit/posix/src/mqueuedeletesupp.c new file mode 100644 index 0000000000..bf2e52fd64 --- /dev/null +++ b/cpukit/posix/src/mqueuedeletesupp.c @@ -0,0 +1,78 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/score/wkspace.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Message_queue_Delete + */ + +void _POSIX_Message_queue_Delete( + POSIX_Message_queue_Control *the_mq +) +{ + if ( !the_mq->linked && !the_mq->open_count ) { + /* the name memory may have been freed by unlink. */ + if ( the_mq->Object.name ) + _Workspace_Free( the_mq->Object.name ); + + _Objects_Close( &_POSIX_Message_queue_Information, &the_mq->Object ); + + _CORE_message_queue_Close( + &the_mq->Message_queue, + NULL, /* no MP support */ + CORE_MESSAGE_QUEUE_STATUS_WAS_DELETED + ); + + _POSIX_Message_queue_Free( the_mq ); + +#if 0 && defined(RTEMS_MULTIPROCESSING) + if ( the_mq->process_shared == PTHREAD_PROCESS_SHARED ) { + + _Objects_MP_Close( + &_POSIX_Message_queue_Information, + the_mq->Object.id + ); + + _POSIX_Message_queue_MP_Send_process_packet( + POSIX_MESSAGE_QUEUE_MP_ANNOUNCE_DELETE, + the_mq->Object.id, + 0, /* Not used */ + 0 /* Not used */ + ); + } +#endif + + } +} diff --git a/cpukit/posix/src/mqueuegetattr.c b/cpukit/posix/src/mqueuegetattr.c new file mode 100644 index 0000000000..d5cb7ababb --- /dev/null +++ b/cpukit/posix/src/mqueuegetattr.c @@ -0,0 +1,79 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 15.2.8 Get Message Queue Attributes, P1003.1b-1993, p. 283 + */ + +int mq_getattr( + mqd_t mqdes, + struct mq_attr *mqstat +) +{ + POSIX_Message_queue_Control *the_mq; + POSIX_Message_queue_Control_fd *the_mq_fd; + Objects_Locations location; + CORE_message_queue_Attributes *the_mq_attr; + + if ( !mqstat ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + the_mq_fd = _POSIX_Message_queue_Get_fd( mqdes, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EBADF ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + the_mq = the_mq_fd->Queue; + + /* + * Return the old values. + */ + + the_mq_attr = &the_mq->Message_queue.Attributes; + + mqstat->mq_flags = the_mq_fd->oflag; + mqstat->mq_msgsize = the_mq->Message_queue.maximum_message_size; + mqstat->mq_maxmsg = the_mq->Message_queue.maximum_pending_messages; + mqstat->mq_curmsgs = the_mq->Message_queue.number_of_pending_messages; + + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mqueuenametoid.c b/cpukit/posix/src/mqueuenametoid.c new file mode 100644 index 0000000000..91dd9357fd --- /dev/null +++ b/cpukit/posix/src/mqueuenametoid.c @@ -0,0 +1,66 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Message_queue_Name_to_id + * + * Look up the specified name and attempt to locate the id + * for the associated message queue. + */ + +int _POSIX_Message_queue_Name_to_id( + const char *name, + Objects_Id *id +) +{ + Objects_Name_or_id_lookup_errors status; + + if ( !name ) + return EINVAL; + + if ( !name[0] ) + return EINVAL; + + if( strlen(name) > PATH_MAX ) + return ENAMETOOLONG; + + status = _Objects_Name_to_id( + &_POSIX_Message_queue_Information, (char *)name, 0, id ); + + if ( status == OBJECTS_NAME_OR_ID_LOOKUP_SUCCESSFUL ) + return 0; + + return ENOENT; +} diff --git a/cpukit/posix/src/mqueuenotify.c b/cpukit/posix/src/mqueuenotify.c new file mode 100644 index 0000000000..5733346e16 --- /dev/null +++ b/cpukit/posix/src/mqueuenotify.c @@ -0,0 +1,107 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <sys/types.h> +#include <signal.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Message_queue_Notify_handler + * + */ + +void _POSIX_Message_queue_Notify_handler( + void *user_data +) +{ + POSIX_Message_queue_Control *the_mq; + + the_mq = user_data; + + kill( getpid(), the_mq->notification.sigev_signo ); + + _CORE_message_queue_Set_notify( &the_mq->Message_queue, NULL, NULL ); +} + +/*PAGE + * + * 15.2.6 Notify Process that a Message is Available on a Queue, + * P1003.1b-1993, p. 280 + */ + +int mq_notify( + mqd_t mqdes, + const struct sigevent *notification +) +{ + POSIX_Message_queue_Control *the_mq; + POSIX_Message_queue_Control_fd *the_mq_fd; + Objects_Locations location; + + the_mq_fd = _POSIX_Message_queue_Get_fd( mqdes, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EBADF ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + the_mq = the_mq_fd->Queue; + + if ( notification ) { + if ( _CORE_message_queue_Is_notify_enabled( &the_mq->Message_queue ) ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( EBUSY ); + } + + _CORE_message_queue_Set_notify( &the_mq->Message_queue, NULL, NULL ); + + the_mq->notification = *notification; + + _CORE_message_queue_Set_notify( + &the_mq->Message_queue, + _POSIX_Message_queue_Notify_handler, + the_mq + ); + } else { + + _CORE_message_queue_Set_notify( &the_mq->Message_queue, NULL, NULL ); + + } + + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mqueueopen.c b/cpukit/posix/src/mqueueopen.c new file mode 100644 index 0000000000..8195e9d2af --- /dev/null +++ b/cpukit/posix/src/mqueueopen.c @@ -0,0 +1,158 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 15.2.2 Open a Message Queue, P1003.1b-1993, p. 272 + */ + +mqd_t mq_open( + const char *name, + int oflag, + ... + /* mode_t mode, */ + /* struct mq_attr attr */ +) +{ + va_list arg; + mode_t mode; + struct mq_attr *attr = NULL; + int status; + Objects_Id the_mq_id; + POSIX_Message_queue_Control *the_mq; + POSIX_Message_queue_Control_fd *the_mq_fd; + Objects_Locations location; + + _Thread_Disable_dispatch(); + + if ( oflag & O_CREAT ) { + va_start(arg, oflag); + mode = (mode_t) va_arg( arg, unsigned int ); + attr = (struct mq_attr *) va_arg( arg, struct mq_attr * ); + va_end(arg); + } + + the_mq_fd = _POSIX_Message_queue_Allocate_fd(); + if ( !the_mq_fd ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENFILE ); + } + the_mq_fd->oflag = oflag; + + status = _POSIX_Message_queue_Name_to_id( name, &the_mq_id ); + + /* + * If the name to id translation worked, then the message queue exists + * and we can just return a pointer to the id. Otherwise we may + * need to check to see if this is a "message queue does not exist" + * or some other miscellaneous error on the name. + */ + + if ( status ) { + + /* + * Unless provided a valid name that did not already exist + * and we are willing to create then it is an error. + */ + + if ( !( status == ENOENT && (oflag & O_CREAT) ) ) { + _POSIX_Message_queue_Free_fd( the_mq_fd ); + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one_cast( status, mqd_t ); + } + + } else { /* name -> ID translation succeeded */ + + /* + * Check for existence with creation. + */ + + if ( (oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL) ) { + _POSIX_Message_queue_Free_fd( the_mq_fd ); + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one_cast( EEXIST, mqd_t ); + } + + /* + * In this case we need to do an ID->pointer conversion to + * check the mode. + */ + + the_mq = _POSIX_Message_queue_Get( the_mq_id, &location ); + the_mq->open_count += 1; + the_mq_fd->Queue = the_mq; + _Objects_Open( + &_POSIX_Message_queue_Information_fds, + &the_mq_fd->Object, + NULL + ); + _Thread_Enable_dispatch(); + _Thread_Enable_dispatch(); + return (mqd_t)the_mq_fd->Object.id; + + } + + /* + * At this point, the message queue does not exist and everything has been + * checked. We should go ahead and create a message queue. + */ + + status = _POSIX_Message_queue_Create_support( + name, + TRUE, /* shared across processes */ + attr, + &the_mq + ); + + /* + * errno was set by Create_support, so don't set it again. + */ + + if ( status == -1 ) { + _Thread_Enable_dispatch(); + _POSIX_Message_queue_Free_fd( the_mq_fd ); + return (mqd_t) -1; + } + + the_mq_fd->Queue = the_mq; + _Objects_Open( + &_POSIX_Message_queue_Information_fds, + &the_mq_fd->Object, + NULL + ); + + _Thread_Enable_dispatch(); + + return (mqd_t) the_mq_fd->Object.id; +} diff --git a/cpukit/posix/src/mqueuereceive.c b/cpukit/posix/src/mqueuereceive.c new file mode 100644 index 0000000000..e87d5fa8e9 --- /dev/null +++ b/cpukit/posix/src/mqueuereceive.c @@ -0,0 +1,56 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 15.2.5 Receive a Message From a Message Queue, P1003.1b-1993, p. 279 + * + * NOTE: P1003.4b/D8, p. 45 adds mq_timedreceive(). + */ + +ssize_t mq_receive( + mqd_t mqdes, + char *msg_ptr, + size_t msg_len, + unsigned int *msg_prio +) +{ + return _POSIX_Message_queue_Receive_support( + mqdes, + msg_ptr, + msg_len, + msg_prio, + THREAD_QUEUE_WAIT_FOREVER + ); +} diff --git a/cpukit/posix/src/mqueuerecvsupp.c b/cpukit/posix/src/mqueuerecvsupp.c new file mode 100644 index 0000000000..6c2ca9e605 --- /dev/null +++ b/cpukit/posix/src/mqueuerecvsupp.c @@ -0,0 +1,107 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Message_queue_Receive_support + * + * NOTE: XXX Document how size, priority, length, and the buffer go + * through the layers. + */ + +ssize_t _POSIX_Message_queue_Receive_support( + mqd_t mqdes, + char *msg_ptr, + size_t msg_len, + unsigned int *msg_prio, + Watchdog_Interval timeout +) +{ + POSIX_Message_queue_Control *the_mq; + POSIX_Message_queue_Control_fd *the_mq_fd; + Objects_Locations location; + uint32_t length_out; + + the_mq_fd = _POSIX_Message_queue_Get_fd( mqdes, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EBADF ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + if ( (the_mq_fd->oflag & O_ACCMODE) == O_WRONLY ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( EBADF ); + } + + the_mq = the_mq_fd->Queue; + + if ( msg_len < the_mq->Message_queue.maximum_message_size ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( EMSGSIZE ); + } + + /* + * Now if something goes wrong, we return a "length" of -1 + * to indicate an error. + */ + + length_out = -1; + + _CORE_message_queue_Seize( + &the_mq->Message_queue, + mqdes, + msg_ptr, + &length_out, + (the_mq_fd->oflag & O_NONBLOCK) ? FALSE : TRUE, + timeout + ); + + _Thread_Enable_dispatch(); + *msg_prio = + _POSIX_Message_queue_Priority_from_core(_Thread_Executing->Wait.count); + + if ( !_Thread_Executing->Wait.return_code ) + return length_out; + + rtems_set_errno_and_return_minus_one( + _POSIX_Message_queue_Translate_core_message_queue_return_code( + _Thread_Executing->Wait.return_code + ) + ); + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mqueuesend.c b/cpukit/posix/src/mqueuesend.c new file mode 100644 index 0000000000..484fe72183 --- /dev/null +++ b/cpukit/posix/src/mqueuesend.c @@ -0,0 +1,56 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 15.2.4 Send a Message to a Message Queue, P1003.1b-1993, p. 277 + * + * NOTE: P1003.4b/D8, p. 45 adds mq_timedsend(). + */ + +int mq_send( + mqd_t mqdes, + const char *msg_ptr, + size_t msg_len, + unsigned int msg_prio +) +{ + return _POSIX_Message_queue_Send_support( + mqdes, + msg_ptr, + msg_len, + msg_prio, + THREAD_QUEUE_WAIT_FOREVER + ); +} diff --git a/cpukit/posix/src/mqueuesendsupp.c b/cpukit/posix/src/mqueuesendsupp.c new file mode 100644 index 0000000000..33109465e6 --- /dev/null +++ b/cpukit/posix/src/mqueuesendsupp.c @@ -0,0 +1,117 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + + +/*PAGE + * + * _POSIX_Message_queue_Send_support + */ + +int _POSIX_Message_queue_Send_support( + mqd_t mqdes, + const char *msg_ptr, + uint32_t msg_len, + uint32_t msg_prio, + Watchdog_Interval timeout +) +{ + POSIX_Message_queue_Control *the_mq; + POSIX_Message_queue_Control_fd *the_mq_fd; + Objects_Locations location; + CORE_message_queue_Status msg_status; + + /* + * Validate the priority. + * XXX - Do not validate msg_prio is not less than 0. + */ + + if ( msg_prio > MQ_PRIO_MAX ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + the_mq_fd = _POSIX_Message_queue_Get_fd( mqdes, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EBADF ); + + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + + case OBJECTS_LOCAL: + if ( (the_mq_fd->oflag & O_ACCMODE) == O_RDONLY ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( EBADF ); + } + + the_mq = the_mq_fd->Queue; + + msg_status = _CORE_message_queue_Submit( + &the_mq->Message_queue, + (void *) msg_ptr, + msg_len, + mqdes, /* mqd_t is an object id */ +#if defined(RTEMS_MULTIPROCESSING) + NULL, /* XXX _POSIX_Message_queue_Core_message_queue_mp_support*/ +#else + NULL, +#endif + _POSIX_Message_queue_Priority_to_core( msg_prio ), + (the_mq_fd->oflag & O_NONBLOCK) ? FALSE : TRUE, + timeout /* no timeout */ + ); + + _Thread_Enable_dispatch(); + + /* + * If we had to block, then this is where the task returns + * after it wakes up. The returned status is correct for + * non-blocking operations but if we blocked, then we need + * to look at the status in our TCB. + */ + + if ( msg_status == CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_WAIT ) + msg_status = _Thread_Executing->Wait.return_code; + + if ( !msg_status ) + return msg_status; + + rtems_set_errno_and_return_minus_one( + _POSIX_Message_queue_Translate_core_message_queue_return_code( + msg_status + ) + ); + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mqueuesetattr.c b/cpukit/posix/src/mqueuesetattr.c new file mode 100644 index 0000000000..6d3b132ade --- /dev/null +++ b/cpukit/posix/src/mqueuesetattr.c @@ -0,0 +1,81 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 15.2.7 Set Message Queue Attributes, P1003.1b-1993, p. 281 + */ + +int mq_setattr( + mqd_t mqdes, + const struct mq_attr *mqstat, + struct mq_attr *omqstat +) +{ + POSIX_Message_queue_Control_fd *the_mq_fd; + CORE_message_queue_Control *the_core_mq; + Objects_Locations location; + + if ( !mqstat ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + the_mq_fd = _POSIX_Message_queue_Get_fd( mqdes, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EBADF ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + + the_core_mq = &the_mq_fd->Queue->Message_queue; + + /* + * Return the old values. + */ + + if ( omqstat ) { + omqstat->mq_flags = the_mq_fd->oflag; + omqstat->mq_msgsize = the_core_mq->maximum_message_size; + omqstat->mq_maxmsg = the_core_mq->maximum_pending_messages; + omqstat->mq_curmsgs = the_core_mq->number_of_pending_messages; + } + + the_mq_fd->oflag = mqstat->mq_flags; + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mqueuetimedreceive.c b/cpukit/posix/src/mqueuetimedreceive.c new file mode 100644 index 0000000000..e0f605ac91 --- /dev/null +++ b/cpukit/posix/src/mqueuetimedreceive.c @@ -0,0 +1,57 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 15.2.5 Receive a Message From a Message Queue, P1003.1b-1993, p. 279 + * + * NOTE: P1003.4b/D8, p. 45 adds mq_timedreceive(). + */ + +int mq_timedreceive( /* XXX: should this be ssize_t */ + mqd_t mqdes, + char *msg_ptr, + size_t msg_len, + unsigned int *msg_prio, + const struct timespec *timeout +) +{ + return _POSIX_Message_queue_Receive_support( + mqdes, + msg_ptr, + msg_len, + msg_prio, + _POSIX_Timespec_to_interval( timeout ) + ); +} diff --git a/cpukit/posix/src/mqueuetimedsend.c b/cpukit/posix/src/mqueuetimedsend.c new file mode 100644 index 0000000000..89569368be --- /dev/null +++ b/cpukit/posix/src/mqueuetimedsend.c @@ -0,0 +1,57 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 15.2.4 Send a Message to a Message Queue, P1003.1b-1993, p. 277 + * + * NOTE: P1003.4b/D8, p. 45 adds mq_timedsend(). + */ + +int mq_timedsend( + mqd_t mqdes, + const char *msg_ptr, + size_t msg_len, + unsigned int msg_prio, + const struct timespec *timeout +) +{ + return _POSIX_Message_queue_Send_support( + mqdes, + msg_ptr, + msg_len, + msg_prio, + _POSIX_Timespec_to_interval( timeout ) + ); +} diff --git a/cpukit/posix/src/mqueuetranslatereturncode.c b/cpukit/posix/src/mqueuetranslatereturncode.c new file mode 100644 index 0000000000..74e67d0cf7 --- /dev/null +++ b/cpukit/posix/src/mqueuetranslatereturncode.c @@ -0,0 +1,101 @@ +/* + * POSIX Message Queue Error Translation + * + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> +#include <rtems/score/interr.h> + + +/*PAGE + * + * _POSIX_Message_queue_Translate_core_message_queue_return_code + * + * Input parameters: + * the_message_queue_status - message_queue status code to translate + * + * Output parameters: + * rtems status code - translated POSIX status code + * + */ + +int _POSIX_Message_queue_Translate_core_message_queue_return_code( + uint32_t the_message_queue_status +) +{ + switch ( the_message_queue_status ) { + case CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL: + return 0; + + /* + * Bad message size + */ + case CORE_MESSAGE_QUEUE_STATUS_INVALID_SIZE: + return EMSGSIZE; + + /* + * Queue is full of pending messages. + */ + case CORE_MESSAGE_QUEUE_STATUS_TOO_MANY: + return EAGAIN; + + /* + * Out of message buffers to queue pending message + */ + case CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED: + return ENOMEM; + + /* + * No message available on receive poll + */ + case CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_NOWAIT: + return EAGAIN; + + /* + * Queue was deleted while thread blocked on it. + */ + case CORE_MESSAGE_QUEUE_STATUS_WAS_DELETED: + return EBADF; + + /* + * POSIX Real-Time Extensions add timeouts to send and receive. + */ + case CORE_MESSAGE_QUEUE_STATUS_TIMEOUT: + return ETIMEDOUT; + + /* + * RTEMS POSIX API implementation does not support multiprocessing. + */ + case THREAD_STATUS_PROXY_BLOCKING: + return ENOSYS; + } + _Internal_error_Occurred( + INTERNAL_ERROR_POSIX_API, + TRUE, + the_message_queue_status + ); + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mqueueunlink.c b/cpukit/posix/src/mqueueunlink.c new file mode 100644 index 0000000000..3a14983226 --- /dev/null +++ b/cpukit/posix/src/mqueueunlink.c @@ -0,0 +1,85 @@ +/* + * NOTE: The structure of the routines is identical to that of POSIX + * Message_queues to leave the option of having unnamed message + * queues at a future date. They are currently not part of the + * POSIX standard but unnamed message_queues are. This is also + * the reason for the apparently unnecessary tracking of + * the process_shared attribute. [In addition to the fact that + * it would be trivial to add pshared to the mq_attr structure + * and have process private message queues.] + * + * This code ignores the O_RDONLY/O_WRONLY/O_RDWR flag at open + * time. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <pthread.h> +#include <limits.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> + +#include <rtems/system.h> +#include <rtems/score/watchdog.h> +#include <rtems/score/wkspace.h> +#include <rtems/seterr.h> +#include <rtems/posix/mqueue.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 15.2.2 Remove a Message Queue, P1003.1b-1993, p. 276 + */ + +int mq_unlink( + const char *name +) +{ + int status; + register POSIX_Message_queue_Control *the_mq; + Objects_Id the_mq_id; + + _Thread_Disable_dispatch(); + + status = _POSIX_Message_queue_Name_to_id( name, &the_mq_id ); + if ( status != 0 ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( status ); + } + + /* + * Don't support unlinking a remote message queue. + */ + + if ( !_Objects_Is_local_id(the_mq_id) ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENOSYS ); + } + + the_mq = (POSIX_Message_queue_Control *) _Objects_Get_local_object( + &_POSIX_Message_queue_Information, + _Objects_Get_index( the_mq_id ) + ); + +#if 0 && defined(RTEMS_MULTIPROCESSING) + if ( the_mq->process_shared == PTHREAD_PROCESS_SHARED ) { + _Objects_MP_Close( &_POSIX_Message_queue_Information, the_mq_id ); + } +#endif + + + the_mq->linked = FALSE; + _Workspace_Free( the_mq->Object.name ); + _POSIX_Message_queue_Namespace_remove( the_mq ); + _POSIX_Message_queue_Delete( the_mq ); + + _Thread_Enable_dispatch(); + return 0; +} diff --git a/cpukit/posix/src/mutex.c b/cpukit/posix/src/mutex.c new file mode 100644 index 0000000000..b7bde39167 --- /dev/null +++ b/cpukit/posix/src/mutex.c @@ -0,0 +1,54 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Mutex_Manager_initialization + * + * This routine initializes all mutex manager related data structures. + * + * Input parameters: + * maximum_mutexes - maximum configured mutexes + * + * Output parameters: NONE + */ + +void _POSIX_Mutex_Manager_initialization( + uint32_t maximum_mutexes +) +{ + _Objects_Initialize_information( + &_POSIX_Mutex_Information, /* object information table */ + OBJECTS_POSIX_API, /* object API */ + OBJECTS_POSIX_MUTEXES, /* object class */ + maximum_mutexes, /* maximum objects of this class */ + sizeof( POSIX_Mutex_Control ), + /* size of this object's control block */ + FALSE, /* TRUE if names for this object are strings */ + 0 /* maximum length of each object's name */ +#if defined(RTEMS_MULTIPROCESSING) + , + FALSE, /* TRUE if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); +} diff --git a/cpukit/posix/src/mutexattrdestroy.c b/cpukit/posix/src/mutexattrdestroy.c new file mode 100644 index 0000000000..429dbeaee2 --- /dev/null +++ b/cpukit/posix/src/mutexattrdestroy.c @@ -0,0 +1,37 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81 + */ + +int pthread_mutexattr_destroy( + pthread_mutexattr_t *attr +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + attr->is_initialized = FALSE; + return 0; +} diff --git a/cpukit/posix/src/mutexattrgetprioceiling.c b/cpukit/posix/src/mutexattrgetprioceiling.c new file mode 100644 index 0000000000..f0ef90b61f --- /dev/null +++ b/cpukit/posix/src/mutexattrgetprioceiling.c @@ -0,0 +1,38 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128 + */ + +int pthread_mutexattr_getprioceiling( + const pthread_mutexattr_t *attr, + int *prioceiling +) +{ + if ( !attr || !attr->is_initialized || !prioceiling ) + return EINVAL; + + *prioceiling = attr->prio_ceiling; + return 0; +} diff --git a/cpukit/posix/src/mutexattrgetprotocol.c b/cpukit/posix/src/mutexattrgetprotocol.c new file mode 100644 index 0000000000..2537ba00bf --- /dev/null +++ b/cpukit/posix/src/mutexattrgetprotocol.c @@ -0,0 +1,38 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128 + */ + +int pthread_mutexattr_getprotocol( + const pthread_mutexattr_t *attr, + int *protocol +) +{ + if ( !attr || !attr->is_initialized || !protocol ) + return EINVAL; + + *protocol = attr->protocol; + return 0; +} diff --git a/cpukit/posix/src/mutexattrgetpshared.c b/cpukit/posix/src/mutexattrgetpshared.c new file mode 100644 index 0000000000..3374b250ba --- /dev/null +++ b/cpukit/posix/src/mutexattrgetpshared.c @@ -0,0 +1,38 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81 + */ + +int pthread_mutexattr_getpshared( + const pthread_mutexattr_t *attr, + int *pshared +) +{ + if ( !attr || !attr->is_initialized || !pshared ) + return EINVAL; + + *pshared = attr->process_shared; + return 0; +} diff --git a/cpukit/posix/src/mutexattrinit.c b/cpukit/posix/src/mutexattrinit.c new file mode 100644 index 0000000000..0cd6783ce8 --- /dev/null +++ b/cpukit/posix/src/mutexattrinit.c @@ -0,0 +1,37 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81 + */ + +int pthread_mutexattr_init( + pthread_mutexattr_t *attr +) +{ + if ( !attr ) + return EINVAL; + + *attr = _POSIX_Mutex_Default_attributes; + return 0; +} diff --git a/cpukit/posix/src/mutexattrsetprioceiling.c b/cpukit/posix/src/mutexattrsetprioceiling.c new file mode 100644 index 0000000000..da34a2fbb3 --- /dev/null +++ b/cpukit/posix/src/mutexattrsetprioceiling.c @@ -0,0 +1,41 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128 + */ + +int pthread_mutexattr_setprioceiling( + pthread_mutexattr_t *attr, + int prioceiling +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + if ( !_POSIX_Priority_Is_valid( prioceiling ) ) + return EINVAL; + + attr->prio_ceiling = prioceiling; + return 0; +} diff --git a/cpukit/posix/src/mutexattrsetprotocol.c b/cpukit/posix/src/mutexattrsetprotocol.c new file mode 100644 index 0000000000..2f74abf3d2 --- /dev/null +++ b/cpukit/posix/src/mutexattrsetprotocol.c @@ -0,0 +1,46 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128 + */ + +int pthread_mutexattr_setprotocol( + pthread_mutexattr_t *attr, + int protocol +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + switch ( protocol ) { + case PTHREAD_PRIO_NONE: + case PTHREAD_PRIO_INHERIT: + case PTHREAD_PRIO_PROTECT: + attr->protocol = protocol; + return 0; + + default: + return EINVAL; + } +} diff --git a/cpukit/posix/src/mutexattrsetpshared.c b/cpukit/posix/src/mutexattrsetpshared.c new file mode 100644 index 0000000000..10d7a80647 --- /dev/null +++ b/cpukit/posix/src/mutexattrsetpshared.c @@ -0,0 +1,45 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81 + */ + +int pthread_mutexattr_setpshared( + pthread_mutexattr_t *attr, + int pshared +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + switch ( pshared ) { + case PTHREAD_PROCESS_SHARED: + case PTHREAD_PROCESS_PRIVATE: + attr->process_shared = pshared; + return 0; + + default: + return EINVAL; + } +} diff --git a/cpukit/posix/src/mutexdefaultattributes.c b/cpukit/posix/src/mutexdefaultattributes.c new file mode 100644 index 0000000000..bdca71a43b --- /dev/null +++ b/cpukit/posix/src/mutexdefaultattributes.c @@ -0,0 +1,34 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * The default mutex attributes structure. + */ + +const pthread_mutexattr_t _POSIX_Mutex_Default_attributes = { + TRUE, /* is_initialized */ + PTHREAD_PROCESS_PRIVATE, /* process_shared */ + POSIX_SCHEDULER_MAXIMUM_PRIORITY, /* prio_ceiling */ + PTHREAD_PRIO_NONE, /* protocol */ + FALSE /* recursive */ +}; diff --git a/cpukit/posix/src/mutexdestroy.c b/cpukit/posix/src/mutexdestroy.c new file mode 100644 index 0000000000..f4210148cd --- /dev/null +++ b/cpukit/posix/src/mutexdestroy.c @@ -0,0 +1,87 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 11.3.2 Initializing and Destroying a Mutex, P1003.1c/Draft 10, p. 87 + */ + +int pthread_mutex_destroy( + pthread_mutex_t *mutex +) +{ + register POSIX_Mutex_Control *the_mutex; + Objects_Locations location; + + the_mutex = _POSIX_Mutex_Get( mutex, &location ); + switch ( location ) { + case OBJECTS_REMOTE: +#if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + return EINVAL; +#endif + case OBJECTS_ERROR: + return EINVAL; + case OBJECTS_LOCAL: + /* + * XXX: There is an error for the mutex being locked + * or being in use by a condition variable. + */ + + if ( _CORE_mutex_Is_locked( &the_mutex->Mutex ) ) { + _Thread_Enable_dispatch(); + return EBUSY; + } + + _Objects_Close( &_POSIX_Mutex_Information, &the_mutex->Object ); + + _CORE_mutex_Flush( + &the_mutex->Mutex, +#if defined(RTEMS_MULTIPROCESSING) + _POSIX_Mutex_MP_Send_object_was_deleted, +#else + NULL, +#endif + EINVAL + ); + + _POSIX_Mutex_Free( the_mutex ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( the_mutex->process_shared == PTHREAD_PROCESS_SHARED ) { + + _Objects_MP_Close( &_POSIX_Mutex_Information, the_mutex->Object.id ); + + _POSIX_Mutex_MP_Send_process_packet( + POSIX_MUTEX_MP_ANNOUNCE_DELETE, + the_mutex->Object.id, + 0, /* Not used */ + 0 /* Not used */ + ); + } +#endif + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mutexfromcorestatus.c b/cpukit/posix/src/mutexfromcorestatus.c new file mode 100644 index 0000000000..3c6f617861 --- /dev/null +++ b/cpukit/posix/src/mutexfromcorestatus.c @@ -0,0 +1,52 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Mutex_From_core_mutex_status + */ + +int _POSIX_Mutex_From_core_mutex_status( + CORE_mutex_Status status +) +{ + switch ( status ) { + case CORE_MUTEX_STATUS_SUCCESSFUL: + return 0; + case CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT: + return EBUSY; + case CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED: + return EDEADLK; + case CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE: + return EPERM; + case CORE_MUTEX_WAS_DELETED: + return EINVAL; + case CORE_MUTEX_TIMEOUT: + return EAGAIN; + case CORE_MUTEX_STATUS_CEILING_VIOLATED: + return EINVAL; + default: + break; + } + assert( 0 ); + return 0; +} diff --git a/cpukit/posix/src/mutexgetprioceiling.c b/cpukit/posix/src/mutexgetprioceiling.c new file mode 100644 index 0000000000..4e43325560 --- /dev/null +++ b/cpukit/posix/src/mutexgetprioceiling.c @@ -0,0 +1,55 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 13.6.2 Change the Priority Ceiling of a Mutex, P1003.1c/Draft 10, p. 131 + */ + +int pthread_mutex_getprioceiling( + pthread_mutex_t *mutex, + int *prioceiling +) +{ + register POSIX_Mutex_Control *the_mutex; + Objects_Locations location; + + if ( !prioceiling ) + return EINVAL; + + the_mutex = _POSIX_Mutex_Get( mutex, &location ); + switch ( location ) { + case OBJECTS_REMOTE: +#if defined(RTEMS_MULTIPROCESSING) + return POSIX_MP_NOT_IMPLEMENTED(); /* XXX feels questionable */ +#endif + case OBJECTS_ERROR: + return EINVAL; + case OBJECTS_LOCAL: + *prioceiling = _POSIX_Priority_From_core( + the_mutex->Mutex.Attributes.priority_ceiling + ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mutexinit.c b/cpukit/posix/src/mutexinit.c new file mode 100644 index 0000000000..3af8c1d621 --- /dev/null +++ b/cpukit/posix/src/mutexinit.c @@ -0,0 +1,186 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 11.3.2 Initializing and Destroying a Mutex, P1003.1c/Draft 10, p. 87 + * + * NOTE: XXX Could be optimized so all the attribute error checking + * is not performed when attr is NULL. + */ + +int pthread_mutex_init( + pthread_mutex_t *mutex, + const pthread_mutexattr_t *attr +) +{ + POSIX_Mutex_Control *the_mutex; + CORE_mutex_Attributes *the_mutex_attr; + const pthread_mutexattr_t *the_attr; + CORE_mutex_Disciplines the_discipline; +#if 0 + register POSIX_Mutex_Control *mutex_in_use; + Objects_Locations location; +#endif + + if ( attr ) the_attr = attr; + else the_attr = &_POSIX_Mutex_Default_attributes; + + /* Check for NULL mutex */ + + if ( !mutex ) + return EINVAL; + + /* + * This code should eventually be removed. + * + * Although the POSIX specification says: + * + * "Attempting to initialize an already initialized mutex results + * in undefined behavior." + * + * Trying to keep the caller from doing the create when *mutex + * is actually a valid ID causes grief. All it takes is the wrong + * value in an uninitialized variable to make this fail. As best + * I can tell, RTEMS was the only pthread implementation to choose + * this option for "undefined behavior" and doing so has created + * portability problems. In particular, Rosimildo DaSilva + * <rdasilva@connecttel.com> saw seemingly random failures in the + * RTEMS port of omniORB2 when this code was enabled. + * + * Joel Sherrill <joel@OARcorp.com> 14 May 1999 + */ + + +#if 0 + /* avoid infinite recursion on call to this routine in _POSIX_Mutex_Get */ + + if ( *mutex != PTHREAD_MUTEX_INITIALIZER ) { + + /* EBUSY if *mutex is a valid id */ + + mutex_in_use = _POSIX_Mutex_Get( mutex, &location ); + switch ( location ) { + case OBJECTS_REMOTE: + case OBJECTS_ERROR: + break; + case OBJECTS_LOCAL: + _Thread_Enable_dispatch(); + return EBUSY; + } + } +#endif + + if ( !the_attr->is_initialized ) + return EINVAL; + + /* + * XXX: Be careful about attributes when global!!! + */ + + assert( the_attr->process_shared == PTHREAD_PROCESS_PRIVATE ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED ) + return POSIX_MP_NOT_IMPLEMENTED(); +#endif + + /* + * Determine the discipline of the mutex + */ + + switch ( the_attr->protocol ) { + case PTHREAD_PRIO_NONE: + the_discipline = CORE_MUTEX_DISCIPLINES_FIFO; + break; + case PTHREAD_PRIO_INHERIT: + the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT; + break; + case PTHREAD_PRIO_PROTECT: + the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING; + break; + default: + return EINVAL; + } + + if ( !_POSIX_Priority_Is_valid( the_attr->prio_ceiling ) ) + return EINVAL; + + _Thread_Disable_dispatch(); + + the_mutex = _POSIX_Mutex_Allocate(); + + if ( !the_mutex ) { + _Thread_Enable_dispatch(); + return EAGAIN; + } + +#if defined(RTEMS_MULTIPROCESSING) + if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED && + !( _Objects_MP_Allocate_and_open( &_POSIX_Mutex_Information, 0, + the_mutex->Object.id, FALSE ) ) ) { + _POSIX_Mutex_Free( the_mutex ); + _Thread_Enable_dispatch(); + return EAGAIN; + } +#endif + + the_mutex->process_shared = the_attr->process_shared; + + the_mutex_attr = &the_mutex->Mutex.Attributes; + + if ( the_attr->recursive ) + the_mutex_attr->lock_nesting_behavior = CORE_MUTEX_NESTING_ACQUIRES; + else + the_mutex_attr->lock_nesting_behavior = CORE_MUTEX_NESTING_IS_ERROR; + the_mutex_attr->only_owner_release = TRUE; + the_mutex_attr->priority_ceiling = + _POSIX_Priority_To_core( the_attr->prio_ceiling ); + the_mutex_attr->discipline = the_discipline; + + /* + * Must be initialized to unlocked. + */ + + _CORE_mutex_Initialize( + &the_mutex->Mutex, + the_mutex_attr, + CORE_MUTEX_UNLOCKED + ); + + _Objects_Open( &_POSIX_Mutex_Information, &the_mutex->Object, 0 ); + + *mutex = the_mutex->Object.id; + +#if defined(RTEMS_MULTIPROCESSING) + if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED ) + _POSIX_Mutex_MP_Send_process_packet( + POSIX_MUTEX_MP_ANNOUNCE_CREATE, + the_mutex->Object.id, + 0, /* Name not used */ + 0 /* Not used */ + ); +#endif + + _Thread_Enable_dispatch(); + return 0; +} diff --git a/cpukit/posix/src/mutexlock.c b/cpukit/posix/src/mutexlock.c new file mode 100644 index 0000000000..b040dc08d4 --- /dev/null +++ b/cpukit/posix/src/mutexlock.c @@ -0,0 +1,35 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 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 +) +{ + return _POSIX_Mutex_Lock_support( mutex, TRUE, THREAD_QUEUE_WAIT_FOREVER ); +} diff --git a/cpukit/posix/src/mutexlocksupp.c b/cpukit/posix/src/mutexlocksupp.c new file mode 100644 index 0000000000..9e8ee10172 --- /dev/null +++ b/cpukit/posix/src/mutexlocksupp.c @@ -0,0 +1,67 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Mutex_Lock_support + * + * A support routine which implements guts of the blocking, non-blocking, and + * timed wait version of mutex lock. + */ + +int _POSIX_Mutex_Lock_support( + pthread_mutex_t *mutex, + boolean blocking, + Watchdog_Interval timeout +) +{ + register POSIX_Mutex_Control *the_mutex; + Objects_Locations location; + ISR_Level level; + + the_mutex = _POSIX_Mutex_Get_interrupt_disable( mutex, &location, &level ); + switch ( location ) { + case OBJECTS_REMOTE: +#if defined(RTEMS_MULTIPROCESSING) + return _POSIX_Mutex_MP_Send_request_packet( + POSIX_MUTEX_MP_OBTAIN_REQUEST, + *mutex, + 0, /* must define the option set */ + WATCHDOG_NO_TIMEOUT + ); +#endif + case OBJECTS_ERROR: + return EINVAL; + case OBJECTS_LOCAL: + _CORE_mutex_Seize( + &the_mutex->Mutex, + the_mutex->Object.id, + blocking, + timeout, + level + ); + return _POSIX_Mutex_From_core_mutex_status( + (CORE_mutex_Status) _Thread_Executing->Wait.return_code + ); + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mutexmp.c b/cpukit/posix/src/mutexmp.c new file mode 100644 index 0000000000..75db779ce4 --- /dev/null +++ b/cpukit/posix/src/mutexmp.c @@ -0,0 +1,66 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/* + * TEMPORARY + */ + +#if defined(RTEMS_MULTIPROCESSING) +void _POSIX_Mutex_MP_Send_process_packet ( + POSIX_Mutex_MP_Remote_operations operation, + Objects_Id mutex_id, + Objects_Name name, + Objects_Id proxy_id +) +{ + (void) POSIX_MP_NOT_IMPLEMENTED(); +} + +void _POSIX_Mutex_MP_Send_object_was_deleted ( + Thread_Control *the_proxy +) +{ + (void) POSIX_MP_NOT_IMPLEMENTED(); +} + +int _POSIX_Mutex_MP_Send_request_packet ( + POSIX_Mutex_MP_Remote_operations operation, + Objects_Id mutex_id, + boolean wait, /* XXX options */ + Watchdog_Interval timeout +) +{ + return POSIX_MP_NOT_IMPLEMENTED(); +} + +void _POSIX_Threads_mutex_MP_support( + Thread_Control *the_thread, + Objects_Id id +) +{ + (void) POSIX_MP_NOT_IMPLEMENTED(); /* XXX: should never get here */ +} +#endif + +/* + * END OF TEMPORARY + */ diff --git a/cpukit/posix/src/mutexsetprioceiling.c b/cpukit/posix/src/mutexsetprioceiling.c new file mode 100644 index 0000000000..60c82a4f19 --- /dev/null +++ b/cpukit/posix/src/mutexsetprioceiling.c @@ -0,0 +1,82 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 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 +) +{ + register POSIX_Mutex_Control *the_mutex; + Objects_Locations location; + Priority_Control the_priority; + int status; + + if ( !old_ceiling ) + return EINVAL; + + if ( !_POSIX_Priority_Is_valid( prioceiling ) ) + return EINVAL; + + the_priority = _POSIX_Priority_To_core( prioceiling ); + + /* + * Must acquire the mutex before we can change it's ceiling + */ + + status = pthread_mutex_lock( mutex ); + if ( status ) + return status; + + the_mutex = _POSIX_Mutex_Get( mutex, &location ); + switch ( location ) { + case OBJECTS_REMOTE: +#if defined(RTEMS_MULTIPROCESSING) + /* XXX It feels questionable to set the ceiling on a remote mutex. */ + return EINVAL; +#endif + case OBJECTS_ERROR: + return EINVAL; /* impossible to get here */ + case OBJECTS_LOCAL: + *old_ceiling = _POSIX_Priority_From_core( + the_mutex->Mutex.Attributes.priority_ceiling + ); + the_mutex->Mutex.Attributes.priority_ceiling = the_priority; + _CORE_mutex_Surrender( + &the_mutex->Mutex, + the_mutex->Object.id, +#if defined(RTEMS_MULTIPROCESSING) + _POSIX_Threads_mutex_MP_support +#else + NULL +#endif + ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/mutextimedlock.c b/cpukit/posix/src/mutextimedlock.c new file mode 100644 index 0000000000..6555f5a4d2 --- /dev/null +++ b/cpukit/posix/src/mutextimedlock.c @@ -0,0 +1,40 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 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_timedlock( + pthread_mutex_t *mutex, + const struct timespec *timeout +) +{ + return _POSIX_Mutex_Lock_support( + mutex, + TRUE, + _POSIX_Timespec_to_interval( timeout ) + ); +} diff --git a/cpukit/posix/src/mutextrylock.c b/cpukit/posix/src/mutextrylock.c new file mode 100644 index 0000000000..68df754b0a --- /dev/null +++ b/cpukit/posix/src/mutextrylock.c @@ -0,0 +1,35 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 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_trylock( + pthread_mutex_t *mutex +) +{ + return _POSIX_Mutex_Lock_support( mutex, FALSE, THREAD_QUEUE_WAIT_FOREVER ); +} diff --git a/cpukit/posix/src/mutexunlock.c b/cpukit/posix/src/mutexunlock.c new file mode 100644 index 0000000000..b88ae4c269 --- /dev/null +++ b/cpukit/posix/src/mutexunlock.c @@ -0,0 +1,66 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> + +#include <rtems/system.h> +#include <rtems/score/coremutex.h> +#include <rtems/score/watchdog.h> +#if defined(RTEMS_MULTIPROCESSING) +#include <rtems/score/mpci.h> +#endif +#include <rtems/posix/mutex.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 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_unlock( + pthread_mutex_t *mutex +) +{ + register POSIX_Mutex_Control *the_mutex; + Objects_Locations location; + CORE_mutex_Status status; + + the_mutex = _POSIX_Mutex_Get( mutex, &location ); + switch ( location ) { + case OBJECTS_REMOTE: +#if defined(RTEMS_MULTIPROCESSING) + return _POSIX_Mutex_MP_Send_request_packet( + POSIX_MUTEX_MP_RELEASE_REQUEST, + *mutex, + 0, /* Not used */ + MPCI_DEFAULT_TIMEOUT + ); +#endif + case OBJECTS_ERROR: + return EINVAL; + case OBJECTS_LOCAL: + status = _CORE_mutex_Surrender( + &the_mutex->Mutex, + the_mutex->Object.id, +#if defined(RTEMS_MULTIPROCESSING) + _POSIX_Threads_mutex_MP_support +#else + NULL +#endif + ); + _Thread_Enable_dispatch(); + return _POSIX_Mutex_From_core_mutex_status( status ); + break; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c new file mode 100644 index 0000000000..06fc1bc5cb --- /dev/null +++ b/cpukit/posix/src/nanosleep.c @@ -0,0 +1,104 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269 + */ + +int nanosleep( + const struct timespec *rqtp, + struct timespec *rmtp +) +{ + Watchdog_Interval ticks; + struct timespec *the_rqtp; + + if ( !rqtp ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + the_rqtp = (struct timespec *)rqtp; + + /* + * Return EAGAIN if the delay interval is negative. + * + * NOTE: This behavior is beyond the POSIX specification. + * FSU pthreads shares this behavior. + */ + + if ( the_rqtp->tv_sec < 0 ) + the_rqtp->tv_sec = 0; + + if ( /* the_rqtp->tv_sec < 0 || */ the_rqtp->tv_nsec < 0 ) + rtems_set_errno_and_return_minus_one( EAGAIN ); + + if ( the_rqtp->tv_nsec >= TOD_NANOSECONDS_PER_SECOND ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + ticks = _POSIX_Timespec_to_interval( the_rqtp ); + + /* + * This behavior is also beyond the POSIX specification but is + * consistent with the RTEMS api and yields desirable behavior. + */ + + if ( !ticks ) { + _Thread_Disable_dispatch(); + _Thread_Yield_processor(); + _Thread_Enable_dispatch(); + if ( rmtp ) { + rmtp->tv_sec = 0; + rmtp->tv_nsec = 0; + } + return 0; + } + + _Thread_Disable_dispatch(); + _Thread_Set_state( + _Thread_Executing, + STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL + ); + _Watchdog_Initialize( + &_Thread_Executing->Timer, + _Thread_Delay_ended, + _Thread_Executing->Object.id, + NULL + ); + _Watchdog_Insert_ticks( &_Thread_Executing->Timer, ticks ); + _Thread_Enable_dispatch(); + + /* calculate time remaining */ + + if ( rmtp ) { + ticks -= + _Thread_Executing->Timer.stop_time - _Thread_Executing->Timer.start_time; + + _POSIX_Interval_to_timespec( ticks, rmtp ); + + /* + * If there is time remaining, then we were interrupted by a signal. + */ + + if ( ticks ) + rtems_set_errno_and_return_minus_one( EINTR ); + } + + return 0; +} diff --git a/cpukit/posix/src/pause.c b/cpukit/posix/src/pause.c new file mode 100644 index 0000000000..e4a8782bc4 --- /dev/null +++ b/cpukit/posix/src/pause.c @@ -0,0 +1,40 @@ +/* + * 3.4.2 Suspend Process Execution, P1003.1b-1993, p. 81 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> + +/* + * 3.4.2 Suspend Process Execution, P1003.1b-1993, p. 81 + */ + +int pause( void ) +{ + sigset_t all_signals; + int status; + + (void) sigfillset( &all_signals ); + + status = sigtimedwait( &all_signals, NULL, NULL ); + + return status; +} diff --git a/cpukit/posix/src/posixintervaltotimespec.c b/cpukit/posix/src/posixintervaltotimespec.c new file mode 100644 index 0000000000..916b890d8a --- /dev/null +++ b/cpukit/posix/src/posixintervaltotimespec.c @@ -0,0 +1,38 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Interval_to_timespec + */ + +void _POSIX_Interval_to_timespec( + Watchdog_Interval ticks, + struct timespec *time +) +{ + uint32_t usecs; + + usecs = ticks * _TOD_Microseconds_per_tick; + + time->tv_sec = usecs / TOD_MICROSECONDS_PER_SECOND; + time->tv_nsec = (usecs % TOD_MICROSECONDS_PER_SECOND) * + TOD_NANOSECONDS_PER_MICROSECOND; +} diff --git a/cpukit/posix/src/posixtimespecsubtract.c b/cpukit/posix/src/posixtimespecsubtract.c new file mode 100644 index 0000000000..0fa611b6ea --- /dev/null +++ b/cpukit/posix/src/posixtimespecsubtract.c @@ -0,0 +1,50 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Timespec_subtract + */ + +void _POSIX_Timespec_subtract( + const struct timespec *the_start, + const struct timespec *end, + struct timespec *result +) +{ + struct timespec start_struct = *the_start; + struct timespec *start = &start_struct; + uint32_t nsecs_per_sec = TOD_NANOSECONDS_PER_SECOND; + + if (end->tv_nsec < start->tv_nsec) { + int seconds = (start->tv_nsec - end->tv_nsec) / nsecs_per_sec + 1; + start->tv_nsec -= nsecs_per_sec * seconds; + start->tv_sec += seconds; + } + + if (end->tv_nsec - start->tv_nsec > nsecs_per_sec) { + int seconds = (start->tv_nsec - end->tv_nsec) / nsecs_per_sec; + start->tv_nsec += nsecs_per_sec * seconds; + start->tv_sec -= seconds; + } + + result->tv_sec = end->tv_sec - start->tv_sec; + result->tv_nsec = end->tv_nsec - start->tv_nsec; +} diff --git a/cpukit/posix/src/posixtimespectointerval.c b/cpukit/posix/src/posixtimespectointerval.c new file mode 100644 index 0000000000..3e4d5cf130 --- /dev/null +++ b/cpukit/posix/src/posixtimespectointerval.c @@ -0,0 +1,42 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Timespec_to_interval + */ + +Watchdog_Interval _POSIX_Timespec_to_interval( + const struct timespec *time +) +{ + Watchdog_Interval ticks; + + ticks = (time->tv_sec * TOD_MICROSECONDS_PER_SECOND) / + _TOD_Microseconds_per_tick; + + ticks += (time->tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND) / + _TOD_Microseconds_per_tick; + + if (ticks) + return ticks; + + return 1; +} diff --git a/cpukit/posix/src/psignal.c b/cpukit/posix/src/psignal.c new file mode 100644 index 0000000000..be8a7dadf4 --- /dev/null +++ b/cpukit/posix/src/psignal.c @@ -0,0 +1,206 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <string.h> /* memcpy */ +#include <stdlib.h> /* exit */ + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tqdata.h> +#include <rtems/score/wkspace.h> +#include <rtems/seterr.h> +#include <rtems/posix/threadsup.h> +#include <rtems/posix/psignal.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/time.h> +#include <stdio.h> + +/*** PROCESS WIDE STUFF ****/ + +sigset_t _POSIX_signals_Pending; + +void _POSIX_signals_Abnormal_termination_handler( int signo ) +{ + exit( 1 ); +} + +#define SIG_ARRAY_MAX (SIGRTMAX + 1) +struct sigaction _POSIX_signals_Default_vectors[ SIG_ARRAY_MAX ] = { + /* NO SIGNAL 0 */ SIGACTION_IGNORE, + /* SIGHUP 1 */ SIGACTION_TERMINATE, + /* SIGINT 2 */ SIGACTION_TERMINATE, + /* SIGQUIT 3 */ SIGACTION_TERMINATE, + /* SIGILL 4 */ SIGACTION_TERMINATE, + /* SIGTRAP 5 */ SIGACTION_TERMINATE, + /* SIGIOT 6 */ SIGACTION_TERMINATE, + /* SIGABRT 6 SIGACTION_TERMINATE, -- alias for SIGIOT */ + /* SIGEMT 7 */ SIGACTION_TERMINATE, + /* SIGFPE 8 */ SIGACTION_TERMINATE, + /* SIGKILL 9 */ SIGACTION_TERMINATE, + /* SIGBUS 10 */ SIGACTION_TERMINATE, + /* SIGSEGV 11 */ SIGACTION_TERMINATE, + /* SIGSYS 12 */ SIGACTION_TERMINATE, + /* SIGPIPE 13 */ SIGACTION_TERMINATE, + /* SIGALRM 14 */ SIGACTION_TERMINATE, + /* SIGTERM 15 */ SIGACTION_TERMINATE, + /* SIGURG 16 */ SIGACTION_TERMINATE, + /* SIGSTOP 17 */ SIGACTION_TERMINATE, + /* SIGTSTP 18 */ SIGACTION_TERMINATE, + /* SIGCONT 19 */ SIGACTION_TERMINATE, + /* SIGCHLD 20 */ SIGACTION_TERMINATE, + /* SIGTTIN 21 */ SIGACTION_TERMINATE, + /* SIGTTOU 22 */ SIGACTION_TERMINATE, + /* SIGIO 23 */ SIGACTION_TERMINATE, + /* SIGWINCH 24 */ SIGACTION_TERMINATE, + /* SIGUSR1 25 */ SIGACTION_TERMINATE, + /* SIGUSR2 26 */ SIGACTION_TERMINATE, + /* SIGRT 27 */ SIGACTION_TERMINATE, + /* SIGRT 28 */ SIGACTION_TERMINATE, + /* SIGRT 29 */ SIGACTION_TERMINATE, + /* SIGRT 30 */ SIGACTION_TERMINATE, + /* SIGRTMAX 31 */ SIGACTION_TERMINATE +}; + +struct sigaction _POSIX_signals_Vectors[ SIG_ARRAY_MAX ]; + +Thread_queue_Control _POSIX_signals_Wait_queue; + +Chain_Control _POSIX_signals_Inactive_siginfo; +Chain_Control _POSIX_signals_Siginfo[ SIG_ARRAY_MAX ]; + +/*PAGE + * + * XXX - move these + */ + +#define _States_Is_interruptible_signal( _states ) \ + ( ((_states) & \ + (STATES_WAITING_FOR_SIGNAL|STATES_INTERRUPTIBLE_BY_SIGNAL)) == \ + (STATES_WAITING_FOR_SIGNAL|STATES_INTERRUPTIBLE_BY_SIGNAL)) + +/* + * _POSIX_signals_Post_switch_extension + */ + +void _POSIX_signals_Post_switch_extension( + Thread_Control *the_thread +) +{ + POSIX_API_Control *api; + int signo; + ISR_Level level; + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + /* + * If we invoke any user code, there is the possibility that + * a new signal has been posted that we should process so we + * restart the loop if a signal handler was invoked. + * + * The first thing done is to check there are any signals to be + * processed at all. No point in doing this loop otherwise. + */ + +restart: + _ISR_Disable( level ); + if ( !(~api->signals_blocked & + (api->signals_pending | _POSIX_signals_Pending)) ) { + _ISR_Enable( level ); + return; + } + _ISR_Enable( level ); + + for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) { + + if ( _POSIX_signals_Check_signal( api, signo, FALSE ) ) + goto restart; + + if ( _POSIX_signals_Check_signal( api, signo, TRUE ) ) + goto restart; + + } + +/* XXX - add __SIGFIRSTNOTRT or something like that to newlib signal .h */ + + for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) { + + if ( _POSIX_signals_Check_signal( api, signo, FALSE ) ) + goto restart; + + if ( _POSIX_signals_Check_signal( api, signo, TRUE ) ) + goto restart; + + } + +} + +/*PAGE + * + * _POSIX_signals_Manager_Initialization + */ + +void _POSIX_signals_Manager_Initialization( + int maximum_queued_signals +) +{ + uint32_t signo; + + /* + * Ensure we have the same number of vectors and default vector entries + */ + + assert( + sizeof(_POSIX_signals_Vectors) == sizeof(_POSIX_signals_Default_vectors) + ); + + memcpy( + _POSIX_signals_Vectors, + _POSIX_signals_Default_vectors, + sizeof( _POSIX_signals_Vectors ) + ); + + /* + * Initialize the set of pending signals for the entire process + */ + + sigemptyset( &_POSIX_signals_Pending ); + + /* + * Initialize the queue we use to block for signals + */ + + _Thread_queue_Initialize( + &_POSIX_signals_Wait_queue, + THREAD_QUEUE_DISCIPLINE_PRIORITY, + STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL, + EAGAIN + ); + + /* XXX status codes */ + + /* + * Allocate the siginfo pools. + */ + + for ( signo=1 ; signo<= SIGRTMAX ; signo++ ) + _Chain_Initialize_empty( &_POSIX_signals_Siginfo[ signo ] ); + + _Chain_Initialize( + &_POSIX_signals_Inactive_siginfo, + _Workspace_Allocate_or_fatal_error( + maximum_queued_signals * sizeof( POSIX_signals_Siginfo_node ) + ), + maximum_queued_signals, + sizeof( POSIX_signals_Siginfo_node ) + ); +} diff --git a/cpukit/posix/src/psignalchecksignal.c b/cpukit/posix/src/psignalchecksignal.c new file mode 100644 index 0000000000..0da7887afd --- /dev/null +++ b/cpukit/posix/src/psignalchecksignal.c @@ -0,0 +1,93 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tqdata.h> +#include <rtems/score/wkspace.h> +#include <rtems/seterr.h> +#include <rtems/posix/threadsup.h> +#include <rtems/posix/psignal.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/time.h> +#include <stdio.h> + + +/*PAGE + * + * _POSIX_signals_Check_signal + */ + +boolean _POSIX_signals_Check_signal( + POSIX_API_Control *api, + int signo, + boolean is_global +) +{ + siginfo_t siginfo_struct; + sigset_t saved_signals_blocked; + + if ( ! _POSIX_signals_Clear_signals( api, signo, &siginfo_struct, + is_global, TRUE ) ) + return FALSE; + + /* + * Since we made a union of these, only one test is necessary but this is + * safer. + */ + + assert( _POSIX_signals_Vectors[ signo ].sa_handler || + _POSIX_signals_Vectors[ signo ].sa_sigaction ); + + /* + * Just to prevent sending a signal which is currently being ignored. + */ + + if ( _POSIX_signals_Vectors[ signo ].sa_handler == SIG_IGN ) + return FALSE; + + /* + * Block the signals requested in sa_mask + */ + + saved_signals_blocked = api->signals_blocked; + api->signals_blocked |= _POSIX_signals_Vectors[ signo ].sa_mask; + + /* Here, the signal handler function executes */ + + switch ( _POSIX_signals_Vectors[ signo ].sa_flags ) { + case SA_SIGINFO: +/* + * + * assert( is_global ); + */ + (*_POSIX_signals_Vectors[ signo ].sa_sigaction)( + signo, + &siginfo_struct, + NULL /* context is undefined per 1003.1b-1993, p. 66 */ + ); + break; + default: + (*_POSIX_signals_Vectors[ signo ].sa_handler)( signo ); + break; + } + + /* + * Restore the previous set of blocked signals + */ + + api->signals_blocked = saved_signals_blocked; + + return TRUE; +} diff --git a/cpukit/posix/src/psignalclearprocesssignals.c b/cpukit/posix/src/psignalclearprocesssignals.c new file mode 100644 index 0000000000..1ff39534d3 --- /dev/null +++ b/cpukit/posix/src/psignalclearprocesssignals.c @@ -0,0 +1,42 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tqdata.h> +#include <rtems/score/wkspace.h> +#include <rtems/seterr.h> +#include <rtems/posix/threadsup.h> +#include <rtems/posix/psignal.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/time.h> +#include <stdio.h> + +/*PAGE + * + * _POSIX_signals_Clear_process_signals + */ + +void _POSIX_signals_Clear_process_signals( + sigset_t mask +) +{ + ISR_Level level; + + _ISR_Disable( level ); + _POSIX_signals_Pending &= ~mask; + if ( !_POSIX_signals_Pending ) + _Thread_Do_post_task_switch_extension--; + _ISR_Enable( level ); +} diff --git a/cpukit/posix/src/psignalclearsignals.c b/cpukit/posix/src/psignalclearsignals.c new file mode 100644 index 0000000000..a1e397c695 --- /dev/null +++ b/cpukit/posix/src/psignalclearsignals.c @@ -0,0 +1,89 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tqdata.h> +#include <rtems/score/wkspace.h> +#include <rtems/seterr.h> +#include <rtems/posix/threadsup.h> +#include <rtems/posix/psignal.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/time.h> +#include <stdio.h> + +/*PAGE + * + * _POSIX_signals_Clear_signals + */ + +boolean _POSIX_signals_Clear_signals( + POSIX_API_Control *api, + int signo, + siginfo_t *info, + boolean is_global, + boolean check_blocked +) +{ + sigset_t mask; + sigset_t signals_blocked; + ISR_Level level; + boolean do_callout; + POSIX_signals_Siginfo_node *psiginfo; + + mask = signo_to_mask( signo ); + + do_callout = FALSE; + + /* set blocked signals based on if checking for them, SIGNAL_ALL_MASK + * insures that no signals are blocked and all are checked. + */ + + if ( check_blocked ) + signals_blocked = ~api->signals_blocked; + else + signals_blocked = SIGNAL_ALL_MASK; + + /* XXX this is not right for siginfo type signals yet */ + /* XXX since they can't be cleared the same way */ + + _ISR_Disable( level ); + if ( is_global ) { + if ( mask & (_POSIX_signals_Pending & signals_blocked) ) { + if ( _POSIX_signals_Vectors[ signo ].sa_flags == SA_SIGINFO ) { + psiginfo = (POSIX_signals_Siginfo_node *) + _Chain_Get_unprotected( &_POSIX_signals_Siginfo[ signo ] ); + if ( _Chain_Is_empty( &_POSIX_signals_Siginfo[ signo ] ) ) + _POSIX_signals_Clear_process_signals( mask ); + if ( psiginfo ) { + *info = psiginfo->Info; + _Chain_Append_unprotected( + &_POSIX_signals_Inactive_siginfo, + &psiginfo->Node + ); + } else + do_callout = FALSE; + } else + _POSIX_signals_Clear_process_signals( mask ); + do_callout = TRUE; + } + } else { + if ( mask & (api->signals_pending & signals_blocked) ) { + api->signals_pending &= ~mask; + do_callout = TRUE; + } + } + _ISR_Enable( level ); + return do_callout; +} diff --git a/cpukit/posix/src/psignalsetprocesssignals.c b/cpukit/posix/src/psignalsetprocesssignals.c new file mode 100644 index 0000000000..65cb51664e --- /dev/null +++ b/cpukit/posix/src/psignalsetprocesssignals.c @@ -0,0 +1,42 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tqdata.h> +#include <rtems/score/wkspace.h> +#include <rtems/seterr.h> +#include <rtems/posix/threadsup.h> +#include <rtems/posix/psignal.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/time.h> +#include <stdio.h> + +/*PAGE + * + * _POSIX_signals_Set_process_signals + */ + +void _POSIX_signals_Set_process_signals( + sigset_t mask +) +{ + ISR_Level level; + + _ISR_Disable( level ); + if ( !_POSIX_signals_Pending ) + _Thread_Do_post_task_switch_extension++; + _POSIX_signals_Pending |= mask; + _ISR_Enable( level ); +} diff --git a/cpukit/posix/src/psignalunblockthread.c b/cpukit/posix/src/psignalunblockthread.c new file mode 100644 index 0000000000..249d16392a --- /dev/null +++ b/cpukit/posix/src/psignalunblockthread.c @@ -0,0 +1,93 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tqdata.h> +#include <rtems/score/wkspace.h> +#include <rtems/seterr.h> +#include <rtems/posix/threadsup.h> +#include <rtems/posix/psignal.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/time.h> +#include <stdio.h> + + +/*PAGE + * + * _POSIX_signals_Unblock_thread + */ + +/* XXX this routine could probably be cleaned up */ +boolean _POSIX_signals_Unblock_thread( + Thread_Control *the_thread, + int signo, + siginfo_t *info +) +{ + POSIX_API_Control *api; + sigset_t mask; + siginfo_t *the_info = NULL; + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + mask = signo_to_mask( signo ); + + /* + * Is the thread is specifically waiting for a signal? + */ + + if ( _States_Is_interruptible_signal( the_thread->current_state ) ) { + + if ( (the_thread->Wait.option & mask) || (~api->signals_blocked & mask) ) { + the_thread->Wait.return_code = EINTR; + + the_info = (siginfo_t *) the_thread->Wait.return_argument; + + if ( !info ) { + the_info->si_signo = signo; + the_info->si_code = SI_USER; + the_info->si_value.sival_int = 0; + } else { + *the_info = *info; + } + + _Thread_queue_Extract_with_proxy( the_thread ); + return TRUE; + } + + /* + * This should only be reached via pthread_kill(). + */ + + return FALSE; + } + + if ( ~api->signals_blocked & mask ) { + the_thread->do_post_task_switch_extension = TRUE; + + if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) { + the_thread->Wait.return_code = EINTR; + if ( _States_Is_waiting_on_thread_queue(the_thread->current_state) ) + _Thread_queue_Extract_with_proxy( the_thread ); + else if ( _States_Is_delaying(the_thread->current_state)){ + if ( _Watchdog_Is_active( &the_thread->Timer ) ) + (void) _Watchdog_Remove( &the_thread->Timer ); + _Thread_Unblock( the_thread ); + } + } + } + return FALSE; + +} diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c new file mode 100644 index 0000000000..0212f9d6ac --- /dev/null +++ b/cpukit/posix/src/pthread.c @@ -0,0 +1,387 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/apiext.h> +#include <rtems/score/stack.h> +#include <rtems/score/thread.h> +#include <rtems/score/userext.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/cancel.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/psignal.h> +#include <rtems/posix/config.h> +#include <rtems/posix/key.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * The default pthreads attributes structure. + * + * NOTE: Be careful .. if the default attribute set changes, + * _POSIX_Threads_Initialize_user_threads will need to be examined. + * + */ + +const pthread_attr_t _POSIX_Threads_Default_attributes = { + TRUE, /* is_initialized */ + NULL, /* stackaddr */ + PTHREAD_MINIMUM_STACK_SIZE, /* stacksize */ + PTHREAD_SCOPE_PROCESS, /* contentionscope */ + PTHREAD_INHERIT_SCHED, /* inheritsched */ + SCHED_FIFO, /* schedpolicy */ + { /* schedparam */ + 2, /* sched_priority */ + 0, /* ss_low_priority */ + { 0L, 0 }, /* ss_replenish_period */ + { 0L, 0 } /* ss_initial_budget */ + }, + PTHREAD_CREATE_JOINABLE, /* detachstate */ + 1 /* cputime_clock_allowed */ +}; + +/*PAGE + * + * _POSIX_Threads_Sporadic_budget_TSR + */ + +void _POSIX_Threads_Sporadic_budget_TSR( + Objects_Id id, + void *argument +) +{ + uint32_t ticks; + uint32_t new_priority; + Thread_Control *the_thread; + POSIX_API_Control *api; + + the_thread = argument; + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + ticks = _POSIX_Timespec_to_interval( &api->schedparam.ss_initial_budget ); + + if ( !ticks ) + ticks = 1; + + the_thread->cpu_time_budget = ticks; + + new_priority = _POSIX_Priority_To_core( api->ss_high_priority ); + the_thread->real_priority = new_priority; + + if ( the_thread->resource_count == 0 || + the_thread->current_priority > new_priority ) + _Thread_Change_priority( the_thread, new_priority, TRUE ); + + ticks = _POSIX_Timespec_to_interval( &api->schedparam.ss_replenish_period ); + + if ( !ticks ) + ticks = 1; + + _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks ); +} + +/*PAGE + * + * _POSIX_Threads_Sporadic_budget_callout + */ + +void _POSIX_Threads_Sporadic_budget_callout( + Thread_Control *the_thread +) +{ + POSIX_API_Control *api; + uint32_t new_priority; + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + /* + * This will prevent the thread from consuming its entire "budget" + * while at low priority. + */ + + + the_thread->cpu_time_budget = 0xFFFFFFFF; /* XXX should be based on MAX_U32 */ + + new_priority = _POSIX_Priority_To_core( api->schedparam.ss_low_priority ); + the_thread->real_priority = new_priority; + + if ( the_thread->resource_count == 0 || + the_thread->current_priority > new_priority ) + _Thread_Change_priority( the_thread, new_priority, TRUE ); +} + +/*PAGE + * + * _POSIX_Threads_Create_extension + * + * XXX + */ + +boolean _POSIX_Threads_Create_extension( + Thread_Control *executing, + Thread_Control *created +) +{ + POSIX_API_Control *api; + POSIX_API_Control *executing_api; + + api = _Workspace_Allocate( sizeof( POSIX_API_Control ) ); + + if ( !api ) + return FALSE; + + created->API_Extensions[ THREAD_API_POSIX ] = api; + + /* XXX check all fields are touched */ + api->Attributes = _POSIX_Threads_Default_attributes; + api->detachstate = _POSIX_Threads_Default_attributes.detachstate; + api->schedpolicy = _POSIX_Threads_Default_attributes.schedpolicy; + api->schedparam = _POSIX_Threads_Default_attributes.schedparam; + api->schedparam.sched_priority = + _POSIX_Priority_From_core( created->current_priority ); + + /* + * POSIX 1003.1 1996, 18.2.2.2 + */ + api->cancelation_requested = 0; + api->cancelability_state = PTHREAD_CANCEL_ENABLE; + api->cancelability_type = PTHREAD_CANCEL_DEFERRED; + _Chain_Initialize_empty (&api->Cancellation_Handlers); + + /* + * If the thread is not a posix thread, then all posix signals are blocked + * by default. + */ + + /* XXX use signal constants */ + api->signals_pending = 0; + if ( _Objects_Get_API( created->Object.id ) == OBJECTS_POSIX_API && + _Objects_Get_class( created->Object.id ) == 1 ) { + executing_api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + api->signals_blocked = api->signals_blocked; + } else + api->signals_blocked = 0xffffffff; + + _Thread_queue_Initialize( + &api->Join_List, + THREAD_QUEUE_DISCIPLINE_FIFO, + STATES_WAITING_FOR_JOIN_AT_EXIT, + 0 + ); + + _Watchdog_Initialize( + &api->Sporadic_timer, + _POSIX_Threads_Sporadic_budget_TSR, + created->Object.id, + created + ); + + return TRUE; +} + +/*PAGE + * + * _POSIX_Threads_Delete_extension + */ + +User_extensions_routine _POSIX_Threads_Delete_extension( + Thread_Control *executing, + Thread_Control *deleted +) +{ + Thread_Control *the_thread; + POSIX_API_Control *api; + void **value_ptr; + + api = deleted->API_Extensions[ THREAD_API_POSIX ]; + + /* + * Run the POSIX cancellation handlers + */ + + _POSIX_Keys_Run_destructors( deleted ); + + /* + * Wakeup all the tasks which joined with this one + */ + + value_ptr = (void **) deleted->Wait.return_argument; + + while ( (the_thread = _Thread_queue_Dequeue( &api->Join_List )) ) + *(void **)the_thread->Wait.return_argument = value_ptr; + + if ( api->schedpolicy == SCHED_SPORADIC ) + (void) _Watchdog_Remove( &api->Sporadic_timer ); + + deleted->API_Extensions[ THREAD_API_POSIX ] = NULL; + + (void) _Workspace_Free( api ); +} + +/* + * + * _POSIX_Threads_Exitted_extension + */ + +User_extensions_routine _POSIX_Threads_Exitted_extension( + Thread_Control *executing +) +{ + pthread_exit( executing->Wait.return_argument ); +} + +/*PAGE + * + * _POSIX_Threads_Initialize_user_threads + * + * This routine creates and starts all configured user + * initialzation threads. + * + * Input parameters: NONE + * + * Output parameters: NONE + */ + +void _POSIX_Threads_Initialize_user_threads( void ) +{ + int status; + uint32_t index; + uint32_t maximum; + posix_initialization_threads_table *user_threads; + pthread_t thread_id; + pthread_attr_t attr; + + user_threads = _POSIX_Threads_User_initialization_threads; + maximum = _POSIX_Threads_Number_of_initialization_threads; + + if ( !user_threads || maximum == 0 ) + return; + + /* + * Be careful .. if the default attribute set changes, this may need to. + * + * Setting the attributes explicitly is critical, since we don't want + * to inherit the idle tasks attributes. + */ + + for ( index=0 ; index < maximum ; index++ ) { + status = pthread_attr_init( &attr ); + assert( !status ); + + status = pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); + assert( !status ); + + status = pthread_attr_setstacksize( &attr, user_threads[ index ].stack_size); + assert( !status ); + + status = pthread_create( + &thread_id, + &attr, + user_threads[ index ].thread_entry, + NULL + ); + assert( !status ); + } +} + +/*PAGE + * + * API Extension control structures + */ + +API_extensions_Control _POSIX_Threads_API_extensions = { + { NULL, NULL }, + NULL, /* predriver */ + _POSIX_Threads_Initialize_user_threads, /* postdriver */ + _POSIX_signals_Post_switch_extension, /* post switch */ +}; + +User_extensions_Control _POSIX_Threads_User_extensions = { + { NULL, NULL }, + { { NULL, NULL }, NULL }, + { _POSIX_Threads_Create_extension, /* create */ + NULL, /* start */ + NULL, /* restart */ + _POSIX_Threads_Delete_extension, /* delete */ + NULL, /* switch */ + NULL, /* begin */ + _POSIX_Threads_Exitted_extension, /* exitted */ + NULL /* fatal */ + } +}; + +/*PAGE + * + * _POSIX_Threads_Manager_initialization + * + * This routine initializes all threads manager related data structures. + * + * Input parameters: + * maximum_pthreads - maximum configured pthreads + * + * Output parameters: NONE + */ + +void _POSIX_Threads_Manager_initialization( + uint32_t maximum_pthreads, + uint32_t number_of_initialization_threads, + posix_initialization_threads_table *user_threads + +) +{ + _POSIX_Threads_Number_of_initialization_threads = + number_of_initialization_threads; + _POSIX_Threads_User_initialization_threads = user_threads; + + /* + * There may not be any POSIX initialization threads configured. + */ + +#if 0 + if ( user_threads == NULL || number_of_initialization_threads == 0 ) + _Internal_error_Occurred( INTERNAL_ERROR_POSIX_API, TRUE, EINVAL ); +#endif + + _Objects_Initialize_information( + &_POSIX_Threads_Information, /* object information table */ + OBJECTS_POSIX_API, /* object API */ + OBJECTS_POSIX_THREADS, /* object class */ + maximum_pthreads, /* maximum objects of this class */ + sizeof( Thread_Control ), + /* size of this object's control block */ + FALSE, /* TRUE if names for this object are strings */ + 0 /* maximum length of each object's name */ +#if defined(RTEMS_MULTIPROCESSING) + , + FALSE, /* TRUE if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); + + /* + * Add all the extensions for this API + */ + + _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions ); + + _API_extensions_Add( &_POSIX_Threads_API_extensions ); + + + /* + * If we supported MP, then here we would ... + * Register the MP Process Packet routine. + */ + +} diff --git a/cpukit/posix/src/pthreadatfork.c b/cpukit/posix/src/pthreadatfork.c new file mode 100644 index 0000000000..7bc398ed85 --- /dev/null +++ b/cpukit/posix/src/pthreadatfork.c @@ -0,0 +1,31 @@ +/* + * pthread_atfork() - POSIX 1003.1b 3.1.3 + * + * 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." + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <errno.h> + +int pthread_atfork( + void (*prepare)(void), + void (*parent)(void), + void (*child)(void) +) +{ + errno = ENOSYS; + return -1; +} diff --git a/cpukit/posix/src/pthreadattrdestroy.c b/cpukit/posix/src/pthreadattrdestroy.c new file mode 100644 index 0000000000..9b5858ff60 --- /dev/null +++ b/cpukit/posix/src/pthreadattrdestroy.c @@ -0,0 +1,32 @@ +/* + * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> + +int pthread_attr_destroy( + pthread_attr_t *attr +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + attr->is_initialized = FALSE; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrgetdetachstate.c b/cpukit/posix/src/pthreadattrgetdetachstate.c new file mode 100644 index 0000000000..bd8b9a02ae --- /dev/null +++ b/cpukit/posix/src/pthreadattrgetdetachstate.c @@ -0,0 +1,31 @@ +/* + * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_getdetachstate( + const pthread_attr_t *attr, + int *detachstate +) +{ + if ( !attr || !attr->is_initialized || !detachstate ) + return EINVAL; + + *detachstate = attr->detachstate; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrgetinheritsched.c b/cpukit/posix/src/pthreadattrgetinheritsched.c new file mode 100644 index 0000000000..e924f2d26c --- /dev/null +++ b/cpukit/posix/src/pthreadattrgetinheritsched.c @@ -0,0 +1,31 @@ +/* + * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_getinheritsched( + const pthread_attr_t *attr, + int *inheritsched +) +{ + if ( !attr || !attr->is_initialized || !inheritsched ) + return EINVAL; + + *inheritsched = attr->inheritsched; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrgetschedparam.c b/cpukit/posix/src/pthreadattrgetschedparam.c new file mode 100644 index 0000000000..2ec95d729e --- /dev/null +++ b/cpukit/posix/src/pthreadattrgetschedparam.c @@ -0,0 +1,31 @@ +/* + * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_getschedparam( + const pthread_attr_t *attr, + struct sched_param *param +) +{ + if ( !attr || !attr->is_initialized || !param ) + return EINVAL; + + *param = attr->schedparam; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrgetschedpolicy.c b/cpukit/posix/src/pthreadattrgetschedpolicy.c new file mode 100644 index 0000000000..571430e953 --- /dev/null +++ b/cpukit/posix/src/pthreadattrgetschedpolicy.c @@ -0,0 +1,31 @@ +/* + * 13.5.1 Thread Creation Scheduling Parameters, P1003.1c/Draft 10, p. 120 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_getschedpolicy( + const pthread_attr_t *attr, + int *policy +) +{ + if ( !attr || !attr->is_initialized || !policy ) + return EINVAL; + + *policy = attr->schedpolicy; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrgetscope.c b/cpukit/posix/src/pthreadattrgetscope.c new file mode 100644 index 0000000000..2d74dc30ba --- /dev/null +++ b/cpukit/posix/src/pthreadattrgetscope.c @@ -0,0 +1,31 @@ +/* + * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_getscope( + const pthread_attr_t *attr, + int *contentionscope +) +{ + if ( !attr || !attr->is_initialized || !contentionscope ) + return EINVAL; + + *contentionscope = attr->contentionscope; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrgetstackaddr.c b/cpukit/posix/src/pthreadattrgetstackaddr.c new file mode 100644 index 0000000000..3ca66112aa --- /dev/null +++ b/cpukit/posix/src/pthreadattrgetstackaddr.c @@ -0,0 +1,31 @@ +/* + * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_getstackaddr( + const pthread_attr_t *attr, + void **stackaddr +) +{ + if ( !attr || !attr->is_initialized || !stackaddr ) + return EINVAL; + + *stackaddr = attr->stackaddr; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrgetstacksize.c b/cpukit/posix/src/pthreadattrgetstacksize.c new file mode 100644 index 0000000000..f7f23c6dd6 --- /dev/null +++ b/cpukit/posix/src/pthreadattrgetstacksize.c @@ -0,0 +1,31 @@ +/* + * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_getstacksize( + const pthread_attr_t *attr, + size_t *stacksize +) +{ + if ( !attr || !attr->is_initialized || !stacksize ) + return EINVAL; + + *stacksize = attr->stacksize; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrinit.c b/cpukit/posix/src/pthreadattrinit.c new file mode 100644 index 0000000000..1862623e3e --- /dev/null +++ b/cpukit/posix/src/pthreadattrinit.c @@ -0,0 +1,33 @@ +/* + * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> + +int pthread_attr_init( + pthread_attr_t *attr +) +{ + if ( !attr ) + return EINVAL; + + *attr = _POSIX_Threads_Default_attributes; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrsetdetachstate.c b/cpukit/posix/src/pthreadattrsetdetachstate.c new file mode 100644 index 0000000000..cb29f44d3a --- /dev/null +++ b/cpukit/posix/src/pthreadattrsetdetachstate.c @@ -0,0 +1,38 @@ +/* + * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_setdetachstate( + pthread_attr_t *attr, + int detachstate +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + switch ( detachstate ) { + case PTHREAD_CREATE_DETACHED: + case PTHREAD_CREATE_JOINABLE: + attr->detachstate = detachstate; + return 0; + + default: + return EINVAL; + } +} diff --git a/cpukit/posix/src/pthreadattrsetinheritsched.c b/cpukit/posix/src/pthreadattrsetinheritsched.c new file mode 100644 index 0000000000..0819eb48b7 --- /dev/null +++ b/cpukit/posix/src/pthreadattrsetinheritsched.c @@ -0,0 +1,41 @@ +/* + * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> + +int pthread_attr_setinheritsched( + pthread_attr_t *attr, + int inheritsched +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + switch ( inheritsched ) { + case PTHREAD_INHERIT_SCHED: + case PTHREAD_EXPLICIT_SCHED: + attr->inheritsched = inheritsched; + return 0; + + default: + return ENOTSUP; + } +} diff --git a/cpukit/posix/src/pthreadattrsetschedparam.c b/cpukit/posix/src/pthreadattrsetschedparam.c new file mode 100644 index 0000000000..cb310a9893 --- /dev/null +++ b/cpukit/posix/src/pthreadattrsetschedparam.c @@ -0,0 +1,31 @@ +/* + * 13.5.1 Thread Creation Scheduling Parameters, P1003.1c/Draft 10, p. 120 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_setschedparam( + pthread_attr_t *attr, + const struct sched_param *param +) +{ + if ( !attr || !attr->is_initialized || !param ) + return EINVAL; + + attr->schedparam = *param; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrsetschedpolicy.c b/cpukit/posix/src/pthreadattrsetschedpolicy.c new file mode 100644 index 0000000000..ab61e000ed --- /dev/null +++ b/cpukit/posix/src/pthreadattrsetschedpolicy.c @@ -0,0 +1,43 @@ +/* + * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> + +int pthread_attr_setschedpolicy( + pthread_attr_t *attr, + int policy +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + switch ( policy ) { + case SCHED_OTHER: + case SCHED_FIFO: + case SCHED_RR: + case SCHED_SPORADIC: + attr->schedpolicy = policy; + return 0; + + default: + return ENOTSUP; + } +} diff --git a/cpukit/posix/src/pthreadattrsetscope.c b/cpukit/posix/src/pthreadattrsetscope.c new file mode 100644 index 0000000000..8c6d1c3f9c --- /dev/null +++ b/cpukit/posix/src/pthreadattrsetscope.c @@ -0,0 +1,43 @@ +/* + * 13.5.1 Thread Creation Scheduling Attributes, P1003.1c/Draft 10, p. 120 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> + +int pthread_attr_setscope( + pthread_attr_t *attr, + int contentionscope +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + switch ( contentionscope ) { + case PTHREAD_SCOPE_PROCESS: + attr->contentionscope = contentionscope; + return 0; + + case PTHREAD_SCOPE_SYSTEM: + return ENOTSUP; + + default: + return EINVAL; + } +} diff --git a/cpukit/posix/src/pthreadattrsetstackaddr.c b/cpukit/posix/src/pthreadattrsetstackaddr.c new file mode 100644 index 0000000000..b7ed212546 --- /dev/null +++ b/cpukit/posix/src/pthreadattrsetstackaddr.c @@ -0,0 +1,31 @@ +/* + * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_setstackaddr( + pthread_attr_t *attr, + void *stackaddr +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + attr->stackaddr = stackaddr; + return 0; +} diff --git a/cpukit/posix/src/pthreadattrsetstacksize.c b/cpukit/posix/src/pthreadattrsetstacksize.c new file mode 100644 index 0000000000..9598a8a7d7 --- /dev/null +++ b/cpukit/posix/src/pthreadattrsetstacksize.c @@ -0,0 +1,37 @@ +/* + * 16.1.1 Thread Creation Attributes, P1003.1c/Draft 10, p, 140 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> + +int pthread_attr_setstacksize( + pthread_attr_t *attr, + size_t stacksize +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + if (stacksize < PTHREAD_MINIMUM_STACK_SIZE) + attr->stacksize = PTHREAD_MINIMUM_STACK_SIZE; + else + attr->stacksize = stacksize; + return 0; +} diff --git a/cpukit/posix/src/pthreadcreate.c b/cpukit/posix/src/pthreadcreate.c new file mode 100644 index 0000000000..61a59c01f8 --- /dev/null +++ b/cpukit/posix/src/pthreadcreate.c @@ -0,0 +1,256 @@ +/* + * 16.1.2 Thread Creation, P1003.1c/Draft 10, p. 144 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +int pthread_create( + pthread_t *thread, + const pthread_attr_t *attr, + void *(*start_routine)( void * ), + void *arg +) +{ + const pthread_attr_t *the_attr; + Priority_Control core_priority; + Thread_CPU_budget_algorithms budget_algorithm; + Thread_CPU_budget_algorithm_callout budget_callout; + boolean is_fp; + boolean status; + Thread_Control *the_thread; + POSIX_API_Control *api; + int schedpolicy = SCHED_RR; + struct sched_param schedparam; + + the_attr = (attr) ? attr : &_POSIX_Threads_Default_attributes; + + if ( !the_attr->is_initialized ) + return EINVAL; + + /* + * Core Thread Initialize insures we get the minimum amount of + * stack space if it is allowed to allocate it itself. + */ + + if ( the_attr->stackaddr && !_Stack_Is_enough( the_attr->stacksize ) ) + return EINVAL; + +#if 0 + int cputime_clock_allowed; /* see time.h */ + POSIX_NOT_IMPLEMENTED(); +#endif + + /* + * P1003.1c/Draft 10, p. 121. + * + * If inheritsched is set to PTHREAD_INHERIT_SCHED, then this thread + * inherits scheduling attributes from the creating thread. If it is + * PTHREAD_EXPLICIT_SCHED, then scheduling parameters come from the + * attributes structure. + */ + + switch ( the_attr->inheritsched ) { + case PTHREAD_INHERIT_SCHED: + api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + schedpolicy = api->schedpolicy; + schedparam = api->schedparam; + break; + + case PTHREAD_EXPLICIT_SCHED: + schedpolicy = the_attr->schedpolicy; + schedparam = the_attr->schedparam; + break; + + default: + return EINVAL; + } + + /* + * Check the contentionscope since rtems only supports PROCESS wide + * contention (i.e. no system wide contention). + */ + + if ( the_attr->contentionscope != PTHREAD_SCOPE_PROCESS ) + return ENOTSUP; + + /* + * Interpret the scheduling parameters. + */ + + if ( !_POSIX_Priority_Is_valid( schedparam.sched_priority ) ) + return EINVAL; + + core_priority = _POSIX_Priority_To_core( schedparam.sched_priority ); + + /* + * Set the core scheduling policy information. + */ + + budget_callout = NULL; + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; + + switch ( schedpolicy ) { + case SCHED_OTHER: + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE; + break; + + case SCHED_FIFO: + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; + break; + + case SCHED_RR: + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE; + break; + + case SCHED_SPORADIC: + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT; + budget_callout = _POSIX_Threads_Sporadic_budget_callout; + + if ( _POSIX_Timespec_to_interval( &schedparam.ss_replenish_period ) < + _POSIX_Timespec_to_interval( &schedparam.ss_initial_budget ) ) + return EINVAL; + + if ( !_POSIX_Priority_Is_valid( schedparam.ss_low_priority ) ) + return EINVAL; + + break; + + default: + return EINVAL; + } + + /* + * Currently all POSIX threads are floating point if the hardware + * supports it. + */ + + +#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + is_fp = TRUE; +#else + is_fp = FALSE; +#endif + + /* + * Disable dispatch for protection + */ + + _Thread_Disable_dispatch(); + + /* + * Allocate the thread control block. + * + * NOTE: Global threads are not currently supported. + */ + + the_thread = _POSIX_Threads_Allocate(); + + if ( !the_thread ) { + _Thread_Enable_dispatch(); + return EAGAIN; + } + + /* + * Initialize the core thread for this task. + */ + + status = _Thread_Initialize( + &_POSIX_Threads_Information, + the_thread, + the_attr->stackaddr, + the_attr->stacksize, + is_fp, + core_priority, + TRUE, /* preemptible */ + budget_algorithm, + budget_callout, + 0, /* isr level */ + NULL /* posix threads don't have a name */ + ); + + if ( !status ) { + _POSIX_Threads_Free( the_thread ); + _Thread_Enable_dispatch(); + return EAGAIN; + } + + /* + * finish initializing the per API structure + */ + + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + api->Attributes = *the_attr; + api->detachstate = the_attr->detachstate; + api->schedpolicy = schedpolicy; + api->schedparam = schedparam; + + /* + * This insures we evaluate the process-wide signals pending when we + * first run. + * + * NOTE: Since the thread starts with all unblocked, this is necessary. + */ + + the_thread->do_post_task_switch_extension = TRUE; + + /* + * POSIX threads are allocated and started in one operation. + */ + + status = _Thread_Start( + the_thread, + THREAD_START_POINTER, + start_routine, + arg, + 0 /* unused */ + ); + + if ( schedpolicy == SCHED_SPORADIC ) { + _Watchdog_Insert_ticks( + &api->Sporadic_timer, + _POSIX_Timespec_to_interval( &api->schedparam.ss_replenish_period ) + ); + } + + /* + * _Thread_Start only fails if the thread was in the incorrect state + */ + + if ( !status ) { + _POSIX_Threads_Free( the_thread ); + _Thread_Enable_dispatch(); + return EINVAL; + } + + /* + * Return the id and indicate we successfully created the thread + */ + + *thread = the_thread->Object.id; + + _Thread_Enable_dispatch(); + + return 0; +} diff --git a/cpukit/posix/src/pthreaddetach.c b/cpukit/posix/src/pthreaddetach.c new file mode 100644 index 0000000000..7d7629f18a --- /dev/null +++ b/cpukit/posix/src/pthreaddetach.c @@ -0,0 +1,47 @@ +/* + * 16.1.4 Detaching a Thread, P1003.1c/Draft 10, p. 149 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/posix/pthread.h> + +int pthread_detach( + pthread_t thread +) +{ + register Thread_Control *the_thread; + POSIX_API_Control *api; + Objects_Locations location; + + the_thread = _POSIX_Threads_Get( thread, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: + return ESRCH; + case OBJECTS_LOCAL: + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + api->detachstate = PTHREAD_CREATE_DETACHED; + _Thread_Enable_dispatch(); + return 0; + } + + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/pthreadequal.c b/cpukit/posix/src/pthreadequal.c new file mode 100644 index 0000000000..39136cc388 --- /dev/null +++ b/cpukit/posix/src/pthreadequal.c @@ -0,0 +1,82 @@ +/* + * 16.1.7 Compare Thread IDs, p1003.1c/Draft 10, p. 153 + * + * NOTE: POSIX does not define the behavior when either thread id is invalid. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/score/thread.h> + +int pthread_equal( + pthread_t t1, + pthread_t t2 +) +{ + /* + * If the system is configured for debug, then we will do everything we + * can to insure that both ids are valid. Otherwise, we will do the + * cheapest possible thing to determine if they are equal. + */ + +#ifndef RTEMS_DEBUG + return _Objects_Are_ids_equal( t1, t2 ); +#else + int status; + Objects_Locations location; + + /* + * By default this is not a match. + */ + + status = 0; + + /* + * Validate the first id and return 0 if it is not valid + */ + + (void) _POSIX_Threads_Get( t1, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: + break; + + case OBJECTS_LOCAL: + + /* + * Validate the second id and return 0 if it is not valid + */ + + (void) _POSIX_Threads_Get( t2, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: + break; + case OBJECTS_LOCAL: + status = _Objects_Are_ids_equal( t1, t2 ); + break; + } + _Thread_Unnest_dispatch(); + break; + } + + _Thread_Enable_dispatch(); + return status; +#endif +} diff --git a/cpukit/posix/src/pthreadexit.c b/cpukit/posix/src/pthreadexit.c new file mode 100644 index 0000000000..8346f139b8 --- /dev/null +++ b/cpukit/posix/src/pthreadexit.c @@ -0,0 +1,48 @@ +/* + * 16.1.5.1 Thread Termination, p1003.1c/Draft 10, p. 150 + * + * NOTE: Key destructors are executed in the POSIX api delete extension. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> +#include <assert.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/posix/pthread.h> + +void pthread_exit( + void *value_ptr +) +{ + Objects_Information *the_information; + + the_information = _Objects_Get_information( _Thread_Executing->Object.id ); + + /* This should never happen if _Thread_Get() works right */ + assert( the_information ); + + _Thread_Disable_dispatch(); + + _Thread_Executing->Wait.return_argument = value_ptr; + + _Thread_Close( the_information, _Thread_Executing ); + + _POSIX_Threads_Free( _Thread_Executing ); + + _Thread_Enable_dispatch(); +} diff --git a/cpukit/posix/src/pthreadgetcpuclockid.c b/cpukit/posix/src/pthreadgetcpuclockid.c new file mode 100644 index 0000000000..7769e4b7c6 --- /dev/null +++ b/cpukit/posix/src/pthreadgetcpuclockid.c @@ -0,0 +1,29 @@ +/* + * 20.1.6 Accessing a Thread CPU-time Clock, P1003.4b/Draft 8, p. 58 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> + +int pthread_getcpuclockid( + pthread_t pid, + clockid_t *clock_id +) +{ + return POSIX_NOT_IMPLEMENTED(); +} diff --git a/cpukit/posix/src/pthreadgetcputime.c b/cpukit/posix/src/pthreadgetcputime.c new file mode 100644 index 0000000000..7c9bb46c7b --- /dev/null +++ b/cpukit/posix/src/pthreadgetcputime.c @@ -0,0 +1,31 @@ +/* + * 20.1.7 CPU-time Clock Thread Creation Attribute, P1003.4b/Draft 8, p. 59 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_getcputime( + pthread_attr_t *attr, + int *clock_allowed +) +{ + if ( !attr || !attr->is_initialized || !clock_allowed ) + return EINVAL; + + *clock_allowed = attr->cputime_clock_allowed; + return 0; +} diff --git a/cpukit/posix/src/pthreadgetschedparam.c b/cpukit/posix/src/pthreadgetschedparam.c new file mode 100644 index 0000000000..8b399b75ba --- /dev/null +++ b/cpukit/posix/src/pthreadgetschedparam.c @@ -0,0 +1,59 @@ +/* + * 13.5.2 Dynamic Thread Scheduling Parameters Access, + * P1003.1c/Draft 10, p. 124 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/priority.h> + +int pthread_getschedparam( + pthread_t thread, + int *policy, + struct sched_param *param +) +{ + Objects_Locations location; + POSIX_API_Control *api; + register Thread_Control *the_thread; + + if ( !policy || !param ) + return EINVAL; + + the_thread = _POSIX_Threads_Get( thread, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: + return ESRCH; + case OBJECTS_LOCAL: + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + if ( policy ) + *policy = api->schedpolicy; + if ( param ) { + *param = api->schedparam; + param->sched_priority = + _POSIX_Priority_From_core( the_thread->current_priority ); + } + _Thread_Enable_dispatch(); + return 0; + } + + return POSIX_BOTTOM_REACHED(); + +} diff --git a/cpukit/posix/src/pthreadjoin.c b/cpukit/posix/src/pthreadjoin.c new file mode 100644 index 0000000000..669028335c --- /dev/null +++ b/cpukit/posix/src/pthreadjoin.c @@ -0,0 +1,71 @@ +/* + * 16.1.3 Wait for Thread Termination, P1003.1c/Draft 10, p. 147 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> +#include <rtems/posix/pthread.h> + +int pthread_join( + pthread_t thread, + void **value_ptr +) +{ + register Thread_Control *the_thread; + POSIX_API_Control *api; + Objects_Locations location; + void *return_pointer; + + the_thread = _POSIX_Threads_Get( thread, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: + return ESRCH; + case OBJECTS_LOCAL: + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + if ( api->detachstate == PTHREAD_CREATE_DETACHED ) { + _Thread_Enable_dispatch(); + return EINVAL; + } + + if ( _Thread_Is_executing( the_thread ) ) { + _Thread_Enable_dispatch(); + return EDEADLK; + } + + /* + * Put ourself on the threads join list + */ + + _Thread_Executing->Wait.return_argument = &return_pointer; + + _Thread_queue_Enter_critical_section( &api->Join_List ); + + _Thread_queue_Enqueue( &api->Join_List, WATCHDOG_NO_TIMEOUT ); + + _Thread_Enable_dispatch(); + + if ( value_ptr ) + *value_ptr = return_pointer; + return 0; + } + + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/pthreadkill.c b/cpukit/posix/src/pthreadkill.c new file mode 100644 index 0000000000..c6624eb8be --- /dev/null +++ b/cpukit/posix/src/pthreadkill.c @@ -0,0 +1,83 @@ +/* + * 3.3.10 Send a Signal to a Thread, P1003.1c/D10, p. 43 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/score/isr.h> +#include <rtems/seterr.h> + +int pthread_kill( + pthread_t thread, + int sig +) +{ + POSIX_API_Control *api; + Thread_Control *the_thread; + Objects_Locations location; + + if ( !sig ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( !is_valid_signo(sig) ) + rtems_set_errno_and_return_minus_one( EINVAL ); + +/* commented out when posix timers added + if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO ) + rtems_set_errno_and_return_minus_one( ENOSYS ); +*/ + + the_thread = _POSIX_Threads_Get( thread, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: + rtems_set_errno_and_return_minus_one( ESRCH ); + case OBJECTS_LOCAL: + /* + * If sig == 0 then just validate arguments + */ + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + if ( sig ) { + + if ( _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN ) { + _Thread_Enable_dispatch(); + return 0; + } + + /* XXX critical section */ + + api->signals_pending |= signo_to_mask( sig ); + + (void) _POSIX_signals_Unblock_thread( the_thread, sig, NULL ); + + the_thread->do_post_task_switch_extension = TRUE; + + if ( _ISR_Is_in_progress() && _Thread_Is_executing( the_thread ) ) + _ISR_Signals_to_thread_executing = TRUE; + } + _Thread_Enable_dispatch(); + return 0; + } + + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/pthreadonce.c b/cpukit/posix/src/pthreadonce.c new file mode 100644 index 0000000000..b1371c8def --- /dev/null +++ b/cpukit/posix/src/pthreadonce.c @@ -0,0 +1,44 @@ +/* + * 16.1.8 Dynamic Package Initialization, P1003.1c/Draft 10, p. 154 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/system.h> +#include <rtems/score/thread.h> + +int pthread_once( + pthread_once_t *once_control, + void (*init_routine)(void) +) +{ + if ( !once_control || !init_routine ) + return EINVAL; + + if ( !once_control->init_executed ) { + rtems_mode saveMode; + rtems_task_mode(RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &saveMode); + if ( !once_control->init_executed ) { + once_control->is_initialized = TRUE; + once_control->init_executed = TRUE; + (*init_routine)(); + } + rtems_task_mode(saveMode, RTEMS_PREEMPT_MASK, &saveMode); + } + return 0; +} diff --git a/cpukit/posix/src/pthreadself.c b/cpukit/posix/src/pthreadself.c new file mode 100644 index 0000000000..c1baf85177 --- /dev/null +++ b/cpukit/posix/src/pthreadself.c @@ -0,0 +1,27 @@ +/* + * 16.1.6 Get Calling Thread's ID, p1003.1c/Draft 10, p. 152 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/thread.h> + +pthread_t pthread_self( void ) +{ + return _Thread_Executing->Object.id; +} diff --git a/cpukit/posix/src/pthreadsetcputime.c b/cpukit/posix/src/pthreadsetcputime.c new file mode 100644 index 0000000000..70b9594ab9 --- /dev/null +++ b/cpukit/posix/src/pthreadsetcputime.c @@ -0,0 +1,38 @@ +/* + * 20.1.7 CPU-time Clock Thread Creation Attribute, P1003.4b/Draft 8, p. 59 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +int pthread_attr_setcputime( + pthread_attr_t *attr, + int clock_allowed +) +{ + if ( !attr || !attr->is_initialized ) + return EINVAL; + + switch ( clock_allowed ) { + case CLOCK_ENABLED: + case CLOCK_DISABLED: + attr->cputime_clock_allowed = clock_allowed; + return 0; + + default: + return EINVAL; + } +} diff --git a/cpukit/posix/src/pthreadsetschedparam.c b/cpukit/posix/src/pthreadsetschedparam.c new file mode 100644 index 0000000000..3413dbfc74 --- /dev/null +++ b/cpukit/posix/src/pthreadsetschedparam.c @@ -0,0 +1,129 @@ +/* + * 13.5.2 Dynamic Thread Scheduling Parameters Access, + * P1003.1c/Draft 10, p. 124 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +int pthread_setschedparam( + pthread_t thread, + int policy, + struct sched_param *param +) +{ + register Thread_Control *the_thread; + POSIX_API_Control *api; + Thread_CPU_budget_algorithms budget_algorithm; + Thread_CPU_budget_algorithm_callout budget_callout; + Objects_Locations location; + + /* + * Check all the parameters + */ + + if ( !param ) + return EINVAL; + + if ( !_POSIX_Priority_Is_valid( param->sched_priority ) ) + return EINVAL; + + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; + budget_callout = NULL; + + switch ( policy ) { + case SCHED_OTHER: + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE; + break; + + case SCHED_FIFO: + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE; + break; + + case SCHED_RR: + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE; + break; + + case SCHED_SPORADIC: + budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT; + budget_callout = _POSIX_Threads_Sporadic_budget_callout; + + if ( _POSIX_Timespec_to_interval( ¶m->ss_replenish_period ) < + _POSIX_Timespec_to_interval( ¶m->ss_initial_budget ) ) + return EINVAL; + + if ( !_POSIX_Priority_Is_valid( param->ss_low_priority ) ) + return EINVAL; + + break; + + default: + return EINVAL; + } + + /* + * Actually change the scheduling policy and parameters + */ + + the_thread = _POSIX_Threads_Get( thread, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: + return ESRCH; + case OBJECTS_LOCAL: + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + if ( api->schedpolicy == SCHED_SPORADIC ) + (void) _Watchdog_Remove( &api->Sporadic_timer ); + + api->schedpolicy = policy; + api->schedparam = *param; + the_thread->budget_algorithm = budget_algorithm; + the_thread->budget_callout = budget_callout; + + switch ( api->schedpolicy ) { + case SCHED_OTHER: + case SCHED_FIFO: + case SCHED_RR: + the_thread->cpu_time_budget = _Thread_Ticks_per_timeslice; + + the_thread->real_priority = + _POSIX_Priority_To_core( api->schedparam.sched_priority ); + + _Thread_Change_priority( + the_thread, + the_thread->real_priority, + TRUE + ); + break; + + case SCHED_SPORADIC: + api->ss_high_priority = api->schedparam.sched_priority; + _Watchdog_Remove( &api->Sporadic_timer ); + _POSIX_Threads_Sporadic_budget_TSR( 0, the_thread ); + break; + } + + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/pthreadsigmask.c b/cpukit/posix/src/pthreadsigmask.c new file mode 100644 index 0000000000..59bc688fcd --- /dev/null +++ b/cpukit/posix/src/pthreadsigmask.c @@ -0,0 +1,73 @@ +/* + * 3.3.5 Examine and Change Blocked Signals, P1003.1b-1993, p. 73 + * + * NOTE: P1003.1c/D10, p. 37 adds pthread_sigmask(). + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> + +int pthread_sigmask( + int how, + const sigset_t *set, + sigset_t *oset +) +{ + POSIX_API_Control *api; + + if ( !set && !oset ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + if ( oset ) + *oset = api->signals_blocked; + + if ( !set ) + return 0; + + switch ( how ) { + case SIG_BLOCK: + api->signals_blocked |= *set; + break; + case SIG_UNBLOCK: + api->signals_blocked &= ~*set; + break; + case SIG_SETMASK: + api->signals_blocked = *set; + break; + default: + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* XXX are there critical section problems here? */ + + /* XXX evaluate the new set */ + + if ( ~api->signals_blocked & + (api->signals_pending | _POSIX_signals_Pending) ) { + _Thread_Executing->do_post_task_switch_extension = TRUE; + _Thread_Dispatch(); + } + + return 0; +} diff --git a/cpukit/posix/src/ptimer.c b/cpukit/posix/src/ptimer.c new file mode 100644 index 0000000000..a2666c86f9 --- /dev/null +++ b/cpukit/posix/src/ptimer.c @@ -0,0 +1,101 @@ +/* + * ptimer.c,v 1.1 1996/06/03 16:29:58 joel Exp + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/posix/time.h> + +/************************************/ +/* These includes are now necessary */ +/************************************/ + +#include <sys/features.h> +#include <rtems/rtems/status.h> +#include <rtems/rtems/types.h> +#include <rtems/rtems/timer.h> +#include <rtems/rtems/clock.h> +#include <rtems/posix/psignal.h> +#include <rtems/score/wkspace.h> +#include <pthread.h> +#include <stdio.h> +#include <signal.h> + +/*****************************/ +/* End of necessary includes */ +/*****************************/ + +#include <rtems/posix/timer.h> + +/* *************************************************************************** + * TIMER_INITIALIZE_S + * + * Description: Initialize the data of a timer + * ***************************************************************************/ + +void TIMER_INITIALIZE_S ( int timer_pos ) +{ + + /* + * Indicates that the position in the table is free + */ + + timer_struct[timer_pos].state = STATE_FREE_C; + + /* + * The initial data of timing are set with null value + */ + + timer_struct[timer_pos].timer_data.it_value.tv_sec = 0; + timer_struct[timer_pos].timer_data.it_value.tv_nsec = 0; + timer_struct[timer_pos].timer_data.it_interval.tv_sec = 0; + timer_struct[timer_pos].timer_data.it_interval.tv_nsec = 0; + + /* + * The count of expirations is 0 + */ + + timer_struct[timer_pos].overrun = 0; + +} + +/* *************************************************************************** + * _POSIX_Timer_Manager_initialization + * + * Description: Initialize the internal structure in which the data of all + * the timers are stored + * ***************************************************************************/ + +int timer_max; +POSIX_Timer_Control *timer_struct; + + +void _POSIX_Timer_Manager_initialization ( int max_timers ) +{ + int index; + + timer_struct = _Workspace_Allocate_or_fatal_error( + max_timers * sizeof(POSIX_Timer_Control) ); + + /* + * Initialize all the timers + */ + + timer_max = max_timers; + + for (index=0; index<max_timers; index++) + TIMER_INITIALIZE_S( index ); + + timer_max = max_timers; +} diff --git a/cpukit/posix/src/ptimer1.c b/cpukit/posix/src/ptimer1.c new file mode 100644 index 0000000000..368dff43ff --- /dev/null +++ b/cpukit/posix/src/ptimer1.c @@ -0,0 +1,799 @@ +/* + * ptimer.c,v 1.1 1996/06/03 16:29:58 joel Exp + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/posix/time.h> + +/************************************/ +/* These includes are now necessary */ +/************************************/ + +#include <sys/features.h> +#include <rtems/rtems/status.h> +#include <rtems/rtems/types.h> +#include <rtems/rtems/timer.h> +#include <rtems/rtems/clock.h> +#include <rtems/posix/psignal.h> +#include <rtems/score/wkspace.h> +#include <pthread.h> +#include <stdio.h> +#include <signal.h> + +#include <rtems/seterr.h> +#include <rtems/posix/timer.h> + +/*****************************/ +/* End of necessary includes */ +/*****************************/ + +/* ************ + * Constants + * ************/ + +/* +#define DEBUG_MESSAGES + */ + +/* + * Data for the signals + */ + +/*********************************** + * Definition of Internal Functions + ***********************************/ + +/* *************************************************************************** + * TIMER_INITIALIZE_S + * + * Description: Initialize the data of a timer + * ***************************************************************************/ + +extern void TIMER_INITIALIZE_S ( int timer_pos ); + +/* *************************************************************************** + * _POSIX_Timer_Manager_initialization + * + * Description: Initialize the internal structure in which the data of all + * the timers are stored + * ***************************************************************************/ + +/* split to reduce minimum size */ + +/* *************************************************************************** + * FIRST_FREE_POSITION_F + * + * Description: Returns the first free position in the table of timers. + * If there is not a free position, it returns NO_MORE_TIMERS_C + * ***************************************************************************/ + +int FIRST_FREE_POSITION_F () +{ + int index; + + for (index=0; index<timer_max; index++) { + if ( timer_struct[index].state == STATE_FREE_C ) { + return index; + } + } + + /* The function reaches this point only if all the position are occupied */ + + return NO_MORE_TIMERS_C; +} + +/* *************************************************************************** + * TIMER_POSITION_F + * + * Description: Returns the position in the table of timers in which the + * data of the timer are stored. + * If the timer identifier does not exist, it returns + * BAD_TIMER_C + * ***************************************************************************/ + +int TIMER_POSITION_F ( timer_t timer_id ) +{ + int index; + + for (index=0; index<timer_max; index++ ) { + + /* Looks for the position of the timer. The timer must exist and the + * position can not be free */ + if ( ( timer_struct[index].timer_id == timer_id ) && + ( timer_struct[index].state != STATE_FREE_C ) ) { + return index; + } + } + + /* If the function reaches this point is because the timer identifier + * is not correct */ + + return BAD_TIMER_C; + +} + +/* *************************************************************************** + * COPY_ITIMERSPEC_S + * + * Description: Does a copy of a variable of type struct itimerspec + * ***************************************************************************/ + +void COPY_ITIMERSPEC_S ( const struct itimerspec *source, + struct itimerspec *target ) +{ + + target->it_value.tv_sec = source->it_value.tv_sec; + target->it_value.tv_nsec = source->it_value.tv_nsec; + target->it_interval.tv_sec = source->it_interval.tv_sec; + target->it_interval.tv_nsec = source->it_interval.tv_nsec; + +} + +/* *************************************************************************** + * ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S + * + * Description: This function converts the data of a structure itimerspec + * into structure rtems_time_of_day + * ***************************************************************************/ + +void ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S + ( const struct itimerspec *itimer, rtems_time_of_day *rtems_time ) +{ + unsigned long int seconds; + + /* The leap years and the months with 28, 29 or 31 days have not been + * considerated. It will be made in the future */ + + seconds = itimer->it_value.tv_sec; + + rtems_time->year = seconds / SECONDS_PER_YEAR_C; + seconds = seconds % SECONDS_PER_YEAR_C; + + rtems_time->month = seconds / SECONDS_PER_MONTH_C; + seconds = seconds % SECONDS_PER_MONTH_C; + + rtems_time->day = seconds / SECONDS_PER_DAY_C; + seconds = seconds % SECONDS_PER_DAY_C; + + rtems_time->hour = seconds / SECONDS_PER_HOUR_C; + seconds = seconds % SECONDS_PER_HOUR_C; + + rtems_time->minute = seconds / SECONDS_PER_MINUTE_C; + seconds = seconds % SECONDS_PER_MINUTE_C; + + rtems_time->second = seconds; + + rtems_time->ticks = itimer->it_value.tv_nsec/ + (NSEC_PER_SEC_C / SEC_TO_TICKS_C); + +} + + +/* *************************************************************************** + * FIRE_TIMER_S + * + * Description: This is the operation that is ran when a timer expires + * ***************************************************************************/ + + +rtems_timer_service_routine FIRE_TIMER_S (rtems_id timer, void *data) +{ + int timer_pos; /* Position in the table of the timer that + * has expirated */ + rtems_status_code return_v; /* Return value of rtems_timer_fire_after */ + int sig_number; /* Number of the signal to send */ + + + /* The position of the table of timers that contains the data of the + * expired timer will be stored in "timer_pos". In theory a timer can not + * expire if it has not been created or has been deleted */ + + timer_pos = TIMER_POSITION_F(timer); + + /* Increases the number of expiration of the timer in one unit. */ + timer_struct[timer_pos].overrun = timer_struct[timer_pos].overrun + 1; + + + if ( ( timer_struct[timer_pos].timer_data.it_interval.tv_sec != 0 ) || + ( timer_struct[timer_pos].timer_data.it_interval.tv_nsec != 0 ) ) { + + /* The timer must be reprogrammed */ + + return_v = rtems_timer_fire_after ( timer, + timer_struct[timer_pos].ticks, + FIRE_TIMER_S, + NULL ); + + /* Stores the time when the timer was started again */ + + timer_struct[timer_pos].time = _TOD_Current; + + /* The state has not to be actualized, because nothing modifies it */ + + timer_struct[timer_pos].state = STATE_CREATE_RUN_C; + + } else { + /* Indicates that the timer is stopped */ + + timer_struct[timer_pos].state = STATE_CREATE_STOP_C; + + } + + /* + * The sending of the signal to the process running the handling function + * specified for that signal is simulated + */ + + sig_number = timer_struct[timer_pos].inf.sigev_signo; + + if( pthread_kill ( timer_struct[timer_pos].thread_id , + timer_struct[timer_pos].inf.sigev_signo ) ) { + /* XXX error handling */ + } + + /* + * After the signal handler returns, the count of expirations of the + * timer must be set to 0. + */ + + timer_struct[timer_pos].overrun = 0; + +} + +/* ********************************************************************* + * 14.2.2 Create a Per-Process Timer, P1003.1b-1993, p. 264 + * ********************************************************************/ + +/* ************** + * timer_create + * **************/ + +int timer_create( + clockid_t clock_id, + struct sigevent *evp, + timer_t *timerid +) +{ + + rtems_status_code return_v; /* return value of the operation */ + rtems_id timer_id; /* created timer identifier */ + int timer_pos; /* Position in the table of timers */ + + if ( clock_id != CLOCK_REALTIME ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + /* + * The data of the structure evp are checked in order to verify if they + * are coherent. + */ + + if (evp != NULL) { + /* The structure has data */ + if ( ( evp->sigev_notify != SIGEV_NONE ) && + ( evp->sigev_notify != SIGEV_SIGNAL ) ) { + /* The value of the field sigev_notify is not valid */ + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + if ( !evp->sigev_signo ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( !is_valid_signo(evp->sigev_signo) ) + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* + * A timer is created using the primitive rtems_timer_create + */ + + return_v = rtems_timer_create ( clock_id, &timer_id ); + + switch (return_v) { + case RTEMS_SUCCESSFUL : + + /* + * The timer has been created properly + */ + + /* Obtains the first free position in the table of timers */ + + timer_pos = FIRST_FREE_POSITION_F(); + + if ( timer_pos == NO_MORE_TIMERS_C ) { + /* There is not position for another timers in spite of RTEMS + * supports it. It will necessaty to increase the structure used */ + + rtems_set_errno_and_return_minus_one( EAGAIN ); + } + + /* Exit parameter */ + + *timerid = timer_id; + + /* The data of the created timer are stored to use them later */ + + timer_struct[timer_pos].state = STATE_CREATE_NEW_C; + + /* NEW VERSION*/ + timer_struct[timer_pos].thread_id = pthread_self (); + + if ( evp != NULL ) { + timer_struct[timer_pos].inf.sigev_notify = evp->sigev_notify; + timer_struct[timer_pos].inf.sigev_signo = evp->sigev_signo; + timer_struct[timer_pos].inf.sigev_value = evp->sigev_value; + } + + timer_struct[timer_pos].timer_id = timer_id; + timer_struct[timer_pos].overrun = 0; + + timer_struct[timer_pos].timer_data.it_value.tv_sec = 0; + timer_struct[timer_pos].timer_data.it_value.tv_nsec = 0; + timer_struct[timer_pos].timer_data.it_interval.tv_sec = 0; + timer_struct[timer_pos].timer_data.it_interval.tv_nsec = 0; + + return 0; + + case RTEMS_INVALID_NAME : /* The assigned name is not valid */ + + rtems_set_errno_and_return_minus_one( EINVAL ); + + case RTEMS_TOO_MANY : + + /* There has been created too much timers for the same process */ + rtems_set_errno_and_return_minus_one( EAGAIN ); + + default : + + /* + * Does nothing. It only returns the error without assigning a value + * to errno. In theory, it can not happen because the call to + * rtems_timer_create can not return other different value. + */ + + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* + * The next sentence is used to avoid singular situations + */ + + rtems_set_errno_and_return_minus_one( EINVAL ); +} + +/* + * 14.2.3 Delete a Per_process Timer, P1003.1b-1993, p. 266 + */ + +int timer_delete( + timer_t timerid +) +{ + + /* + * IDEA: This function must probably stop the timer first and then delete it + * + * It will have to do a call to rtems_timer_cancel and then another + * call to rtems_timer_delete. + * The call to rtems_timer_delete will be probably unnecessary, + * because rtems_timer_delete stops the timer before deleting it. + */ + + int timer_pos; + rtems_status_code status; + + + /* First the position in the table of timers is obtained */ + + timer_pos = TIMER_POSITION_F ( timerid ); + + if ( timer_pos == BAD_TIMER_C ) { + /* The timer identifier is erroneus */ + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* The timer is deleted */ + + status = rtems_timer_delete ( timerid ); + + if ( status == RTEMS_INVALID_ID ) { + /* The timer identifier is erroneus */ + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* Initializes the data of the timer */ + + TIMER_INITIALIZE_S ( timer_pos ); + return 0; +} + +/* + * 14.2.4 Per-Process Timers, P1003.1b-1993, p. 267 + */ + +/* ************** + * timer_settime + * **************/ + + +int timer_settime( + timer_t timerid, + int flags, + const struct itimerspec *value, + struct itimerspec *ovalue +) +{ + + rtems_status_code return_v; /* Return of the calls to RTEMS */ + int timer_pos; /* Position of the timer in the table */ + rtems_time_of_day rtems_time; /* Time in RTEMS */ + + + /* First the position in the table of timers is obtained */ + + timer_pos = TIMER_POSITION_F ( timerid ); + + if ( timer_pos == BAD_TIMER_C ) { + /* The timer identifier is erroneus */ + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + if ( value == NULL ) { + /* The stucture of times of the timer is free, and then returns an + error but the variable errno is not actualized */ + + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* If the function reaches this point, then it will be necessary to do + * something with the structure of times of the timer: to stop, start + * or start it again */ + + /* First, it verifies if the timer must be stopped */ + + if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) { + /* The timer is stopped */ + + return_v = rtems_timer_cancel ( timerid ); + + /* The old data of the timer are returned */ + + if ( ovalue ) + *ovalue = timer_struct[timer_pos].timer_data; + + /* The new data are set */ + + timer_struct[timer_pos].timer_data = *value; + + /* Indicates that the timer is created and stopped */ + + timer_struct[timer_pos].state = STATE_CREATE_STOP_C; + + /* Returns with success */ + + return 0; + } + + /* + * If the function reaches this point, then the timer will have to be + * initialized with new values: to start it or start it again + */ + + /* First, it verifies if the structure "value" is correct */ + + if ( ( value->it_value.tv_nsec > MAX_NSEC_C ) || + ( value->it_value.tv_nsec < MIN_NSEC_C ) ) { + /* The number of nanoseconds is not correct */ + + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* Then, "value" must be converted from seconds and nanoseconds to clock + * ticks, to use it in the calls to RTEMS */ + + /* It is also necessary to take in account if the time is absolute + * or relative */ + + switch (flags) { + case TIMER_ABSTIME: + + /* The fire time is absolute: + * It has to use "rtems_time_fire_when" */ + + /* First, it converts from struct itimerspec to rtems_time_of_day */ + + ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S ( value, &rtems_time ); + + return_v = rtems_timer_fire_when ( timerid, &rtems_time, FIRE_TIMER_S, NULL); + + switch ( return_v ) { + case RTEMS_SUCCESSFUL: + + /* The timer has been started and is running */ + + /* Actualizes the data of the structure and + * returns the old ones in "ovalue" */ + + if ( ovalue ) + *ovalue = timer_struct[timer_pos].timer_data; + + timer_struct[timer_pos].timer_data = *value; + + /* It indicates that the time is running */ + + timer_struct[timer_pos].state = STATE_CREATE_RUN_C; + + /* Stores the time in which the timer was started again */ + + timer_struct[timer_pos].time = _TOD_Current; + return 0; + + break; + + case RTEMS_INVALID_ID: + + /* XXX error handling */ + break; + + case RTEMS_NOT_DEFINED: + + /* XXX error handling */ + break; + + case RTEMS_INVALID_CLOCK: + + /* XXX error handling */ + break; + + default: break; + + + } + + break; + + case TIMER_RELATIVE_C: + + /* The fire time is relative: + * It has to use "rtems_time_fire_after" */ + + /* First, it converts from seconds and nanoseconds to ticks */ + + /* The form in which this operation is done can produce a lost + * of precision of 1 second */ + +/* This is the process to convert from nanoseconds to ticks + * + * There is a tick every 10 miliseconds, then the nanoseconds are + * divided between 10**7. The result of this operation will be the + * number of ticks + */ + + timer_struct[timer_pos].ticks = + ( SEC_TO_TICKS_C * value->it_value.tv_sec ) + + ( value->it_value.tv_nsec / (NSEC_PER_SEC_C / SEC_TO_TICKS_C)); + + return_v = rtems_timer_fire_after ( timerid, + timer_struct[timer_pos].ticks, + FIRE_TIMER_S, + NULL ); + + switch (return_v) { + case RTEMS_SUCCESSFUL: + + /* The timer has been started and is running */ + + /* Actualizes the data of the structure and + * returns the old ones in "ovalue" */ + + if ( ovalue ) + *ovalue = timer_struct[timer_pos].timer_data; + + timer_struct[timer_pos].timer_data = *value; + + /* It indicates that the time is running */ + + timer_struct[timer_pos].state = STATE_CREATE_RUN_C; + + /* Stores the time in which the timer was started again */ + + timer_struct[timer_pos].time = _TOD_Current; + + return 0; + + break; + + case RTEMS_INVALID_ID: + + /* The timer identifier is not correct. In theory, this + * situation can not occur, but the solution is easy */ + + rtems_set_errno_and_return_minus_one( EINVAL ); + + break; + + case RTEMS_INVALID_NUMBER: + + /* In this case, RTEMS fails because the values of timing + * are incorrect */ + + /* + * I do not know if errno must be actualized + * + * errno = EINVAL; + */ + + rtems_set_errno_and_return_minus_one( EINVAL ); + break; + + default: break; + } + + break; + + default: break; + + /* It does nothing, although it will be probably necessary to + * return an error */ + } + + /* To avoid problems */ + return 0; +} + + +/* + * 14.2.4 Per-Process Timers, P1003.1b-1993, p. 267 + */ + +/* ************** + * timer_gettime + * **************/ + +int timer_gettime( + timer_t timerid, + struct itimerspec *value +) +{ + + /* + * IDEA: This function does not use functions of RTEMS to the handle + * of timers. It uses some functions for managing the time. + * + * A possible form to do this is the following: + * + * - When a timer is initialized, the value of the time in + * that moment is stored. + * - When this function is called, it returns the difference + * between the current time and the initialization time. + */ + + rtems_time_of_day current_time; + int timer_pos; + uint32_t hours; + uint32_t minutes; + uint32_t seconds; + uint32_t ticks; + uint32_t nanosec; + + + /* Reads the current time */ + + current_time = _TOD_Current; + + timer_pos = TIMER_POSITION_F ( timerid ); + + if ( timer_pos == BAD_TIMER_C ) { + /* The timer identifier is erroneus */ + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* Calculates the difference between the start time of the timer and + * the current one */ + + hours = current_time.hour - timer_struct[timer_pos].time.hour; + + if ( current_time.minute < timer_struct[timer_pos].time.minute ) { + minutes = 60 - timer_struct[timer_pos].time.minute + current_time.minute; + hours--; + } else { + minutes = current_time.minute - timer_struct[timer_pos].time.minute; + } + + if ( current_time.second < timer_struct[timer_pos].time.second ) { + seconds = 60 - timer_struct[timer_pos].time.second + current_time.second; + minutes--; + } else { + seconds = current_time.second - timer_struct[timer_pos].time.second; + } + + if ( current_time.ticks < timer_struct[timer_pos].time.ticks ) { + ticks = 100 - timer_struct[timer_pos].time.ticks + current_time.ticks; + seconds--; + } else { + ticks = current_time.ticks - timer_struct[timer_pos].time.ticks; + } + + /* The time that the timer is running is calculated */ + seconds = hours * 60 * 60 + + minutes * 60 + + seconds; + + nanosec = ticks * 10 * /* msec */ + 1000 * /* microsec */ + 1000; /* nanosec */ + + + /* Calculates the time left before the timer finishes */ + + value->it_value.tv_sec = + timer_struct[timer_pos].timer_data.it_value.tv_sec - seconds; + + value->it_value.tv_nsec = + timer_struct[timer_pos].timer_data.it_value.tv_nsec - nanosec; + + + value->it_interval.tv_sec = + timer_struct[timer_pos].timer_data.it_interval.tv_sec; + value->it_interval.tv_nsec = + timer_struct[timer_pos].timer_data.it_interval.tv_nsec; + + + return 0; + +} + +/* + * 14.2.4 Per-Process Timers, P1003.1b-1993, p. 267 + */ + +/* ***************** + * timer_getoverrun + * *****************/ + +int timer_getoverrun( + timer_t timerid +) +{ + + /* + * IDEA: This function must count the times the timer expires. + * + * The expiration of a timer must increase by one a counter. + * After the signal handler associated to the timer finishs + * its execution, FIRE_TIMER_S will have to set this counter to 0. + */ + + int timer_pos; /* Position of the timer in the structure */ + int overrun; /* Overflow count */ + + + timer_pos = TIMER_POSITION_F ( timerid ); + + if ( timer_pos == BAD_TIMER_C ) { + /* The timer identifier is erroneus */ + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* The overflow count of the timer is stored in "overrun" */ + + overrun = timer_struct[timer_pos].overrun; + + /* It is set to 0 */ + + timer_struct[timer_pos].overrun = 0; + + return overrun; + +} diff --git a/cpukit/posix/src/sched.c b/cpukit/posix/src/sched.c new file mode 100644 index 0000000000..13b8db2a71 --- /dev/null +++ b/cpukit/posix/src/sched.c @@ -0,0 +1,157 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <sched.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/tod.h> +#include <rtems/score/thread.h> +#include <rtems/seterr.h> +#include <rtems/posix/priority.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 13.3.1 Set Scheduling Parameters, P1003.1b-1993, p. 252 + * + */ + +int sched_setparam( + pid_t pid, + const struct sched_param *param +) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +/*PAGE + * + * 13.3.2 Set Scheduling Parameters, P1003.1b-1993, p. 253 + */ + +int sched_getparam( + pid_t pid, + const struct sched_param *param +) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +/*PAGE + * + * 13.3.3 Set Scheduling Policy and Scheduling Parameters, + * P1003.1b-1993, p. 254 + */ + +int sched_setscheduler( + pid_t pid, + int policy, + const struct sched_param *param +) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +/*PAGE + * + * 13.3.4 Get Scheduling Policy, P1003.1b-1993, p. 256 + */ + +int sched_getscheduler( + pid_t pid +) +{ + rtems_set_errno_and_return_minus_one( ENOSYS ); +} + +/*PAGE + * + * 13.3.6 Get Scheduling Parameter Limits, P1003.1b-1993, p. 258 + */ + +int sched_get_priority_max( + int policy +) +{ + switch ( policy ) { + case SCHED_OTHER: + case SCHED_FIFO: + case SCHED_RR: + case SCHED_SPORADIC: + break; + + default: + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + return POSIX_SCHEDULER_MAXIMUM_PRIORITY; +} + +/*PAGE + * + * 13.3.6 Get Scheduling Parameter Limits, P1003.1b-1993, p. 258 + */ + +int sched_get_priority_min( + int policy +) +{ + switch ( policy ) { + case SCHED_OTHER: + case SCHED_FIFO: + case SCHED_RR: + case SCHED_SPORADIC: + break; + + default: + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + return POSIX_SCHEDULER_MINIMUM_PRIORITY; +} + +/*PAGE + * + * 13.3.6 Get Scheduling Parameter Limits, P1003.1b-1993, p. 258 + */ + +int sched_rr_get_interval( + pid_t pid, + struct timespec *interval +) +{ + /* XXX do we need to support different time quantums per thread */ + + /* + * Only supported for the "calling process" (i.e. this node). + */ + + if ( pid && pid != getpid() ) + rtems_set_errno_and_return_minus_one( ESRCH ); + + if ( !interval ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + _POSIX_Interval_to_timespec( _Thread_Ticks_per_timeslice, interval ); + return 0; +} + +/*PAGE + * + * 13.3.5 Yield Processor, P1003.1b-1993, p. 257 + */ + +int sched_yield( void ) +{ + _Thread_Disable_dispatch(); + _Thread_Yield_processor(); + _Thread_Enable_dispatch(); + return 0; +} diff --git a/cpukit/posix/src/semaphore.c b/cpukit/posix/src/semaphore.c new file mode 100644 index 0000000000..3ec96d8366 --- /dev/null +++ b/cpukit/posix/src/semaphore.c @@ -0,0 +1,54 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * _POSIX_Semaphore_Manager_initialization + * + * This routine initializes all semaphore manager related data structures. + * + * Input parameters: + * maximum_semaphores - maximum configured semaphores + * + * Output parameters: NONE + */ + +void _POSIX_Semaphore_Manager_initialization( + uint32_t maximum_semaphores +) +{ + _Objects_Initialize_information( + &_POSIX_Semaphore_Information, /* object information table */ + OBJECTS_POSIX_API, /* object API */ + OBJECTS_POSIX_SEMAPHORES, /* object class */ + maximum_semaphores /* maximum objects of this class */, + sizeof( POSIX_Semaphore_Control ), + /* size of this object's control block */ + TRUE, /* TRUE if names for this object are strings */ + _POSIX_PATH_MAX /* maximum length of each object's name */ +#if defined(RTEMS_MULTIPROCESSING) + , + FALSE, /* TRUE if this is a global object class */ + NULL /* Proxy extraction support callout */ +#endif + ); +} diff --git a/cpukit/posix/src/semaphorecreatesupp.c b/cpukit/posix/src/semaphorecreatesupp.c new file mode 100644 index 0000000000..64d8f435b0 --- /dev/null +++ b/cpukit/posix/src/semaphorecreatesupp.c @@ -0,0 +1,129 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> +#include <string.h> /* strlen */ + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * _POSIX_Semaphore_Create_support + * + * This routine does the actual creation and initialization of + * a poxix semaphore. It is a support routine for sem_init and + * sem_open. + */ + +int _POSIX_Semaphore_Create_support( + const char *name, + int pshared, + unsigned int value, + POSIX_Semaphore_Control **the_sem +) +{ + POSIX_Semaphore_Control *the_semaphore; + CORE_semaphore_Attributes *the_sem_attr; + + _Thread_Disable_dispatch(); + + /* Sharing semaphores among processes is not currently supported */ + if (pshared != 0) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENOSYS ); + } + + if ( name ) { + if( strlen(name) > PATH_MAX ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENAMETOOLONG ); + } + } + + the_semaphore = _POSIX_Semaphore_Allocate(); + + if ( !the_semaphore ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENOSPC ); + } + +#if defined(RTEMS_MULTIPROCESSING) + if ( pshared == PTHREAD_PROCESS_SHARED && + !( _Objects_MP_Allocate_and_open( &_POSIX_Semaphore_Information, 0, + the_semaphore->Object.id, FALSE ) ) ) { + _POSIX_Semaphore_Free( the_semaphore ); + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( EAGAIN ); + } +#endif + + the_semaphore->process_shared = pshared; + + if ( name ) { + the_semaphore->named = TRUE; + the_semaphore->open_count = 1; + the_semaphore->linked = TRUE; + } + else + the_semaphore->named = FALSE; + + the_sem_attr = &the_semaphore->Semaphore.Attributes; + + /* + * POSIX does not appear to specify what the discipline for + * blocking tasks on this semaphore should be. It could somehow + * be derived from the current scheduling policy. One + * thing is certain, no matter what we decide, it won't be + * the same as all other POSIX implementations. :) + */ + + the_sem_attr->discipline = CORE_SEMAPHORE_DISCIPLINES_FIFO; + + /* + * This effectively disables limit checking. + */ + + the_sem_attr->maximum_count = 0xFFFFFFFF; + + _CORE_semaphore_Initialize( &the_semaphore->Semaphore, the_sem_attr, value ); + + /* + * Make the semaphore available for use. + */ + + _Objects_Open( + &_POSIX_Semaphore_Information, + &the_semaphore->Object, + (char *) name + ); + + *the_sem = the_semaphore; + +#if defined(RTEMS_MULTIPROCESSING) + if ( pshared == PTHREAD_PROCESS_SHARED ) + _POSIX_Semaphore_MP_Send_process_packet( + POSIX_SEMAPHORE_MP_ANNOUNCE_CREATE, + the_semaphore->Object.id, + (char *) name, + 0 /* proxy id - Not used */ + ); +#endif + + _Thread_Enable_dispatch(); + return 0; +} diff --git a/cpukit/posix/src/semaphoredeletesupp.c b/cpukit/posix/src/semaphoredeletesupp.c new file mode 100644 index 0000000000..44b00fcd67 --- /dev/null +++ b/cpukit/posix/src/semaphoredeletesupp.c @@ -0,0 +1,65 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * _POSIX_Semaphore_Delete + */ + +void _POSIX_Semaphore_Delete( + POSIX_Semaphore_Control *the_semaphore +) +{ + if ( !the_semaphore->linked && !the_semaphore->open_count ) { + _Objects_Close( &_POSIX_Semaphore_Information, &the_semaphore->Object ); + + _CORE_semaphore_Flush( + &the_semaphore->Semaphore, +#if defined(RTEMS_MULTIPROCESSING) + _POSIX_Semaphore_MP_Send_object_was_deleted, +#else + NULL, +#endif + -1 /* XXX should also seterrno -> EINVAL */ + ); + + _POSIX_Semaphore_Free( the_semaphore ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( the_semaphore->process_shared == PTHREAD_PROCESS_SHARED ) { + + _Objects_MP_Close( + &_POSIX_Semaphore_Information, + the_semaphore->Object.id + ); + + _POSIX_Semaphore_MP_Send_process_packet( + POSIX_SEMAPHORE_MP_ANNOUNCE_DELETE, + the_semaphore->Object.id, + 0, /* Not used */ + 0 /* Not used */ + ); + } +#endif + + } +} diff --git a/cpukit/posix/src/semaphoremp.c b/cpukit/posix/src/semaphoremp.c new file mode 100644 index 0000000000..d5a4cf9f1e --- /dev/null +++ b/cpukit/posix/src/semaphoremp.c @@ -0,0 +1,146 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +#if defined(RTEMS_MULTIPROCESSING) +/* + * _POSIX_Semaphore_MP_Send_process_packet + * + * DESCRIPTION: + * + * This routine performs a remote procedure call so that a + * process operation can be performed on another node. + */ + +void _POSIX_Semaphore_MP_Send_process_packet( + POSIX_Semaphore_MP_Remote_operations operation, + Objects_Id semaphore_id, + Objects_Name name, + Objects_Id proxy_id +) +{ + POSIX_MP_NOT_IMPLEMENTED(); +} + +/* + * _POSIX_Semaphore_MP_Send_request_packet + * + * DESCRIPTION: + * + * This routine performs a remote procedure call so that a + * directive operation can be initiated on another node. + */ + +int _POSIX_Semaphore_MP_Send_request_packet( + POSIX_Semaphore_MP_Remote_operations operation, + Objects_Id semaphore_id, + boolean wait, /* XXX options */ + Watchdog_Interval timeout +) +{ + POSIX_MP_NOT_IMPLEMENTED(); + return 0; +} + +/* + * _POSIX_Semaphore_MP_Send_response_packet + * + * DESCRIPTION: + * + * This routine performs a remote procedure call so that a + * directive can be performed on another node. + */ + +void _POSIX_Semaphore_MP_Send_response_packet( + POSIX_Semaphore_MP_Remote_operations operation, + Objects_Id semaphore_id, + Thread_Control *the_thread +) +{ + POSIX_MP_NOT_IMPLEMENTED(); +} + +/* + * + * _POSIX_Semaphore_MP_Process_packet + * + * DESCRIPTION: + * + * This routine performs the actions specific to this package for + * the request from another node. + */ + +void _POSIX_Semaphore_MP_Process_packet( + MP_packet_Prefix *the_packet_prefix +) +{ + POSIX_MP_NOT_IMPLEMENTED(); +} + +/* + * _POSIX_Semaphore_MP_Send_object_was_deleted + * + * DESCRIPTION: + * + * This routine is invoked indirectly by the thread queue + * when a proxy has been removed from the thread queue and + * the remote node must be informed of this. + */ + +void _POSIX_Semaphore_MP_Send_object_was_deleted( + Thread_Control *the_proxy +) +{ + POSIX_MP_NOT_IMPLEMENTED(); +} + +/* + * _POSIX_Semaphore_MP_Send_extract_proxy + * + * DESCRIPTION: + * + * This routine is invoked when a task is deleted and it + * has a proxy which must be removed from a thread queue and + * the remote node must be informed of this. + */ + +void _POSIX_Semaphore_MP_Send_extract_proxy( + Thread_Control *the_thread +) +{ + POSIX_MP_NOT_IMPLEMENTED(); +} + +/* + * _POSIX_Semaphore_MP_Get_packet + * + * DESCRIPTION: + * + * This function is used to obtain a semaphore mp packet. + */ + +POSIX_Semaphore_MP_Packet *_POSIX_Semaphore_MP_Get_packet( void ) +{ + POSIX_MP_NOT_IMPLEMENTED(); + return NULL; +} + +#endif /* endif RTEMS_MULTIPROCESSING */ diff --git a/cpukit/posix/src/semaphorenametoid.c b/cpukit/posix/src/semaphorenametoid.c new file mode 100644 index 0000000000..eb1a4686cf --- /dev/null +++ b/cpukit/posix/src/semaphorenametoid.c @@ -0,0 +1,51 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * _POSIX_Semaphore_Name_to_id + * + * Look up the specified name and attempt to locate the id + * for the associated semaphore. + */ + +int _POSIX_Semaphore_Name_to_id( + const char *name, + sem_t *id +) +{ + Objects_Name_or_id_lookup_errors status; + + if ( !name ) + return EINVAL; + + if ( !name[0] ) + return EINVAL; + + status = _Objects_Name_to_id( + &_POSIX_Semaphore_Information, (char *)name, 0, (Objects_Id*)id ); + + if ( status == OBJECTS_NAME_OR_ID_LOOKUP_SUCCESSFUL ) + return 0; + + return ENOENT; +} diff --git a/cpukit/posix/src/semaphorewaitsupp.c b/cpukit/posix/src/semaphorewaitsupp.c new file mode 100644 index 0000000000..7c76ff87bd --- /dev/null +++ b/cpukit/posix/src/semaphorewaitsupp.c @@ -0,0 +1,71 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * _POSIX_Semaphore_Wait_support + */ + +int _POSIX_Semaphore_Wait_support( + sem_t *sem, + boolean blocking, + Watchdog_Interval timeout +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + _CORE_semaphore_Seize( + &the_semaphore->Semaphore, + the_semaphore->Object.id, + blocking, + timeout + ); + _Thread_Enable_dispatch(); + switch ( _Thread_Executing->Wait.return_code ) { + case CORE_SEMAPHORE_STATUS_SUCCESSFUL: + break; + case CORE_SEMAPHORE_STATUS_UNSATISFIED_NOWAIT: + rtems_set_errno_and_return_minus_one( EAGAIN ); + case CORE_SEMAPHORE_WAS_DELETED: + rtems_set_errno_and_return_minus_one( EAGAIN ); + case CORE_SEMAPHORE_TIMEOUT: + rtems_set_errno_and_return_minus_one( ETIMEDOUT ); + break; + case CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED: + /* + * This error can not occur since we set the maximum + * count to the largest value the count can hold. + */ + break; + } + } + return 0; +} diff --git a/cpukit/posix/src/semclose.c b/cpukit/posix/src/semclose.c new file mode 100644 index 0000000000..83b72f36e0 --- /dev/null +++ b/cpukit/posix/src/semclose.c @@ -0,0 +1,55 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + + +/*PAGE + * + * sem_close + * + * Routine to close a semaphore that has been opened or initialized. + * + * 11.2.4 Close a Named Semaphore, P1003.1b-1993, p.224 + */ + +int sem_close( + sem_t *sem +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + the_semaphore->open_count -= 1; + _POSIX_Semaphore_Delete( the_semaphore ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/semdestroy.c b/cpukit/posix/src/semdestroy.c new file mode 100644 index 0000000000..2daccce17c --- /dev/null +++ b/cpukit/posix/src/semdestroy.c @@ -0,0 +1,58 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * 11.2.2 Destroy an Unnamed Semaphore, P1003.1b-1993, p.220 + */ + +int sem_destroy( + sem_t *sem +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + /* + * Undefined operation on a named semaphore. + */ + + if ( the_semaphore->named == TRUE ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + _POSIX_Semaphore_Delete( the_semaphore ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/semgetvalue.c b/cpukit/posix/src/semgetvalue.c new file mode 100644 index 0000000000..e2bf9f83b2 --- /dev/null +++ b/cpukit/posix/src/semgetvalue.c @@ -0,0 +1,50 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * 11.2.8 Get the Value of a Semaphore, P1003.1b-1993, p.229 + */ + +int sem_getvalue( + sem_t *sem, + int *sval +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + *sval = _CORE_semaphore_Get_count( &the_semaphore->Semaphore ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/seminit.c b/cpukit/posix/src/seminit.c new file mode 100644 index 0000000000..449f2c1c01 --- /dev/null +++ b/cpukit/posix/src/seminit.c @@ -0,0 +1,51 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * 11.2.1 Initialize an Unnamed Semaphore, P1003.1b-1993, p.219 + */ + +int sem_init( + sem_t *sem, + int pshared, + unsigned int value +) +{ + int status; + POSIX_Semaphore_Control *the_semaphore; + + if ( !sem ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + status = _POSIX_Semaphore_Create_support( + NULL, + pshared, + value, + &the_semaphore + ); + + if ( status != -1 ) + *sem = the_semaphore->Object.id; + + return status; +} diff --git a/cpukit/posix/src/semopen.c b/cpukit/posix/src/semopen.c new file mode 100644 index 0000000000..522177d3b0 --- /dev/null +++ b/cpukit/posix/src/semopen.c @@ -0,0 +1,122 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * sem_open + * + * Opens a named semaphore. Used in conjunction with the sem_close + * and sem_unlink commands. + * + * 11.2.3 Initialize/Open a Named Semaphore, P1003.1b-1993, p.221 + * + * NOTE: When oflag is O_CREAT, then optional third and fourth + * parameters must be present. + */ + +sem_t *sem_open( + const char *name, + int oflag, + ... + /* mode_t mode, */ + /* unsigned int value */ +) +{ + va_list arg; + mode_t mode; + unsigned int value = 0; + int status; + sem_t the_semaphore_id; + POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + _Thread_Disable_dispatch(); + + if ( oflag & O_CREAT ) { + va_start(arg, oflag); + mode = (mode_t) va_arg( arg, unsigned int ); + value = va_arg( arg, unsigned int ); + va_end(arg); + } + + status = _POSIX_Semaphore_Name_to_id( name, &the_semaphore_id ); + + /* + * If the name to id translation worked, then the semaphore exists + * and we can just return a pointer to the id. Otherwise we may + * need to check to see if this is a "semaphore does not exist" + * or some other miscellaneous error on the name. + */ + + if ( status ) { + + /* + * Unless provided a valid name that did not already exist + * and we are willing to create then it is an error. + */ + + if ( !( status == ENOENT && (oflag & O_CREAT) ) ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one_cast( status, sem_t * ); + } + } else { + + /* + * Check for existence with creation. + */ + + if ( (oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL) ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one_cast( EEXIST, sem_t * ); + } + + the_semaphore = _POSIX_Semaphore_Get( &the_semaphore_id, &location ); + the_semaphore->open_count += 1; + _Thread_Enable_dispatch(); + _Thread_Enable_dispatch(); + return (sem_t *)&the_semaphore->Object.id; + + } + + /* + * At this point, the semaphore does not exist and everything has been + * checked. We should go ahead and create a semaphore. + */ + + status =_POSIX_Semaphore_Create_support( + name, + FALSE, /* not shared across processes */ + value, + &the_semaphore + ); + + /* + * errno was set by Create_support, so don't set it again. + */ + + _Thread_Enable_dispatch(); + + if ( status == -1 ) + return SEM_FAILED; + + return (sem_t *) &the_semaphore->Object.id; +} diff --git a/cpukit/posix/src/sempost.c b/cpukit/posix/src/sempost.c new file mode 100644 index 0000000000..a4d7a36876 --- /dev/null +++ b/cpukit/posix/src/sempost.c @@ -0,0 +1,57 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * 11.2.7 Unlock a Semaphore, P1003.1b-1993, p.227 + */ + +int sem_post( + sem_t *sem +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + rtems_set_errno_and_return_minus_one( EINVAL ); + case OBJECTS_LOCAL: + _CORE_semaphore_Surrender( + &the_semaphore->Semaphore, + the_semaphore->Object.id, +#if defined(RTEMS_MULTIPROCESSING) + NULL /* XXX need to define a routine to handle this case */ +#else + NULL +#endif + ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} diff --git a/cpukit/posix/src/semtimedwait.c b/cpukit/posix/src/semtimedwait.c new file mode 100644 index 0000000000..f5904c59fd --- /dev/null +++ b/cpukit/posix/src/semtimedwait.c @@ -0,0 +1,40 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * 11.2.6 Lock a Semaphore, P1003.1b-1993, p.226 + * + * NOTE: P1003.4b/D8 adds sem_timedwait(), p. 27 + */ + +int sem_timedwait( + sem_t *sem, + const struct timespec *timeout +) +{ + return _POSIX_Semaphore_Wait_support( + sem, + TRUE, + _POSIX_Timespec_to_interval( timeout ) + ); +} diff --git a/cpukit/posix/src/semtrywait.c b/cpukit/posix/src/semtrywait.c new file mode 100644 index 0000000000..2aecde9425 --- /dev/null +++ b/cpukit/posix/src/semtrywait.c @@ -0,0 +1,35 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * 11.2.6 Lock a Semaphore, P1003.1b-1993, p.226 + * + * NOTE: P1003.4b/D8 adds sem_timedwait(), p. 27 + */ + +int sem_trywait( + sem_t *sem +) +{ + return _POSIX_Semaphore_Wait_support( sem, FALSE, THREAD_QUEUE_WAIT_FOREVER ); +} diff --git a/cpukit/posix/src/semunlink.c b/cpukit/posix/src/semunlink.c new file mode 100644 index 0000000000..b694ea19f9 --- /dev/null +++ b/cpukit/posix/src/semunlink.c @@ -0,0 +1,75 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * sem_unlink + * + * Unlinks a named semaphore, sem_close must also be called to remove + * the semaphore. + * + * 11.2.5 Remove a Named Semaphore, P1003.1b-1993, p.225 + */ + +int sem_unlink( + const char *name +) +{ + int status; + register POSIX_Semaphore_Control *the_semaphore; + sem_t the_semaphore_id; + + _Thread_Disable_dispatch(); + + status = _POSIX_Semaphore_Name_to_id( name, &the_semaphore_id ); + if ( status != 0 ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( status ); + } + + /* + * Don't support unlinking a remote semaphore. + */ + + if ( !_Objects_Is_local_id((Objects_Id)the_semaphore_id) ) { + _Thread_Enable_dispatch(); + rtems_set_errno_and_return_minus_one( ENOSYS ); + } + + the_semaphore = (POSIX_Semaphore_Control *) _Objects_Get_local_object( + &_POSIX_Semaphore_Information, + _Objects_Get_index( the_semaphore_id ) + ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( the_semaphore->process_shared == PTHREAD_PROCESS_SHARED ) { + _Objects_MP_Close( &_POSIX_Semaphore_Information, the_semaphore_id ); + } +#endif + + the_semaphore->linked = FALSE; + _POSIX_Semaphore_Namespace_remove( the_semaphore ); + _POSIX_Semaphore_Delete( the_semaphore ); + + _Thread_Enable_dispatch(); + return 0; +} diff --git a/cpukit/posix/src/semwait.c b/cpukit/posix/src/semwait.c new file mode 100644 index 0000000000..9ef787c727 --- /dev/null +++ b/cpukit/posix/src/semwait.c @@ -0,0 +1,35 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +/*PAGE + * + * 11.2.6 Lock a Semaphore, P1003.1b-1993, p.226 + * + * NOTE: P1003.4b/D8 adds sem_timedwait(), p. 27 + */ + +int sem_wait( + sem_t *sem +) +{ + return _POSIX_Semaphore_Wait_support( sem, TRUE, THREAD_QUEUE_WAIT_FOREVER ); +} diff --git a/cpukit/posix/src/setcancelstate.c b/cpukit/posix/src/setcancelstate.c new file mode 100644 index 0000000000..94050bfc91 --- /dev/null +++ b/cpukit/posix/src/setcancelstate.c @@ -0,0 +1,61 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/cancel.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/threadsup.h> + +/*PAGE + * + * 18.2.2 Setting Cancelability State, P1003.1c/Draft 10, p. 183 + */ + +int pthread_setcancelstate( + int state, + int *oldstate +) +{ + POSIX_API_Control *thread_support; + + /* + * Don't even think about deleting a resource from an ISR. + * Besides this request is supposed to be for _Thread_Executing + * and the ISR context is not a thread. + */ + + if ( _ISR_Is_in_progress() ) + return EPROTO; + + if ( !oldstate ) + return EINVAL; + + if ( state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE ) + return EINVAL; + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + _Thread_Disable_dispatch(); + *oldstate = thread_support->cancelability_state; + thread_support->cancelability_state = state; + + if ( thread_support->cancelability_state == PTHREAD_CANCEL_ENABLE && + thread_support->cancelability_type == PTHREAD_CANCEL_ASYNCHRONOUS && + thread_support->cancelation_requested ) + _POSIX_Threads_cancel_run( _Thread_Executing ); + _Thread_Enable_dispatch(); + + return 0; +} diff --git a/cpukit/posix/src/setcanceltype.c b/cpukit/posix/src/setcanceltype.c new file mode 100644 index 0000000000..a7b7655f1d --- /dev/null +++ b/cpukit/posix/src/setcanceltype.c @@ -0,0 +1,61 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/cancel.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/threadsup.h> + +/*PAGE + * + * 18.2.2 Setting Cancelability State, P1003.1c/Draft 10, p. 183 + */ + +int pthread_setcanceltype( + int type, + int *oldtype +) +{ + POSIX_API_Control *thread_support; + + /* + * Don't even think about deleting a resource from an ISR. + * Besides this request is supposed to be for _Thread_Executing + * and the ISR context is not a thread. + */ + + if ( _ISR_Is_in_progress() ) + return EPROTO; + + if ( !oldtype ) + return EINVAL; + + if ( type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS ) + return EINVAL; + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + _Thread_Disable_dispatch(); + *oldtype = thread_support->cancelability_type; + thread_support->cancelability_type = type; + + if ( thread_support->cancelability_state == PTHREAD_CANCEL_ENABLE && + thread_support->cancelability_type == PTHREAD_CANCEL_ASYNCHRONOUS && + thread_support->cancelation_requested ) + _POSIX_Threads_cancel_run( _Thread_Executing ); + _Thread_Enable_dispatch(); + + return 0; +} diff --git a/cpukit/posix/src/sigaction.c b/cpukit/posix/src/sigaction.c new file mode 100644 index 0000000000..a8d48f9f3b --- /dev/null +++ b/cpukit/posix/src/sigaction.c @@ -0,0 +1,93 @@ +/* + * 3.3.4 Examine and Change Signal Action, P1003.1b-1993, p. 70 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> +#include <rtems/score/isr.h> + +/* + * PARAMETERS_PASSING_S is defined in ptimer.c + */ + +extern void PARAMETERS_PASSING_S (int num_signal, const struct sigaction inf); + +int sigaction( + int sig, + const struct sigaction *act, + struct sigaction *oact +) +{ + ISR_Level level; + + if ( oact ) + *oact = _POSIX_signals_Vectors[ sig ]; + + if ( !sig ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( !is_valid_signo(sig) ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + /* + * Some signals cannot be ignored (P1003.1b-1993, pp. 70-72 and references. + * + * NOTE: Solaris documentation claims to "silently enforce" this which + * contradicts the POSIX specification. + */ + + if ( sig == SIGKILL ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + /* + * Evaluate the new action structure and set the global signal vector + * appropriately. + */ + + if ( act ) { + + /* + * Unless the user is installing the default signal actions, then + * we can just copy the provided sigaction structure into the vectors. + */ + + _ISR_Disable( level ); + if ( act->sa_handler == SIG_DFL ) { + _POSIX_signals_Vectors[ sig ] = _POSIX_signals_Default_vectors[ sig ]; + } else { + _POSIX_signals_Clear_process_signals( signo_to_mask(sig) ); + _POSIX_signals_Vectors[ sig ] = *act; + } + _ISR_Enable( level ); + } + + /* + * No need to evaluate or dispatch because: + * + * + If we were ignoring the signal before, none could be pending + * now (signals not posted when SIG_IGN). + * + If we are now ignoring a signal that was previously pending, + * we clear the pending signal indicator. + */ + + return 0; +} diff --git a/cpukit/posix/src/sigaddset.c b/cpukit/posix/src/sigaddset.c new file mode 100644 index 0000000000..5ac0fe0f17 --- /dev/null +++ b/cpukit/posix/src/sigaddset.c @@ -0,0 +1,42 @@ +/* + * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> + +int sigaddset( + sigset_t *set, + int signo +) +{ + if ( !set ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( !signo ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( !is_valid_signo(signo) ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + *set |= signo_to_mask(signo); + return 0; +} diff --git a/cpukit/posix/src/sigdelset.c b/cpukit/posix/src/sigdelset.c new file mode 100644 index 0000000000..be0135a7b5 --- /dev/null +++ b/cpukit/posix/src/sigdelset.c @@ -0,0 +1,46 @@ +/* + * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> + +/* + * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 + */ + +int sigdelset( + sigset_t *set, + int signo +) +{ + if ( !set ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( !signo ) + return 0; + + if ( !is_valid_signo(signo) ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + *set &= ~signo_to_mask(signo); + return 0; +} diff --git a/cpukit/posix/src/sigemptyset.c b/cpukit/posix/src/sigemptyset.c new file mode 100644 index 0000000000..a216ad7a8c --- /dev/null +++ b/cpukit/posix/src/sigemptyset.c @@ -0,0 +1,35 @@ +/* + * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> + +int sigemptyset( + sigset_t *set +) +{ + if ( !set ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + *set = 0; + return 0; +} diff --git a/cpukit/posix/src/sigfillset.c b/cpukit/posix/src/sigfillset.c new file mode 100644 index 0000000000..dd8aa82c69 --- /dev/null +++ b/cpukit/posix/src/sigfillset.c @@ -0,0 +1,35 @@ +/* + * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> + +int sigfillset( + sigset_t *set +) +{ + if ( !set ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + *set = SIGNAL_ALL_MASK; + return 0; +} diff --git a/cpukit/posix/src/sigismember.c b/cpukit/posix/src/sigismember.c new file mode 100644 index 0000000000..3bdd32b729 --- /dev/null +++ b/cpukit/posix/src/sigismember.c @@ -0,0 +1,44 @@ +/* + * 3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> + +int sigismember( + const sigset_t *set, + int signo +) +{ + if ( !set ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( !signo ) + return 0; + + if ( !is_valid_signo(signo) ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( *set & signo_to_mask(signo) ) + return 1; + + return 0; +} diff --git a/cpukit/posix/src/signal_2.c b/cpukit/posix/src/signal_2.c new file mode 100644 index 0000000000..8d9c483803 --- /dev/null +++ b/cpukit/posix/src/signal_2.c @@ -0,0 +1,52 @@ +/* + * signal(2) - Install signal handler + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <signal.h> +#include <errno.h> + +typedef void (*sighandler_t)(int); + +sighandler_t signal( + int signum, + sighandler_t handler +) +{ + struct sigaction s; + struct sigaction old; + + s.sa_handler = handler ; + sigemptyset(&s.sa_mask); + + /* + * Depending on which system we want to behave like, one of + * the following versions should be chosen. + */ + +/* #define signal_like_linux */ + +#if defined(signal_like_linux) + s.sa_flags = SA_RESTART | SA_INTERRUPT | SA_NOMASK; + s.sa_restorer= NULL ; +#elif defined(signal_like_SVR4) + s.sa_flags = SA_RESTART; +#else + s.sa_flags = 0; +#endif + + sigaction( signum, &s, &old ); + return (sighandler_t) old.sa_handler; +} diff --git a/cpukit/posix/src/sigpending.c b/cpukit/posix/src/sigpending.c new file mode 100644 index 0000000000..9f22760a58 --- /dev/null +++ b/cpukit/posix/src/sigpending.c @@ -0,0 +1,40 @@ +/* + * 3.3.6 Examine Pending Signals, P1003.1b-1993, p. 75 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> + +int sigpending( + sigset_t *set +) +{ + POSIX_API_Control *api; + + if ( !set ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + *set = api->signals_pending | _POSIX_signals_Pending; + + return 0; +} diff --git a/cpukit/posix/src/sigprocmask.c b/cpukit/posix/src/sigprocmask.c new file mode 100644 index 0000000000..c149a39065 --- /dev/null +++ b/cpukit/posix/src/sigprocmask.c @@ -0,0 +1,39 @@ +/* + * 3.3.5 Examine and Change Blocked Signals, P1003.1b-1993, p. 73 + * + * NOTE: P1003.1c/D10, p. 37 adds pthread_sigmask(). + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> + +int sigprocmask( + int how, + const sigset_t *set, + sigset_t *oset +) +{ + /* + * P1003.1c/Draft 10, p. 38 maps sigprocmask to pthread_sigmask. + */ + + return pthread_sigmask( how, set, oset ); +} diff --git a/cpukit/posix/src/sigqueue.c b/cpukit/posix/src/sigqueue.c new file mode 100644 index 0000000000..727f2c6b42 --- /dev/null +++ b/cpukit/posix/src/sigqueue.c @@ -0,0 +1,32 @@ +/* + * 3.3.9 Queue a Signal to a Process, P1003.1b-1993, p. 78 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> + +int sigqueue( + pid_t pid, + int signo, + const union sigval value +) +{ + return killinfo( pid, signo, &value ); +} diff --git a/cpukit/posix/src/sigsuspend.c b/cpukit/posix/src/sigsuspend.c new file mode 100644 index 0000000000..aa330bc71c --- /dev/null +++ b/cpukit/posix/src/sigsuspend.c @@ -0,0 +1,53 @@ +/* + * 3.3.7 Wait for a Signal, P1003.1b-1993, p. 75 + * + * COPYRIGHT (c) 1989-2004. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> + +int sigsuspend( + const sigset_t *sigmask +) +{ + sigset_t saved_signals_blocked; + sigset_t all_signals; + int status; + POSIX_API_Control *api; + + api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + status = sigprocmask( SIG_BLOCK, sigmask, &saved_signals_blocked ); + + (void) sigfillset( &all_signals ); + + status = sigtimedwait( &all_signals, NULL, NULL ); + + (void) sigprocmask( SIG_SETMASK, &saved_signals_blocked, NULL ); + + /* + * sigtimedwait() returns the signal number while sigsuspend() + * is supposed to return -1 and EINTR when a signal is caught. + */ + if ( status != -1 ) + rtems_set_errno_and_return_minus_one( EINTR ); + + return status; +} diff --git a/cpukit/posix/src/sigtimedwait.c b/cpukit/posix/src/sigtimedwait.c new file mode 100644 index 0000000000..1486be3054 --- /dev/null +++ b/cpukit/posix/src/sigtimedwait.c @@ -0,0 +1,140 @@ +/* + * 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/seterr.h> +#include <rtems/posix/time.h> +#include <rtems/score/isr.h> + +int _POSIX_signals_Get_highest( + sigset_t set +) +{ + int signo; + + for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) { + if ( set & signo_to_mask( signo ) ) + return signo; + } + +/* XXX - add __SIGFIRSTNOTRT or something like that to newlib signal .h */ + + for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) { + if ( set & signo_to_mask( signo ) ) + return signo; + } + + return 0; +} + +int sigtimedwait( + const sigset_t *set, + siginfo_t *info, + const struct timespec *timeout +) +{ + Thread_Control *the_thread; + POSIX_API_Control *api; + Watchdog_Interval interval; + siginfo_t signal_information; + siginfo_t *the_info; + int signo; + ISR_Level level; + + /* + * Error check parameters before disabling interrupts. + */ + + interval = 0; + if ( timeout ) { + + if ( timeout->tv_nsec < 0 || + timeout->tv_nsec >= TOD_NANOSECONDS_PER_SECOND) { + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + interval = _POSIX_Timespec_to_interval( timeout ); + } + + /* + * Initialize local variables. + */ + + the_info = ( info ) ? info : &signal_information; + + the_thread = _Thread_Executing; + + api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + + /* + * What if they are already pending? + */ + + /* API signals pending? */ + + _ISR_Disable( level ); + if ( *set & api->signals_pending ) { + /* XXX real info later */ + the_info->si_signo = _POSIX_signals_Get_highest( api->signals_pending ); + _POSIX_signals_Clear_signals( api, the_info->si_signo, the_info, FALSE, FALSE ); + _ISR_Enable( level ); + + the_info->si_code = SI_USER; + the_info->si_value.sival_int = 0; + return the_info->si_signo; + } + + /* Process pending signals? */ + + if ( *set & _POSIX_signals_Pending ) { + signo = _POSIX_signals_Get_highest( _POSIX_signals_Pending ); + _POSIX_signals_Clear_signals( api, signo, the_info, TRUE, FALSE ); + _ISR_Enable( level ); + + the_info->si_signo = signo; + the_info->si_code = SI_USER; + the_info->si_value.sival_int = 0; + return signo; + } + + the_info->si_signo = -1; + + _Thread_Disable_dispatch(); + the_thread->Wait.queue = &_POSIX_signals_Wait_queue; + the_thread->Wait.return_code = EINTR; + the_thread->Wait.option = *set; + the_thread->Wait.return_argument = the_info; + _Thread_queue_Enter_critical_section( &_POSIX_signals_Wait_queue ); + _ISR_Enable( level ); + _Thread_queue_Enqueue( &_POSIX_signals_Wait_queue, interval ); + _Thread_Enable_dispatch(); + + /* + * When the thread is set free by a signal, it is need to eliminate + * the signal. + */ + + _POSIX_signals_Clear_signals( api, the_info->si_signo, the_info, FALSE, FALSE ); + errno = _Thread_Executing->Wait.return_code; + return the_info->si_signo; +} diff --git a/cpukit/posix/src/sigwait.c b/cpukit/posix/src/sigwait.c new file mode 100644 index 0000000000..1c34b5ee5b --- /dev/null +++ b/cpukit/posix/src/sigwait.c @@ -0,0 +1,44 @@ +/* + * 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 + * + * NOTE: P1003.1c/D10, p. 39 adds sigwait(). + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> + +int sigwait( + const sigset_t *set, + int *sig +) +{ + int status; + + status = sigtimedwait( set, NULL, NULL ); + + if ( status != -1 ) { + if ( sig ) + *sig = status; + return 0; + } + + return errno; +} diff --git a/cpukit/posix/src/sigwaitinfo.c b/cpukit/posix/src/sigwaitinfo.c new file mode 100644 index 0000000000..2c61e2a8fc --- /dev/null +++ b/cpukit/posix/src/sigwaitinfo.c @@ -0,0 +1,33 @@ +/* + * 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 + * + * NOTE: P1003.1c/D10, p. 39 adds sigwait(). + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <signal.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> + +int sigwaitinfo( + const sigset_t *set, + siginfo_t *info +) +{ + return sigtimedwait( set, info, NULL ); +} diff --git a/cpukit/posix/src/sleep.c b/cpukit/posix/src/sleep.c new file mode 100644 index 0000000000..501fe5770f --- /dev/null +++ b/cpukit/posix/src/sleep.c @@ -0,0 +1,31 @@ +/* + * 3.4.3 Delay Process Execution, P1003.1b-1993, p. 81 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <time.h> +#include <unistd.h> + +#include <rtems/system.h> + + +unsigned int sleep( + unsigned int seconds +) +{ + /* XXX can we get away with this implementation? */ + struct timespec tp; + struct timespec tm; + + tp.tv_sec = seconds; + tp.tv_nsec = 0; + + nanosleep( &tp, &tm ); + + return tm.tv_sec; /* seconds remaining */ +} diff --git a/cpukit/posix/src/sysconf.c b/cpukit/posix/src/sysconf.c new file mode 100644 index 0000000000..4a8add9e35 --- /dev/null +++ b/cpukit/posix/src/sysconf.c @@ -0,0 +1,49 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <time.h> +#include <unistd.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/tod.h> + +/*PAGE + * + * 4.8.1 Get Configurable System Variables, P1003.1b-1993, p. 95 + */ + +long sysconf( + int name +) +{ + + switch (name) { + case _SC_CLK_TCK: + return _TOD_Ticks_per_second; + + case _SC_OPEN_MAX: { + extern uint32_t rtems_libio_number_iops; + return rtems_libio_number_iops; + } + + case _SC_GETPW_R_SIZE_MAX: + return 1024; + +#if defined(__sparc__) + case 515: /* Solaris _SC_STACK_PROT */ + return 0; +#endif + + default: + break; + } + + errno = EINVAL; + return -1; +} diff --git a/cpukit/posix/src/testcancel.c b/cpukit/posix/src/testcancel.c new file mode 100644 index 0000000000..8d80794e2d --- /dev/null +++ b/cpukit/posix/src/testcancel.c @@ -0,0 +1,46 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/chain.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/wkspace.h> +#include <rtems/posix/cancel.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/threadsup.h> + +/*PAGE + * + * 18.2.2 Setting Cancelability State, P1003.1c/Draft 10, p. 183 + */ + +void pthread_testcancel( void ) +{ + POSIX_API_Control *thread_support; + + /* + * Don't even think about deleting a resource from an ISR. + * Besides this request is supposed to be for _Thread_Executing + * and the ISR context is not a thread. + */ + + if ( _ISR_Is_in_progress() ) + return; + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + + _Thread_Disable_dispatch(); + if ( thread_support->cancelability_state == PTHREAD_CANCEL_ENABLE && + thread_support->cancelation_requested ) + _POSIX_Threads_cancel_run( _Thread_Executing ); + _Thread_Enable_dispatch(); +} diff --git a/cpukit/posix/src/time.c b/cpukit/posix/src/time.c new file mode 100644 index 0000000000..69592b7318 --- /dev/null +++ b/cpukit/posix/src/time.c @@ -0,0 +1,52 @@ +/* + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <time.h> +#include <errno.h> + +#include <rtems/system.h> +#include <rtems/score/isr.h> +#include <rtems/score/thread.h> +#include <rtems/score/tod.h> + +#include <rtems/seterr.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * 4.5.1 Get System Time, P1003.1b-1993, p. 91 + */ + +/* Using the implementation in newlib */ +#if 0 +time_t time( + time_t *tloc +) +{ + time_t seconds_since_epoch; + + /* + * No error is the time of day is not set. For RTEMS the system time + * starts out at the rtems epoch. + */ + + /* + * Internally the RTEMS epoch is 1988. This must be taken into account. + */ + + seconds_since_epoch = _TOD_Seconds_since_epoch; + + seconds_since_epoch += POSIX_TIME_SECONDS_1970_THROUGH_1988; + + if ( tloc ) + *tloc = seconds_since_epoch; + + return seconds_since_epoch; +} +#endif diff --git a/cpukit/posix/src/types.c b/cpukit/posix/src/types.c new file mode 100644 index 0000000000..d9befea289 --- /dev/null +++ b/cpukit/posix/src/types.c @@ -0,0 +1,46 @@ +/* + * This file is the shell of what it initially was and is now misnamed. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <limits.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/seterr.h> + +/* + * TEMPORARY + */ + +#include <assert.h> + +int POSIX_MP_NOT_IMPLEMENTED() +{ + assert( 0 ); + return 0; +} + +int POSIX_BOTTOM_REACHED() +{ + assert( 0 ); + return 0; +} + +int POSIX_NOT_IMPLEMENTED() +{ + assert( 0 ); + return 0; +} + +/* + * END OF TEMPORARY + */ diff --git a/cpukit/posix/src/ualarm.c b/cpukit/posix/src/ualarm.c new file mode 100644 index 0000000000..ab268d105c --- /dev/null +++ b/cpukit/posix/src/ualarm.c @@ -0,0 +1,94 @@ +/* + * XXX 3.4.1 Schedule Alarm, P1003.1b-1993, p. 79 + * + * COPYRIGHT (c) 1989-2003. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> +/* #include <errno.h> */ + +#include <rtems/system.h> +#include <rtems/posix/pthread.h> +#include <rtems/posix/psignal.h> +#include <rtems/posix/time.h> + +Watchdog_Control _POSIX_signals_Ualarm_timer; + +/*PAGE + * + * _POSIX_signals_Ualarm_TSR + */ + +void _POSIX_signals_Ualarm_TSR( + Objects_Id id, + void *argument +) +{ + int status; + + status = kill( getpid(), SIGALRM ); + /* XXX can't print from an ISR, should this be fatal? */ +} + +useconds_t ualarm( + useconds_t useconds, + useconds_t interval +) +{ + useconds_t remaining = 0; + Watchdog_Control *the_timer; + Watchdog_Interval ticks; + struct timespec tp; + + the_timer = &_POSIX_signals_Ualarm_timer; + + /* + * Initialize the timer used to implement alarm(). + */ + + if ( !the_timer->routine ) { + _Watchdog_Initialize( the_timer, _POSIX_signals_Ualarm_TSR, 0, NULL ); + } else { + switch ( _Watchdog_Remove( the_timer ) ) { + case WATCHDOG_INACTIVE: + case WATCHDOG_BEING_INSERTED: + break; + + case WATCHDOG_ACTIVE: + case WATCHDOG_REMOVE_IT: + /* + * The stop_time and start_time fields are snapshots of ticks since + * boot. Since alarm() is dealing in seconds, we must account for + * this. + */ + + + ticks = the_timer->initial - + ((the_timer->stop_time - the_timer->start_time) / + _TOD_Ticks_per_second); + + _POSIX_Interval_to_timespec( ticks, &tp ); + remaining = tp.tv_sec * TOD_MICROSECONDS_PER_SECOND; + remaining += tp.tv_nsec / 1000; + break; + } + } + + tp.tv_sec = useconds / TOD_MICROSECONDS_PER_SECOND; + tp.tv_nsec = (useconds % TOD_MICROSECONDS_PER_SECOND) * 1000; + ticks = _POSIX_Timespec_to_interval( &tp ); + _Watchdog_Insert_ticks( the_timer, ticks ); + + return remaining; +} diff --git a/cpukit/posix/src/usleep.c b/cpukit/posix/src/usleep.c new file mode 100644 index 0000000000..6753cfe713 --- /dev/null +++ b/cpukit/posix/src/usleep.c @@ -0,0 +1,34 @@ +/* + * XXX 3.4.3 Delay Process Execution, P1003.1b-1993, p. 81 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <time.h> +#include <unistd.h> + +#include <rtems/system.h> +#include <rtems/score/tod.h> + + +unsigned usleep( + unsigned int useconds +) +{ + struct timespec tp; + struct timespec tm; + unsigned remaining; + + tp.tv_sec = useconds / TOD_MICROSECONDS_PER_SECOND; + tp.tv_nsec = (useconds % TOD_MICROSECONDS_PER_SECOND) * 1000; + + nanosleep( &tp, &tm ); + + remaining = tm.tv_sec * TOD_MICROSECONDS_PER_SECOND; + remaining += tm.tv_nsec / 1000; + return remaining; /* seconds remaining */ +} diff --git a/cpukit/posix/src/wait.c b/cpukit/posix/src/wait.c new file mode 100644 index 0000000000..5bfa8ce943 --- /dev/null +++ b/cpukit/posix/src/wait.c @@ -0,0 +1,21 @@ +/* + * waitpid() - POSIX 1003.1b 3.2.1 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> + +int wait( + int *stat_loc +) +{ + errno = ENOSYS; + return -1; +} diff --git a/cpukit/posix/src/waitpid.c b/cpukit/posix/src/waitpid.c new file mode 100644 index 0000000000..5201f56a05 --- /dev/null +++ b/cpukit/posix/src/waitpid.c @@ -0,0 +1,23 @@ +/* + * waitpid() - POSIX 1003.1 3.2.1 + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> + +int waitpid( + pid_t pid, + int *stat_loc, + int options +) +{ + errno = ENOSYS; + return -1; +} |