OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/trunk/ecos-2.0/packages/compat/posix
    from Rev 1254 to Rev 1765
    Reverse comparison

Rev 1254 → Rev 1765

/v2_0/cdl/posix.cdl
0,0 → 1,317
# ====================================================================
#
# posix.cdl
#
# POSIX layer configuration data
#
# ====================================================================
#####ECOSGPLCOPYRIGHTBEGIN####
## -------------------------------------------
## This file is part of eCos, the Embedded Configurable Operating System.
## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
##
## eCos is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free
## Software Foundation; either version 2 or (at your option) any later version.
##
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
## for more details.
##
## You should have received a copy of the GNU General Public License along
## with eCos; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
##
## As a special exception, if other files instantiate templates or use macros
## or inline functions from this file, or you compile this file and link it
## with other works to produce a work based on this file, this file does not
## by itself cause the resulting work to be covered by the GNU General Public
## License. However the source code for this file must still be made available
## in accordance with section (3) of the GNU General Public License.
##
## This exception does not invalidate any other reasons why a work based on
## this file might be covered by the GNU General Public License.
##
## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
## at http://sources.redhat.com/ecos/ecos-license/
## -------------------------------------------
#####ECOSGPLCOPYRIGHTEND####
# ====================================================================
######DESCRIPTIONBEGIN####
#
# Author(s): nickg
# Contributors:
# Date: 2000-3-28
#
#####DESCRIPTIONEND####
#
# ====================================================================
 
cdl_package CYGPKG_POSIX {
display "POSIX compatibility layer"
description "This package enables the POSIX compatibility
layer that implements IEEE 1003.1."
doc ref/posix-compatibility.html
include_dir cyg/posix
requires CYGPKG_KERNEL
requires CYGPKG_ISOINFRA
requires CYGPKG_ERROR
requires CYGINT_ISO_ERRNO
requires CYGINT_ISO_ERRNO_CODES
requires CYGIMP_KERNEL_SCHED_SORTED_QUEUES
 
implements CYGINT_ISO_SCHED_IMPL
implements CYGINT_ISO_POSIX_LIMITS
implements CYGINT_ISO_PMUTEXTYPES
implements CYGINT_ISO_PTHREAD_MUTEX
requires { CYGBLD_ISO_POSIX_LIMITS_HEADER == \
"<cyg/posix/limits.h>" }
requires { CYGBLD_ISO_PMUTEXTYPES_HEADER == \
"<cyg/posix/muttypes.h>" }
requires { CYGBLD_ISO_PTHREAD_MUTEX_HEADER == \
"<cyg/posix/mutex.h>" }
compile mqueue.cxx mutex.cxx misc.cxx
compile -library=libextras.a startup.cxx
 
cdl_option _POSIX_THREAD_PRIO_INHERIT {
display "POSIX mutex priority inheritance feature test macro"
flavor bool
default_value 1
requires CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
description "This option defines the POSIX feature test macro
for supporting priority inheritance protocol in
mutexes."
}
cdl_option _POSIX_THREAD_PRIO_PROTECT {
display "POSIX mutex priority ceiling feature test macro"
flavor bool
default_value 1
requires CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
description "This option defines the POSIX feature test macro
for supporting priority ceiling protocol in mutexes."
}
# ----------------------------------------------------------------
# Scheduling component
cdl_component CYGPKG_POSIX_SCHED {
display "POSIX scheduling configuration"
flavor bool
default_value 1
description "This component provides controls over scheduling
in POSIX."
requires CYGPKG_POSIX_CLOCKS
compile sched.cxx
 
cdl_option _POSIX_PRIORITY_SCHEDULING {
display "POSIX priority scheduling feature test macro"
flavor bool
calculated 1
requires CYGSEM_KERNEL_SCHED_MLQUEUE
description "This option defines the POSIX feature test macro
that indicates that priority scheduling is present.
This should not be undefined."
}
}
 
# ----------------------------------------------------------------
# Pthreads component
 
cdl_component CYGPKG_POSIX_PTHREAD {
display "POSIX pthread configuration"
flavor bool
default_value 1
description "This component provides configuration controls for
the POSIX pthreads package."
compile pthread.cxx
script pthread.cdl
}
 
# ----------------------------------------------------------------
# Timers component
 
cdl_option CYGPKG_POSIX_CLOCKS {
display "POSIX clocks"
flavor bool
default_value 1
implements CYGINT_ISO_POSIX_CLOCK_TYPES
implements CYGINT_ISO_POSIX_CLOCKS
implements CYGINT_ISO_POSIX_SLEEP
requires { CYGBLD_ISO_POSIX_CLOCK_TYPES_HEADER == \
"<cyg/posix/time.h>" }
requires { CYGBLD_ISO_POSIX_CLOCKS_HEADER == \
"<cyg/posix/time.h>" }
requires CYGPKG_KERNEL
requires CYGVAR_KERNEL_COUNTERS_CLOCK
compile time.cxx
description "This component provides configuration controls for
the POSIX clocks."
}
 
# ----------------------------------------------------------------
# Timers component
 
cdl_option CYGPKG_POSIX_TIMERS {
display "POSIX timers"
flavor bool
default_value 1
implements CYGINT_ISO_POSIX_TIMER_TYPES
implements CYGINT_ISO_POSIX_TIMERS
implements CYGINT_ISO_POSIX_TIMER_OPS
requires { CYGBLD_ISO_POSIX_TIMER_TYPES_HEADER == \
"<cyg/posix/time.h>" }
requires { CYGBLD_ISO_POSIX_TIMERS_HEADER == \
"<cyg/posix/time.h>" }
requires CYGPKG_KERNEL
requires CYGVAR_KERNEL_COUNTERS_CLOCK
requires CYGPKG_POSIX_PTHREAD
requires CYGPKG_POSIX_CLOCKS
requires CYGPKG_POSIX_SIGNALS
description "This component provides configuration controls for
the POSIX timers."
}
 
# ----------------------------------------------------------------
# Semaphores component
 
cdl_option CYGPKG_POSIX_SEMAPHORES {
display "POSIX semaphores"
flavor bool
default_value 1
implements CYGINT_ISO_SEMAPHORES
requires { CYGBLD_ISO_SEMAPHORES_HEADER == \
"<cyg/posix/semaphore.h>" }
description "This component provides configuration controls for
POSIX semaphores."
 
compile sem.cxx
}
 
# ----------------------------------------------------------------
# Message queues component
 
cdl_component CYGPKG_POSIX_MQUEUES {
display "POSIX message queues"
flavor bool
default_value 1
implements CYGINT_ISO_MQUEUE
requires CYGPKG_KERNEL
requires CYGINT_ISO_MALLOC
requires CYGINT_ISO_ERRNO
requires CYGINT_ISO_STRING_STRFUNCS
description "This component provides configuration controls for
POSIX message queues."
 
cdl_option CYGNUM_POSIX_MQUEUE_OPEN_MAX {
display "Maximum number of message queues"
flavor data
default_value 8
legal_values 1 to 999999
}
 
cdl_option CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR {
display "Validate queue descriptors"
flavor bool
default_value 1
description "
This option turns on checking that message queue descriptors
(of type mqd_t) passed into mq_* functions are valid. If so,
the functions will fail with EBADF, as POSIX 1003.1 mandates.
If this option is disabled, if an invalid descriptor is used,
random corruption may occur, or the system may crash. If
you are confident invalid descriptors will not be used,
you may wish to be disable this to save some per-instance
memory and execution time."
}
 
cdl_option CYGFUN_POSIX_MQUEUE_NOTIFY {
display "Allow empty queue notification"
flavor bool
requires CYGPKG_POSIX_SIGNALS
default_value CYGPKG_POSIX_SIGNALS
description "
Enabling this option adds the function mq_notify() to the
API. Without it, some code and per-message queue descriptor
space is saved, as well as no longer requiring POSIX realtime
signal support."
}
}
 
# ----------------------------------------------------------------
# Signals component
 
cdl_component CYGPKG_POSIX_SIGNALS {
display "POSIX signals configuration"
flavor bool
default_value 1
requires CYGPKG_KERNEL_EXCEPTIONS
requires CYGPKG_POSIX_PTHREAD
requires CYGPKG_POSIX_TIMERS
implements CYGINT_POSIX_REALTIME_SIGNALS
implements CYGINT_ISO_SIGSETJMP
requires { CYGBLD_ISO_SIGSETJMP_HEADER == \
"<cyg/posix/sigsetjmp.h>" }
implements CYGINT_ISO_SIGNAL_NUMBERS
implements CYGINT_ISO_SIGNAL_IMPL
requires { CYGBLD_ISO_SIGNAL_NUMBERS_HEADER == \
"<cyg/posix/signal.h>" }
requires { CYGBLD_ISO_SIGNAL_IMPL_HEADER == \
"<cyg/posix/signal.h>" }
description "This component provides configuration controls for
the POSIX signals."
compile signal.cxx except.cxx
}
 
# ----------------------------------------------------------------
# uname structure component
 
cdl_component CYGPKG_POSIX_UTSNAME {
display "POSIX utsname configuration"
flavor bool
default_value 1
requires { CYGBLD_ISO_UTSNAME_HEADER == \
"<cyg/posix/utsname.h>" }
description "This component provides configuration controls for
the POSIX utsname structure and the uname() function."
 
cdl_option CYG_POSIX_UTSNAME_LENGTH {
display "Length of name strings in utsname structure"
flavor data
default_value 65
legal_values 1 to 99999999
}
 
cdl_option CYG_POSIX_UTSNAME_NODENAME_LENGTH {
display "Length of nodename string in utsname structure"
flavor data
default_value { CYG_POSIX_UTSNAME_LENGTH }
legal_values 1 to 99999999
}
 
}
 
# ----------------------------------------------------------------
# Tests
 
cdl_option CYGPKG_POSIX_TESTS {
display "POSIX tests"
flavor data
no_define
calculated {
"tests/pthread1 tests/pthread2 tests/pthread3 tests/mutex3 tests/mqueue2"
. ((CYGPKG_POSIX_SIGNALS) ? " tests/mqueue1 tests/signal1 tests/signal2 tests/signal3 tests/sigsetjmp tests/timer1 tests/tm_basic" : "")
}
description "
This option specifies the set of tests for the POSIX package."
}
 
}
 
# ====================================================================
# End of posix.cdl
 
 
/v2_0/cdl/pthread.cdl
0,0 → 1,197
# ====================================================================
#
# pthread.cdl
#
# POSIX pthread configuration data
#
# ====================================================================
#####ECOSGPLCOPYRIGHTBEGIN####
## -------------------------------------------
## This file is part of eCos, the Embedded Configurable Operating System.
## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
##
## eCos is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free
## Software Foundation; either version 2 or (at your option) any later version.
##
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
## for more details.
##
## You should have received a copy of the GNU General Public License along
## with eCos; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
##
## As a special exception, if other files instantiate templates or use macros
## or inline functions from this file, or you compile this file and link it
## with other works to produce a work based on this file, this file does not
## by itself cause the resulting work to be covered by the GNU General Public
## License. However the source code for this file must still be made available
## in accordance with section (3) of the GNU General Public License.
##
## This exception does not invalidate any other reasons why a work based on
## this file might be covered by the GNU General Public License.
##
## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
## at http://sources.redhat.com/ecos/ecos-license/
## -------------------------------------------
#####ECOSGPLCOPYRIGHTEND####
# ====================================================================
######DESCRIPTIONBEGIN####
#
# Author(s): nickg
# Contributors: jlarmour
# Date: 2000-3-28
#
#####DESCRIPTIONEND####
#
# ====================================================================
 
cdl_option CYGPKG_POSIX_PTHREAD_REQUIREMENTS {
display "Generic requirements of pthread package"
flavor bool
calculated 1
implements CYGINT_ISO_PTHREADTYPES
implements CYGINT_ISO_PTHREAD_IMPL
requires CYGPKG_POSIX_SCHED
requires CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
requires CYGSEM_KERNEL_SCHED_ASR_SUPPORT
requires CYGSEM_KERNEL_SCHED_ASR_GLOBAL
requires !CYGSEM_KERNEL_SCHED_ASR_DATA_GLOBAL
requires CYGFUN_KERNEL_THREADS_STACK_LIMIT
requires { CYGBLD_ISO_PTHREADTYPES_HEADER == \
"<cyg/posix/types.h>" }
requires { CYGBLD_ISO_PTHREAD_IMPL_HEADER == \
"<cyg/posix/pthread.h>" }
description "This option exists merely to carry the pthread
package requirements."
 
}
 
# ====================================================================
 
cdl_component CYGPKG_POSIX_PTHREAD_VALUES {
display "Constant values used in pthread package"
flavor bool
calculated 1
description "These are values that are either configurable, or derived
from system parameters."
 
cdl_option CYGNUM_POSIX_PTHREAD_DESTRUCTOR_ITERATIONS {
display "Maximum number of iterations of key destructors"
flavor data
legal_values 4 to 100
default_value 4
description "Maximum number of iterations of key destructors allowed."
}
 
cdl_option CYGNUM_POSIX_PTHREAD_KEYS_MAX {
display "Maximum number of per-thread data keys allowed"
flavor data
legal_values 128 to 65535
default_value 128
description "Number of per-thread data keys supported."
}
 
cdl_option CYGNUM_POSIX_PTHREAD_THREADS_MAX {
display "Maximum number of threads allowed"
flavor data
legal_values 64 to 1024
default_value 64
description "Maximum number of threads supported."
}
 
}
 
# ====================================================================
 
cdl_component CYGPKG_POSIX_PTHREAD_FEATURES {
display "Fixed Feature test macros for POSIX"
flavor bool
calculated 1
description "These options define POSIX feature test macros that
describe the eCos implementation of pthreads. These
are not changeable configuration options."
 
cdl_option _POSIX_THREADS {
display "POSIX thread support feature test macro"
flavor bool
calculated 1
requires CYGSEM_KERNEL_SCHED_TIMESLICE
requires CYGVAR_KERNEL_THREADS_DATA
description "This option defines the POSIX feature test macro
for thread support."
}
 
cdl_option _POSIX_THREAD_PRIORITY_SCHEDULING {
display "POSIX thread priority scheduling feature test macro"
flavor bool
calculated 1
requires CYGSEM_KERNEL_SCHED_MLQUEUE
requires _POSIX_THREADS
description "This option defines the POSIX feature test macro
for thread priority scheduling support."
}
 
cdl_option _POSIX_THREAD_ATTR_STACKADDR {
display "POSIX stack address attribute feature test macro"
flavor bool
calculated 1
description "This option defines the POSIX feature test macro
for supporting the thread stack address in the thread
attribute object."
}
 
cdl_option _POSIX_THREAD_ATTR_STACKSIZE {
display "POSIX stack size attribute feature test macro"
flavor bool
calculated 1
description "This option defines the POSIX feature test macro
for supporting the thread stack size in the thread
attribute object."
}
 
cdl_option _POSIX_THREAD_PROCESS_SHARED {
display "POSIX process shared attribute feature test macro"
flavor bool
calculated 0
description "This option defines the POSIX feature test macro
for supporting process shared mutexes. Since eCos
does not have processes, this attribute is undefined."
}
 
}
 
# ====================================================================
 
cdl_component CYGPKG_POSIX_MAIN_THREAD {
display "Main thread configuration"
flavor bool
calculated 1
requires { 0 != CYGPKG_LIBC_STARTUP }
requires CYGSEM_LIBC_STARTUP_MAIN_OTHER
implements CYGINT_LIBC_STARTUP_EXTERNAL_INVOKE_MAIN_POSSIBLE
description "These options control the thread used to
run the main() application entry routine."
cdl_option CYGNUM_POSIX_MAIN_DEFAULT_PRIORITY {
display "main()'s default thread priority"
flavor data
legal_values 0 to 31
default_value 16
description "
POSIX compatibility requires that the application's
main() function be invoked in a thread.
This option controls the priority of that thread. This
priority is the POSIX priority and is NOT the same as
an eCos thread priority. With POSIX thread priorities,
lower numbers are lower priority, and higher numbers are
higher priority."
}
}
 
# ====================================================================
# End of pthread.cdl
 
 
/v2_0/tests/signal1.c
0,0 → 1,302
//==========================================================================
//
// signal1.cxx
//
// POSIX signal test 1
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-04-10
// Description: Tests POSIX signal functionality.
//
//####DESCRIPTIONEND####
//==========================================================================
 
#include <cyg/infra/testcase.h>
#include <pkgconf/posix.h>
 
#if !defined(CYGPKG_POSIX_SIGNALS)
#define NA_MSG "POSIX signals not enabled"
#elif !defined(CYGPKG_POSIX_PTHREAD)
#define NA_MSG "POSIX threads not enabled"
#endif
 
#ifdef NA_MSG
void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA(NA_MSG);
}
#else
 
#include <sys/types.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <errno.h>
 
//--------------------------------------------------------------------------
// Thread stack.
 
char thread_stack[PTHREAD_STACK_MIN*2];
 
//--------------------------------------------------------------------------
// Local variables
 
// Sync semaphore
sem_t sem;
 
// Thread ID
pthread_t thread1;
 
volatile int sigusr2_called = 0;
volatile int sigalrm_called = 0;
 
//--------------------------------------------------------------------------
// Signal handler functions
 
static void sigusr2( int signo )
{
CYG_TEST_INFO( "sigusr2() handler called" );
CYG_TEST_CHECK( signo == SIGUSR2, "Signal not SIGUSR2");
CYG_TEST_CHECK( pthread_equal(pthread_self(), thread1), "Not called in thread1");
 
sigusr2_called++;
}
 
static void sigalrm( int signo )
{
CYG_TEST_INFO( "sigalrm() handler called" );
CYG_TEST_CHECK( signo == SIGALRM, "Signal not SIGALRM");
CYG_TEST_CHECK( pthread_equal(pthread_self(), thread1), "Not called in thread1");
 
sigalrm_called++;
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry1( void *arg)
{
sigset_t mask;
siginfo_t info;
struct timespec timeout;
int sig, sig2, err;
CYG_TEST_INFO( "Thread 1 running" );
 
// Should have inherited parent's signal mask
pthread_sigmask( 0, NULL, &mask );
CYG_TEST_CHECK( sigismember( &mask, SIGALRM),
"SIGALRM mask inherited");
CYG_TEST_CHECK( sigismember( &mask, SIGUSR1),
"SIGUSR1 mask inherited");
CYG_TEST_CHECK( sigismember( &mask, SIGUSR2),
"SIGUSR2 mask inherited");
CYG_TEST_CHECK( sigismember( &mask, SIGSEGV),
"SIGSEGV mask inherited");
 
// Make a full set
sigfillset( &mask );
 
// remove USR2 and ALRM signals
sigdelset( &mask, SIGUSR2 );
sigdelset( &mask, SIGALRM );
 
// Set signal mask
pthread_sigmask( SIG_SETMASK, &mask, NULL );
// Get main thread going again
sem_post( &sem );
 
// set up timeout
timeout.tv_sec = 10;
timeout.tv_nsec = 0;
 
CYG_TEST_INFO( "Thread1: calling sigtimedwait()");
// Wait for a signal to be delivered
sig = sigtimedwait( &mask, &info, &timeout );
 
sig2 = info.si_signo;
CYG_TEST_CHECK( sig == sig2, "sigtimedwait return value not equal");
CYG_TEST_CHECK( sig == SIGUSR1, "Signal not delivered");
 
while( sigusr2_called != 2 )
{
CYG_TEST_INFO( "Thread1: calling pause()");
pause();
}
 
errno = 0; // strictly correct to reset errno first
 
// now wait for SIGALRM to be delivered
CYG_TEST_INFO( "Thread1: calling pause()");
err = pause();
CYG_TEST_CHECK( -1==err, "pause returned -1");
CYG_TEST_CHECK( EINTR==errno, "errno set to EINTR");
 
// generate another SIGALRM and wait for it to be delivered too
// we need to mask it first though
 
// Make a full set
sigfillset( &mask );
 
// Set signal mask
pthread_sigmask( SIG_SETMASK, &mask, NULL );
alarm(1);
CYG_TEST_INFO( "Thread1: calling sigwait()");
err = sigwait( &mask, &sig);
CYG_TEST_CHECK( 0==err, "sigwait returned -1");
CYG_TEST_CHECK( sig==SIGALRM, "sigwait caught alarm");
 
CYG_TEST_INFO( "Thread1: calling pthread_exit()");
pthread_exit( (void *)((int)arg+sig2) );
}
 
//--------------------------------------------------------------------------
 
int main(int argc, char **argv)
{
int ret;
sigset_t mask;
pthread_attr_t attr;
void *retval;
union sigval value;
CYG_TEST_INIT();
 
// Make a full signal set
sigfillset( &mask );
 
// Install signal handlers
{
struct sigaction sa;
 
sa.sa_handler = sigusr2;
sa.sa_mask = mask;
sa.sa_flags = 0;
 
ret = sigaction( SIGUSR2, &sa, NULL );
 
CYG_TEST_CHECK( ret == 0 , "sigaction returned error");
}
 
{
struct sigaction sa;
 
sa.sa_handler = sigalrm;
sa.sa_mask = mask;
sa.sa_flags = 0;
 
ret = sigaction( SIGALRM, &sa, NULL );
 
CYG_TEST_CHECK( ret == 0 , "sigaction returned error");
}
// Mask all signals
pthread_sigmask( SIG_SETMASK, &mask, NULL );
sem_init( &sem, 0, 0 );
// Create test thread
pthread_attr_init( &attr );
 
pthread_attr_setstackaddr( &attr, (void *)&thread_stack[sizeof(thread_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread_stack) );
 
pthread_create( &thread1,
&attr,
pthread_entry1,
(void *)0x12345678);
 
// Wait for other thread to get started
CYG_TEST_INFO( "Main: calling sem_wait()");
sem_wait( &sem );
 
value.sival_int = 0;
 
// send a signal to the other thread
CYG_TEST_INFO( "Main: calling sigqueue(SIGUSR1)");
sigqueue( 0, SIGUSR1, value );
 
// Send the signal via kill
CYG_TEST_INFO( "Main: calling kill(0, SIGUSR2)");
kill( 0, SIGUSR2 );
 
// Wait for thread1 to call pause()
CYG_TEST_INFO( "Main: calling sleep(1)");
sleep(1);
 
// And again
CYG_TEST_INFO( "Main: calling kill(0, SIGUSR2)");
kill( 0, SIGUSR2 );
 
// Set up an alarm for 1 second hence
CYG_TEST_INFO( "Main: calling alarm(1)");
alarm(1);
// Wait for alarm signal to be delivered to thread1
CYG_TEST_INFO( "Main: calling sleep(2)");
sleep(2);
// Now join with thread1
CYG_TEST_INFO( "Main: calling pthread_join()");
pthread_join( thread1, &retval );
 
CYG_TEST_CHECK( sigusr2_called == 2, "SIGUSR2 signal handler not called twice" );
 
CYG_TEST_CHECK( sigalrm_called == 1, "SIGALRM signal handler not called" );
// check retval
if( (long)retval == 0x12345678+SIGUSR1 )
CYG_TEST_PASS_FINISH( "signal1" );
else
CYG_TEST_FAIL_FINISH( "signal1" );
}
 
#endif
 
//--------------------------------------------------------------------------
// end of signal1.c
/v2_0/tests/signal2.c
0,0 → 1,313
//==========================================================================
//
// signal2.cxx
//
// POSIX signal test 2
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: jlarmour
// Date: 2000-04-10
// Description: Tests POSIX signal functionality.
//
//####DESCRIPTIONEND####
//==========================================================================
 
#include <pkgconf/isoinfra.h>
#include <cyg/hal/hal_intr.h> // For exception codes
 
#include <sys/types.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
 
#include <setjmp.h>
 
#include <cyg/infra/testcase.h>
 
#if CYGINT_ISO_SETJMP == 0
# define NA_MSG "Requires setjmp/longjmp implementation"
#elif !defined(CYGPKG_POSIX_SIGNALS)
# define NA_MSG "POSIX signals not enabled"
#endif
 
#ifdef NA_MSG
void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA( NA_MSG );
}
#else
 
//--------------------------------------------------------------------------
// Local variables
 
static jmp_buf jbuf;
 
//--------------------------------------------------------------------------
 
// PowerPC is a special case as it has the alignment exception, but it
// doesn't trigger for this function unless in little-endian mode (although
// the exception exists for other instructions not used by this function so
// CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS will still be defined
 
#if defined(CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS) && !(defined(CYGPKG_HAL_POWERPC) && (CYG_BYTEORDER==CYG_MSBFIRST))
 
static void
cause_unaligned_access(void)
{
volatile int x;
volatile CYG_ADDRESS p=(CYG_ADDRESS) &jbuf;
 
x = *(volatile int *)(p+1);
 
} // cause_unaligned_access()
 
#endif
 
//--------------------------------------------------------------------------
 
#ifdef CYGNUM_HAL_EXCEPTION_DATA_ACCESS
 
static void
cause_illegal_access(void)
{
#ifdef CYGPKG_HAL_I386
 
// In the x86 architecture, although we have the DATA_ACCESS
// exception available, it is not possible to provoke it using the
// normal code of this test. This is because the normal segments we
// have installed in the segment registers cover all of memory. Instead we
// set GS to a descriptor that does not cover 0xF0000000-0xFFFFFFFF and
// poke at that.
 
__asm__ ( "movw $0x20,%%ax\n"
"movw %%ax,%%gs\n"
"movl %%gs:0xF0000000,%%eax\n"
:
:
: "eax"
);
#else
volatile int x;
volatile CYG_ADDRESS p=(CYG_ADDRESS) &jbuf;
 
do
{
x = *(volatile int *)(p);
p += (CYG_ADDRESS)0x100000;
} while( p != (CYG_ADDRESS)&jbuf );
 
#endif
} // cause_illegal_access()
 
#endif
 
//--------------------------------------------------------------------------
 
#ifdef CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO
 
// num must always be 0 - do it this way in case the optimizer tries to
// get smart
 
static int
cause_fpe(int num)
{
double a;
 
a = 1.0/num; // Depending on FPU emulation and/or
// the FPU architecture, this may
// cause an exception.
// (float division by zero)
 
return ((int)a)/num; // This may cause an exception if
// the architecture supports it.
// (integer division by zero).
} // cause_fpe()
 
#endif
 
//--------------------------------------------------------------------------
// Signal handler functions
 
static void sigsegv( int signo )
{
CYG_TEST_INFO( "sigsegv() handler called" );
CYG_TEST_CHECK( signo == SIGSEGV, "Signal not SIGSEGV");
 
longjmp( jbuf, 1 );
}
 
static void sigbus( int signo )
{
CYG_TEST_INFO( "sigbus() handler called" );
CYG_TEST_CHECK( signo == SIGBUS, "Signal not SIGBUS");
 
longjmp( jbuf, 1 );
}
 
static void sigfpe( int signo )
{
CYG_TEST_INFO( "sigfpe() handler called" );
CYG_TEST_CHECK( signo == SIGFPE, "Signal not SIGFPE");
 
longjmp( jbuf, 1 );
}
 
 
//--------------------------------------------------------------------------
 
int main(int argc, char **argv)
{
int ret;
sigset_t mask;
struct sigaction sa;
CYG_TEST_INIT();
 
// Make a full signal set
sigfillset( &mask );
 
// Install signal handlers
 
sa.sa_mask = mask;
sa.sa_flags = 0;
 
sa.sa_handler = sigsegv;
ret = sigaction( SIGSEGV, &sa, NULL );
CYG_TEST_CHECK( ret == 0 , "sigaction returned error");
 
sa.sa_handler = sigbus;
ret = sigaction( SIGBUS, &sa, NULL );
CYG_TEST_CHECK( ret == 0 , "sigaction returned error");
 
sa.sa_handler = sigfpe;
ret = sigaction( SIGFPE, &sa, NULL );
CYG_TEST_CHECK( ret == 0 , "sigaction returned error");
 
// now make an empty signal set
sigemptyset( &mask );
// Now reset the various exception handlers to eCos handlers so that we
// have control; this is the target side equivalent of the CYG_TEST_GDBCMD
// lines above:
#ifdef HAL_VSR_SET_TO_ECOS_HANDLER
// Reclaim the VSR off CygMon possibly
#ifdef CYGNUM_HAL_EXCEPTION_DATA_ACCESS
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_ACCESS, NULL );
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS, NULL );
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS, NULL );
#endif
#ifdef CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION, NULL );
#endif
#ifdef CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO
HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO, NULL );
#endif
#endif
 
// PowerPC is a special case as it has the alignment exception, but it
// doesn't trigger for this function unless in little-endian mode (although
// the exception exists for other instructions not used by this function so
// CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS will still be defined
 
#if defined(CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS) && !(defined(CYGPKG_HAL_POWERPC) && (CYG_BYTEORDER==CYG_MSBFIRST))
CYG_TEST_INFO("Test 1 - provoke unaligned access");
if( setjmp( jbuf ) == 0 )
{
pthread_sigmask( SIG_SETMASK, &mask, NULL );
cause_unaligned_access();
CYG_TEST_FAIL("Didn't cause exception");
}
 
#else
 
CYG_TEST_INFO("Test 1 - provoke unaligned access - not supported");
 
#endif
 
#ifdef CYGNUM_HAL_EXCEPTION_DATA_ACCESS
CYG_TEST_INFO("Test 2 - provoke illegal access");
if( setjmp( jbuf ) == 0 )
{
pthread_sigmask( SIG_SETMASK, &mask, NULL );
cause_illegal_access();
CYG_TEST_FAIL("Didn't cause exception");
}
 
#else
 
CYG_TEST_INFO("Test 1 - provoke illegal access - not supported");
 
#endif
#ifdef CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO
CYG_TEST_INFO("Test 3 - provoke FP error");
 
if( setjmp( jbuf ) == 0 )
{
pthread_sigmask( SIG_SETMASK, &mask, NULL );
cause_fpe(0);
CYG_TEST_FAIL("Didn't cause exception");
}
 
#else
 
CYG_TEST_INFO("Test 3 - provoke FP error - not supported");
#endif
 
CYG_TEST_PASS_FINISH( "signal2" );
}
 
#endif // ifndef NA_MSG
 
//--------------------------------------------------------------------------
// end of signal1.c
/v2_0/tests/signal3.c
0,0 → 1,174
//==========================================================================
//
// signal3.cxx
//
// POSIX signal test 3
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2003-01-30
// Description: Tests POSIX signal functionality.
//
//####DESCRIPTIONEND####
//==========================================================================
 
#include <cyg/infra/testcase.h>
#include <pkgconf/posix.h>
 
#if !defined(CYGPKG_POSIX_SIGNALS)
#define NA_MSG "POSIX signals not enabled"
#elif !defined(CYGPKG_POSIX_PTHREAD)
#define NA_MSG "POSIX threads not enabled"
#endif
 
#ifdef NA_MSG
void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA(NA_MSG);
}
#else
 
#include <signal.h>
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <cyg/infra/diag.h>
 
volatile int sigusr1_called = 0;
 
//--------------------------------------------------------------------------
// Signal handler functions
 
static void sigusr1( int signo )
{
CYG_TEST_INFO( "sigusr1() handler called" );
CYG_TEST_CHECK( signo == SIGUSR1, "Signal not SIGUSR1");
 
sigusr1_called++;
}
 
//--------------------------------------------------------------------------
 
int main (int argc, char **argv)
{
int ret_val;
sigset_t set;
int sig;
struct itimerspec timerValue; // Timeout value on eCos
timer_t timer1; // Timer
struct sigevent sev;
 
CYG_TEST_INIT();
 
{
struct sigaction sa;
 
sa.sa_handler = sigusr1;
sigfillset( &sa.sa_mask );
sa.sa_flags = 0;
 
ret_val = sigaction( SIGUSR1, &sa, NULL );
 
CYG_TEST_CHECK( ret_val == 0 , "sigaction returned error");
}
// unblock all the signals
sigfillset (&set);
pthread_sigmask (SIG_UNBLOCK, &set, (sigset_t*)NULL);
//--------------------------------------------------------------------
// <start of timer initialization section>
//--------------------------------------------------------------------
// Notification type --- Deliver the signal
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR1;
sev.sigev_value.sival_int = 0xABCDEF01;
// Timer values --- 1 Second
timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;
ret_val = timer_create (CLOCK_REALTIME, &sev, &timer1);
 
CYG_TEST_CHECK( ret_val==0, "Error in creating the timer");
 
ret_val = timer_settime (timer1, 0, &timerValue, NULL );
CYG_TEST_CHECK( ret_val==0,"Error in setting the time");
 
//--------------------------------------------------------------------
// <end of timer initialization section>
//--------------------------------------------------------------------
 
CYG_TEST_INFO ("Timer initialisation is completed..");
 
CYG_TEST_INFO ("Calling pause()");
ret_val = pause();
CYG_TEST_CHECK( ret_val==-1, "pause() did not return -1");
CYG_TEST_CHECK( EINTR==errno, "errno set to EINTR");
CYG_TEST_CHECK( sigusr1_called==1, "Siguser1 handler not called");
// Block all the signals
sigfillset (&set);
pthread_sigmask (SIG_BLOCK, &set, (sigset_t*)NULL);
 
CYG_TEST_INFO ("Calling sigwait()");
// Wait for any signal to arrive
sigfillset (&set);
ret_val = sigwait (&set, &sig);
 
CYG_TEST_CHECK( ret_val==0, "sigwait returned error");
CYG_TEST_CHECK( sig==SIGUSR1, "sigwait returned wrong signo!");
CYG_TEST_CHECK( sigusr1_called==1, "Siguser1 handler called!");
CYG_TEST_INFO ("Program terminating");
 
CYG_TEST_PASS_FINISH( "signal3" );
return 0;
}
 
 
#endif
 
//--------------------------------------------------------------------------
// end of signal3.c
/v2_0/tests/timer1.c
0,0 → 1,343
//==========================================================================
//
// timer1.cxx
//
// POSIX signal test 1
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-04-10
// Description: Tests POSIX signal functionality.
//
//####DESCRIPTIONEND####
//==========================================================================
 
#include <cyg/infra/testcase.h>
#include <pkgconf/posix.h>
 
#ifndef CYGPKG_POSIX_SIGNALS
#define NA_MSG "No POSIX signals"
#elif !defined(CYGPKG_POSIX_TIMERS)
#define NA_MSG "No POSIX timers"
#endif
 
#ifdef NA_MSG
void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA(NA_MSG);
}
#else
 
#include <sys/types.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <time.h>
 
//--------------------------------------------------------------------------
// Thread stack.
 
char thread1_stack[PTHREAD_STACK_MIN*2];
char thread2_stack[PTHREAD_STACK_MIN*2];
 
//--------------------------------------------------------------------------
// Local variables
 
// Sync semaphore
sem_t sem;
 
// Thread IDs
pthread_t thread1;
pthread_t thread2;
 
timer_t timer1;
timer_t timer2;
 
volatile int sigusr1_called = 0;
volatile int sigusr2_called = 0;
 
//--------------------------------------------------------------------------
// Signal handler functions
 
static void sigusr1( int signo, siginfo_t *info, void *context )
{
CYG_TEST_INFO( "sigusr1() handler called" );
CYG_TEST_CHECK( signo == SIGUSR1, "Signal not SIGUSR1");
CYG_TEST_CHECK( signo == info->si_signo, "Bad signal number in siginfo" );
CYG_TEST_CHECK( info->si_code == SI_TIMER, "Siginfo code not SI_TIMER" );
CYG_TEST_CHECK( info->si_value.sival_int == 0xABCDEF01, "Siginfo value wrong");
CYG_TEST_CHECK( pthread_equal(pthread_self(), thread1), "Not called in thread1");
 
sigusr1_called++;
}
 
static void sigusr2( int signo, siginfo_t *info, void *context )
{
CYG_TEST_INFO( "sigusr2() handler called" );
CYG_TEST_CHECK( signo == SIGUSR2, "Signal not SIGUSR2");
CYG_TEST_CHECK( signo == info->si_signo, "Bad signal number in siginfo" );
CYG_TEST_CHECK( info->si_code == SI_TIMER, "Siginfo code not SI_TIMER" );
CYG_TEST_CHECK( info->si_value.sival_int == 0xABCDEF02, "Siginfo value wrong");
CYG_TEST_CHECK( pthread_equal(pthread_self(), thread2), "Not called in thread2");
 
sigusr2_called++;
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry1( void *arg)
{
sigset_t mask;
 
CYG_TEST_INFO( "Thread 1 running" );
 
// Make a full set
sigfillset( &mask );
 
// remove USR1 signal
sigdelset( &mask, SIGUSR1 );
 
// Set signal mask
pthread_sigmask( SIG_SETMASK, &mask, NULL );
// Get main thread going again
sem_post( &sem );
 
while( sigusr1_called < 1 )
{
CYG_TEST_INFO( "Thread1: calling pause()");
pause();
}
 
CYG_TEST_INFO( "Thread1: calling pthread_exit()");
pthread_exit( arg );
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry2( void *arg)
{
sigset_t mask;
CYG_TEST_INFO( "Thread 2 running" );
 
// Make a full set
sigfillset( &mask );
 
// remove USR2 signal
sigdelset( &mask, SIGUSR2 );
 
// Set signal mask
pthread_sigmask( SIG_SETMASK, &mask, NULL );
// Get main thread going again
sem_post( &sem );
 
while( sigusr2_called < 6 )
{
CYG_TEST_INFO( "Thread2: calling pause()");
pause();
}
 
CYG_TEST_INFO( "Thread2: calling pthread_exit()");
pthread_exit( arg );
}
 
//--------------------------------------------------------------------------
 
int main(int argc, char **argv)
{
int ret;
sigset_t mask;
pthread_attr_t attr;
void *retval;
CYG_TEST_INIT();
 
// Make a full signal set
sigfillset( &mask );
 
// Install signal handlers
{
struct sigaction sa;
 
sa.sa_sigaction = sigusr1;
sa.sa_mask = mask;
sa.sa_flags = SA_SIGINFO;
 
ret = sigaction( SIGUSR1, &sa, NULL );
 
CYG_TEST_CHECK( ret == 0 , "sigaction returned error");
}
{
struct sigaction sa;
 
sa.sa_sigaction = sigusr2;
sa.sa_mask = mask;
sa.sa_flags = SA_SIGINFO;
 
ret = sigaction( SIGUSR2, &sa, NULL );
 
CYG_TEST_CHECK( ret == 0 , "sigaction returned error");
}
 
 
// Create the timers
 
{
struct sigevent sev;
struct itimerspec value;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR1;
sev.sigev_value.sival_int = 0xABCDEF01;
 
value.it_value.tv_sec = 1;
value.it_value.tv_nsec = 0;
value.it_interval.tv_sec = 0;
value.it_interval.tv_nsec = 0;
ret = timer_create( CLOCK_REALTIME, &sev, &timer1 );
 
CYG_TEST_CHECK( ret == 0 , "timer_create returned error");
 
ret = timer_settime( timer1, 0, &value, NULL );
 
CYG_TEST_CHECK( ret == 0 , "timer_settime returned error");
}
 
#if 1
{
struct sigevent sev;
struct itimerspec value;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR2;
sev.sigev_value.sival_int = 0xABCDEF02;
 
value.it_value.tv_sec = 0;
value.it_value.tv_nsec = 500000000;
value.it_interval.tv_sec = 0;
value.it_interval.tv_nsec = 250000000;
ret = timer_create( CLOCK_REALTIME, &sev, &timer2 );
 
CYG_TEST_CHECK( ret == 0 , "timer_create returned error");
 
ret = timer_settime( timer2, 0, &value, NULL );
 
CYG_TEST_CHECK( ret == 0 , "timer_settime returned error");
}
#endif
// Mask all signals
pthread_sigmask( SIG_SETMASK, &mask, NULL );
sem_init( &sem, 0, 0 );
// Create test threads
 
{
pthread_attr_init( &attr );
 
pthread_attr_setstackaddr( &attr, (void *)&thread1_stack[sizeof(thread1_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread1_stack) );
 
pthread_create( &thread1,
&attr,
pthread_entry1,
(void *)0x12345671);
}
 
{
pthread_attr_init( &attr );
 
pthread_attr_setstackaddr( &attr, (void *)&thread2_stack[sizeof(thread2_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread2_stack) );
 
pthread_create( &thread2,
&attr,
pthread_entry2,
(void *)0x12345672);
}
// Wait for other thread to get started
CYG_TEST_INFO( "Main: calling sem_wait()");
sem_wait( &sem );
CYG_TEST_INFO( "Main: calling sem_wait() again");
sem_wait( &sem );
 
// Now join with thread1
CYG_TEST_INFO( "Main: calling pthread_join(thread1)");
pthread_join( thread1, &retval );
 
CYG_TEST_CHECK( retval == (void *)0x12345671, "Thread 1 retval wrong");
// And thread 2
CYG_TEST_INFO( "Main: calling pthread_join(thread2)");
pthread_join( thread2, &retval );
 
// now delete the timers
CYG_TEST_INFO( "Main: calling timer_delete(timer1)");
ret = timer_delete( timer1 );
 
CYG_TEST_CHECK( ret == 0 , "timer_delete(timer1) returned error");
 
CYG_TEST_INFO( "Main: calling timer_delete(timer2)");
ret = timer_delete( timer2 );
 
CYG_TEST_CHECK( ret == 0 , "timer_delete(timer2) returned error");
 
CYG_TEST_CHECK( retval == (void *)0x12345672, "Thread 2 retval wrong");
CYG_TEST_CHECK( sigusr1_called == 1, "SIGUSR1 signal handler not called once" );
CYG_TEST_CHECK( sigusr2_called == 6, "SIGUSR2 signal handler not called six times" );
 
CYG_TEST_PASS_FINISH( "timer1" );
}
 
#endif
 
//--------------------------------------------------------------------------
// end of timer1.c
/v2_0/tests/tm_basic.cxx
0,0 → 1,1696
//==========================================================================
//
// tm_basic.cxx
//
// Basic timing test / scaffolding
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Jonathan Larmour
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas,nickg
// Contributors: jlarmour
// Date: 1998-10-19
// Description: Very simple kernel timing test
//####DESCRIPTIONEND####
//==========================================================================
 
 
#include <cyg/infra/testcase.h>
#include <cyg/infra/diag.h>
#include <pkgconf/posix.h>
#include <pkgconf/system.h>
#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#endif
 
#ifndef CYGPKG_POSIX_SIGNALS
#define NA_MSG "No POSIX signals"
#elif !defined(CYGPKG_POSIX_TIMERS)
#define NA_MSG "No POSIX timers"
#elif !defined(CYGPKG_POSIX_PTHREAD)
#define NA_MSG "POSIX threads not enabled"
#elif !defined(CYGFUN_KERNEL_API_C)
#define NA_MSG "Kernel C API not enabled"
#elif !defined(CYGSEM_KERNEL_SCHED_MLQUEUE)
#define NA_MSG "Kernel mlqueue scheduler not enabled"
#elif !defined(CYGVAR_KERNEL_COUNTERS_CLOCK)
#define NA_MSG "Kernel clock not enabled"
#elif CYGNUM_KERNEL_SCHED_PRIORITIES <= 12
#define NA_MSG "Kernel scheduler properties <= 12"
#endif
 
//==========================================================================
 
#ifdef NA_MSG
extern "C" void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA(NA_MSG);
}
#else
 
#include <pkgconf/kernel.h>
#include <pkgconf/hal.h>
 
#include <cyg/kernel/sched.hxx>
#include <cyg/kernel/thread.hxx>
#include <cyg/kernel/thread.inl>
#include <cyg/kernel/mutex.hxx>
#include <cyg/kernel/sema.hxx>
#include <cyg/kernel/sched.inl>
#include <cyg/kernel/clock.hxx>
#include <cyg/kernel/clock.inl>
#include <cyg/kernel/kapi.h>
 
#include <cyg/infra/testcase.h>
 
#include <cyg/kernel/test/stackmon.h>
#include CYGHWR_MEMORY_LAYOUT_H
 
 
// POSIX headers
 
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
 
//==========================================================================
// Define this to see the statistics with the first sample datum removed.
// This can expose the effects of caches on the speed of operations.
 
#undef STATS_WITHOUT_FIRST_SAMPLE
 
//==========================================================================
 
// Structure used to keep track of times
typedef struct fun_times {
cyg_uint32 start;
cyg_uint32 end;
} fun_times;
 
//==========================================================================
 
#define STACK_SIZE (PTHREAD_STACK_MIN*2)
 
// Defaults
#define NTEST_THREADS 16
#define NMUTEXES 32
#define NMBOXES 32
#define NSEMAPHORES 32
#define NTIMERS 32
 
 
#define NSAMPLES 32
#define NTHREAD_SWITCHES 128
#define NSCHEDS 128
 
#define NSAMPLES_SIM 2
#define NTEST_THREADS_SIM 2
#define NTHREAD_SWITCHES_SIM 4
#define NMUTEXES_SIM 2
#define NMBOXES_SIM 2
#define NSEMAPHORES_SIM 2
#define NSCHEDS_SIM 4
#define NTIMERS_SIM 2
 
//==========================================================================
 
static int nsamples;
static int ntest_threads;
static int nthread_switches;
static int nmutexes;
static int nmboxes;
static int nsemaphores;
static int nscheds;
static int ntimers;
 
static char stacks[NTEST_THREADS][STACK_SIZE];
static pthread_t threads[NTEST_THREADS];
static int overhead;
static sem_t synchro;
static fun_times thread_ft[NTEST_THREADS];
 
static fun_times test2_ft[NTHREAD_SWITCHES];
 
static pthread_mutex_t test_mutexes[NMUTEXES];
static fun_times mutex_ft[NMUTEXES];
static pthread_t mutex_test_thread_handle;
 
#if 0
static cyg_mbox test_mboxes[NMBOXES];
static cyg_handle_t test_mbox_handles[NMBOXES];
static fun_times mbox_ft[NMBOXES];
static cyg_thread mbox_test_thread;
static cyg_handle_t mbox_test_thread_handle;
#endif
 
static sem_t test_semaphores[NSEMAPHORES];
static fun_times semaphore_ft[NSEMAPHORES];
static pthread_t semaphore_test_thread_handle;
 
static fun_times sched_ft[NSCHEDS];
 
static timer_t timers[NTIMERS];
static fun_times timer_ft[NTIMERS];
 
static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
static long ns_per_system_clock;
 
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY)
// Data kept by kernel real time clock measuring clock interrupt latency
extern cyg_tick_count total_clock_latency, total_clock_interrupts;
extern cyg_int32 min_clock_latency, max_clock_latency;
extern bool measure_clock_latency;
#endif
 
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)
extern cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls;
extern cyg_int32 min_clock_dsr_latency, max_clock_dsr_latency;
extern bool measure_clock_latency;
#endif
 
//==========================================================================
 
void run_sched_tests(void);
void run_thread_tests(void);
void run_thread_switch_test(void);
void run_mutex_tests(void);
void run_mutex_circuit_test(void);
void run_mbox_tests(void);
void run_mbox_circuit_test(void);
void run_semaphore_tests(void);
void run_semaphore_circuit_test(void);
void run_timer_tests(void);
 
//==========================================================================
 
#ifndef max
#define max(n,m) (m > n ? n : m)
#endif
 
//==========================================================================
// Wait until a clock tick [real time clock] has passed. This should keep it
// from happening again during a measurement, thus minimizing any fluctuations
void
wait_for_tick(void)
{
cyg_tick_count_t tv0, tv1;
tv0 = cyg_current_time();
while (true) {
tv1 = cyg_current_time();
if (tv1 != tv0) break;
}
}
 
//--------------------------------------------------------------------------
// Display a number of ticks as microseconds
// Note: for improved calculation significance, values are kept in ticks*1000
void
show_ticks_in_us(cyg_uint32 ticks)
{
long long ns;
ns = (ns_per_system_clock * (long long)ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
ns += 5; // for rounding to .01us
diag_printf("%5d.%02d", (int)(ns/1000), (int)((ns%1000)/10));
}
 
//--------------------------------------------------------------------------
//
// If the kernel is instrumented to measure clock interrupt latency, these
// measurements can be drastically perturbed by printing via "diag_printf()"
// since that code may run with interrupts disabled for long periods.
//
// In order to get accurate/reasonable latency figures _for the kernel
// primitive functions beint tested_, the kernel's latency measurements
// are suspended while the printing actually takes place.
//
// The measurements are reenabled after the printing, thus allowing for
// fair measurements of the kernel primitives, which are not distorted
// by the printing mechanisms.
 
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
void
disable_clock_latency_measurement(void)
{
wait_for_tick();
measure_clock_latency = false;
}
 
void
enable_clock_latency_measurement(void)
{
wait_for_tick();
measure_clock_latency = true;
}
 
// Ensure that the measurements are reasonable (no startup anomalies)
void
reset_clock_latency_measurement(void)
{
disable_clock_latency_measurement();
total_clock_latency = 0;
total_clock_interrupts = 0;
min_clock_latency = 0x7FFFFFFF;
max_clock_latency = 0;
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)
total_clock_dsr_latency = 0;
total_clock_dsr_calls = 0;
min_clock_dsr_latency = 0x7FFFFFFF;
max_clock_dsr_latency = 0;
#endif
enable_clock_latency_measurement();
}
#else
#define disable_clock_latency_measurement()
#define enable_clock_latency_measurement()
#define reset_clock_latency_measurement()
#endif
 
//--------------------------------------------------------------------------
 
void
show_times_hdr(void)
{
disable_clock_latency_measurement();
diag_printf("\n");
diag_printf(" Confidence\n");
diag_printf(" Ave Min Max Var Ave Min Function\n");
diag_printf(" ====== ====== ====== ====== ========== ========\n");
enable_clock_latency_measurement();
}
 
void
show_times_detail(fun_times ft[], int nsamples, char *title, bool ignore_first)
{
int i, delta, min, max, con_ave, con_min, ave_dev;
int start_sample, total_samples;
cyg_int32 total, ave;
 
if (ignore_first) {
start_sample = 1;
total_samples = nsamples-1;
} else {
start_sample = 0;
total_samples = nsamples;
}
total = 0;
min = 0x7FFFFFFF;
max = 0;
for (i = start_sample; i < nsamples; i++) {
if (ft[i].end < ft[i].start) {
// Clock wrapped around (timer tick)
delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
} else {
delta = ft[i].end - ft[i].start;
}
delta -= overhead;
if (delta < 0) delta = 0;
delta *= 1000;
total += delta;
if (delta < min) min = delta;
if (delta > max) max = delta;
}
ave = total / total_samples;
total = 0;
ave_dev = 0;
for (i = start_sample; i < nsamples; i++) {
if (ft[i].end < ft[i].start) {
// Clock wrapped around (timer tick)
delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
} else {
delta = ft[i].end - ft[i].start;
}
delta -= overhead;
if (delta < 0) delta = 0;
delta *= 1000;
delta = delta - ave;
if (delta < 0) delta = -delta;
ave_dev += delta;
}
ave_dev /= total_samples;
con_ave = 0;
con_min = 0;
for (i = start_sample; i < nsamples; i++) {
if (ft[i].end < ft[i].start) {
// Clock wrapped around (timer tick)
delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
} else {
delta = ft[i].end - ft[i].start;
}
delta -= overhead;
if (delta < 0) delta = 0;
delta *= 1000;
if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++;
if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++;
}
con_ave = (con_ave * 100) / total_samples;
con_min = (con_min * 100) / total_samples;
show_ticks_in_us(ave);
show_ticks_in_us(min);
show_ticks_in_us(max);
show_ticks_in_us(ave_dev);
disable_clock_latency_measurement();
diag_printf(" %3d%% %3d%%", con_ave, con_min);
diag_printf(" %s\n", title);
enable_clock_latency_measurement();
}
 
void
show_times(fun_times ft[], int nsamples, char *title)
{
show_times_detail(ft, nsamples, title, false);
#ifdef STATS_WITHOUT_FIRST_SAMPLE
show_times_detail(ft, nsamples, "", true);
#endif
}
 
//--------------------------------------------------------------------------
 
void
show_test_parameters(void)
{
disable_clock_latency_measurement();
diag_printf("\nTesting parameters:\n");
diag_printf(" Clock samples: %5d\n", nsamples);
diag_printf(" Threads: %5d\n", ntest_threads);
diag_printf(" Thread switches: %5d\n", nthread_switches);
diag_printf(" Mutexes: %5d\n", nmutexes);
diag_printf(" Mailboxes: %5d\n", nmboxes);
diag_printf(" Semaphores: %5d\n", nsemaphores);
diag_printf(" Scheduler operations: %5d\n", nscheds);
diag_printf(" Timers: %5d\n", ntimers);
diag_printf("\n");
enable_clock_latency_measurement();
}
 
void
end_of_test_group(void)
{
disable_clock_latency_measurement();
diag_printf("\n");
enable_clock_latency_measurement();
}
 
//--------------------------------------------------------------------------
// Compute a name for a thread
 
char *
thread_name(char *basename, int indx) {
return "<<NULL>>"; // Not currently used
}
 
//--------------------------------------------------------------------------
// test0 - null test, just return
 
void *
test0(void *indx)
{
return indx;
}
 
//--------------------------------------------------------------------------
// test3 - loop, yeilding repeatedly and checking for cancellation
 
void *
test3(void *indx)
{
for(;;)
{
sched_yield();
pthread_testcancel();
}
return indx;
}
 
//--------------------------------------------------------------------------
// test1 - empty test, simply exit. Last thread signals parent.
 
void *
test1( void *indx)
{
if ((cyg_uint32)indx == (cyg_uint32)(ntest_threads-1)) {
sem_post(&synchro); // Signal that last thread is dying
}
return indx;
}
 
//--------------------------------------------------------------------------
// test2 - measure thread switch times
 
void *
test2(void *indx)
{
int i;
for (i = 0; i < nthread_switches; i++) {
if ((int)indx == 0) {
HAL_CLOCK_READ(&test2_ft[i].start);
} else {
HAL_CLOCK_READ(&test2_ft[i].end);
}
sched_yield();
}
if ((int)indx == 1) {
sem_post(&synchro);
}
 
return indx;
}
 
//--------------------------------------------------------------------------
// Full-circuit mutex unlock/lock test
 
void *
mutex_test(void * indx)
{
int i;
pthread_mutex_lock(&test_mutexes[0]);
for (i = 0; i < nmutexes; i++) {
sem_wait(&synchro);
wait_for_tick(); // Wait until the next clock tick to minimize aberations
HAL_CLOCK_READ(&mutex_ft[i].start);
pthread_mutex_unlock(&test_mutexes[0]);
pthread_mutex_lock(&test_mutexes[0]);
sem_post(&synchro);
}
return indx;
}
 
//--------------------------------------------------------------------------
// Full-circuit mbox put/get test
 
#if 0
void
mbox_test(cyg_uint32 indx)
{
void *item;
do {
item = cyg_mbox_get(test_mbox_handles[0]);
HAL_CLOCK_READ(&mbox_ft[(int)item].end);
cyg_semaphore_post(&synchro);
} while ((int)item != (nmboxes-1));
cyg_thread_exit(0);
}
#endif
 
//--------------------------------------------------------------------------
// Full-circuit semaphore post/wait test
 
void *
semaphore_test(void * indx)
{
int i;
for (i = 0; i < nsemaphores; i++) {
sem_wait(&test_semaphores[0]);
HAL_CLOCK_READ(&semaphore_ft[i].end);
sem_post(&synchro);
}
return indx;
}
 
//--------------------------------------------------------------------------
//
// This set of tests is used to measure kernel primitives that deal with threads
//
 
void
run_thread_tests(void)
{
 
int i;
struct sched_param schedparam;
pthread_attr_t attr;
int policy;
void *retval;
// Set my priority higher than any I plan to create
schedparam.sched_priority = 30;
pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
 
// Initiaize thread creation attributes
 
pthread_attr_init( &attr );
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
schedparam.sched_priority = 10;
pthread_attr_setschedparam( &attr, &schedparam );
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntest_threads; i++) {
HAL_CLOCK_READ(&thread_ft[i].start);
 
pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
pthread_attr_setstacksize( &attr, STACK_SIZE );
pthread_create( &threads[i],
&attr,
test0,
(void *)i
);
HAL_CLOCK_READ(&thread_ft[i].end);
}
show_times(thread_ft, ntest_threads, "Create thread");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntest_threads; i++) {
HAL_CLOCK_READ(&thread_ft[i].start);
sched_yield();
HAL_CLOCK_READ(&thread_ft[i].end);
}
show_times(thread_ft, ntest_threads, "Yield thread [all lower priority]");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntest_threads; i++) {
HAL_CLOCK_READ(&thread_ft[i].start);
 
schedparam.sched_priority = 11;
pthread_attr_setschedparam( &attr, &schedparam );
pthread_setschedparam(threads[i], SCHED_RR, &schedparam);
 
HAL_CLOCK_READ(&thread_ft[i].end);
}
show_times(thread_ft, ntest_threads, "Set priority");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntest_threads; i++) {
HAL_CLOCK_READ(&thread_ft[i].start);
pthread_getschedparam( threads[i], &policy, &schedparam );
HAL_CLOCK_READ(&thread_ft[i].end);
}
show_times(thread_ft, ntest_threads, "Get priority");
 
cyg_thread_delay(1); // Let the test threads run
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntest_threads; i++) {
HAL_CLOCK_READ(&thread_ft[i].start);
pthread_join(threads[i], &retval);
HAL_CLOCK_READ(&thread_ft[i].end);
}
show_times(thread_ft, ntest_threads, "Join exited thread");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntest_threads; i++) {
HAL_CLOCK_READ(&thread_ft[i].start);
sched_yield();
HAL_CLOCK_READ(&thread_ft[i].end);
}
show_times(thread_ft, ntest_threads, "Yield [no other] thread");
 
// Recreate the test set
 
schedparam.sched_priority = 10;
pthread_attr_setschedparam( &attr, &schedparam );
for (i = 0; i < ntest_threads; i++) {
pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
pthread_attr_setstacksize( &attr, STACK_SIZE );
pthread_create( &threads[i],
&attr,
test3,
(void *)i
);
}
 
cyg_thread_delay(1); // Let the test threads run
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntest_threads; i++) {
HAL_CLOCK_READ(&thread_ft[i].start);
pthread_cancel(threads[i]);
HAL_CLOCK_READ(&thread_ft[i].end);
}
show_times(thread_ft, ntest_threads, "Cancel [running] thread");
 
cyg_thread_delay(1); // Let the test threads do their cancellations
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntest_threads; i++) {
HAL_CLOCK_READ(&thread_ft[i].start);
pthread_join(threads[i], &retval);
HAL_CLOCK_READ(&thread_ft[i].end);
}
show_times(thread_ft, ntest_threads, "Join [cancelled] thread");
 
// Set my priority lower than any I plan to create
schedparam.sched_priority = 5;
pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
// Set up the end-of-threads synchronizer
sem_init(&synchro, 0, 0);
 
schedparam.sched_priority = 10;
pthread_attr_setschedparam( &attr, &schedparam );
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntest_threads; i++) {
HAL_CLOCK_READ(&thread_ft[i].start);
 
pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
pthread_attr_setstacksize( &attr, STACK_SIZE );
pthread_create( &threads[i],
&attr,
test2,
(void *)i
);
HAL_CLOCK_READ(&thread_ft[i].end);
}
show_times(thread_ft, ntest_threads, "Create [high priority] thread");
 
sem_wait(&synchro); // Wait for all threads to finish
 
// Make sure they are all dead
for (i = 0; i < ntest_threads; i++) {
pthread_join(threads[i], &retval);
}
 
run_thread_switch_test();
end_of_test_group();
 
}
 
//--------------------------------------------------------------------------
 
void
run_thread_switch_test(void)
{
 
int i;
struct sched_param schedparam;
pthread_attr_t attr;
void *retval;
 
// Set my priority higher than any I plan to create
schedparam.sched_priority = 30;
pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
 
// Initiaize thread creation attributes
 
pthread_attr_init( &attr );
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
schedparam.sched_priority = 10;
pthread_attr_setschedparam( &attr, &schedparam );
// Set up the end-of-threads synchronizer
 
sem_init(&synchro, 0, 0);
// Set up for thread context switch
 
for (i = 0; i < 2; i++) {
pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
pthread_attr_setstacksize( &attr, STACK_SIZE );
pthread_create( &threads[i],
&attr,
test2,
(void *)i
);
}
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
sem_wait(&synchro);
 
show_times(test2_ft, nthread_switches, "Thread switch");
 
// Clean up
for (i = 0; i < 2; i++) {
pthread_join(threads[i], &retval);
}
 
}
 
 
//--------------------------------------------------------------------------
 
void
run_mutex_tests(void)
{
 
int i;
pthread_mutexattr_t attr;
 
pthread_mutexattr_init( &attr );
// Mutex primitives
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmutexes; i++) {
HAL_CLOCK_READ(&mutex_ft[i].start);
pthread_mutex_init(&test_mutexes[i], &attr);
HAL_CLOCK_READ(&mutex_ft[i].end);
}
show_times(mutex_ft, nmutexes, "Init mutex");
 
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmutexes; i++) {
HAL_CLOCK_READ(&mutex_ft[i].start);
pthread_mutex_lock(&test_mutexes[i]);
HAL_CLOCK_READ(&mutex_ft[i].end);
}
show_times(mutex_ft, nmutexes, "Lock [unlocked] mutex");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmutexes; i++) {
HAL_CLOCK_READ(&mutex_ft[i].start);
pthread_mutex_unlock(&test_mutexes[i]);
HAL_CLOCK_READ(&mutex_ft[i].end);
}
show_times(mutex_ft, nmutexes, "Unlock [locked] mutex");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmutexes; i++) {
HAL_CLOCK_READ(&mutex_ft[i].start);
pthread_mutex_trylock(&test_mutexes[i]);
HAL_CLOCK_READ(&mutex_ft[i].end);
}
show_times(mutex_ft, nmutexes, "Trylock [unlocked] mutex");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmutexes; i++) {
HAL_CLOCK_READ(&mutex_ft[i].start);
pthread_mutex_trylock(&test_mutexes[i]);
HAL_CLOCK_READ(&mutex_ft[i].end);
}
show_times(mutex_ft, nmutexes, "Trylock [locked] mutex");
 
// Must unlock mutices before destroying them.
for (i = 0; i < nmutexes; i++) {
pthread_mutex_unlock(&test_mutexes[i]);
}
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmutexes; i++) {
HAL_CLOCK_READ(&mutex_ft[i].start);
pthread_mutex_destroy(&test_mutexes[i]);
HAL_CLOCK_READ(&mutex_ft[i].end);
}
show_times(mutex_ft, nmutexes, "Destroy mutex");
 
 
run_mutex_circuit_test();
end_of_test_group();
}
 
//--------------------------------------------------------------------------
 
void
run_mutex_circuit_test(void)
{
int i;
pthread_mutexattr_t mattr;
struct sched_param schedparam;
pthread_attr_t attr;
void *retval;
 
// Set my priority lower than any I plan to create
schedparam.sched_priority = 5;
pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
 
// Initiaize thread creation attributes
 
pthread_attr_init( &attr );
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
schedparam.sched_priority = 10;
pthread_attr_setschedparam( &attr, &schedparam );
// Set up for full mutex unlock/lock test
pthread_mutexattr_init( &mattr );
pthread_mutex_init(&test_mutexes[0], &mattr);
sem_init(&synchro, 0, 0);
 
pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] );
pthread_attr_setstacksize( &attr, STACK_SIZE );
pthread_create( &mutex_test_thread_handle,
&attr,
mutex_test,
(void *)0
);
// Need to raise priority so that this thread will block on the "lock"
schedparam.sched_priority = 20;
pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
for (i = 0; i < nmutexes; i++) {
sem_post(&synchro);
pthread_mutex_lock(&test_mutexes[0]);
HAL_CLOCK_READ(&mutex_ft[i].end);
pthread_mutex_unlock(&test_mutexes[0]);
sem_wait(&synchro);
}
pthread_join(mutex_test_thread_handle, &retval);
show_times(mutex_ft, nmutexes, "Unlock/Lock mutex");
 
}
 
 
//--------------------------------------------------------------------------
// Message queue tests
 
// Currently disabled, pending implementation of POSIX message queues
 
#if 0
void
run_mbox_tests(void)
{
int i, cnt;
void *item;
// Mailbox primitives
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cyg_mbox_create(&test_mbox_handles[i], &test_mboxes[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Create mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cnt = cyg_mbox_peek(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Peek [empty] mbox");
 
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cyg_mbox_put(test_mbox_handles[i], (void *)i);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Put [first] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cnt = cyg_mbox_peek(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Peek [1 msg] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cyg_mbox_put(test_mbox_handles[i], (void *)i);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Put [second] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cnt = cyg_mbox_peek(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Peek [2 msgs] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
item = cyg_mbox_get(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Get [first] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
item = cyg_mbox_get(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Get [second] mbox");
#endif // ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cyg_mbox_tryput(test_mbox_handles[i], (void *)i);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Tryput [first] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
item = cyg_mbox_peek_item(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Peek item [non-empty] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
item = cyg_mbox_tryget(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Tryget [non-empty] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
item = cyg_mbox_peek_item(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Peek item [empty] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
item = cyg_mbox_tryget(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Tryget [empty] mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cyg_mbox_waiting_to_get(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Waiting to get mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cyg_mbox_waiting_to_put(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Waiting to put mbox");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nmboxes; i++) {
HAL_CLOCK_READ(&mbox_ft[i].start);
cyg_mbox_delete(test_mbox_handles[i]);
HAL_CLOCK_READ(&mbox_ft[i].end);
}
show_times(mbox_ft, nmboxes, "Delete mbox");
 
run_mbox_circuit_test();
end_of_test_group();
}
 
//--------------------------------------------------------------------------
 
void
run_mbox_circuit_test(void)
{
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
int i;
// Set my priority lower than any I plan to create
cyg_thread_set_priority(cyg_thread_self(), 3);
// Set up for full mbox put/get test
cyg_mbox_create(&test_mbox_handles[0], &test_mboxes[0]);
cyg_semaphore_init(&synchro, 0);
cyg_thread_create(2, // Priority - just a number
mbox_test, // entry
0, // index
thread_name("thread", 0), // Name
&stacks[0][0], // Stack
STACK_SIZE, // Size
&mbox_test_thread_handle, // Handle
&mbox_test_thread // Thread data structure
);
cyg_thread_resume(mbox_test_thread_handle);
for (i = 0; i < nmboxes; i++) {
wait_for_tick(); // Wait until the next clock tick to minimize aberations
HAL_CLOCK_READ(&mbox_ft[i].start);
cyg_mbox_put(test_mbox_handles[0], (void *)i);
cyg_semaphore_wait(&synchro);
}
cyg_thread_delete(mbox_test_thread_handle);
show_times(mbox_ft, nmboxes, "Put/Get mbox");
#endif
}
 
#endif
 
//--------------------------------------------------------------------------
 
void
run_semaphore_tests(void)
{
 
int i;
int sem_val;
 
// Semaphore primitives
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nsemaphores; i++) {
HAL_CLOCK_READ(&semaphore_ft[i].start);
sem_init(&test_semaphores[i], 0, 0);
HAL_CLOCK_READ(&semaphore_ft[i].end);
}
show_times(semaphore_ft, nsemaphores, "Init semaphore");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nsemaphores; i++) {
HAL_CLOCK_READ(&semaphore_ft[i].start);
sem_post(&test_semaphores[i]);
HAL_CLOCK_READ(&semaphore_ft[i].end);
}
show_times(semaphore_ft, nsemaphores, "Post [0] semaphore");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nsemaphores; i++) {
HAL_CLOCK_READ(&semaphore_ft[i].start);
sem_wait(&test_semaphores[i]);
HAL_CLOCK_READ(&semaphore_ft[i].end);
}
show_times(semaphore_ft, nsemaphores, "Wait [1] semaphore");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nsemaphores; i++) {
HAL_CLOCK_READ(&semaphore_ft[i].start);
sem_trywait(&test_semaphores[i]);
HAL_CLOCK_READ(&semaphore_ft[i].end);
}
show_times(semaphore_ft, nsemaphores, "Trywait [0] semaphore");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nsemaphores; i++) {
sem_post(&test_semaphores[i]);
HAL_CLOCK_READ(&semaphore_ft[i].start);
sem_trywait(&test_semaphores[i]);
HAL_CLOCK_READ(&semaphore_ft[i].end);
}
show_times(semaphore_ft, nsemaphores, "Trywait [1] semaphore");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nsemaphores; i++) {
HAL_CLOCK_READ(&semaphore_ft[i].start);
sem_getvalue(&test_semaphores[i], &sem_val);
HAL_CLOCK_READ(&semaphore_ft[i].end);
}
show_times(semaphore_ft, nsemaphores, "Get value of semaphore");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < nsemaphores; i++) {
HAL_CLOCK_READ(&semaphore_ft[i].start);
sem_destroy(&test_semaphores[i]);
HAL_CLOCK_READ(&semaphore_ft[i].end);
}
show_times(semaphore_ft, nsemaphores, "Destroy semaphore");
 
run_semaphore_circuit_test();
end_of_test_group();
}
 
//--------------------------------------------------------------------------
 
void
run_semaphore_circuit_test(void)
{
 
int i;
struct sched_param schedparam;
pthread_attr_t attr;
void *retval;
 
// Set my priority lower than any I plan to create
schedparam.sched_priority = 5;
pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
 
// Initiaize thread creation attributes
 
pthread_attr_init( &attr );
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
schedparam.sched_priority = 10;
pthread_attr_setschedparam( &attr, &schedparam );
// Set up for full semaphore post/wait test
sem_init(&test_semaphores[0], 0, 0);
sem_init(&synchro, 0, 0);
 
pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] );
pthread_attr_setstacksize( &attr, STACK_SIZE );
pthread_create( &semaphore_test_thread_handle,
&attr,
semaphore_test,
(void *)0
);
for (i = 0; i < nsemaphores; i++) {
wait_for_tick(); // Wait until the next clock tick to minimize aberations
HAL_CLOCK_READ(&semaphore_ft[i].start);
sem_post(&test_semaphores[0]);
sem_wait(&synchro);
}
pthread_join(semaphore_test_thread_handle, &retval);
show_times(semaphore_ft, nsemaphores, "Post/Wait semaphore");
 
 
}
 
//--------------------------------------------------------------------------
 
// Timer callback function
void
sigrt0(int signo, siginfo_t *info, void *context)
{
diag_printf("sigrt0 called\n");
// empty call back
}
 
// Callback used to test determinancy
static volatile int timer_cnt;
void
sigrt1(int signo, siginfo_t *info, void *context)
{
if (timer_cnt == nscheds) return;
sched_ft[timer_cnt].start = 0;
HAL_CLOCK_READ(&sched_ft[timer_cnt++].end);
if (timer_cnt == nscheds) {
sem_post(&synchro);
}
}
 
static sem_t timer_sem;
 
static void
sigrt2(int signo, siginfo_t *info, void *context)
{
if (timer_cnt == nscheds) {
sem_post(&synchro);
sem_post(&timer_sem);
} else {
sched_ft[timer_cnt].start = 0;
sem_post(&timer_sem);
}
}
 
// Null thread, used to keep scheduler busy
void *
timer_test(void * id)
{
while (true) {
cyg_thread_yield();
pthread_testcancel();
}
 
return id;
}
 
// Thread that suspends itself at the first opportunity
void *
timer_test2(void *id)
{
while (timer_cnt != nscheds) {
HAL_CLOCK_READ(&sched_ft[timer_cnt++].end);
sem_wait(&timer_sem);
}
return id;
}
 
void
run_timer_tests(void)
{
int res;
int i;
struct sigaction sa;
struct sigevent sigev;
struct itimerspec tp;
// Install signal handlers
sigemptyset( &sa.sa_mask );
sa.sa_flags = SA_SIGINFO;
 
sa.sa_sigaction = sigrt0;
sigaction( SIGRTMIN, &sa, NULL );
 
sa.sa_sigaction = sigrt1;
sigaction( SIGRTMIN+1, &sa, NULL );
 
sa.sa_sigaction = sigrt2;
sigaction( SIGRTMIN+2, &sa, NULL );
 
// Set up common bits of sigevent
 
sigev.sigev_notify = SIGEV_SIGNAL;
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntimers; i++) {
HAL_CLOCK_READ(&timer_ft[i].start);
sigev.sigev_signo = SIGRTMIN;
sigev.sigev_value.sival_ptr = (void*)(&timers[i]);
res = timer_create( CLOCK_REALTIME, &sigev, &timers[i]);
HAL_CLOCK_READ(&timer_ft[i].end);
CYG_ASSERT( res == 0 , "timer_create() returned error");
}
show_times(timer_ft, ntimers, "Create timer");
 
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
tp.it_value.tv_sec = 0;
tp.it_value.tv_nsec = 0;
tp.it_interval.tv_sec = 0;
tp.it_interval.tv_nsec = 0;
for (i = 0; i < ntimers; i++) {
HAL_CLOCK_READ(&timer_ft[i].start);
res = timer_settime( timers[i], 0, &tp, NULL );
HAL_CLOCK_READ(&timer_ft[i].end);
CYG_ASSERT( res == 0 , "timer_settime() returned error");
}
show_times(timer_ft, ntimers, "Initialize timer to zero");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
tp.it_value.tv_sec = 1;
tp.it_value.tv_nsec = 250000000;
tp.it_interval.tv_sec = 0;
tp.it_interval.tv_nsec = 0;
for (i = 0; i < ntimers; i++) {
HAL_CLOCK_READ(&timer_ft[i].start);
res = timer_settime( timers[i], 0, &tp, NULL );
HAL_CLOCK_READ(&timer_ft[i].end);
CYG_ASSERT( res == 0 , "timer_settime() returned error");
}
show_times(timer_ft, ntimers, "Initialize timer to 1.25 sec");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
tp.it_value.tv_sec = 0;
tp.it_value.tv_nsec = 0;
tp.it_interval.tv_sec = 0;
tp.it_interval.tv_nsec = 0;
for (i = 0; i < ntimers; i++) {
HAL_CLOCK_READ(&timer_ft[i].start);
res = timer_settime( timers[i], 0, &tp, NULL );
HAL_CLOCK_READ(&timer_ft[i].end);
CYG_ASSERT( res == 0 , "timer_settime() returned error");
}
show_times(timer_ft, ntimers, "Disable timer");
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
for (i = 0; i < ntimers; i++) {
HAL_CLOCK_READ(&timer_ft[i].start);
res = timer_delete( timers[i] );
HAL_CLOCK_READ(&timer_ft[i].end);
CYG_ASSERT( res == 0 , "timer_settime() returned error");
}
show_times(timer_ft, ntimers, "Delete timer");
 
sigev.sigev_signo = SIGRTMIN+1;
sigev.sigev_value.sival_ptr = (void*)(&timers[i]);
res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]);
CYG_ASSERT( res == 0 , "timer_create() returned error");
tp.it_value.tv_sec = 0;
tp.it_value.tv_nsec = 50000000;
tp.it_interval.tv_sec = 0;
tp.it_interval.tv_nsec = 50000000;;
timer_cnt = 0;
res = timer_settime( timers[0], 0, &tp, NULL );
CYG_ASSERT( res == 0 , "timer_settime() returned error");
sem_init(&synchro, 0, 0);
wait_for_tick(); // Wait until the next clock tick to minimize aberations
do
{ res = sem_wait(&synchro);
} while( res == -1 && errno == EINTR );
CYG_ASSERT( res == 0 , "sem_wait() returned error");
tp.it_value.tv_sec = 0;
tp.it_value.tv_nsec = 0;
tp.it_interval.tv_sec = 0;
tp.it_interval.tv_nsec = 0;
res = timer_settime( timers[0], 0, &tp, NULL );
CYG_ASSERT( res == 0 , "timer_settime() returned error");
res = timer_delete( timers[0] );
CYG_ASSERT( res == 0 , "timer_delete() returned error");
show_times(sched_ft, nscheds, "Timer latency [0 threads]");
 
 
 
struct sched_param schedparam;
pthread_attr_t attr;
void *retval;
// Set my priority higher than any I plan to create
schedparam.sched_priority = 20;
pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
 
// Initiaize thread creation attributes
 
pthread_attr_init( &attr );
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
schedparam.sched_priority = 10;
pthread_attr_setschedparam( &attr, &schedparam );
for (i = 0; i < 2; i++) {
pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
pthread_attr_setstacksize( &attr, STACK_SIZE );
res = pthread_create( &threads[i],
&attr,
timer_test,
(void *)i
);
CYG_ASSERT( res == 0 , "pthread_create() returned error");
}
 
wait_for_tick(); // Wait until the next clock tick to minimize aberations
 
sigev.sigev_signo = SIGRTMIN+1;
sigev.sigev_value.sival_ptr = (void*)(&timers[i]);
res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]);
CYG_ASSERT( res == 0 , "timer_create() returned error");
tp.it_value.tv_sec = 0;
tp.it_value.tv_nsec = 50000000;
tp.it_interval.tv_sec = 0;
tp.it_interval.tv_nsec = 50000000;;
timer_cnt = 0;
res = timer_settime( timers[0], 0, &tp, NULL );
CYG_ASSERT( res == 0 , "timer_settime() returned error");
sem_init(&synchro, 0, 0);
do
{ res = sem_wait(&synchro);
} while( res == -1 && errno == EINTR );
CYG_ASSERT( res == 0 , "sem_wait() returned error");
res = timer_delete(timers[0]);
CYG_ASSERT( res == 0 , "timerdelete() returned error");
show_times(sched_ft, nscheds, "Timer latency [2 threads]");
for (i = 0; i < 2; i++) {
pthread_cancel(threads[i]);
pthread_join(threads[i], &retval);
}
 
 
for (i = 0; i < ntest_threads; i++) {
pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
pthread_attr_setstacksize( &attr, STACK_SIZE );
res = pthread_create( &threads[i],
&attr,
timer_test,
(void *)i
);
CYG_ASSERT( res == 0 , "pthread_create() returned error");
}
wait_for_tick(); // Wait until the next clock tick to minimize aberations
sigev.sigev_signo = SIGRTMIN+1;
sigev.sigev_value.sival_ptr = (void*)(&timers[i]);
res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]);
CYG_ASSERT( res == 0 , "timer_create() returned error");
tp.it_value.tv_sec = 0;
tp.it_value.tv_nsec = 50000000;
tp.it_interval.tv_sec = 0;
tp.it_interval.tv_nsec = 50000000;;
timer_cnt = 0;
res = timer_settime( timers[0], 0, &tp, NULL );
CYG_ASSERT( res == 0 , "timer_settime() returned error");
sem_init(&synchro, 0, 0);
do
{ res = sem_wait(&synchro);
} while( res == -1 && errno == EINTR );
CYG_ASSERT( res == 0 , "sem_wait() returned error");
res = timer_delete(timers[0]);
CYG_ASSERT( res == 0 , "timerdelete() returned error");
show_times(sched_ft, nscheds, "Timer latency [many threads]");
for (i = 0; i < ntest_threads; i++) {
pthread_cancel(threads[i]);
pthread_join(threads[i], &retval);
}
 
sem_init(&synchro, 0, 0);
sem_init(&timer_sem, 0, 0);
pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] );
pthread_attr_setstacksize( &attr, STACK_SIZE );
res = pthread_create( &threads[0],
&attr,
timer_test2,
(void *)0
);
CYG_ASSERT( res == 0 , "pthread_create() returned error");
wait_for_tick(); // Wait until the next clock tick to minimize aberations
sigev.sigev_signo = SIGRTMIN+2;
sigev.sigev_value.sival_ptr = (void*)(threads[0]);
res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]);
CYG_ASSERT( res == 0 , "timer_create() returned error");
tp.it_value.tv_sec = 0;
tp.it_value.tv_nsec = 50000000;
tp.it_interval.tv_sec = 0;
tp.it_interval.tv_nsec = 50000000;;
timer_cnt = 0;
res = timer_settime( timers[0], 0, &tp, NULL );
CYG_ASSERT( res == 0 , "timer_settime() returned error");
 
do
{ res = sem_wait(&synchro);
} while( res == -1 && errno == EINTR );
CYG_ASSERT( res == 0 , "sem_wait() returned error");
res = timer_delete(timers[0]);
CYG_ASSERT( res == 0 , "timerdelete() returned error");
show_times(sched_ft, nscheds, "Timer -> thread post latency");
sem_post(&timer_sem);
// pthread_cancel(threads[0]);
pthread_join(threads[0], &retval);
 
 
end_of_test_group();
}
 
 
//--------------------------------------------------------------------------
 
void
run_all_tests()
{
int i;
cyg_uint32 tv[nsamples], tv0, tv1;
// cyg_uint32 min_stack, max_stack, total_stack, actual_stack, j;
cyg_tick_count_t ticks, tick0, tick1;
#ifdef CYG_SCHEDULER_LOCK_TIMINGS
cyg_uint32 lock_ave, lock_max;
#endif
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
cyg_int32 clock_ave;
#endif
 
disable_clock_latency_measurement();
 
// cyg_test_dump_thread_stack_stats( "Startup, main stack", thread[0] );
cyg_test_dump_interrupt_stack_stats( "Startup" );
cyg_test_dump_idlethread_stack_stats( "Startup" );
cyg_test_clear_interrupt_stack();
 
diag_printf("\neCos Kernel Timings\n");
diag_printf("Notes: all times are in microseconds (.000001) unless otherwise stated\n");
#ifdef STATS_WITHOUT_FIRST_SAMPLE
diag_printf(" second line of results have first sample removed\n");
#endif
 
cyg_thread_delay(2); // Make sure the clock is actually running
 
ns_per_system_clock = 1000000/rtc_resolution[1];
 
for (i = 0; i < nsamples; i++) {
HAL_CLOCK_READ(&tv[i]);
}
tv0 = 0;
for (i = 1; i < nsamples; i++) {
tv0 += tv[i] - tv[i-1];
}
end_of_test_group();
overhead = tv0 / (nsamples-1);
diag_printf("Reading the hardware clock takes %d 'ticks' overhead\n", overhead);
diag_printf("... this value will be factored out of all other measurements\n");
 
// Try and measure how long the clock interrupt handling takes
for (i = 0; i < nsamples; i++) {
tick0 = cyg_current_time();
while (true) {
tick1 = cyg_current_time();
if (tick0 != tick1) break;
}
HAL_CLOCK_READ(&tv[i]);
}
tv1 = 0;
for (i = 0; i < nsamples; i++) {
tv1 += tv[i] * 1000;
}
tv1 = tv1 / nsamples;
tv1 -= overhead; // Adjust out the cost of getting the timer value
diag_printf("Clock interrupt took");
show_ticks_in_us(tv1);
diag_printf(" microseconds (%d raw clock ticks)\n", tv1/1000);
enable_clock_latency_measurement();
 
ticks = cyg_current_time();
 
show_test_parameters();
show_times_hdr();
 
reset_clock_latency_measurement();
 
run_thread_tests();
run_mutex_tests();
// run_mbox_tests();
run_semaphore_tests();
run_timer_tests();
 
#ifdef CYG_SCHEDULER_LOCK_TIMINGS
Cyg_Scheduler::get_lock_times(&lock_ave, &lock_max);
diag_printf("\nMax lock:");
show_ticks_in_us(lock_max);
diag_printf(", Ave lock:");
show_ticks_in_us(lock_ave);
diag_printf("\n");
#endif
 
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
// Display latency figures in same format as all other numbers
disable_clock_latency_measurement();
clock_ave = (total_clock_latency*1000) / total_clock_interrupts;
show_ticks_in_us(clock_ave);
show_ticks_in_us(min_clock_latency*1000);
show_ticks_in_us(max_clock_latency*1000);
show_ticks_in_us(0);
diag_printf(" Clock/interrupt latency\n\n");
enable_clock_latency_measurement();
#endif
 
#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)
disable_clock_latency_measurement();
clock_ave = (total_clock_dsr_latency*1000) / total_clock_dsr_calls;
show_ticks_in_us(clock_ave);
show_ticks_in_us(min_clock_dsr_latency*1000);
show_ticks_in_us(max_clock_dsr_latency*1000);
show_ticks_in_us(0);
diag_printf(" Clock DSR latency\n\n");
enable_clock_latency_measurement();
#endif
 
#if 0
disable_clock_latency_measurement();
min_stack = STACK_SIZE;
max_stack = 0;
total_stack = 0;
for (i = 0; i < (int)NTEST_THREADS; i++) {
for (j = 0; j < STACK_SIZE; j++) {
if (stacks[i][j]) break;
}
actual_stack = STACK_SIZE-j;
if (actual_stack < min_stack) min_stack = actual_stack;
if (actual_stack > max_stack) max_stack = actual_stack;
total_stack += actual_stack;
}
for (j = 0; j < STACKSIZE; j++) {
if (((char *)stack[0])[j]) break;
}
diag_printf("%5d %5d %5d (main stack: %5d) Thread stack used (%d total)\n",
total_stack/NTEST_THREADS, min_stack, max_stack,
STACKSIZE - j, STACK_SIZE);
#endif
// cyg_test_dump_thread_stack_stats( "All done, main stack", thread[0] );
cyg_test_dump_interrupt_stack_stats( "All done" );
cyg_test_dump_idlethread_stack_stats( "All done" );
 
enable_clock_latency_measurement();
 
ticks = cyg_current_time();
diag_printf("\nTiming complete - %d ms total\n\n", (int)((ticks*ns_per_system_clock)/1000));
 
CYG_TEST_PASS_FINISH("Basic timing OK");
}
 
int main( int argc, char **argv )
{
CYG_TEST_INIT();
 
if (cyg_test_is_simulator) {
nsamples = NSAMPLES_SIM;
ntest_threads = NTEST_THREADS_SIM;
nthread_switches = NTHREAD_SWITCHES_SIM;
nmutexes = NMUTEXES_SIM;
nmboxes = NMBOXES_SIM;
nsemaphores = NSEMAPHORES_SIM;
nscheds = NSCHEDS_SIM;
ntimers = NTIMERS_SIM;
} else {
nsamples = NSAMPLES;
ntest_threads = NTEST_THREADS;
nthread_switches = NTHREAD_SWITCHES;
nmutexes = NMUTEXES;
nmboxes = NMBOXES;
nsemaphores = NSEMAPHORES;
nscheds = NSCHEDS;
ntimers = NTIMERS;
}
 
// Sanity
#ifdef WORKHORSE_TEST
ntest_threads = max(512, ntest_threads);
nmutexes = max(1024, nmutexes);
nsemaphores = max(1024, nsemaphores);
nmboxes = max(1024, nmboxes);
ncounters = max(1024, ncounters);
ntimers = max(1024, ntimers);
#else
ntest_threads = max(64, ntest_threads);
nmutexes = max(32, nmutexes);
nsemaphores = max(32, nsemaphores);
nmboxes = max(32, nmboxes);
ntimers = max(32, ntimers);
#endif
 
run_all_tests();
}
 
#endif // CYGFUN_KERNEL_API_C, etc.
 
// EOF tm_basic.cxx
/v2_0/tests/mqueue1.c
0,0 → 1,359
/*========================================================================
//
// mqueue1.c
//
// POSIX Message queues tests
//
//========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jlarmour
// Contributors:
// Date: 2000-05-18
// Purpose: This file provides tests for POSIX mqueues
// Description:
// Usage:
//
//####DESCRIPTIONEND####
//
//======================================================================
*/
 
/* CONFIGURATION */
 
#include <pkgconf/posix.h>
 
#ifndef CYGPKG_POSIX_MQUEUES
# define NA_MSG "Message queues not configured"
#endif
 
#ifdef NA_MSG
#include <cyg/infra/testcase.h> // test API
void
cyg_user_start(void)
{
CYG_TEST_NA( NA_MSG );
}
 
#else
 
/* INCLUDES */
 
#include <fcntl.h> // O_*
#include <errno.h> // errno
#include <sys/stat.h> // file modes
#include <mqueue.h> // Mqueue Header
#include <cyg/infra/testcase.h> // test API
 
/* FUNCTIONS */
 
static int
my_memcmp(const void *m1, const void *m2, size_t n)
{
char *s1 = (char *)m1;
char *s2 = (char *)m2;
 
while (n--) {
if (*s1 != *s2)
return *s1 - *s2;
s1++;
s2++;
}
return 0;
} // my_memcmp()
 
//************************************************************************
 
int
main(void)
{
mqd_t q1, q2;
char buf[20];
ssize_t recvlen;
unsigned int prio;
struct mq_attr attr, oattr;
mode_t mode;
int err;
 
CYG_TEST_INIT();
CYG_TEST_INFO( "Starting POSIX message test 1" );
 
q1 = mq_open( "/mq1", O_RDWR );
CYG_TEST_PASS_FAIL( q1 == (mqd_t)-1, "error for non-existent queue" );
CYG_TEST_PASS_FAIL( ENOENT == errno,
"errno correct for non-existent queue" );
 
attr.mq_flags = 0;
attr.mq_maxmsg = 4;
attr.mq_msgsize = 20;
mode = S_IRWXU|S_IRWXG|S_IRWXO; // rwx for all
 
q1 = mq_open( "/mq1", O_CREAT|O_NONBLOCK|O_WRONLY, mode, &attr );
CYG_TEST_PASS_FAIL( q1 != (mqd_t)-1, "simple mq_open (write only)" );
err = mq_getattr( q1, &attr );
CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr" );
CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
(20 == attr.mq_msgsize) &&
(O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
(O_RDONLY != (attr.mq_flags & O_RDONLY)) &&
(O_WRONLY == (attr.mq_flags & O_WRONLY)) &&
(O_RDWR != (attr.mq_flags & O_RDWR)) &&
(0 == attr.mq_curmsgs ), "getattr attributes correct" );
err = mq_send( q1, "Vik is brill", sizeof("Vik is brill"), 10 );
 
CYG_TEST_PASS_FAIL( 0 == err, "simple mq_send" );
err = mq_getattr( q1, &attr );
CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr after send" );
CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
(20 == attr.mq_msgsize) &&
(O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
(O_RDONLY != (attr.mq_flags & O_RDONLY)) &&
(O_WRONLY == (attr.mq_flags & O_WRONLY)) &&
(O_RDWR != (attr.mq_flags & O_RDWR)) &&
(1 == attr.mq_curmsgs ),
"getattr attributes correct #2" );
q2 = mq_open( "/mq1", O_RDONLY|O_CREAT|O_EXCL );
CYG_TEST_PASS_FAIL( q2 == (mqd_t)-1,
"error for exclusive open of existing queue" );
CYG_TEST_PASS_FAIL( EEXIST == errno,
"errno correct for exclusive open of existing queue" );
q2 = mq_open( "/mq1", O_RDONLY );
CYG_TEST_PASS_FAIL( q2 != (mqd_t)-1, "simple mq_open (read only)" );
err = mq_getattr( q2, &attr );
CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr, different mqd_t" );
CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
(20 == attr.mq_msgsize) &&
(O_NONBLOCK != (attr.mq_flags & O_NONBLOCK)) &&
(O_RDONLY == (attr.mq_flags & O_RDONLY)) &&
(O_WRONLY != (attr.mq_flags & O_WRONLY)) &&
(O_RDWR != (attr.mq_flags & O_RDWR)) &&
(1 == attr.mq_curmsgs ),
"getattr attributes correct #3" );
 
err = mq_close( q2 );
CYG_TEST_PASS_FAIL( 0 == err, "simple mq_close" );
q2 = mq_open( "/mq1", O_RDONLY );
CYG_TEST_PASS_FAIL( q2 != (mqd_t)-1, "mq_open reopen (read only)" );
err = mq_getattr( q2, &attr );
CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr, different mqd_t" );
CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
(20 == attr.mq_msgsize) &&
(O_NONBLOCK != (attr.mq_flags & O_NONBLOCK)) &&
(O_RDONLY == (attr.mq_flags & O_RDONLY)) &&
(O_WRONLY != (attr.mq_flags & O_WRONLY)) &&
(O_RDWR != (attr.mq_flags & O_RDWR)) &&
(1 == attr.mq_curmsgs ),
"getattr attributes correct #4" );
 
recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
CYG_TEST_PASS_FAIL( recvlen == sizeof("Vik is brill"),
"receive message length" );
CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "Vik is brill",
sizeof("Vik is brill")),
"received message data intact" );
CYG_TEST_PASS_FAIL( 10 == prio, "received at correct priority" );
 
err = mq_getattr( q1, &attr );
CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr after send" );
CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
(20 == attr.mq_msgsize) &&
(O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
(O_RDONLY != (attr.mq_flags & O_RDONLY)) &&
(O_WRONLY == (attr.mq_flags & O_WRONLY)) &&
(O_RDWR != (attr.mq_flags & O_RDWR)) &&
(0 == attr.mq_curmsgs ),
"getattr attributes correct #5" );
 
attr.mq_flags |= O_NONBLOCK;
err = mq_setattr( q2, &attr, &oattr );
CYG_TEST_PASS_FAIL( 0 == err, "mq_setattr O_NONBLOCK" );
CYG_TEST_PASS_FAIL( (4 == oattr.mq_maxmsg) &&
(20 == oattr.mq_msgsize) &&
(O_NONBLOCK != (oattr.mq_flags & O_NONBLOCK)) &&
(O_RDONLY == (oattr.mq_flags & O_RDONLY)) &&
(O_WRONLY != (oattr.mq_flags & O_WRONLY)) &&
(O_RDWR != (oattr.mq_flags & O_RDWR)) &&
(0 == oattr.mq_curmsgs ),
"old attribute correct" );
err = mq_getattr( q2, &attr );
CYG_TEST_PASS_FAIL( 0 == err, "mq_getattr after O_NONBLOCK" );
CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
(20 == attr.mq_msgsize) &&
(O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
(O_RDONLY == (attr.mq_flags & O_RDONLY)) &&
(O_WRONLY != (attr.mq_flags & O_WRONLY)) &&
(O_RDWR != (attr.mq_flags & O_RDWR)) &&
(0 == attr.mq_curmsgs ),
"new attribute correct" );
 
recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1,
"mq_receive, empty buffer, non-blocking" );
CYG_TEST_PASS_FAIL( EAGAIN == errno,
"errno correct for non-blocking" );
err = mq_send( q2, "foo", sizeof("foo"), 1 );
CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send on read-only descriptor" );
CYG_TEST_PASS_FAIL( EBADF == errno,
"errno correct for mq_send on r/o descriptor" );
err = mq_send( q2, "supercalifragilisticexpealidocious", 21, 2 );
CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send (message too long)" );
CYG_TEST_PASS_FAIL( EMSGSIZE == errno,
"errno correct for mq_send (message too long)" );
err = mq_send( q1, "", sizeof(""), 5 );
CYG_TEST_PASS_FAIL( 0 == err, "mq_send \"\"" );
err = mq_send( q1, "I love Vik", sizeof("I love Vik"), 7 );
CYG_TEST_PASS_FAIL( 0 == err, "mq_send (different priority)" );
err = mq_send( q1, "a lot!", sizeof("a lot!"), 7 );
CYG_TEST_PASS_FAIL( 0 == err, "mq_send (same priority)" );
err = mq_send( q1, "Vik is a babe", sizeof("Vik is a babe"), 6 );
CYG_TEST_PASS_FAIL( 0 == err, "mq_send (middle priority)" );
err = mq_send( q1, "wibble", sizeof("wibble"), 6 );
CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send with full queue" );
CYG_TEST_PASS_FAIL( EAGAIN == errno,
"errno correct for mq_send full queue" );
err = mq_getattr( q2, &attr );
CYG_TEST_PASS_FAIL( 0 == err, "mq_getattr after sends" );
CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
(20 == attr.mq_msgsize) &&
(O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
(O_RDONLY == (attr.mq_flags & O_RDONLY)) &&
(O_WRONLY != (attr.mq_flags & O_WRONLY)) &&
(O_RDWR != (attr.mq_flags & O_RDWR)) &&
(4 == attr.mq_curmsgs ),
"getattr attributes correct #5" );
 
recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
CYG_TEST_PASS_FAIL( recvlen == sizeof("I love Vik"),
"receive message length (prioritized) #1" );
CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "I love Vik",
sizeof("I love Vik")),
"received message data intact (prioritized) #1" );
CYG_TEST_PASS_FAIL( 7 == prio,
"received at correct priority (prioritized) #1" );
 
recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
CYG_TEST_PASS_FAIL( recvlen == sizeof("a lot!"),
"receive message length (prioritized) #2" );
CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "a lot!",
sizeof("a lot!")),
"received message data intact (prioritized) #2" );
CYG_TEST_PASS_FAIL( 7 == prio,
"received at correct priority (prioritized) #2" );
 
recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
CYG_TEST_PASS_FAIL( recvlen == sizeof("Vik is a babe"),
"receive message length (prioritized) #3" );
CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "Vik is a babe",
sizeof("Vik is a babe")),
"received message data intact (prioritized) #3" );
CYG_TEST_PASS_FAIL( 6 == prio,
"received at correct priority (prioritized) #3" );
 
recvlen = mq_receive( q2, buf, 0, &prio );
CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1,
"mq_receive, zero-sized buffer" );
 
recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
CYG_TEST_PASS_FAIL( recvlen == sizeof(""),
"receive message length (prioritized) #4" );
CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "",
sizeof("")),
"received message data intact (prioritized) #4" );
CYG_TEST_PASS_FAIL( 5 == prio,
"received at correct priority (prioritzed) #4" );
 
recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1,
"mq_receive, empty buffer, non-blocking #2" );
CYG_TEST_PASS_FAIL( EAGAIN == errno,
"errno correct for non-blocking #2" );
err = mq_send( q1, "12345678901234567890", 20, 15 );
CYG_TEST_PASS_FAIL( 0 == err, "mq_send (before closing)" );
err = mq_unlink( "/foo" );
CYG_TEST_PASS_FAIL( -1 == err, "mq_unlink (wrong name)" );
CYG_TEST_PASS_FAIL( ENOENT == errno,
"errno correct for mq_unlink (wrong name)" );
 
err = mq_unlink( "/mq1" );
CYG_TEST_PASS_FAIL( 0 == err, "mq_unlink (before closing)" );
 
err = mq_close( q1 );
CYG_TEST_PASS_FAIL( 0 == err, "mq_close (send descriptor)" );
 
recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
CYG_TEST_PASS_FAIL( recvlen == 20,
"receive message length (mid close)" );
CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "12345678901234567890", 20 ),
"received message data intact (mid close)" );
CYG_TEST_PASS_FAIL( 15 == prio,
"received at correct priority (mid close)" );
 
err = mq_close( q2 );
CYG_TEST_PASS_FAIL( 0 == err, "mq_close (receive descriptor)" );
 
q1 = mq_open( "/mq1", O_RDONLY );
CYG_TEST_PASS_FAIL( q1 == (mqd_t)-1, "error for non-existent queue" );
CYG_TEST_PASS_FAIL( ENOENT == errno,
"errno correct for non-existent queue" );
 
CYG_TEST_EXIT("POSIX message test 1");
 
return 0;
} // main()
 
//------------------------------------------------------------------------
 
#endif
 
/* EOF mqueue1.c */
/v2_0/tests/mqueue2.c
0,0 → 1,276
/*========================================================================
//
// mqueue2.c
//
// POSIX Message queues tests - mq_notify
//
//========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jlarmour
// Contributors:
// Date: 2000-05-18
// Purpose: This file provides tests for POSIX mqueue mq_notify
// Description:
// Usage:
//
//####DESCRIPTIONEND####
//
//======================================================================
*/
 
/* CONFIGURATION */
 
#include <pkgconf/posix.h>
 
#ifndef CYGPKG_POSIX_MQUEUES
# define NA_MSG "Message queues not configured"
#elif !defined(CYGPKG_POSIX_SIGNALS)
# define NA_MSG "No POSIX signals configured"
#endif
 
#ifdef NA_MSG
#include <cyg/infra/testcase.h> // test API
void
cyg_user_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA( NA_MSG );
}
 
#else
 
/* INCLUDES */
 
#include <fcntl.h> // O_*
#include <errno.h> // errno
#include <sys/stat.h> // file modes
#include <mqueue.h> // Mqueue Header
#include <cyg/infra/testcase.h> // test API
#include <signal.h> // signals
 
/* GLOBALS */
sig_atomic_t signals=0;
char buf[20];
unsigned int prio;
 
 
/* FUNCTIONS */
 
static int
my_memcmp(const void *m1, const void *m2, size_t n)
{
char *s1 = (char *)m1;
char *s2 = (char *)m2;
 
while (n--) {
if (*s1 != *s2)
return *s1 - *s2;
s1++;
s2++;
}
return 0;
} // my_memcmp()
 
static char *
my_strcpy(char *s1, const char *s2)
{
char *s = s1;
while (*s2) {
*s1++ = *s2++;
}
return s;
} // my_strcpy()
 
static size_t
my_strlen(const char *s)
{
const char *start = s;
while (*s)
s++;
return (s - start);
} // my_strcpy()
 
 
 
//************************************************************************
 
static void
sigusr1_handler( int signo, siginfo_t *info, void *context )
{
ssize_t recvlen;
char mybuf[20];
unsigned int myprio;
mqd_t *q = (mqd_t *)info->si_value.sival_ptr;
 
CYG_TEST_PASS_FAIL( SIGUSR1 == signo, "correct signal number #1" );
CYG_TEST_PASS_FAIL( SIGUSR1 == info->si_signo, "correct signal number #2" );
CYG_TEST_PASS_FAIL( SI_MESGQ == info->si_code, "correct signal code" );
 
signals++;
 
// retrieve message and compare with buf
recvlen = mq_receive( *q, mybuf, sizeof(mybuf), &myprio );
CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf),
"receive message length" );
CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)),
"received message data intact" );
CYG_TEST_PASS_FAIL( prio == myprio,
"received at correct priority" );
}
 
//************************************************************************
 
int
main(void)
{
mqd_t q1;
struct mq_attr attr;
mode_t mode;
int err;
ssize_t recvlen;
char mybuf[20];
unsigned int myprio;
struct sigevent ev;
struct sigaction act;
 
CYG_TEST_INIT();
CYG_TEST_INFO( "Starting POSIX message test 2" );
 
#if 0
if ( 0 != pthread_create( &thr, NULL, &thread, NULL ) ) {
CYG_TEST_FAIL_FINISH( "Couldn't create a helper thread" );
}
#endif
 
attr.mq_flags = 0;
attr.mq_maxmsg = 4;
attr.mq_msgsize = 20;
mode = S_IRWXU|S_IRWXG|S_IRWXO; // rwx for all
 
q1 = mq_open( "/mq1", O_CREAT|O_NONBLOCK|O_RDWR, mode, &attr );
CYG_TEST_PASS_FAIL( q1 != (mqd_t)-1, "simple mq_open (write only)" );
err = mq_getattr( q1, &attr );
CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr" );
CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
(20 == attr.mq_msgsize) &&
(O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
(O_RDWR == (attr.mq_flags & O_RDWR)) &&
(0 == attr.mq_curmsgs ), "getattr attributes correct" );
 
 
act.sa_sigaction = &sigusr1_handler;
sigfillset( &act.sa_mask ); // enable all signals
act.sa_flags = SA_SIGINFO;
if ( 0 != sigaction( SIGUSR1, &act, NULL ) ) {
CYG_TEST_FAIL_FINISH( "Couldn't register signal handler" );
}
 
ev.sigev_notify = SIGEV_SIGNAL;
ev.sigev_signo = SIGUSR1;
ev.sigev_value.sival_ptr = (void *)&q1;
 
err = mq_notify( q1, &ev );
CYG_TEST_PASS_FAIL( 0 == err, "simple mq_notify" );
 
my_strcpy( buf, "Vik is the best" );
prio = 7;
err = mq_send( q1, buf, my_strlen(buf), prio );
 
CYG_TEST_PASS_FAIL( 0 == err, "mq_send #1" );
 
CYG_TEST_PASS_FAIL( 1 == signals, "got notification" );
 
my_strcpy( buf, "Scrummy Vik" );
prio = 6;
err = mq_send( q1, buf, my_strlen(buf), prio );
CYG_TEST_PASS_FAIL( 0 == err, "mq_send #2" );
 
CYG_TEST_PASS_FAIL( 1 == signals, "correctly didn't get notification" );
 
recvlen = mq_receive( q1, mybuf, sizeof(mybuf), &myprio );
CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf),
"receive message length" );
CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)),
"received message data intact" );
CYG_TEST_PASS_FAIL( prio == myprio,
"received at correct priority" );
 
err = mq_notify( q1, &ev );
CYG_TEST_PASS_FAIL( 0 == err, "mq_notify #2" );
 
err = mq_notify( q1, &ev );
CYG_TEST_PASS_FAIL( -1 == err, "second mq_notify returns error" );
CYG_TEST_PASS_FAIL( EBUSY == errno,
"errno correct for second mq_notify error" );
 
err = mq_notify( q1, NULL );
CYG_TEST_PASS_FAIL( 0 == err, "clear notification" );
 
my_strcpy( buf, "Vik is k3wl" );
prio = 8;
err = mq_send( q1, buf, my_strlen(buf), prio );
 
CYG_TEST_PASS_FAIL( 0 == err, "mq_send #2" );
 
CYG_TEST_PASS_FAIL( 1 == signals, "correctly didn't get notification #2" );
 
recvlen = mq_receive( q1, mybuf, sizeof(mybuf), &myprio );
CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf),
"receive message length" );
CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)),
"received message data intact" );
CYG_TEST_PASS_FAIL( prio == myprio,
"received at correct priority" );
err = mq_close( q1 );
CYG_TEST_PASS_FAIL( 0 == err, "mq_close" );
 
err = mq_unlink( "/mq1" );
CYG_TEST_PASS_FAIL( 0 == err, "mq_unlink" );
 
CYG_TEST_EXIT("POSIX message test 2");
 
return 0;
} // main()
 
//------------------------------------------------------------------------
 
#endif
 
/* EOF mqueue2.c */
/v2_0/tests/mutex3.c
0,0 → 1,672
//==========================================================================
//
// mutex3.cxx
//
// Mutex test 3 - priority inheritance
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): hmt
// Contributors: hmt, nickg, jlarmour
// Date: 2000-01-06
// Description: Tests mutex priority inheritance. This is simply a translation
// of the similarly named kernel test to the POSIX API
//####DESCRIPTIONEND####
 
// ------------------------------------------------------------------------
 
#include <cyg/infra/testcase.h>
#include <pkgconf/posix.h>
#include <pkgconf/system.h>
#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#endif
 
#ifdef CYGPKG_ISOINFRA
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <time.h>
# include <unistd.h>
#endif
 
#if !defined(CYGPKG_POSIX_PTHREAD)
#define NA_MSG "POSIX threads not enabled"
 
// ------------------------------------------------------------------------
//
// These checks should be enough; any other scheduler which has priorities
// should manifest as having no priority inheritance, but otherwise fine,
// so the test should work correctly.
 
#elif !defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
#define NA_MSG "No POSIX thread priority scheduling enabled"
#elif !defined(_POSIX_THREAD_PRIO_INHERIT)
#define NA_MSG "No POSIX thread priority inheritance enabled"
#elif !defined(_POSIX_SEMAPHORES)
#define NA_MSG "No POSIX sempaphore support enabled enabled"
#elif !defined(CYGFUN_KERNEL_API_C)
#define NA_MSG "Kernel C API not enabled"
#elif defined(CYGPKG_KERNEL_SMP_SUPPORT)
#define NA_MSG "Test cannot run with SMP support"
#endif
 
#ifdef NA_MSG
void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA(NA_MSG);
}
#else
 
#include <cyg/infra/cyg_ass.h>
#include <cyg/infra/cyg_trac.h>
#include <cyg/infra/diag.h> // diag_printf
 
#include <cyg/kernel/kapi.h> // Some extras
 
// ------------------------------------------------------------------------
// Management functions
//
// Stolen from testaux.hxx and copied in here because I want to be able to
// reset the world also.
// ... and subsequently POSIXized out of all similarly with its progenitors.
 
#define NTHREADS 7
 
#define STACKSIZE (PTHREAD_STACK_MIN*2)
 
static pthread_t thread[NTHREADS] = { 0 };
 
typedef CYG_WORD64 CYG_ALIGNMENT_TYPE;
 
static CYG_ALIGNMENT_TYPE stack[NTHREADS] [
(STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1)
/ sizeof(CYG_ALIGNMENT_TYPE) ];
 
// Semaphores to halt execution of threads
static sem_t hold[NTHREADS];
 
// Flag to tell all threads to exit
static int all_exit;
 
// Application thread data is passed here, the thread
// argument is
static CYG_ADDRWORD thread_data[NTHREADS];
 
static volatile int nthreads = 0;
 
// Sleep for 1 tick...
static struct timespec sleeptime;
 
 
static pthread_t new_thread( void *(*entry)(void *),
CYG_ADDRWORD data,
int priority,
int do_resume)
{
pthread_attr_t attr;
int _nthreads = nthreads++;
 
struct sched_param schedparam;
schedparam.sched_priority = priority;
pthread_attr_init( &attr );
pthread_attr_setstackaddr( &attr, (void *)((char *)(&stack[_nthreads])+STACKSIZE) );
pthread_attr_setstacksize( &attr, STACKSIZE );
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
pthread_attr_setschedparam( &attr, &schedparam );
CYG_ASSERT(_nthreads < NTHREADS,
"Attempt to create more than NTHREADS threads");
 
thread_data[_nthreads] = data;
 
sem_init( &hold[_nthreads], 0, do_resume ? 1 : 0 );
all_exit = 0;
 
pthread_create( &thread[_nthreads],
&attr,
entry,
(void *)_nthreads);
 
return thread[_nthreads];
}
 
 
static void kill_threads( void )
{
CYG_ASSERT(nthreads <= NTHREADS,
"More than NTHREADS threads");
CYG_ASSERT( pthread_equal(pthread_self(),thread[0]),
"kill_threads() not called from thread 0");
all_exit = 1;
while ( nthreads > 1 ) {
nthreads--;
if ( 0 != thread[nthreads] ) {
sem_post( &hold[nthreads] );
pthread_cancel( thread[nthreads] );
pthread_join( thread[nthreads], NULL );
thread[nthreads] = 0;
sem_destroy( &hold[nthreads] );
}
}
CYG_ASSERT(nthreads == 1,
"No threads left");
}
 
// ------------------------------------------------------------------------
 
#define DELAYFACTOR 1 // for debugging
 
// ------------------------------------------------------------------------
 
pthread_mutex_t mutex;
 
// These are for reporting back to the master thread
volatile int got_it = 0;
volatile int t3ran = 0;
volatile int t3ended = 0;
volatile int extras[4] = {0,0,0,0};
volatile int go_flag = 0; // but this one controls thread 3 from thread 2
 
// ------------------------------------------------------------------------
// 0 to 3 of these run generally to interfere with the other processing,
// to cause multiple prio inheritances, and clashes in any orders.
 
static void *extra_thread( void *arg )
{
#define XINFO( z ) \
do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 )
 
static char running[] = "Extra thread Xa running";
static char exiting[] = "Extra thread Xa exiting";
static char resumed[] = "Extra thread Xa resumed";
static char locked[] = "Extra thread Xa locked";
static char unlocked[] = "Extra thread Xa unlocked";
 
int id = (int)arg;
CYG_ADDRWORD data = thread_data[id];
 
CYG_ASSERT( (id >= 4 && id <= 6), "extra_thread invalid id" );
// Emulate resume behaviour
sem_wait( &hold[id] );
if( all_exit ) return 0;
XINFO( running );
 
sem_wait( &hold[id] );
XINFO( resumed );
 
pthread_mutex_lock( &mutex );
 
XINFO( locked );
 
pthread_mutex_unlock( &mutex );
 
XINFO( unlocked );
 
extras[ data ] ++;
 
XINFO( exiting );
 
return NULL;
}
 
// ------------------------------------------------------------------------
 
static void *t1( void *arg )
{
int id = (int)arg;
//CYG_ADDRWORD data = thread_data[id];
// Emulate resume behaviour
sem_wait( &hold[id] );
if( all_exit ) return 0;
 
CYG_TEST_INFO( "Thread 1 running" );
 
sem_wait( &hold[id] );
 
pthread_mutex_lock( &mutex );
 
got_it++;
 
CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" );
 
pthread_mutex_unlock( &mutex );
 
CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" );
 
// That's all.
 
CYG_TEST_INFO( "Thread 1 exit" );
 
return 0;
}
 
// ------------------------------------------------------------------------
 
static void *t2( void *arg )
{
int i;
int id = (int)arg;
CYG_ADDRWORD data = thread_data[id];
cyg_tick_count_t now, then;
// Emulate resume behaviour
sem_wait( &hold[id] );
if( all_exit ) return 0;
 
CYG_TEST_INFO( "Thread 2 running" );
 
CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" );
CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" );
 
sem_wait( &hold[id] );
 
// depending on our config argument, optionally restart some of the
// extra threads to throw noise into the scheduler:
for ( i = 0; i < 3; i++ )
if ( (1 << i) & data ) // bits 0-2 control
sem_post( &hold[i+4] ); // made sure extras are thread[4-6]
 
// let those threads run
for( i = 0; i < DELAYFACTOR * 10; i++ )
nanosleep( &sleeptime, NULL );
 
cyg_scheduler_lock(); // do this next lot atomically
 
go_flag = 1; // unleash thread 3
sem_post( &hold[1] ); // resume thread 1
 
// depending on our config argument, optionally restart some of the
// extra threads to throw noise into the scheduler at this later point:
for ( i = 4; i < 7; i++ )
if ( (1 << i) & data ) // bits 4-6 control
sem_post( &hold[i] ); // made sure extras are thread[4-6]
 
cyg_scheduler_unlock(); // let scheduling proceed
 
// Need a delay (but not a CPU yield) to allow t3 to awaken and act on
// the go_flag, otherwise we check these details below too soon.
// Actually, waiting for the clock to tick a couple of times would be
// better, so that is what we will do. Must be a busy-wait.
then = cyg_current_time();
do {
now = cyg_current_time();
// Wait longer than the delay in t3 waiting on go_flag
} while ( now < (then + 3) );
 
#ifdef _POSIX_THREAD_PRIO_INHERIT
CYG_TEST_INFO( "Checking for mutex priority inheritance" );
CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
#else
CYG_TEST_INFO( "Checking for NO mutex priority inheritance" );
CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" );
CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" );
#endif
 
CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" );
 
for( i = 0; i < DELAYFACTOR * 20; i++ )
nanosleep( &sleeptime, NULL ); // let those threads run
 
CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" );
 
for ( i = 0; i < 3; i++ )
if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control
CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" );
else
CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" );
 
CYG_TEST_PASS( "Thread 2 exiting, AOK" );
// That's all: restart the control thread.
sem_post( &hold[0] );
 
return 0;
}
 
// ------------------------------------------------------------------------
 
static void *t3( void *arg )
{
int i;
int id = (int)arg;
//CYG_ADDRWORD data = thread_data[id];
// Emulate resume behaviour
sem_wait( &hold[id] );
if( all_exit ) return 0;
CYG_TEST_INFO( "Thread 3 running" );
 
pthread_mutex_lock( &mutex );
 
for( i = 0; i < DELAYFACTOR * 5; i++ )
nanosleep( &sleeptime, NULL ); // let thread 3a run
 
sem_post( &hold[2] ); // resume thread 2
 
while ( 0 == go_flag )
nanosleep( &sleeptime, NULL ); // wait until we are told to go
 
t3ran ++; // record the fact
 
CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" );
 
pthread_mutex_unlock( &mutex );
 
t3ended ++; // record that we came back
 
CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
 
CYG_TEST_INFO( "Thread 3 exit" );
 
return 0;
}
 
// ------------------------------------------------------------------------
 
static void *control_thread( void *arg )
{
int i,z;
int id = (int)arg;
//CYG_ADDRWORD data = thread_data[id];
// Emulate resume behaviour
sem_wait( &hold[id] );
if( all_exit ) return 0;
// one tick sleep time
sleeptime.tv_nsec = 10000000;
sleeptime.tv_sec = 0;
CYG_TEST_INIT();
CYG_TEST_INFO( "Control Thread running" );
 
// Go through the 27 possibilitied of resuming the extra threads
// 0: not at all
// 1: early in the process
// 2: later on
// which are represented by bits 0-3 and 4-6 resp in the argument to
// thread 2 (none set means no resume at all).
for ( i = 0; i < 27; i++ ) {
static int xx[] = { 0, 1, 16 };
int j = i % 3;
int k = (i / 3) % 3;
int l = (i / 9) % 3;
 
int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ;
 
if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) )
continue; // 13 is 111 base 3, 26 is 222 base 3
 
#ifdef _POSIX_THREAD_PRIO_INHERIT
// If the simple scheme plus relay enhancement, or any other
// *complete* scheme, we can run all three ancillary threads no
// problem, so no special action here.
 
#else
// If no priority inheritance at all, running threads 1a and 2a is
// OK, but not thread 3a; it blocks the world.
if ( l ) // Cannot run thread 3a if no
break; // priority inheritance at all.
#endif
 
// Reinitialize mutex to provide priority inheritance
{
pthread_mutexattr_t attr;
pthread_mutexattr_init( &attr );
pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_INHERIT );
pthread_mutex_init( &mutex, &attr );
}
 
got_it = 0;
t3ran = 0;
t3ended = 0;
for ( z = 0; z < 4; z++ ) extras[z] = 0;
go_flag = 0;
new_thread( t1, 0, 15, 1 ); // Slot 1
new_thread( t2, d, 10, 1 ); // Slot 2
new_thread( t3, 0, 5, 1 ); // Slot 3
new_thread( extra_thread, 1, 17, j ); // Slot 4
new_thread( extra_thread, 2, 12, k ); // Slot 5
new_thread( extra_thread, 3, 8, l ); // Slot 6
{
static char *a[] = { "inactive", "run early", "run late" };
diag_printf( "\n----- [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n",
i, d, a[j], a[k], a[l] );
}
 
sem_wait( &hold[0] );
kill_threads();
pthread_mutex_destroy( &mutex );
}
CYG_TEST_EXIT( "Control Thread exit" );
 
return 0;
}
 
// ------------------------------------------------------------------------
 
static sem_t main_sem;
 
externC int
main( int argc, char **argv )
{
new_thread( control_thread, 0, 20, 1 );
 
// We have nothing for main to do here, so put it to sleep on
// its own semaphore. We cannot let it just exit since that
// will end the whole program.
 
sem_init( &main_sem, 0, 0 );
for(;;) sem_wait( &main_sem );
}
 
// ------------------------------------------------------------------------
// Documentation: enclosed is the design of this test.
//
// It has been carefully constructed so that it does NOT use other kernel
// facilities (aside from delay-task) to test that priority inheritance is
// working, or not, as intended by the configuration.
//
// These notes describe the flow of control in one run of the test with the
// ancillary tasks optionally interspersed. The details of how those extra
// tasks are or are not allowed to run are not described.
//
//
//
// The only change in the test that depends on whether there is inheritance or
// not is the check in thread 2 on "3-ran" and "got it" flags marked ****
//
//
// volatile &c booleans:
// "got it" = FALSE
// "3-ran" = FALSE
// "3-ended" = FALSE
// "extras"[3] = FALSE
//
// thread 1. prio 5, self-suspend.
//
// thread 1a, prio 8, self-suspend.
//
// thread 2. prio 10, self-suspend.
//
// thread 2a, prio 12, self-suspend.
//
// thread 3. prio 15, runs, lock mutex, resume(2)
//
// thread 3a, prio 17, self-suspend.
//
// 2. runs,
// 2. resume(3a) +++OPTIONAL
// 2. resume(2a) +++OPTIONAL
// 2. resume(1a) +++OPTIONAL
// [1a lock-fail] thread 3->prio := 8
//
// [3. runs maybe, does the looping thing]
//
// 2. sleep a while...
//
// [2a lock-fail] thread 3->prio := 12
//
// [3. runs maybe, does the looping thing]
//
// [3a lock-fail] thread 3->prio unchanged
//
// [3. runs maybe, does the looping thing]
//
// 2. lock scheduler
// 2. set "go-flag"
// 2. resume(1)
// 2. resume(1a) +++OPTIONAL
// 2. resume(2a) +++OPTIONAL
// 2. resume(3a) +++OPTIONAL
// 2. unlock scheduler
//
// 1. runs, lock mutex - thread 3 has it locked
//
// 2. busy-waits a bit for thread 3 to come out of its delay() loop.
// This must be a *busy*wait so that 3 can only run via the
// inherited raised priority.
//
// [xa. all do the same: lock mutex, ]
// [xa. unlock mutex ]
// [xa. set a flag "extras"[x] to say we are done. ]
// [xa. exit ]
//
//
//
// INHERIT
// -------
//
// thread 3->prio := 5
//
// 3. runs,
// 3. set a flag to say "3-ran",
// 3. loop with a sleep(1) until "go-flag" is set.
// 3. check "got it" is false,
// 3. then unlock mutex,
//
// thread 3->prio := 15
//
// 1. runs, set a flag to say "got it",
// 1. check "3-ended" flag is false
// 1. unlock mutex,
// 1. check "3-ended" flag is still false
// 1. exit.
//
// [1a locks, unlocks, exits]
//
// 2. runs, check "3-ran" and "got it" flags are TRUE ****
// 2. check "3-ended" flag is false
// 2. sleeps for a while so that...
//
// [2a locks, unlocks, exits]
//
// 3. runs, set "3-ended" flag,
// 3. check "3-ran" and "got it" flags
// 3. exit
//
// [3a locks, unlocks, exits]
//
// 2. awakens, checks all flags true,
// 2. check that all "extra" threads that we started have indeed run
// 2. end of test.
//
//
//
//
// NO-INHERIT
// ----------
// thread 1 is waiting on the mutex
//
// [1a lock-fail]
//
// 2. runs, checks that "3-ran" and "got it" flags are FALSE ****
// 2. check "3-ended" flag is false
// 2. sleeps for a while so that...
//
// [2a. lock-fail]
//
// 3. runs, set a flag to say "3-ran",
// 3. check "got it" is false,
// 3. then unlock mutex,
//
// 1. runs, set a flag to say "got it",
// 1. check "3-ended" flag is false
// 1. unlock mutex,
// 1. check "3-ended" flag is still false
// 1. exit.
//
// [1a locks, unlocks, exits]
// [2a locks, unlocks, exits]
//
// 3. runs, set "3-ended" flag,
// 3. check "3-ran" and "got it" flags
// 3. exit
//
// [3a locks, unlocks, exits]
//
// 2. awakens, checks all flags true,
// 2. check that all "extra" threads that we started have indeed run
// 2. end of test.
//
//
// (the end)
//
//
// ------------------------------------------------------------------------
 
#endif
 
// EOF mutex3.cxx
/v2_0/tests/sigsetjmp.c
0,0 → 1,383
//==========================================================================
//
// sigsetjmp.c
//
// POSIX sigsetjmp test
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-04-10
// Description: Tests POSIX sigsetjmp functionality.
//
//####DESCRIPTIONEND####
//==========================================================================
 
#include <cyg/infra/testcase.h>
#include <pkgconf/posix.h>
 
#if !defined(CYGPKG_POSIX_SIGNALS)
#define NA_MSG "POSIX signals not enabled"
#elif !defined(CYGPKG_POSIX_PTHREAD)
#define NA_MSG "POSIX threads not enabled"
#endif
 
#ifdef NA_MSG
void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA(NA_MSG);
}
#else
 
#include <sys/types.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <time.h>
#include <setjmp.h>
 
#include <cyg/infra/testcase.h>
 
//--------------------------------------------------------------------------
// Thread stack.
 
char thread1_stack[PTHREAD_STACK_MIN*2];
char thread2_stack[PTHREAD_STACK_MIN*2];
 
//--------------------------------------------------------------------------
// Local variables
 
// Sync semaphore
sem_t sem;
 
// Thread IDs
pthread_t thread1;
pthread_t thread2;
 
timer_t timer1;
timer_t timer2;
 
volatile int sigusr1_called = 0;
volatile int sigusr2_called = 0;
 
sigjmp_buf jmpbuf1;
sigjmp_buf jmpbuf2;
 
//--------------------------------------------------------------------------
// Signal handler functions
 
static void sigusr1( int signo, siginfo_t *info, void *context )
{
CYG_TEST_INFO( "sigusr1() handler called" );
CYG_TEST_CHECK( signo == SIGUSR1, "Signal not SIGUSR1");
CYG_TEST_CHECK( signo == info->si_signo, "Bad signal number in siginfo" );
CYG_TEST_CHECK( info->si_code == SI_TIMER, "Siginfo code not SI_TIMER" );
CYG_TEST_CHECK( info->si_value.sival_int == 0xABCDEF01, "Siginfo value wrong");
CYG_TEST_CHECK( pthread_equal(pthread_self(), thread1), "Not called in thread1");
 
sigusr1_called++;
 
CYG_TEST_INFO( "sigusr1() handler calling siglongjmp()" );
siglongjmp( jmpbuf1, sigusr1_called );
}
 
static void sigusr2( int signo, siginfo_t *info, void *context )
{
CYG_TEST_INFO( "sigusr2() handler called" );
CYG_TEST_CHECK( signo == SIGUSR2, "Signal not SIGUSR2");
CYG_TEST_CHECK( signo == info->si_signo, "Bad signal number in siginfo" );
CYG_TEST_CHECK( info->si_code == SI_TIMER, "Siginfo code not SI_TIMER" );
CYG_TEST_CHECK( info->si_value.sival_int == 0xABCDEF02, "Siginfo value wrong");
CYG_TEST_CHECK( pthread_equal(pthread_self(), thread2), "Not called in thread2");
 
sigusr2_called++;
 
CYG_TEST_INFO( "sigusr2() handler calling siglongjmp()" );
siglongjmp( jmpbuf2, sigusr2_called );
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry1( void *arg)
{
sigset_t mask;
 
CYG_TEST_INFO( "Thread 1 running" );
 
// Make a full set
sigfillset( &mask );
 
// remove USR1 signal
sigdelset( &mask, SIGUSR1 );
 
// Set signal mask
pthread_sigmask( SIG_SETMASK, &mask, NULL );
// Get main thread going again
sem_post( &sem );
 
do
{
sigset_t curmask;
 
CYG_TEST_INFO( "Thread1: calling sigsetjmp()");
if( sigsetjmp( jmpbuf1, 1 ) != 0 )
CYG_TEST_INFO( "Thread1: sigsetjmp() returned non-zero");
pthread_sigmask( SIG_SETMASK, NULL, &curmask );
CYG_TEST_CHECK( curmask == mask, "Thread1: Signal masks not equal" );
 
if ( sigusr1_called >= 1 )
break;
CYG_TEST_INFO( "Thread1: calling pause()");
pause();
 
CYG_TEST_INFO( "Thread1: pause() returned");
} while(1);
 
CYG_TEST_INFO( "Thread1: calling pthread_exit()");
pthread_exit( arg );
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry2( void *arg)
{
sigset_t mask;
CYG_TEST_INFO( "Thread 2 running" );
 
// Make a full set
sigfillset( &mask );
 
// remove USR2 signal
sigdelset( &mask, SIGUSR2 );
 
// Set signal mask
pthread_sigmask( SIG_SETMASK, &mask, NULL );
// Get main thread going again
sem_post( &sem );
 
do
{
sigset_t curmask;
 
CYG_TEST_INFO( "Thread2: calling sigsetjmp()");
if( sigsetjmp( jmpbuf2, 1 ) != 0 )
CYG_TEST_INFO( "Thread2: sigsetjmp() returned non-zero");
pthread_sigmask( SIG_SETMASK, NULL, &curmask );
CYG_TEST_CHECK( curmask == mask, "Thread2: Signal masks not equal" );
 
if ( sigusr2_called >= 6 )
break;
CYG_TEST_INFO( "Thread2: calling pause()");
pause();
 
CYG_TEST_INFO( "Thread2: pause() returned");
} while(1);
 
CYG_TEST_INFO( "Thread2: calling pthread_exit()");
pthread_exit( arg );
}
 
//--------------------------------------------------------------------------
 
int main(int argc, char **argv)
{
int ret;
sigset_t mask;
pthread_attr_t attr;
void *retval;
CYG_TEST_INIT();
 
// Make a full signal set
sigfillset( &mask );
 
// Install signal handlers
{
struct sigaction sa;
 
sa.sa_sigaction = sigusr1;
sa.sa_mask = mask;
sa.sa_flags = SA_SIGINFO;
 
ret = sigaction( SIGUSR1, &sa, NULL );
 
CYG_TEST_CHECK( ret == 0 , "sigaction returned error");
}
{
struct sigaction sa;
 
sa.sa_sigaction = sigusr2;
sa.sa_mask = mask;
sa.sa_flags = SA_SIGINFO;
 
ret = sigaction( SIGUSR2, &sa, NULL );
 
CYG_TEST_CHECK( ret == 0 , "sigaction returned error");
}
 
 
// Create the timers
 
{
struct sigevent sev;
struct itimerspec value;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR1;
sev.sigev_value.sival_int = 0xABCDEF01;
 
value.it_value.tv_sec = 1;
value.it_value.tv_nsec = 0;
value.it_interval.tv_sec = 0;
value.it_interval.tv_nsec = 0;
ret = timer_create( CLOCK_REALTIME, &sev, &timer1 );
 
CYG_TEST_CHECK( ret == 0 , "timer_create returned error");
 
ret = timer_settime( timer1, 0, &value, NULL );
 
CYG_TEST_CHECK( ret == 0 , "timer_settime returned error");
}
 
{
struct sigevent sev;
struct itimerspec value;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR2;
sev.sigev_value.sival_int = 0xABCDEF02;
 
value.it_value.tv_sec = 0;
value.it_value.tv_nsec = 500000000;
value.it_interval.tv_sec = 0;
value.it_interval.tv_nsec = 250000000;
ret = timer_create( CLOCK_REALTIME, &sev, &timer2 );
 
CYG_TEST_CHECK( ret == 0 , "timer_create returned error");
 
ret = timer_settime( timer2, 0, &value, NULL );
 
CYG_TEST_CHECK( ret == 0 , "timer_settime returned error");
}
 
// Mask all signals
pthread_sigmask( SIG_SETMASK, &mask, NULL );
sem_init( &sem, 0, 0 );
// Create test threads
 
{
pthread_attr_init( &attr );
 
pthread_attr_setstackaddr( &attr, (void *)&thread1_stack[sizeof(thread1_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread1_stack) );
 
pthread_create( &thread1,
&attr,
pthread_entry1,
(void *)0x12345671);
}
 
{
pthread_attr_init( &attr );
 
pthread_attr_setstackaddr( &attr, (void *)&thread2_stack[sizeof(thread2_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread2_stack) );
 
pthread_create( &thread2,
&attr,
pthread_entry2,
(void *)0x12345672);
}
// Wait for other thread to get started
CYG_TEST_INFO( "Main: calling sem_wait()");
sem_wait( &sem );
CYG_TEST_INFO( "Main: calling sem_wait() again");
sem_wait( &sem );
 
// Now join with thread1
CYG_TEST_INFO( "Main: calling pthread_join(thread1)");
pthread_join( thread1, &retval );
 
CYG_TEST_CHECK( retval == (void *)0x12345671, "Thread 1 retval wrong");
// And thread 2
CYG_TEST_INFO( "Main: calling pthread_join(thread2)");
pthread_join( thread2, &retval );
 
// now delete the timers
CYG_TEST_INFO( "Main: calling timer_delete(timer1)");
ret = timer_delete( timer1 );
 
CYG_TEST_CHECK( ret == 0 , "timer_delete(timer1) returned error");
 
CYG_TEST_INFO( "Main: calling timer_delete(timer2)");
ret = timer_delete( timer2 );
 
CYG_TEST_CHECK( ret == 0 , "timer_delete(timer2) returned error");
 
CYG_TEST_CHECK( retval == (void *)0x12345672, "Thread 2 retval wrong");
CYG_TEST_CHECK( sigusr1_called == 1, "SIGUSR1 signal handler not called once" );
CYG_TEST_CHECK( sigusr2_called == 6, "SIGUSR2 signal handler not called six times" );
 
CYG_TEST_PASS_FINISH( "sigsetjmp" );
}
 
#endif
 
//--------------------------------------------------------------------------
// end of sigsetjmp.c
/v2_0/tests/pthread1.c
0,0 → 1,119
//==========================================================================
//
// pthread1.cxx
//
// POSIX pthread test 1
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-04-10
// Description: Tests POSIX join functionality.
//
//####DESCRIPTIONEND####
//==========================================================================
 
#include <cyg/infra/testcase.h>
#include <pkgconf/posix.h>
 
#ifndef CYGPKG_POSIX_PTHREAD
#define NA_MSG "POSIX threads not enabled"
#endif
 
#ifdef NA_MSG
void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA(NA_MSG);
}
#else
 
#include <sys/types.h>
#include <pthread.h>
 
//--------------------------------------------------------------------------
// Thread stack.
 
char thread_stack[PTHREAD_STACK_MIN*2];
 
//--------------------------------------------------------------------------
 
void *pthread_entry1( void *arg)
{
CYG_TEST_INFO( "Thread 1 running" );
pthread_exit( (void *)((int)arg+1) );
}
 
//--------------------------------------------------------------------------
 
int main(int argc, char **argv)
{
pthread_t thread;
pthread_attr_t attr;
void *retval;
 
CYG_TEST_INIT();
 
// Create test thread
pthread_attr_init( &attr );
 
pthread_attr_setstackaddr( &attr, (void *)&thread_stack[sizeof(thread_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread_stack) );
 
pthread_create( &thread,
&attr,
pthread_entry1,
(void *)0x12345678);
 
// Now join with it
pthread_join( thread, &retval );
 
// check retval
if( (long)retval == 0x12345679 )
CYG_TEST_PASS_FINISH( "pthread1" );
else
CYG_TEST_FAIL_FINISH( "pthread1" );
}
 
#endif
 
//--------------------------------------------------------------------------
// end of pthread1.c
/v2_0/tests/pthread2.c
0,0 → 1,176
//==========================================================================
//
// pthread2.cxx
//
// POSIX pthread test 2 - per-thread data
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-04-10
// Description: Tests POSIX per-thread data.
//
//####DESCRIPTIONEND####
//==========================================================================
 
#include <cyg/infra/testcase.h>
#include <pkgconf/posix.h>
 
#ifndef CYGPKG_POSIX_PTHREAD
#define NA_MSG "POSIX threads not enabled"
#endif
 
#ifdef NA_MSG
void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA(NA_MSG);
}
#else
 
#include <sys/types.h>
#include <pthread.h>
 
//--------------------------------------------------------------------------
// Thread stack.
 
char thread_stack[2][PTHREAD_STACK_MIN*2];
 
pthread_t thread[2];
 
pthread_key_t key;
 
//--------------------------------------------------------------------------
 
void key_destructor( void *val )
{
int ret;
 
CYG_TEST_INFO( "key destructor called" );
 
if( (long)val == 0xAAAAAAAA )
{
ret = pthread_setspecific( key, NULL );
CYG_TEST_CHECK( ret == 0, "pthread_setspecific() returned error");
}
else
{
ret = pthread_setspecific( key, (void *)0xAAAAAAAA );
CYG_TEST_CHECK( ret == 0, "pthread_setspecific() returned error");
}
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry( void *arg)
{
int ret;
int retval = 1;
void *val;
CYG_TEST_INFO( "Thread running" );
 
ret = pthread_setspecific( key, arg );
CYG_TEST_CHECK( ret == 0, "pthread_setspecific() returned error");
val = pthread_getspecific( key );
CYG_TEST_CHECK( val == arg, "pthread_getspecific() did not return expected value");
if( val != arg ) retval = 0;
sched_yield();
 
val = pthread_getspecific( key );
CYG_TEST_CHECK( val == arg, "pthread_getspecific() did not return expected value");
if( val != arg ) retval = 0;
pthread_exit( (void *)retval );
}
 
//--------------------------------------------------------------------------
 
int main(int argc, char **argv)
{
int i;
int ret;
void *retval[2];
 
CYG_TEST_INIT();
 
// allocate data key
ret = pthread_key_create( &key, key_destructor );
CYG_TEST_CHECK( ret == 0, "pthread_key_create() returned error");
// Create test threads
for( i = 0; i < 2; i++ )
{
pthread_attr_t attr;
pthread_attr_init( &attr );
 
pthread_attr_setstackaddr( &attr, (void *)&thread_stack[i][sizeof(thread_stack[i])] );
pthread_attr_setstacksize( &attr, sizeof(thread_stack[i]) );
 
ret = pthread_create( &thread[i],
&attr,
pthread_entry,
(void *)(0x12340000+i));
CYG_TEST_CHECK( ret == 0, "pthread_create() returned error");
}
// Now join with threads
for( i = 0; i < 2; i++ )
pthread_join( thread[i], &retval[i] );
 
 
ret = pthread_key_delete( key );
CYG_TEST_CHECK( ret == 0, "pthread_key_delete() returned error");
// check retvals
 
for( i = 0; i < 2; i++ )
if( !(long)retval[0] )
CYG_TEST_FAIL_FINISH( "pthread2" );
CYG_TEST_PASS_FINISH( "pthread2" );
}
 
#endif
 
//--------------------------------------------------------------------------
// end of pthread2.c
/v2_0/tests/pthread3.c
0,0 → 1,269
//==========================================================================
//
// pthread3.cxx
//
// POSIX pthread test 2 - cancellation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg, jlarmour
// Date: 2000-04-10
// Description: Tests POSIX cancellation.
//
//####DESCRIPTIONEND####
//==========================================================================
 
#include <cyg/infra/testcase.h>
#include <pkgconf/posix.h>
 
#ifndef CYGPKG_POSIX_PTHREAD
#define NA_MSG "POSIX threads not enabled"
#endif
 
#ifdef NA_MSG
void
cyg_start(void)
{
CYG_TEST_INIT();
CYG_TEST_NA(NA_MSG);
}
#else
 
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h> // sleep()
 
//--------------------------------------------------------------------------
// Thread info
 
#define NTHREADS 3
 
char thread_stack[NTHREADS][PTHREAD_STACK_MIN*2];
 
pthread_t thread[NTHREADS];
 
void *pthread_entry1( void *arg);
void *pthread_entry2( void *arg);
void *pthread_entry3( void *arg);
 
void *(*pthread_entry[NTHREADS])(void *) =
{
pthread_entry1,
pthread_entry2,
pthread_entry3
};
 
//--------------------------------------------------------------------------
 
volatile cyg_bool cancel_handler1_called = false;
volatile cyg_bool cancel_handler2_called = false;
volatile cyg_bool cancel_handler3_called = false;
volatile cyg_bool thread_ready[NTHREADS];
 
//--------------------------------------------------------------------------
 
void cancel_handler1( void * arg )
{
CYG_TEST_INFO( "cancel_handler1 called" );
 
CYG_TEST_CHECK( (long)arg == 0x12340000, "cancel_handler1: bad arg value");
cancel_handler1_called = true;
}
 
//--------------------------------------------------------------------------
 
void cancel_handler2( void * arg )
{
CYG_TEST_INFO( "cancel_handler2 called" );
 
CYG_TEST_CHECK( (long)arg == 0xFFFF1111, "cancel_handler2: bad arg value");
cancel_handler2_called = true;
}
 
//--------------------------------------------------------------------------
 
void cancel_handler3( void * arg )
{
CYG_TEST_INFO( "cancel_handler3 called" );
 
CYG_TEST_CHECK( (long)arg == 0x12340001, "cancel_handler3: bad arg value");
cancel_handler3_called = true;
}
 
//--------------------------------------------------------------------------
 
void function1(void)
{
 
pthread_cleanup_push( cancel_handler2, (void *)0xFFFF1111 );
 
for(;;)
{
sched_yield();
pthread_testcancel();
}
 
pthread_cleanup_pop( 0 );
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry1( void *arg)
{
int retval = 1;
 
CYG_TEST_INFO( "pthread_entry1 entered");
 
pthread_setcanceltype( PTHREAD_CANCEL_DEFERRED, NULL );
pthread_cleanup_push( cancel_handler1, arg );
 
thread_ready[0] = true;
 
function1();
pthread_cleanup_pop( 0 );
 
pthread_exit( (void *)retval );
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry2( void *arg)
{
int retval = 1;
 
CYG_TEST_INFO( "pthread_entry2 entered");
 
pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
pthread_cleanup_push( cancel_handler3, arg );
 
thread_ready[1] = true;
 
for(;;) sched_yield();
pthread_cleanup_pop( 0 );
 
pthread_exit( (void *)retval );
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry3( void *arg)
{
int retval = 1;
 
CYG_TEST_INFO( "pthread_entry3 entered");
 
pthread_setcanceltype( PTHREAD_CANCEL_DEFERRED, NULL );
thread_ready[2] = true;
 
// stop in a cancellation point
sleep( 99999 );
pthread_exit( (void *)retval );
}
 
//--------------------------------------------------------------------------
 
int main(int argc, char **argv)
{
int i, j;
int ret;
void *retval[NTHREADS];
 
CYG_TEST_INIT();
 
// Create test threads
for( i = 0; i < NTHREADS; i++ )
{
pthread_attr_t attr;
pthread_attr_init( &attr );
 
pthread_attr_setstackaddr( &attr, (void *)&thread_stack[i][sizeof(thread_stack[i])] );
pthread_attr_setstacksize( &attr, sizeof(thread_stack[i]) );
 
ret = pthread_create( &thread[i],
&attr,
pthread_entry[i],
(void *)(0x12340000+i));
CYG_TEST_CHECK( ret == 0, "pthread_create() returned error");
}
 
// Let the threads get going
for ( i = 0; i < NTHREADS ; i++ ) {
while ( thread_ready[i] == false )
sched_yield();
}
 
// Now wait a bit to be sure that the other threads have reached
// their cancellation points.
for ( j = 0; j < 20 ; j++ )
sched_yield();
// Now cancel them
for( i = 0; i < NTHREADS; i++ )
pthread_cancel( thread[i] );
// Now join with threads
for( i = 0; i < NTHREADS; i++ )
pthread_join( thread[i], &retval[i] );
 
 
// check retvals
for( i = 0; i < NTHREADS; i++ )
CYG_TEST_CHECK( retval[i] == PTHREAD_CANCELED,
"thread didn't exit with PTHREAD_CANCELED" );
 
CYG_TEST_CHECK( cancel_handler1_called, "cancel_handler1 not called" );
CYG_TEST_CHECK( cancel_handler2_called, "cancel_handler2 not called" );
CYG_TEST_CHECK( cancel_handler3_called, "cancel_handler3 not called" );
 
CYG_TEST_PASS_FINISH( "pthread3" );
}
 
#endif
 
//--------------------------------------------------------------------------
// end of pthread3.c
/v2_0/include/muttypes.h
0,0 → 1,138
#ifndef CYGONCE_POSIX_MUTTYPES_H
#define CYGONCE_POSIX_MUTTYPES_H
//=============================================================================
//
// muttypes.h
//
// POSIX mutex types header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg,jlarmour
// Date: 2000-03-17
// Purpose: POSIX types header
// Description: This header contains POSIX type definitions for mutexes
// and cond vars. These types are implementation defined.
//
// Usage: #include <sys/types.h>
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/posix.h>
#include <pkgconf/kernel.h>
 
#include <cyg/infra/cyg_type.h>
 
//-----------------------------------------------------------------------------
// Mutex object
// This structure must exactly correspond in size and layout to the underlying
// eCos C++ class that implements this object. Because we have to support
// PTHREAD_MUTEX_INITIALIZER we cannot abstract this object very easily.
 
typedef struct
{
CYG_WORD32 locked;
CYG_ADDRESS owner;
CYG_ADDRESS queue;
 
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
CYG_WORD32 protocol; // this mutex's protocol
#endif
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
CYG_WORD32 ceiling; // mutex priority ceiling
#endif
} pthread_mutex_t;
 
#if defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC) &&\
defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING)
#define PTHREAD_MUTEX_INITIALIZER { 0, 0, 0, 0, 0 }
#elif defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC) ||\
defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING)
#define PTHREAD_MUTEX_INITIALIZER { 0, 0, 0, 0 }
#else
#define PTHREAD_MUTEX_INITIALIZER { 0, 0, 0 }
#endif
 
//-----------------------------------------------------------------------------
// Mutex attributes structure
 
typedef struct
{
int protocol;
#ifdef _POSIX_THREAD_PRIO_PROTECT
int prioceiling;
#endif
} pthread_mutexattr_t;
 
// Values for protocol
#define PTHREAD_PRIO_NONE 1
#if defined(_POSIX_THREAD_PRIO_INHERIT)
#define PTHREAD_PRIO_INHERIT 2
#endif
#if defined(_POSIX_THREAD_PRIO_PROTECT)
#define PTHREAD_PRIO_PROTECT 3
#endif
 
//-----------------------------------------------------------------------------
// Condition Variable structure.
// Like mutexes, this must match the underlying eCos implementation class.
 
typedef struct
{
CYG_ADDRESS mutex;
CYG_ADDRESS queue;
} pthread_cond_t;
 
#define PTHREAD_COND_INITIALIZER { 0, 0 }
 
//-----------------------------------------------------------------------------
// Condition variable attributes structure
 
typedef struct
{
int dummy;
} pthread_condattr_t;
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_POSIX_MUTTYPES_H
// End of muttypes.h
/v2_0/include/utsname.h
0,0 → 1,98
#ifndef CYGONCE_UTSNAME_H
#define CYGONCE_UTSNAME_H
//=============================================================================
//
// utsname.h
//
// POSIX utsname header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-17
// Purpose: POSIX utsname header
// Description: This header contains all the definitions needed to support
// utsnames under eCos. The reader is referred to the POSIX
// standard or equivalent documentation for details of the
// functionality contained herein.
//
// Usage:
// #include <utsname.h>
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <cyg/infra/cyg_type.h>
 
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_MINIMUM
 
#include <stddef.h> // NULL, size_t
 
#include <limits.h>
 
#include <sys/types.h>
 
#include <sched.h> // SCHED_*
 
//=============================================================================
// UTSName structure
 
struct utsname
{
char sysname[CYG_POSIX_UTSNAME_LENGTH];
char nodename[CYG_POSIX_UTSNAME_NODENAME_LENGTH];
char release[CYG_POSIX_UTSNAME_LENGTH];
char version[CYG_POSIX_UTSNAME_LENGTH];
char machine[CYG_POSIX_UTSNAME_LENGTH];
};
 
//=============================================================================
// uname() function
 
__externC int uname( struct utsname *name );
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_UTSNAME_H
// End of utsname.h
/v2_0/include/signal.h
0,0 → 1,313
#ifndef CYGONCE_SIGNAL_H
#define CYGONCE_SIGNAL_H
//=============================================================================
//
// signal.h
//
// POSIX signal header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg, jlarmour
// Contributors:
// Date: 2000-03-17
// Purpose: POSIX signal header
// Description: This header contains all the definitions needed to support
// the POSIX signal API under eCos.
//
// Usage: This file can either be included directly, or indirectly via
// the C library signal.h header.
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#ifdef CYGPKG_POSIX_SIGNALS
 
#include <stddef.h> // NULL, size_t
 
#include <limits.h>
#include <sys/types.h>
 
//-----------------------------------------------------------------------------
// POSIX feature test macros
 
// We do not support job control
#undef _POSIX_JOB_CONTROL
 
//-----------------------------------------------------------------------------
// Manifest constants
 
#ifdef _POSIX_REALTIME_SIGNALS
// For now we define the topmost 8 signals as realtime
#define SIGRTMIN 24
#define SIGRTMAX 31
#endif
 
//-----------------------------------------------------------------------------
// forward references
 
struct timespec;
 
//-----------------------------------------------------------------------------
// Sigval structure
 
union sigval
{
int sival_int; // used when application-defined value is an int
void *sival_ptr; // used when application-defined value is a pointer
};
 
//-----------------------------------------------------------------------------
// Siginfo structure passed to an SA_SIGINFO style handler
 
typedef struct
{
int si_signo; // signal number
int si_code; // cause of signal
union sigval si_value; // signal value
} siginfo_t;
 
// Values for si_code
# define SI_USER 1
# define SI_QUEUE 2
# define SI_TIMER 3
# define SI_ASYNCIO 4
# define SI_MESGQ 5
# define SI_EXCEPT 6 // signal is result of an exception delivery
 
//-----------------------------------------------------------------------------
// Basic types
 
// Integral type that can be accessed atomically - from ISO C 7.7
typedef cyg_atomic sig_atomic_t;
 
// Type of signal handler functions
typedef void (*sa_sighandler_t)(int);
 
// Type of signal handler used if SA_SIGINFO is set in sa_flags
typedef void (*sa_siginfoaction_t)(int signo, siginfo_t *info,
void *context);
 
//-----------------------------------------------------------------------------
//Signal handlers for use with signal() and sigaction(). We avoid 0
//because in an embedded system this may be start of ROM and thus
//a possible function pointer for reset.
 
#define SIG_DFL ((sa_sighandler_t) 1) // Default action
#define SIG_IGN ((sa_sighandler_t) 2) // Ignore action
#define SIG_ERR ((sa_sighandler_t)-1) // Error return
 
//-----------------------------------------------------------------------------
// Signal values
 
#define SIGNULL 0 // Reserved signal - do not use (POSIX 3.3.1.1)
#define SIGHUP 1 // Hangup on controlling terminal (POSIX)
#define SIGINT 2 // Interactive attention (ISO C)
#define SIGQUIT 3 // Interactive termination (POSIX)
#define SIGILL 4 // Illegal instruction (not reset when caught) (ISO C)
#define SIGTRAP 5 // Trace trap (not reset when caught)
#define SIGIOT 6 // IOT instruction
#define SIGABRT 6 // Abnormal termination - used by abort() (ISO C)
#define SIGEMT 7 // EMT instruction
#define SIGFPE 8 // Floating Point Exception e.g. div by 0 (ISO C)
#define SIGKILL 9 // Kill (cannot be caught or ignored) (POSIX)
#define SIGBUS 10 // Bus error (POSIX)
#define SIGSEGV 11 // Invalid memory reference (ISO C)
#define SIGSYS 12 // Bad argument to system call (used by anything?)
#define SIGPIPE 13 // Write on a pipe with no one to read it (POSIX)
#define SIGALRM 14 // Alarm timeout (POSIX)
#define SIGTERM 15 // Software termination request (ISO C)
#define SIGUSR1 16 // Application-defined signal 1 (POSIX)
#define SIGUSR2 17 // Application-defined signal 2 (POSIX)
 
 
//-----------------------------------------------------------------------------
// Signal sets.
// At present we define a single 32 bit integer mask. We may need, at
// some future point, to extend this to 64 bits, or a structure
// containing an array of masks.
 
typedef cyg_uint32 sigset_t;
 
//-----------------------------------------------------------------------------
// struct sigaction describes the action to be taken when we get a signal
 
struct sigaction
{
sigset_t sa_mask; // Additional signals to be blocked
int sa_flags; // Special flags
union
{
sa_sighandler_t sa_handler; // signal handler
sa_siginfoaction_t sa_sigaction; // Function to call instead of
// sa_handler if SA_SIGINFO is
// set in sa_flags
} sa_sigactionhandler;
#define sa_handler sa_sigactionhandler.sa_handler
#define sa_sigaction sa_sigactionhandler.sa_sigaction
};
 
// sa_flag bits
#define SA_NOCLDSTOP 1 // Don't generate SIGCHLD when children stop
#define SA_SIGINFO 2 // Use the sa_siginfoaction_t style signal
// handler, instead of the single argument handler
 
//-----------------------------------------------------------------------------
// Sigevent structure.
 
struct sigevent
{
int sigev_notify;
int sigev_signo;
union sigval sigev_value;
void (*sigev_notify_function) (union sigval);
pthread_attr_t *sigev_notify_attributes;
};
 
# define SIGEV_NONE 1
# define SIGEV_SIGNAL 2
# define SIGEV_THREAD 3
 
//-----------------------------------------------------------------------------
// Functions to generate signals
 
// Deliver sig to a process.
// eCos only supports the value 0 for pid.
externC int kill (pid_t pid, int sig);
 
externC int pthread_kill (pthread_t thread, int sig);
 
//-----------------------------------------------------------------------------
// Functions to catch signals
 
// Install signal handler for sig.
externC int sigaction (int sig, const struct sigaction *act,
struct sigaction *oact);
 
// Queue signal to process with value.
externC int sigqueue (pid_t pid, int sig, const union sigval value);
 
//-----------------------------------------------------------------------------
// Functions to deal with current blocked and pending masks
 
// Set process blocked signal mask
externC int sigprocmask (int how, const sigset_t *set, sigset_t *oset);
 
// Set calling thread's blocked signal mask
externC int pthread_sigmask (int how, const sigset_t *set, sigset_t *oset);
 
// Get set of pending signals for this process
externC int sigpending (sigset_t *set);
 
// Values for the how arguments:
#define SIG_BLOCK 1
#define SIG_UNBLOCK 2
#define SIG_SETMASK 3
 
//-----------------------------------------------------------------------------
// Wait for or accept signals
 
// Block signals in set and wait for a signal
externC int sigsuspend (const sigset_t *set);
 
// Wait for a signal in set to arrive
externC int sigwait (const sigset_t *set, int *sig);
 
// Do the same as sigwait() except return a siginfo_t object too.
externC int sigwaitinfo (const sigset_t *set, siginfo_t *info);
 
// Do the same as sigwaitinfo() but return anyway after timeout.
externC int sigtimedwait (const sigset_t *set, siginfo_t *info,
const struct timespec *timeout);
 
//-----------------------------------------------------------------------------
// Signal sets
 
// Clear all signals from set.
externC int sigemptyset (sigset_t *set);
 
// Set all signals in set.
externC int sigfillset (sigset_t *set);
 
// Add signo to set.
externC int sigaddset (sigset_t *set, int signo);
 
// Remove signo from set.
externC int sigdelset (sigset_t *set, int signo);
 
// Test whether signo is in set
externC int sigismember (const sigset_t *set, int signo);
 
//-----------------------------------------------------------------------------
// alarm, pause and sleep
 
// Generate SIGALRM after some number of seconds
externC unsigned int alarm( unsigned int seconds );
 
// Wait for a signal to be delivered.
externC int pause( void );
 
// Wait for a signal, or the given number of seconds
externC unsigned int sleep( unsigned int seconds );
 
//-----------------------------------------------------------------------------
// signal() - ISO C 7.7.1 //
//
// Installs a new signal handler for the specified signal, and returns
// the old handler
//
 
externC sa_sighandler_t signal(int __sig, sa_sighandler_t __handler);
 
// raise() - ISO C 7.7.2 //
//
// Raises the signal, which will cause the current signal handler for
// that signal to be called
 
externC int raise(int __sig);
 
#endif // ifdef CYGPKG_POSIX_SIGNALS
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_SIGNAL_H
// End of signal.h
/v2_0/include/time.h
0,0 → 1,151
#ifndef CYGONCE_POSIX_TIME_H
#define CYGONCE_POSIX_TIME_H
/*=============================================================================
//
// time.h
//
// POSIX time header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg, jlarmour
// Date: 2000-03-17
// Purpose: POSIX time header
// Description: This header contains all the definitions needed to support
// the POSIX timer and timer API under eCos.
//
// Usage: Do not include this file directly - instead include <time.h>
//
//
//####DESCRIPTIONEND####
//
//===========================================================================*/
 
#include <pkgconf/posix.h>
#include <cyg/infra/cyg_type.h>
 
/*---------------------------------------------------------------------------*/
/* Types for timers and clocks */
 
typedef int clockid_t;
 
#ifdef CYGPKG_POSIX_TIMERS
typedef int timer_t;
 
/* forward declaration - if the app uses it it will have to include
* signal.h anyway
*/
struct sigevent;
#endif
 
/*---------------------------------------------------------------------------*/
/* Structures */
 
struct timespec
{
time_t tv_sec;
long tv_nsec;
};
 
#ifdef CYGPKG_POSIX_TIMERS
struct itimerspec
{
struct timespec it_interval;
struct timespec it_value;
};
#endif
 
/*---------------------------------------------------------------------------*/
/* Manifest constants */
 
#define CLOCK_REALTIME 0
 
#ifdef CYGPKG_POSIX_TIMERS
#define TIMER_ABSTIME 1
#endif
 
/*---------------------------------------------------------------------------*/
/* Clock functions */
 
/* Set the clocks current time */
__externC int clock_settime( clockid_t clock_id, const struct timespec *tp);
 
/* Get the clocks current time */
__externC int clock_gettime( clockid_t clock_id, struct timespec *tp);
 
/* Get the clocks resolution */
__externC int clock_getres( clockid_t clock_id, struct timespec *tp);
 
 
/*---------------------------------------------------------------------------*/
/* Timer functions */
 
#ifdef CYGPKG_POSIX_TIMERS
 
/* Create a timer based on the given clock. */
__externC int timer_create( clockid_t clock_id,
struct sigevent *evp,
timer_t *timer_id);
 
/* Delete the timer */
__externC int timer_delete( timer_t timer_id );
 
/* Set the expiration time of the timer. */
__externC int timer_settime( timer_t timerid, int flags,
const struct itimerspec *value,
struct itimerspec *ovalue );
 
/* Get current timer values */
__externC int timer_gettime( timer_t timerid, struct itimerspec *value );
 
/* Get number of missed triggers */
__externC int timer_getoverrun( timer_t timerid );
 
#endif
 
/*---------------------------------------------------------------------------*/
/* Nanosleep */
 
/* Sleep for the given time. */
__externC int nanosleep( const struct timespec *rqtp,
struct timespec *rmtp);
 
 
/*---------------------------------------------------------------------------*/
#endif /* ifndef CYGONCE_POSIX_TIME_H */
/* End of time.h */
/v2_0/include/export.h
0,0 → 1,112
#ifndef CYGONCE_POSIX_EXPORT_H
#define CYGONCE_POSIX_EXPORT_H
//=============================================================================
//
// export.h
//
// POSIX export header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Nick Garnett
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-09-18
// Purpose: POSIX export header
// Description: This header contains definitions that the POSIX package exports
// to other packages. These are generally interfaces that are not
// provided by the public API.
//
//
// Usage:
// #ifdef CYGPKG_POSIX
// #include <export.h>
// #endif
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <cyg/infra/cyg_type.h>
 
#include <stddef.h> // NULL, size_t
 
#include <limits.h>
#include <signal.h>
 
#include <sys/types.h>
 
#include <sched.h> // SCHED_*
 
//=============================================================================
// POSIX API function management.
// These macros should be inserted near the start and all returns of
// any function that is part of the POSIX API.
 
__externC void cyg_posix_function_start();
__externC void cyg_posix_function_finish();
 
#define CYG_POSIX_FUNCTION_START() cyg_posix_function_start()
 
#define CYG_POSIX_FUNCTION_FINISH() cyg_posix_function_finish()
 
//-----------------------------------------------------------------------------
// Signal mask management
//
// These are exported to allow functions in other packages to
// manipulate the current threads signal mask. they are currently only
// used in the implementation of cyg_pselect() in the FILEIO package.
 
__externC void cyg_pthread_sigmask_set (const sigset_t *set, sigset_t *oset);
__externC cyg_bool cyg_posix_sigpending(void);
__externC void cyg_posix_deliver_signals(const sigset_t *mask);
 
#define CYG_PTHREAD_SIGMASK_SET cyg_pthread_sigmask_set
 
#define CYG_POSIX_SIGPENDING() cyg_posix_sigpending()
 
#define CYG_POSIX_DELIVER_SIGNALS cyg_posix_deliver_signals
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_POSIX_EXPORT_H
// End of export.h
/v2_0/include/limits.h
0,0 → 1,131
#ifndef CYGONCE_LIMITS_H
#define CYGONCE_LIMITS_H
//=============================================================================
//
// limits.h
//
// POSIX limits header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-17
// Purpose: POSIX limits header
// Description: This file contains the compile time definitions that describe
// the minima and current values of various values and defined
// in POSIX.1 section 2.8.
//
// Usage:
// #include <limits.h>
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/posix.h>
 
//-----------------------------------------------------------------------------
// Runtime invariants
// These are all equal to or greater than the minimum values defined above.
 
// From table 2-4
 
#define NGROUPS_MAX _POSIX_NGROUPS_MAX
 
// From table 2-5
 
#define AIO_LISTIO_MAX _POSIX_AIO_LISTIO_MAX
 
#define AIO_MAX _POSIX_AIO_MAX
 
#define AIO_PRIO_DELTA_MAX 0
 
#define ARG_MAX _POSIX_ARG_MAX
 
#define CHILD_MAX _POSIX_CHILD_MAX
 
#define DELAYTIMER_MAX _POSIX_DELAYTIMER_MAX
 
#define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX
 
#define PAGESIZE 1
 
#define PTHREAD_DESTRUCTOR_ITERATIONS CYGNUM_POSIX_PTHREAD_DESTRUCTOR_ITERATIONS
 
#define PTHREAD_KEYS_MAX CYGNUM_POSIX_PTHREAD_KEYS_MAX
 
// Minimum size needed on a pthread stack to contain its per-thread control
// structures and per-thread data. Since we cannot include all the headers
// necessary to calculate this value here, the following is a generous estimate.
#define PTHREAD_STACK_OVERHEAD (0x180+(PTHREAD_KEYS_MAX*sizeof(void *)))
 
#define PTHREAD_STACK_MIN (CYGNUM_HAL_STACK_SIZE_MINIMUM+PTHREAD_STACK_OVERHEAD)
 
#define PTHREAD_THREADS_MAX CYGNUM_POSIX_PTHREAD_THREADS_MAX
 
#define RTSIG_MAX _POSIX_RTSIG_MAX
 
#define SEM_NSEMS_MAX _POSIX_SEM_NSEMS_MAX
 
#define SEM_VALUE_MAX _POSIX_SEM_VALUE_MAX
 
#define SIGQUEUE_MAX _POSIX_SIGQUEUE_MAX
 
#define STREAM_MAX _POSIX_STREAM_MAX
 
#define TIMER_MAX _POSIX_TIMER_MAX
 
#define TTY_NAME_MAX _POSIX_TTY_NAME_MAX
 
#define TZNAME_MAX _POSIX_TZNAME_MAX
 
 
// From table 2-6.
 
#define MAX_CANON _POSIX_MAX_CANON
 
#define MAX_INPUT _POSIX_MAX_INPUT
 
#define PIPE_BUF _POSIX_PIPE_BUF
 
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_LIMITS_H
// End of limits.h
/v2_0/include/mutex.h
0,0 → 1,172
#ifndef CYGONCE_POSIX_MUTEX_H
#define CYGONCE_POSIX_MUTEX_H
//=============================================================================
//
// mutex.h
//
// POSIX mutex and condition variable function definitions
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg,jlarmour
// Contributors:
// Date: 2001-09-10
// Purpose: POSIX mutex and condition variable function definitions
// Description: This header contains POSIX API definitions for mutexes
// and cond vars.
//
// Usage: #include <pthread.h>
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/posix.h>
 
#include <sys/types.h> // pthread_* types
 
//=============================================================================
// Mutexes
 
//-----------------------------------------------------------------------------
// Mutex attributes manipulation functions
 
// Initialize attribute object
externC int pthread_mutexattr_init ( pthread_mutexattr_t *attr);
 
// Destroy attribute object
externC int pthread_mutexattr_destroy ( pthread_mutexattr_t *attr);
 
#if defined(_POSIX_THREAD_PRIO_INHERIT) || defined(_POSIX_THREAD_PRIO_PROTECT)
 
// Set priority inversion protection protocol
externC int pthread_mutexattr_setprotocol ( pthread_mutexattr_t *attr,
int protocol);
 
// Get priority inversion protection protocol
externC int pthread_mutexattr_getprotocol ( pthread_mutexattr_t *attr,
int *protocol);
 
#if defined(_POSIX_THREAD_PRIO_PROTECT)
 
// Set priority for priority ceiling protocol
externC int pthread_mutexattr_setprioceiling ( pthread_mutexattr_t *attr,
int prioceiling);
 
// Get priority for priority ceiling protocol
externC int pthread_mutexattr_getprioceiling ( pthread_mutexattr_t *attr,
int *prioceiling);
 
// Set priority ceiling of given thread, returning old ceiling.
externC int pthread_mutex_setprioceiling( pthread_mutex_t *mutex,
int prioceiling,
int *old_ceiling);
 
// Get priority ceiling of given thread
externC int pthread_mutex_getprioceiling( pthread_mutex_t *mutex,
int *prioceiling);
#endif
 
#endif
 
//-----------------------------------------------------------------------------
// Mutex functions
 
// Initialize mutex. If mutex_attr is NULL, use default attributes.
externC int pthread_mutex_init (pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutex_attr);
 
// Destroy mutex.
externC int pthread_mutex_destroy (pthread_mutex_t *mutex);
 
// Lock mutex, waiting for it if necessary.
externC int pthread_mutex_lock (pthread_mutex_t *mutex);
 
// Try to lock mutex.
externC int pthread_mutex_trylock (pthread_mutex_t *mutex);
 
 
// Unlock mutex.
externC int pthread_mutex_unlock (pthread_mutex_t *mutex);
 
 
 
//=============================================================================
// Condition Variables
 
//-----------------------------------------------------------------------------
// Attribute manipulation functions
// We do not actually support any attributes at present, so these do nothing.
 
// Initialize condition variable attributes
externC int pthread_condattr_init (pthread_condattr_t *attr);
 
// Destroy condition variable attributes
externC int pthread_condattr_destroy (pthread_condattr_t *attr);
 
//-----------------------------------------------------------------------------
// Condition variable functions
 
// Initialize condition variable.
externC int pthread_cond_init (pthread_cond_t *cond,
const pthread_condattr_t *attr);
 
// Destroy condition variable.
externC int pthread_cond_destroy (pthread_cond_t *cond);
 
// Wake up one thread waiting for condition variable
externC int pthread_cond_signal (pthread_cond_t *cond);
 
// Wake up all threads waiting for condition variable
externC int pthread_cond_broadcast (pthread_cond_t *cond);
 
// Block on condition variable until signalled. The mutex is
// assumed to be locked before this call, will be unlocked
// during the wait, and will be re-locked on wakeup.
externC int pthread_cond_wait (pthread_cond_t *cond,
pthread_mutex_t *mutex);
 
// Block on condition variable until signalled, or the timeout expires.
externC int pthread_cond_timedwait (pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec *abstime);
 
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_POSIX_MUTEX_H
// End of mutex.h
/v2_0/include/semaphore.h
0,0 → 1,127
#ifndef CYGONCE_SEMAPHORE_H
#define CYGONCE_SEMAPHORE_H
//=============================================================================
//
// semaphore.h
//
// POSIX semaphore header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-17
// Purpose: POSIX semaphore header
// Description: This header contains all the definitions needed to support
// semaphores under eCos. The reader is referred to the POSIX
// standard or equivalent documentation for details of the
// functionality contained herein.
//
// Usage:
// #include <semaphore.h>
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <stddef.h> // NULL, size_t
 
#include <limits.h>
 
#include <sys/types.h>
 
//-----------------------------------------------------------------------------
// Semaphore object definition
 
// This structure must exactly correspond in size and layout to the underlying
// eCos C++ class that implements this object.
 
typedef struct
{
CYG_WORD32 sem_value;
CYG_ADDRESS sem_queue;
} sem_t;
 
//-----------------------------------------------------------------------------
// Semaphore functions
 
// Initialize semaphore to value.
// pshared is not supported under eCos.
externC int sem_init (sem_t *sem, int pshared, unsigned int value);
 
// Destroy the semaphore.
externC int sem_destroy (sem_t *sem);
 
// Decrement value if >0 or wait for a post.
externC int sem_wait (sem_t *sem);
 
// Decrement value if >0, return -1 if not.
externC int sem_trywait (sem_t *sem);
 
// Increment value and wake a waiter if one is present.
externC int sem_post (sem_t *sem);
 
// Get current value
externC int sem_getvalue (sem_t *sem, int *sval);
 
//-----------------------------------------------------------------------------
// Named semaphore functions
// These are an optional feature under eCos
 
// Open an existing named semaphore, or create it.
externC sem_t *sem_open (const char *name, int oflag, ...);
 
// Close descriptor for semaphore.
externC int sem_close (sem_t *sem);
 
// Remove named semaphore
externC int sem_unlink (const char *name);
 
//-----------------------------------------------------------------------------
// Special return value for sem_open()
 
#define SEM_FAILED ((sem_t *)NULL)
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_SEMAPHORE_H
// End of semaphore.h
/v2_0/include/types.h
0,0 → 1,112
#ifndef CYGONCE_POSIX_TYPES_H
#define CYGONCE_POSIX_TYPES_H
//=============================================================================
//
// types.h
//
// POSIX types header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-17
// Purpose: POSIX types header
// Description: This header contains various POSIX type definitions. These types
// are implementation defined.
//
// Usage: #include <sys/types.h>
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <cyg/infra/cyg_type.h>
 
//-----------------------------------------------------------------------------
// Basic types.
 
typedef cyg_uint32 pthread_t;
typedef int pthread_key_t;
typedef int pthread_once_t;
 
//-----------------------------------------------------------------------------
// Scheduling parameters. At present only the priority is defined.
// Strictly this should be in <sched.h>, but the requirement for pthread_attr_t
// to contain a sched_param object means that it must be here.
 
struct sched_param
{
int sched_priority;
};
 
//-----------------------------------------------------------------------------
// Thread attribute structure.
 
typedef struct pthread_attr_t
{
unsigned int detachstate:2,
scope:2,
inheritsched:2,
schedpolicy:2,
stackaddr_valid:1,
stacksize_valid:1;
struct sched_param schedparam;
void *stackaddr;
size_t stacksize;
} pthread_attr_t;
 
// Values for detachstate
#define PTHREAD_CREATE_JOINABLE 1
#define PTHREAD_CREATE_DETACHED 2
 
// Values for scope
#define PTHREAD_SCOPE_SYSTEM 1
#define PTHREAD_SCOPE_PROCESS 2
 
// Values for inheritsched
#define PTHREAD_INHERIT_SCHED 1
#define PTHREAD_EXPLICIT_SCHED 2
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_POSIX_TYPES_H
// End of types.h
/v2_0/include/sigsetjmp.h
0,0 → 1,94
#ifndef CYGONCE_SIGSETJMP_H
#define CYGONCE_SIGSETJMP_H
//=============================================================================
//
// sigsetjmp.h
//
// POSIX sigsetjmp header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg, jlarmour
// Contributors:
// Date: 2000-03-17
// Purpose: POSIX sigsetjmp header
// Description: This header contains all the definitions needed to support
// the POSIX sigsetjmp/siglongjmp API under eCos.
//
// Usage: This file must be included indirectly via
// the C library setjmp.h header.
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <signal.h>
#include <cyg/hal/hal_arch.h> // hal_jmp_buf
 
//=============================================================================
// sigjmp_buf structure
// The API requires this to be an array type, but this array actually
// contains three fields:
// 0..sizeof(hal_jmp_buf)-1 HAL jump buffer
// sizeof(hal_jmp_buf) savemask value (an int)
// sizeof(hal_jmp_buf)+sizeof(int)... sigset_t containing saved mask
 
typedef struct {
hal_jmp_buf __jmp_buf;
int __savemask;
sigset_t __sigsavemask;
} sigjmp_buf[1];
 
//=============================================================================
// sigsetjmp() macro
 
#define sigsetjmp( _env_, _savemask_ ) \
( \
((_env_)[0].__savemask = _savemask_), \
((_savemask_)?pthread_sigmask(SIG_BLOCK,NULL,&((_env_)[0].__sigsavemask)):0),\
hal_setjmp((_env_)[0].__jmp_buf) \
)
 
//=============================================================================
// siglongjmp function
 
__externC void siglongjmp( sigjmp_buf env, int val );
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_SIGSETJMP_H
// End of sigsetjmp.h
/v2_0/include/pthread.h
0,0 → 1,320
#ifndef CYGONCE_PTHREAD_H
#define CYGONCE_PTHREAD_H
//=============================================================================
//
// pthread.h
//
// POSIX pthread header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-17
// Purpose: POSIX pthread header
// Description: This header contains all the definitions needed to support
// pthreads under eCos. The reader is referred to the POSIX
// standard or equivalent documentation for details of the
// functionality contained herein.
//
// Usage:
// #include <pthread.h>
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <cyg/infra/cyg_type.h>
 
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_MINIMUM
 
#include <stddef.h> // NULL, size_t
 
#include <limits.h>
 
#include <sys/types.h>
 
#include <sched.h> // SCHED_*
 
//=============================================================================
// General thread operations
 
//-----------------------------------------------------------------------------
// Thread creation and management.
 
// Create a thread.
externC int pthread_create ( pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg);
 
// Get current thread id.
externC pthread_t pthread_self ( void );
 
// Compare two thread identifiers.
externC int pthread_equal (pthread_t thread1, pthread_t thread2);
 
// Terminate current thread.
externC void pthread_exit (void *retval) CYGBLD_ATTRIB_NORET;
 
// Wait for the thread to terminate. If thread_return is not NULL then
// the retval from the thread's call to pthread_exit() is stored at
// *thread_return.
externC int pthread_join (pthread_t thread, void **thread_return);
 
// Set the detachstate of the thread to "detached". The thread then does not
// need to be joined and its resources will be freed when it exits.
externC int pthread_detach (pthread_t thread);
 
//-----------------------------------------------------------------------------
// Thread attribute handling.
 
// Initialize attributes object with default attributes:
// detachstate == PTHREAD_JOINABLE
// scope == PTHREAD_SCOPE_SYSTEM
// inheritsched == PTHREAD_EXPLICIT_SCHED
// schedpolicy == SCHED_OTHER
// schedparam == unset
// stackaddr == unset
// stacksize == 0
//
externC int pthread_attr_init (pthread_attr_t *attr);
 
// Destroy thread attributes object
externC int pthread_attr_destroy (pthread_attr_t *attr);
 
 
// Set the detachstate attribute
externC int pthread_attr_setdetachstate (pthread_attr_t *attr,
int detachstate);
 
// Get the detachstate attribute
externC int pthread_attr_getdetachstate (const pthread_attr_t *attr,
int *detachstate);
 
 
// Set scheduling contention scope
externC int pthread_attr_setscope (pthread_attr_t *attr, int scope);
 
// Get scheduling contention scope
externC int pthread_attr_getscope (const pthread_attr_t *attr, int *scope);
 
 
// Set scheduling inheritance attribute
externC int pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit);
 
// Get scheduling inheritance attribute
externC int pthread_attr_getinheritsched (const pthread_attr_t *attr,
int *inherit);
 
 
// Set scheduling policy
externC int pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy);
 
// Get scheduling policy
externC int pthread_attr_getschedpolicy (const pthread_attr_t *attr,
int *policy);
 
 
// Set scheduling parameters
externC int pthread_attr_setschedparam (pthread_attr_t *attr,
const struct sched_param *param);
 
// Get scheduling parameters
externC int pthread_attr_getschedparam (const pthread_attr_t *attr,
struct sched_param *param);
 
 
// Set starting address of stack. Whether this is at the start or end of
// the memory block allocated for the stack depends on whether the stack
// grows up or down.
externC int pthread_attr_setstackaddr (pthread_attr_t *attr, void *stackaddr);
 
// Get any previously set stack address.
externC int pthread_attr_getstackaddr (const pthread_attr_t *attr,
void **stackaddr);
 
 
// Set minimum creation stack size.
externC int pthread_attr_setstacksize (pthread_attr_t *attr,
size_t stacksize);
 
// Get current minimal stack size.
externC int pthread_attr_getstacksize (const pthread_attr_t *attr,
size_t *stacksize);
 
//-----------------------------------------------------------------------------
// Thread scheduling controls
 
// Set scheduling policy and parameters for the thread
externC int pthread_setschedparam (pthread_t thread,
int policy,
const struct sched_param *param);
 
// Get scheduling policy and parameters for the thread
externC int pthread_getschedparam (pthread_t thread,
int *policy,
struct sched_param *param);
 
 
 
//=============================================================================
// Dynamic package initialization
 
// Initializer for pthread_once_t instances
#define PTHREAD_ONCE_INIT 0
 
// Call init_routine just the once per control variable.
externC int pthread_once (pthread_once_t *once_control,
void (*init_routine) (void));
 
 
 
//=============================================================================
//Thread specific data
 
// Create a key to identify a location in the thread specific data area.
// Each thread has its own distinct thread-specific data area but all are
// addressed by the same keys. The destructor function is called whenever a
// thread exits and the value associated with the key is non-NULL.
externC int pthread_key_create (pthread_key_t *key,
void (*destructor) (void *));
 
// Delete key.
externC int pthread_key_delete (pthread_key_t key);
 
// Store the pointer value in the thread-specific data slot addressed
// by the key.
externC int pthread_setspecific (pthread_key_t key, const void *pointer);
 
// Retrieve the pointer value in the thread-specific data slot addressed
// by the key.
externC void *pthread_getspecific (pthread_key_t key);
 
 
 
//=============================================================================
// Thread Cancellation
 
//-----------------------------------------------------------------------------
// Data structure used to manage cleanup functions
 
struct pthread_cleanup_buffer
{
struct pthread_cleanup_buffer *prev; // Chain cleanup buffers
void (*routine) (void *); // Function to call
void *arg; // Arg to pass
};
 
//-----------------------------------------------------------------------------
// Thread cancelled return value.
// This is a value returned as the retval in pthread_join() of a
// thread that has been cancelled. By making it the address of a
// location we define we can ensure that it differs from NULL and any
// other valid pointer (as required by the standard).
 
externC int pthread_canceled_dummy_var;
 
#define PTHREAD_CANCELED ((void *)(&pthread_canceled_dummy_var))
 
//-----------------------------------------------------------------------------
// Cancelability enable and type
 
#define PTHREAD_CANCEL_ENABLE 1
#define PTHREAD_CANCEL_DISABLE 2
 
#define PTHREAD_CANCEL_ASYNCHRONOUS 1
#define PTHREAD_CANCEL_DEFERRED 2
 
//-----------------------------------------------------------------------------
// Functions
 
// Set cancel state of current thread to ENABLE or DISABLE.
// Returns old state in *oldstate.
externC int pthread_setcancelstate (int state, int *oldstate);
 
// Set cancel type of current thread to ASYNCHRONOUS or DEFERRED.
// Returns old type in *oldtype.
externC int pthread_setcanceltype (int type, int *oldtype);
 
// Cancel the thread.
externC int pthread_cancel (pthread_t thread);
 
// Test for a pending cancellation for the current thread and terminate
// the thread if there is one.
externC void pthread_testcancel (void);
 
// Install a cleanup routine.
// Note that pthread_cleanup_push() and pthread_cleanup_pop() are macros that
// must be used in matching pairs and at the same brace nesting level.
#define pthread_cleanup_push(routine,arg) \
{ \
struct pthread_cleanup_buffer _buffer_; \
pthread_cleanup_push_inner (&_buffer_, (routine), (arg));
 
// Remove a cleanup handler installed by the matching pthread_cleanup_push().
// If execute is non-zero, the handler function is called.
#define pthread_cleanup_pop(execute) \
pthread_cleanup_pop_inner (&_buffer_, (execute)); \
}
 
 
// These two functions actually implement the cleanup push and pop functionality.
externC void pthread_cleanup_push_inner (struct pthread_cleanup_buffer *buffer,
void (*routine) (void *),
void *arg);
 
externC void pthread_cleanup_pop_inner (struct pthread_cleanup_buffer *buffer,
int execute);
 
 
// -------------------------------------------------------------------------
// eCos-specific function to measure stack usage of the supplied thread
 
#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
externC size_t pthread_measure_stack_usage (pthread_t thread);
#endif
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_PTHREAD_H
// End of pthread.h
/v2_0/doc/posix.sgml
0,0 → 1,1568
<!-- {{{ Banner -->
 
<!-- =============================================================== -->
<!-- -->
<!-- posix.sgml -->
<!-- -->
<!-- POSIX Compatibility -->
<!-- -->
<!-- =============================================================== -->
<!-- ####COPYRIGHTBEGIN#### -->
<!-- -->
<!-- =============================================================== -->
<!-- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -->
<!-- This material may be distributed only subject to the terms -->
<!-- and conditions set forth in the Open Publication License, v1.0 -->
<!-- or later (the latest version is presently available at -->
<!-- http://www.opencontent.org/openpub/) -->
<!-- Distribution of the work or derivative of the work in any -->
<!-- standard (paper) book form is prohibited unless prior -->
<!-- permission obtained from the copyright holder -->
<!-- =============================================================== -->
<!-- -->
<!-- ####COPYRIGHTEND#### -->
<!-- =============================================================== -->
<!-- #####DESCRIPTIONBEGIN#### -->
<!-- -->
<!-- ####DESCRIPTIONEND#### -->
<!-- =============================================================== -->
 
<!-- }}} -->
 
<part id="posix-compatibility">
<title>eCos POSIX compatibility layer</title>
 
<chapter id="posix-standard-support">
<title>POSIX Standard Support</title>
 
<!-- {{{ Intro -->
 
<para>
eCos contains support for the POSIX Specification (ISO&sol;IEC
9945-1)&lsqb;POSIX&rsqb;.
</para>
<para>
POSIX support is divided between the POSIX and the FILEIO
packages. The POSIX package provides support for threads,
signals, synchronization, timers and message queues. The FILEIO
package provides support for file and device I&sol;O. The two
packages may be used together or separately, depending on
configuration.
</para>
<para>
This document takes a functional approach to the POSIX
library. Support for a function implies that the data types and
definitions necessary to support that function, and the objects
it manipulates, are also defined. Any exceptions to this are
noted, and unless otherwise noted, implemented functions behave
as specified in the POSIX standard.
</para>
<para>
This document only covers the differences between the eCos
implementation and the standard; it does not provide complete
documentation. For full information, see the POSIX standard
&lsqb;POSIX&rsqb;. Online, the Open Group Single Unix
Specification &lsqb;SUS2&rsqb; provides complete documentation
of a superset of POSIX. If you have access to a Unix system with
POSIX compatibility, then the manual pages for this will be of
use. There are also a number of books available.
&lsqb;Lewine&rsqb; covers the process, signal, file and I&sol;O
functions, while &lsqb;Lewis1&rsqb;, &lsqb;Lewis2&rsqb;,
&lsqb;Nichols&rsqb; and &lsqb;Norton&rsqb; cover Pthreads and
related topics (see Bibliography, xref). However, many of these
books are oriented toward using POSIX in non-embedded systems,
so care should be taken in applying them to programming under
eCos.
</para>
<para>
The remainder of this chapter broadly follows the structure
of the POSIX Specification. References to the appropriate
section of the Standard are included.
</para>
<para>
Omitted functions marked with &ldquo;&sol;&sol; TBA&rdquo;
are potential candidates for later implementation.
</para>
 
<!-- }}} -->
<!-- {{{ Process Primitives -->
 
<sect1 id="posix-process-primitives">
<title>Process Primitives &lsqb;POSIX Section 3&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
int kill(pid&lowbar;t pid, int sig);
int pthread&lowbar;kill(pthread&lowbar;t thread, int sig);
int sigaction(int sig, const struct sigaction &ast;act,
struct sigaction &ast;oact);
int sigqueue(pid&lowbar;t pid, int sig, const union sigval value);
int sigprocmask(int how, const sigset&lowbar;t &ast;set,
sigset&lowbar;t &ast;oset);
int pthread&lowbar;sigmask(int how, const sigset&lowbar;t &ast;set,
sigset&lowbar;t &ast;oset);
int sigpending(sigset&lowbar;t &ast;set);
int sigsuspend(const sigset&lowbar;t &ast;set);
int sigwait(const sigset&lowbar;t &ast;set, int &ast;sig);
int sigwaitinfo(const sigset&lowbar;t &ast;set, siginfo&lowbar;t &ast;info);
int sigtimedwait(const sigset&lowbar;t &ast;set, siginfo&lowbar;t &ast;info,
const struct timespec &ast;timeout);
int sigemptyset(sigset&lowbar;t &ast;set);
int sigfillset(sigset&lowbar;t &ast;set);
int sigaddset(sigset&lowbar;t &ast;set, int signo);
int sigdelset(sigset&lowbar;t &ast;set, int signo);
int sigismember(const sigset&lowbar;t &ast;set, int signo);
unsigned int alarm( unsigned int seconds );
int pause( void );
unsigned int sleep( unsigned int seconds );
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
 
<screen>
pid&lowbar;t fork(void);
int execl( const char &ast;path, const char &ast;arg, ... );
int execv( const char &ast;path, char &ast;const argv&lsqb;&rsqb; );
int execle( const char &ast;path, const char &ast;arg, ... );
int execve( const char &ast;path, char &ast;const argv&lsqb;&rsqb;,
char &ast;const envp&lsqb;&rsqb; );
int execlp( const char &ast;path, const char &ast;arg, ... );
int execvp( const char &ast;path, char &ast;const argv&lsqb;&rsqb; );
int pthread&lowbar;atfork( void(&ast;prepare)(void),
void (&ast;parent)(void),
void (&ast;child)() );
pid&lowbar;t wait( int &ast;stat&lowbar;loc );
pid&lowbar;t waitpid( pid&lowbar;t pid, int &ast;stat&lowbar;loc,
int options );
void &lowbar;exit( int status );
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<itemizedlist>
<listitem>
<para>
Signal handling may be enabled or disabled with the
CYGPKG&lowbar;POSIX&lowbar;SIGNALS option. Since signals are used
by other POSIX components, such as timers, disabling signals will
disable those components too.
</para>
</listitem>
<listitem>
<para>
<emphasis>kill()</emphasis> and
<emphasis>sigqueue()</emphasis> may only take a
<emphasis role="strong">pid</emphasis> argument of zero,
which maps to the current process.
</para>
</listitem>
<listitem>
<para>
The <emphasis>SIGEV&lowbar;THREAD</emphasis> notification type is
not currently implemented.
</para>
</listitem>
<listitem>
<para>
Job Control and Memory Protection signals are
not supported.
</para>
</listitem>
 
<listitem>
<para>
An extra implementation defined
<emphasis>si&lowbar;code</emphasis> value,
<emphasis>SI&lowbar;EXCEPT</emphasis>, is defined to
distinguish hardware generated exceptions from
others.
</para>
</listitem>
 
<listitem>
<para>
Extra signals are defined:
&lowbar;SIGTRAP&lowbar;,&lowbar;SIGIOT&lowbar;,
&lowbar;SIGEMT&lowbar;, and &lowbar;SIGSYS&lowbar;. These are
largely to maintain compatibility with the signal numbers used by
GDB.
</para>
</listitem>
 
<listitem>
<para>
Signal delivery may currently occur at unexpected places in some
API functions. Using <emphasis>longjmp()</emphasis> to transfer
control out of a signal handler may result in the interrupted
function not being able to complete properly. This may result in
later function calls failing or deadlocking.
</para>
</listitem>
</itemizedlist>
</sect2>
 
 
</sect1>
 
<!-- }}} -->
<!-- {{{ Process Environment -->
 
<sect1 id="posix-process-environment">
<title>Process Environment &lsqb;POSIX Section 4&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
int uname( struct utsname &ast;name );
time&lowbar;t time( time&lowbar;t &ast;tloc );
char &ast;getenv( const char &ast;name );
int isatty( int fd );
long sysconf( int name );
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
<screen>
pid&lowbar;t getpid( void );
pid&lowbar;t getppid( void );
uid&lowbar;t getuid( void );
uid&lowbar;t geteuid( void );
gid&lowbar;t getgid( void );
gid&lowbar;t getegid( void );
int setuid( uid&lowbar;t uid );
int setgid( gid&lowbar;t gid );
int getgroups( int gidsetsize, gid&lowbar;t grouplist&lsqb;&rsqb; );
char &ast;getlogin( void );
int getlogin&lowbar;r( char &ast;name, size&lowbar;t namesize );
pid&lowbar;t getpgrp( void );
pid&lowbar;t setsid( void );
int setpgid( pid&lowbar;t pid, pid&lowbar;t pgid );
char &ast;ctermid( char &ast;s);
char &ast;ttyname( int fd ); &sol;&sol; TBA
int ttyname&lowbar;r( int fd, char &ast;name, size&lowbar;t namesize); &sol;&sol; TBA
clock&lowbar;t times( struct tms &ast;buffer ); &sol;&sol; TBA
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<itemizedlist>
<listitem>
<para>The fields of the <emphasis>utsname</emphasis>
structure are initialized as follows:
<screen>
sysname &ldquo;eCos&rdquo;
nodename &ldquo;&rdquo; (gethostname() is currently not available)
release Major version number of the kernel
version Minor version number of the kernel
machine &ldquo;&rdquo; (Requires some config tool changes)
</screen>
</para>
<para>
The sizes of these strings are defined by
CYG&lowbar;POSIX&lowbar;UTSNAME&lowbar;LENGTH and
CYG&lowbar;POSIX&lowbar;UTSNAME&lowbar;NODENAME&lowbar;LENGTH. The
latter defaults to the value of the former, but may also
be set independently to accommodate a longer node name.
</para>
</listitem>
<listitem>
<para>
The <emphasis>time()</emphasis> function is currently
implemented in the C library.
</para>
</listitem>
<listitem>
<para>A set of environment strings may be defined at configuration
time with the CYGDAT&lowbar;LIBC&lowbar;DEFAULT&lowbar;ENVIRONMENT
option. The application may also define an environment by direct
assignment to the <emphasis role="strong">environ</emphasis>
variable.
</para>
</listitem>
<listitem>
<para>
At present <emphasis>isatty()</emphasis> assumes that
any character device is a tty and that all other devices are not
ttys. Since the only kind of device that eCos currently supports
is serial character devices, this is an adequate
distinction.
</para>
</listitem>
<listitem>
<para>
All system variables supported by sysconf will yield a
value. However, those that are irrelevant to eCos will
either return the default minimum defined in
<filename>&lt;limits.h&gt;</filename>,
or zero.
</para>
</listitem>
</itemizedlist>
 
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Files and Directories -->
 
<sect1 id="posix-files-and-directories">
<title>Files and Directories &lsqb;POSIX Section 5&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
DIR &ast;opendir( const char &ast;dirname );
struct dirent &ast;readdir( DIR &ast;dirp );
int readdir&lowbar;r( DIR &ast;dirp, struct dirent &ast;entry,
struct dirent &ast;&ast;result );
void rewinddir( DIR &ast;dirp );
int closedir( DIR &ast;dirp );
int chdir( const char &ast;path );
char &ast;getcwd( char &ast;buf, size&lowbar;t size );
int open( const char &ast; path , int oflag , ... );
int creat( const char &ast; path, mode&lowbar;t mode );
int link( const char &ast;existing, const char &ast;new );
int mkdir( const char &ast;path, mode&lowbar;t mode );
int unlink( const char &ast;path );
int rmdir( const char &ast;path );
int rename( const char &ast;old, const char &ast;new );
int stat( const char &ast;path, struct stat &ast;buf );
int fstat( int fd, struct stat &ast;buf );
int access( const char &ast;path, int amode );
long pathconf(const char &ast;path, int name);
long fpathconf(int fd, int name);
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
 
<screen>
mode&lowbar;t umask( mode&lowbar;t cmask );
int mkfifo( const char &ast;path, mode&lowbar;t mode );
int chmod( const char &ast;path, mode&lowbar;t mode ); &sol;&sol; TBA
int fchmod( int fd, mode&lowbar;t mode ); &sol;&sol; TBA
int chown( const char &ast;path, uid&lowbar;t owner, gid&lowbar;t group );
int utime( const char &ast;path, const struct utimbuf &ast;times ); &sol;&sol; TBA
int ftruncate( int fd, off&lowbar;t length ); &sol;&sol; TBA
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
 
<itemizedlist>
<listitem>
<para>
If a call to <function>open()</function> or <function>creat()</function> supplies
the third &lowbar;mode&lowbar; parameter, it will
currently be ignored.
</para>
</listitem>
<listitem>
<para>
Most of the functionality of these functions depends on
the underlying filesystem.
</para>
</listitem>
<listitem>
<para>
Currently<emphasis> access()</emphasis> only checks the
<emphasis>F&lowbar;OK</emphasis> mode explicitly, the others are
all assumed to be true by default.
</para>
</listitem>
<listitem>
<para>
The maximum number of open files allowed is supplied by
the CYGNUM&lowbar;FILEIO&lowbar;NFILE option. The maximum number
of file descriptors is supplied by the CYGNUM&lowbar;FILEIO&lowbar;NFD
option.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Input and Output -->
 
<sect1 id="posix-input-and-output">
<title>Input and Output &lsqb;POSIX Section 6&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
int dup( int fd );
int dup2( int fd, int fd2 );
int close(int fd);
ssize&lowbar;t read(int fd, void &ast;buf, size&lowbar;t nbyte);
ssize&lowbar;t write(int fd, const void &ast;buf, size&lowbar;t nbyte);
int fcntl( int fd, int cmd, ... );
off&lowbar;t lseek(int fd, off&lowbar;t offset, int whence);
int fsync( int fd );
int fdatasync( int fd );</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
<screen>
int pipe( int fildes&lsqb;2&rsqb; );
int aio&lowbar;read( struct aiocb &ast;aiocbp ); &sol;&sol; TBA
int aio&lowbar;write( struct aiocb &ast;aiocbp ); &sol;&sol; TBA
int lio&lowbar;listio( int mode, struct aiocb &ast;const list&lsqb;&rsqb;,
int nent, struct sigevent &ast;sig); &sol;&sol; TBA
int aio&lowbar;error( struct aiocb &ast;aiocbp ); &sol;&sol; TBA
int aio&lowbar;return( struct aiocb &ast;aiocbp ); &sol;&sol; TBA
int aio&lowbar;cancel( int fd, struct aiocb &ast;aiocbp ); &sol;&sol; TBA
int aio&lowbar;suspend( const struct aiocb &ast;const list&lsqb;&rsqb;,
int nent, const struct timespec &ast;timeout ); &sol;&sol; TBA
int aio&lowbar;fsync( int op, struct aiocb &ast;aiocbp );
&sol;&sol; TBA
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<itemizedlist>
<listitem>
<para>
Only the <emphasis>F&lowbar;DUPFD</emphasis> command
of <emphasis>fcntl()</emphasis> is currently implemented.
</para>
</listitem>
<listitem>
<para>
Most of the functionality of these functions depends on
the underlying filesystem.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Device and Class Specific Functions -->
 
<sect1 id="posix-device-and-class-specific-functions">
<title>Device and Class Specific Functions &lsqb;POSIX Section 7&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
<screen>
speed&lowbar;t cfgetospeed( const struct termios &ast;termios&lowbar;p );
int cfsetospeed( struct termios &ast;termios&lowbar;p, speed&lowbar;t speed );
speed&lowbar;t cfgetispeed( const struct termios &ast;termios&lowbar;p );
int cfsetispeed( struct termios &ast;termios&lowbar;p, speed&lowbar;t speed );
int tcgetattr( int fd, struct termios &ast;termios&lowbar;p );
int tcsetattr( int fd, int optional&lowbar;actions,
const struct termios &ast;termios&lowbar;p );
int tcsendbreak( int fd, int duration );
int tcdrain( int fd );
int tcflush( int fd, int queue&lowbar;selector );
int tcsendbreak( int fd, int action );
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
 
<screen>
pid&lowbar;t tcgetpgrp( int fd );
int tcsetpgrp( int fd, pid&lowbar;t pgrp );</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<itemizedlist>
<listitem>
<para>
Only the functionality relevant to basic serial device
control is implemented. Only very limited support for
canonical input is provided, and then only via the
&ldquo;tty&rdquo; devices, not the &ldquo;serial&rdquo;
devices. None of the functionality relevant to job
control, controlling terminals and sessions is
implemented.
</para>
</listitem>
<listitem>
<para>
Only <emphasis>MIN</emphasis> &equals; 0 and
<emphasis>TIME</emphasis> &equals; 0 functionality is
provided.
</para>
</listitem>
<listitem>
<para>
Hardware flow control is supported if the underlying
device driver and serial port support it.
</para>
</listitem>
<listitem>
<para>
Support for break, framing and parity errors depends on
the functionality of the hardware and device driver.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ C Language Services -->
 
<sect1 id="posix-C-language-services">
<title>C Language Services &lsqb;POSIX Section 8&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
<screen>
char &ast;setlocale( int category, const char &ast;locale );
int fileno( FILE &ast;stream );
FILE &ast;fdopen( int fd, const char &ast;type );
int getc&lowbar;unlocked( FILE &ast;stream);
int getchar&lowbar;unlocked( void );
int putc&lowbar;unlocked( FILE &ast;stream );
int putchar&lowbar;unlocked( void );
char &ast;strtok&lowbar;r( char &ast;s, const char &ast;sep,
char &ast;&ast;lasts );
char &ast;asctime&lowbar;r( const struct tm &ast;tm, char &ast;buf );
char &ast;ctime&lowbar;r( const time&lowbar;t &ast;clock, char &ast;buf );
struct tm &ast;gmtime&lowbar;r( const time&lowbar;t &ast;clock,
struct tm &ast;result );
struct tm &ast;localtime&lowbar;r( const time&lowbar;t &ast;clock,
struct tm &ast;result );
int rand&lowbar;r( unsigned int &ast;seed );
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
<screen>
void flockfile( FILE &ast;file );
int ftrylockfile( FILE &ast;file );
void funlockfile( FILE &ast;file );
int sigsetjmp( sigjmp&lowbar;buf env, int savemask ); &sol;&sol; TBA
void siglongjmp( sigjmp&lowbar;buf env, int val ); &sol;&sol; TBA
void tzset(void); &sol;&sol; TBA
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<itemizedlist>
<listitem>
<para>
<emphasis>setlocale()</emphasis> is implemented in the C
library Internationalization package.
</para>
</listitem>
<listitem>
<para>
Functions <emphasis>fileno()</emphasis> and
<emphasis>fdopen()</emphasis> are implemented in the C
library STDIO package.
</para>
</listitem>
<listitem>
<para>
Functions <emphasis>getc&lowbar;unlocked()</emphasis>,
<emphasis>getchar&lowbar;unlocked()</emphasis>,
<emphasis>putc&lowbar;unlocked()</emphasis> and
<emphasis>putchar&lowbar;unlocked()</emphasis> are defined
but are currently identical to their non-unlocked
equivalents.
</para>
</listitem>
<listitem>
<para>
<emphasis>strtok&lowbar;r()</emphasis>, <emphasis>asctime&lowbar;r()</emphasis>,
<emphasis>ctime&lowbar;r()</emphasis>, <emphasis>gmtime&lowbar;r()</emphasis>,
<emphasis>localtime&lowbar;r()</emphasis> and
<emphasis>rand&lowbar;r()</emphasis> are all currently in
the C library, alongside their non-reentrant versions.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ System Databases -->
 
<sect1 id="posix-system-databases">
<title>System Databases &lsqb;POSIX Section 9&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
<para>
&lt;none&gt;
</para>
 
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
 
<screen>
struct group &ast;getgrgid( gid&lowbar;t gid );
int getgrgid( gid&lowbar;t gid, struct group &ast;grp, char &ast;buffer,
size&lowbar;t bufsize, struct group &ast;&ast;result );
struct group &ast;getgrname( const char &ast;name );
int getgrname&lowbar;r( const char &ast;name, struct group &ast;grp,
char &ast;buffer, size&lowbar;t bufsize, struct group &ast;&ast;result );
struct passwd &ast;getpwuid( uid&lowbar;t uid );
int getpwuid&lowbar;r( uid&lowbar;t uid, struct passwd &ast;pwd,
char &ast;buffer, size&lowbar;t bufsize, struct passwd &ast;&ast;result );
struct passwd &ast;getpwnam( const char &ast;name );
int getpwnam&lowbar;r( const char &ast;name, struct passwd &ast;pwd,
char &ast;buffer, size&lowbar;t bufsize, struct passwd &ast;&ast;result );
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<itemizedlist>
<listitem>
<para>
None of the functions in this section are implemented.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Data Interchange Format -->
 
<sect1 id="posix-data-interchange-format">
<title>Data Interchange Format &lsqb;POSIX Section 10&rsqb;</title>
<para>
This section details <emphasis>tar</emphasis> and
<emphasis>cpio</emphasis> formats. Neither of these is supported by
eCos.
</para>
</sect1>
 
<!-- }}} -->
<!-- {{{ Synchronization -->
 
<sect1 id="posix-synchronization">
<title>Synchronization &lsqb;POSIX Section 11&rsqb;</title>
 
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
int sem&lowbar;init(sem&lowbar;t &ast;sem, int pshared, unsigned int value);
int sem&lowbar;destroy(sem&lowbar;t &ast;sem);
int sem&lowbar;wait(sem&lowbar;t &ast;sem);
int sem&lowbar;trywait(sem&lowbar;t &ast;sem);
int sem&lowbar;post(sem&lowbar;t &ast;sem);
int sem&lowbar;getvalue(sem&lowbar;t &ast;sem, int &ast;sval);
int pthread&lowbar;mutexattr&lowbar;init( pthread&lowbar;mutexattr&lowbar;t &ast;attr);
int pthread&lowbar;mutexattr&lowbar;destroy( pthread&lowbar;mutexattr&lowbar;t &ast;attr);
int pthread&lowbar;mutex&lowbar;init(pthread&lowbar;mutex&lowbar;t &ast;mutex,
const pthread&lowbar;mutexattr&lowbar;t &ast;mutex&lowbar;attr);
int pthread&lowbar;mutex&lowbar;destroy(pthread&lowbar;mutex&lowbar;t &ast;mutex);
int pthread&lowbar;mutex&lowbar;lock(pthread&lowbar;mutex&lowbar;t &ast;mutex);
int pthread&lowbar;mutex&lowbar;trylock(pthread&lowbar;mutex&lowbar;t &ast;mutex);
int pthread&lowbar;mutex&lowbar;unlock(pthread&lowbar;mutex&lowbar;t &ast;mutex);
int pthread&lowbar;condattr&lowbar;init(pthread&lowbar;condattr&lowbar;t &ast;attr);
int pthread&lowbar;condattr&lowbar;destroy(pthread&lowbar;condattr&lowbar;t &ast;attr);
int pthread&lowbar;cond&lowbar;init(pthread&lowbar;cond&lowbar;t &ast;cond,
const pthread&lowbar;condattr&lowbar;t &ast;attr);
int pthread&lowbar;cond&lowbar;destroy(pthread&lowbar;cond&lowbar;t &ast;cond);
int pthread&lowbar;cond&lowbar;signal(pthread&lowbar;cond&lowbar;t &ast;cond);
int pthread&lowbar;cond&lowbar;broadcast(pthread&lowbar;cond&lowbar;t &ast;cond);
int pthread&lowbar;cond&lowbar;wait(pthread&lowbar;cond&lowbar;t &ast;cond,
pthread&lowbar;mutex&lowbar;t &ast;mutex);
int pthread&lowbar;cond&lowbar;timedwait(pthread&lowbar;cond&lowbar;t &ast;cond,
pthread&lowbar;mutex&lowbar;t &ast;mutex,
const struct timespec &ast;abstime);
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
 
<screen>
sem&lowbar;t &ast;sem&lowbar;open(const char &ast;name, int oflag, ...); &sol;&sol; TBA
int sem&lowbar;close(sem&lowbar;t &ast;sem); &sol;&sol; TBA
int sem&lowbar;unlink(const char &ast;name); &sol;&sol; TBA
int pthread&lowbar;mutexattr&lowbar;getpshared( const pthread&lowbar;mutexattr&lowbar;t &ast;attr,
int &ast;pshared );
int pthread&lowbar;mutexattr&lowbar;setpshared( const pthread&lowbar;mutexattr&lowbar;t &ast;attr,
int pshared );
int pthread&lowbar;condattr&lowbar;getpshared( const pthread&lowbar;condattr&lowbar;t &ast;attr,
int &ast;pshared);
int pthread&lowbar;condattr&lowbar;setpshared( const pthread&lowbar;condattr&lowbar;t &ast;attr,
int pshared);</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<itemizedlist>
<listitem>
<para>
The presence of semaphores is controlled by the
CYGPKG&lowbar;POSIX&lowbar;SEMAPHORES option. This in turn
causes the &lowbar;POSIX&lowbar;SEMAPHORES feature test
macro to be defined and the semaphore API to be made
available.
</para>
</listitem>
<listitem>
<para>
The <emphasis role="strong">pshared</emphasis> argument to
<emphasis>sem&lowbar;init()</emphasis> is not implemented,
its value is ignored.
</para>
</listitem>
<listitem>
<para>
Functions <emphasis>sem&lowbar;open()</emphasis>,
<emphasis>sem&lowbar;close()</emphasis> and
<emphasis>sem&lowbar;unlink()</emphasis> are present but
always return an error (ENOSYS).
</para>
</listitem>
 
<listitem>
<para>
The exact priority inversion protocols supported may be
controlled with the
&lowbar;POSIX&lowbar;THREAD&lowbar;PRIO&lowbar;INHERIT and
&lowbar;POSIX&lowbar;THREAD&lowbar;PRIO&lowbar;PROTECT
configuration options.
</para>
</listitem>
<listitem>
<para>
&lcub;&lowbar;POSIX&lowbar;THREAD&lowbar;PROCESS&lowbar;SHARED&rcub; is
not defined, so the
<emphasis role="strong">process-shared</emphasis> mutex
and condition variable attributes are not supported, and
neither are the functions
<emphasis>pthread&lowbar;mutexattr&lowbar;getpshared()</emphasis>,
<emphasis>pthread&lowbar;mutexattr&lowbar;setpshared()</emphasis>,
<emphasis>pthread&lowbar;condattr&lowbar;getpshared()</emphasis> and
<emphasis>pthread&lowbar;condattr&lowbar;setpshared()</emphasis>.
</para>
</listitem>
<listitem>
<para>
Condition variables do not become bound to a particular
mutex when
<emphasis>pthread&lowbar;cond&lowbar;wait()</emphasis> is
called. Hence different threads may wait on a condition
variable with different mutexes. This is at variance with
the standard, which requires a condition variable to
become (dynamically) bound by the first waiter, and
unbound when the last finishes. However, this difference
is largely benign, and the cost of policing this feature
is non-trivial.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Memory Management -->
 
<sect1 id="posix-memory-management">
<title>Memory Management &lsqb;POSIX Section 12&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
<para>
&lt;none&gt;
</para>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
 
<screen>
int mlockall( int flags );
int munlockall( void );
int mlock( const void &ast;addr, size&lowbar;t len );
int munlock( const void &ast;addr, size&lowbar;t len );
void mmap( void &ast;addr, size&lowbar;t len, int prot, int flags,
int fd, off&lowbar;t off );
int munmap( void &ast;addr, size&lowbar;t len );
int mprotect( const void &ast;addr, size&lowbar;t len, int prot );
int msync( void &ast;addr, size&lowbar;t len, int flags );
int shm&lowbar;open( const char &ast;name, int oflag, mode&lowbar;t mode );
int shm&lowbar;unlink( const char &ast;name );
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<para>
None of these functions are currently provided. Some may
be implemented in a restricted form in the future.
</para>
 
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Execution Scheduling -->
 
<sect1 id="posix-execution-scheduling">
<title>Execution Scheduling &lsqb;POSIX Section 13&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
int sched&lowbar;yield(void);
int sched&lowbar;get&lowbar;priority&lowbar;max(int policy);
int sched&lowbar;get&lowbar;priority&lowbar;min(int policy);
int sched&lowbar;rr&lowbar;get&lowbar;interval(pid&lowbar;t pid, struct timespec &ast;t);
int pthread&lowbar;attr&lowbar;setscope(pthread&lowbar;attr&lowbar;t &ast;attr, int scope);
int pthread&lowbar;attr&lowbar;getscope(const pthread&lowbar;attr&lowbar;t &ast;attr, int &ast;scope);
int pthread&lowbar;attr&lowbar;setinheritsched(pthread&lowbar;attr&lowbar;t &ast;attr, int inherit);
int pthread&lowbar;attr&lowbar;getinheritsched(const pthread&lowbar;attr&lowbar;t &ast;attr, int &ast;inherit);
int pthread&lowbar;attr&lowbar;setschedpolicy(pthread&lowbar;attr&lowbar;t &ast;attr, int policy);
int pthread&lowbar;attr&lowbar;getschedpolicy(const pthread&lowbar;attr&lowbar;t &ast;attr, int &ast;policy);
int pthread&lowbar;attr&lowbar;setschedparam( pthread&lowbar;attr&lowbar;t &ast;attr, const struct sched&lowbar;param &ast;param);
int pthread&lowbar;attr&lowbar;getschedparam( const pthread&lowbar;attr&lowbar;t &ast;attr,
struct sched&lowbar;param &ast;param);
int pthread&lowbar;setschedparam(pthread&lowbar;t thread, int policy,
const struct sched&lowbar;param &ast;param);
int pthread&lowbar;getschedparam(pthread&lowbar;t thread, int &ast;policy,
struct sched&lowbar;param &ast;param);
int pthread&lowbar;mutexattr&lowbar;setprotocol( pthread&lowbar;mutexattr&lowbar;t &ast;attr,
int protocol);
int pthread&lowbar;mutexattr&lowbar;getprotocol( pthread&lowbar;mutexattr&lowbar;t &ast;attr,
int &ast;protocol);
int pthread&lowbar;mutexattr&lowbar;setprioceiling( pthread&lowbar;mutexattr&lowbar;t &ast;attr,
int prioceiling);
int pthread&lowbar;mutexattr&lowbar;getprioceiling( pthread&lowbar;mutexattr&lowbar;t &ast;attr,
int &ast;prioceiling);
int pthread&lowbar;mutex&lowbar;setprioceiling( pthread&lowbar;mutex&lowbar;t &ast;mutex,
int prioceiling,
int &ast;old&lowbar;ceiling);
int pthread&lowbar;mutex&lowbar;getprioceiling( pthread&lowbar;mutex&lowbar;t &ast;mutex,
int &ast;prioceiling);
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
 
<screen>
int sched&lowbar;setparam(pid&lowbar;t pid, const struct sched&lowbar;param &ast;param);
int sched&lowbar;getparam(pid&lowbar;t pid, struct sched&lowbar;param &ast;param);
int sched&lowbar;setscheduler(pid&lowbar;t pid, int policy,
const struct sched&lowbar;param &ast;param);
int sched&lowbar;getscheduler(pid&lowbar;t pid);
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<itemizedlist>
<listitem>
<para>
The functions <emphasis>sched&lowbar;setparam()</emphasis>,
<emphasis>sched&lowbar;getparam()</emphasis>,
<emphasis>sched&lowbar;setscheduler()</emphasis> and
<emphasis>sched&lowbar;getscheduler()</emphasis> are present
but always return an error.
</para>
</listitem>
<listitem>
<para>
The scheduler policy <emphasis>SCHED&lowbar;OTHER</emphasis> is
equivalent to <emphasis>SCHED&lowbar;RR</emphasis>.
</para>
</listitem>
<listitem>
<para>
Only <emphasis>PTHREAD&lowbar;SCOPE&lowbar;SYSTEM</emphasis>
is supported as a
<emphasis role="strong">contentionscope</emphasis>
attribute.
</para>
</listitem>
<listitem>
<para>
The default thread scheduling attributes are:
<screen>
contentionscope PTHREAD&lowbar;SCOPE&lowbar;SYSTEM
inheritsched PTHREAD&lowbar;INHERIT&lowbar;SCHED
schedpolicy SCHED&lowbar;OTHER
schedparam.sched 0
</screen>
</para>
</listitem>
<listitem>
<para>
Mutex priority inversion protection is controlled by a
number of kernel configuration options.
If CYGSEM&lowbar;KERNEL&lowbar;SYNCH&lowbar;MUTEX&lowbar;PRIORITY&lowbar;INVERSION&lowbar;PROTOCOL&lowbar;INHERIT
is defined then
&lcub;&lowbar;POSIX&lowbar;THREAD&lowbar;PRIO&lowbar;INHERIT&rcub;
will be defined and PTHREAD&lowbar;PRIO&lowbar;INHERIT may
be set as the protocol in a
<emphasis>pthread&lowbar;mutexattr&lowbar;t</emphasis>
object.
If CYGSEM&lowbar;KERNEL&lowbar;SYNCH&lowbar;MUTEX&lowbar;PRIORITY&lowbar;INVERSION&lowbar;PROTOCOL&lowbar;CEILING
is defined then
&lcub;&lowbar;POSIX&lowbar;THREAD&lowbar;PRIO&lowbar;PROTECT&rcub;
will be defined and PTHREAD&lowbar;PRIO&lowbar;PROTECT may
be set as the protocol in a
<emphasis>pthread&lowbar;mutexattr&lowbar;t</emphasis> object.
</para>
</listitem>
<listitem>
<para>
The default attribute values set by
<emphasis>pthread&lowbar;mutexattr&lowbar;init()</emphasis>
is to set the protocol attribute to
PTHREAD&lowbar;PRIO&lowbar;NONE and the prioceiling
attribute to zero.
</para>
</listitem>
</itemizedlist>
 
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Clocks and Timers -->
 
<sect1 id="posix-clocks-and-timers">
<title>Clocks and Timers &lsqb;POSIX Section 14&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
int clock&lowbar;settime( clockid&lowbar;t clock&lowbar;id,
const struct timespec &ast;tp);
int clock&lowbar;gettime( clockid&lowbar;t clock&lowbar;id, struct timespec &ast;tp);
int clock&lowbar;getres( clockid&lowbar;t clock&lowbar;id, struct timespec &ast;tp);
int timer&lowbar;create( clockid&lowbar;t clock&lowbar;id, struct sigevent &ast;evp,
timer&lowbar;t &ast;timer&lowbar;id);
int timer&lowbar;delete( timer&lowbar;t timer&lowbar;id );
int timer&lowbar;settime( timer&lowbar;t timerid, int flags,
const struct itimerspec &ast;value,
struct itimerspec &ast;ovalue );
int timer&lowbar;gettime( timer&lowbar;t timerid, struct itimerspec &ast;value );
int timer&lowbar;getoverrun( timer&lowbar;t timerid );
int nanosleep( const struct timespec &ast;rqtp, struct timespec &ast;rmtp);
</screen>
 
</sect2>
 
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
<para>
&lt;none&gt;
</para>
 
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
 
<itemizedlist>
<listitem>
<para>
Currently <emphasis>timer&lowbar;getoverrun()</emphasis> only
reports timer notifications that are delayed in the timer
subsystem. If they are delayed in the signal subsystem, due to
signal masks for example, this is not counted as an overrun.
</para>
</listitem>
 
<listitem>
<para>
The option CYGPKG&lowbar;POSIX&lowbar;TIMERS allows the timer support to be
enabled or disabled, and causes &lowbar;POSIX&lowbar;TIMERS to be defined
appropriately. This will cause other parts of the POSIX system to
have limited functionality.
</para>
</listitem>
 
</itemizedlist>
 
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Message Passing -->
 
<sect1 id="posix-message-passing">
<title>Message Passing &lsqb;POSIX Section 15&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
mqd&lowbar;t mq&lowbar;open( const char &ast;name, int oflag, ... );
int mq&lowbar;close( mqd&lowbar;t mqdes );
int mq&lowbar;unlink( const char &ast;name );
int mq&lowbar;send( mqd&lowbar;t mqdes, const char &ast;msg&lowbar;ptr,
size&lowbar;t msg&lowbar;len, unsigned int msg&lowbar;prio );
ssize&lowbar;t mq&lowbar;receive( mqd&lowbar;t mqdes, char &ast;msg&lowbar;ptr,
size&lowbar;t msg&lowbar;len, unsigned int &ast;msg&lowbar;prio );
int mq&lowbar;setattr( mqd&lowbar;t mqdes, const struct mq&lowbar;attr &ast;mqstat,
struct mq&lowbar;attr &ast;omqstat );
int mq&lowbar;getattr( mqd&lowbar;t mqdes, struct mq&lowbar;attr &ast;mqstat );
int mq&lowbar;notify( mqd&lowbar;t mqdes, const struct sigevent &ast;notification );
</screen>
<para>From POSIX 1003.1d draft: </para>
<screen>
int mq&lowbar;send( mqd&lowbar;t mqdes, const char &ast;msg&lowbar;ptr,
size&lowbar;t msg&lowbar;len, unsigned int msg&lowbar;prio,
const struct timespec *abs_timeout );
ssize&lowbar;t mq&lowbar;receive( mqd&lowbar;t mqdes, char &ast;msg&lowbar;ptr,
size&lowbar;t msg&lowbar;len, unsigned int &ast;msg&lowbar;prio,
const struct timespec *abs_timeout );
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
<para>
&lt;none&gt;
</para>
 
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
 
<itemizedlist>
<listitem>
<para>
The presence of message queues is controlled by the
CYGPKG&lowbar;POSIX&lowbar;MQUEUES option. Setting this will
cause &lsqb;&lowbar;POSIX&lowbar;MESSAGE&lowbar;PASSING&rsqb; to
be defined and the message queue API to be made available.
</para>
</listitem>
 
<listitem>
<para>
Message queues are not currently filesystem objects. They live in
their own name and descriptor spaces.
</para>
</listitem>
</itemizedlist>
 
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Thread Management -->
 
<sect1 id="posix-thread-management">
<title>Thread Management &lsqb;POSIX Section 16&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
int pthread&lowbar;attr&lowbar;init(pthread&lowbar;attr&lowbar;t &ast;attr);
int pthread&lowbar;attr&lowbar;destroy(pthread&lowbar;attr&lowbar;t &ast;attr);
int pthread&lowbar;attr&lowbar;setdetachstate(pthread&lowbar;attr&lowbar;t &ast;attr,
int detachstate);
int pthread&lowbar;attr&lowbar;getdetachstate(const pthread&lowbar;attr&lowbar;t &ast;attr,
int &ast;detachstate);
int pthread&lowbar;attr&lowbar;setstackaddr(pthread&lowbar;attr&lowbar;t &ast;attr,
void &ast;stackaddr);
int pthread&lowbar;attr&lowbar;getstackaddr(const pthread&lowbar;attr&lowbar;t &ast;attr,
void &ast;&ast;stackaddr);
int pthread&lowbar;attr&lowbar;setstacksize(pthread&lowbar;attr&lowbar;t &ast;attr,
size&lowbar;t stacksize);
int pthread&lowbar;attr&lowbar;getstacksize(const pthread&lowbar;attr&lowbar;t &ast;attr,
size&lowbar;t &ast;stacksize);
int pthread&lowbar;create( pthread&lowbar;t &ast;thread,
const pthread&lowbar;attr&lowbar;t &ast;attr,
void &ast;(&ast;start&lowbar;routine)(void &ast;),
void &ast;arg);
pthread&lowbar;t pthread&lowbar;self( void );
int pthread&lowbar;equal(pthread&lowbar;t thread1, pthread&lowbar;t thread2);
void pthread&lowbar;exit(void &ast;retval);
int pthread&lowbar;join(pthread&lowbar;t thread, void &ast;&ast;thread&lowbar;return);
int pthread&lowbar;detach(pthread&lowbar;t thread);
int pthread&lowbar;once(pthread&lowbar;once&lowbar;t &ast;once&lowbar;control,
void (&ast;init&lowbar;routine)(void));
</screen>
 
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
<para>
&lt;none&gt;
</para>
 
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
 
<itemizedlist>
<listitem>
<para>
The presence of thread support as a whole is controlled by the the
CYGPKG_POSIX_PTHREAD configuration option. Note that disabling
this will also disable many other features of the POSIX package,
since these are intimately bound up with the thread mechanism.
</para>
</listitem>
<listitem>
<para>
The default (non-scheduling) thread attributes are:
</para>
<screen>
detachstate PTHREAD&lowbar;CREATE&lowbar;JOINABLE
stackaddr unset
stacksize unset
</screen>
</listitem>
<listitem>
<para>
Dynamic thread stack allocation is only provided if there is an
implementation of
<emphasis>malloc()</emphasis> configured (i.e. a package
implements the
CYGINT&lowbar;MEMALLOC&lowbar;MALLOC&lowbar;ALLOCATORS
interface). If there is no malloc() available, then the thread
creator must supply a stack. If only a stack address is supplied
then the stack is assumed to be PTHREAD&lowbar;STACK&lowbar;MIN
bytes long. This size is seldom useful for any but the most
trivial of threads. If a different sized stack is used, both
the stack address and stack size must be supplied.
</para>
</listitem>
<listitem>
<para>
The value of PTHREAD&lowbar;THREADS&lowbar;MAX is supplied by
the CYGNUM&lowbar;POSIX&lowbar;PTHREAD&lowbar;THREADS&lowbar;MAX
option. This defines the maximum number of threads allowed. The
POSIX standard requires this value to be at least 64, and this
is the default value set.
</para>
</listitem>
 
<listitem>
<para>
When the POSIX package is installed, the thread that calls
<emphasis>main()</emphasis> is initialized as a POSIX thread. The
priority of that thread is controlled by the
CYGNUM&lowbar;POSIX&lowbar;MAIN&lowbar;DEFAULT&lowbar;PRIORITY option.
</para>
</listitem>
</itemizedlist>
 
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Thread-Specific Data -->
 
<sect1 id="posix-thread-specific-data">
<title>Thread-Specific Data &lsqb;POSIX Section 17&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
int pthread&lowbar;key&lowbar;create(pthread&lowbar;key&lowbar;t &ast;key,
void (&ast;destructor)(void &ast;));
int pthread&lowbar;setspecific(pthread&lowbar;key&lowbar;t key, const void &ast;pointer);
void &ast;pthread&lowbar;getspecific(pthread&lowbar;key&lowbar;t key);
int pthread&lowbar;key&lowbar;delete(pthread&lowbar;key&lowbar;t key);
</screen>
 
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
<para>
&lt;none&gt;
</para>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
 
<itemizedlist>
<listitem>
<para>
The value of PTHREAD&lowbar;DESTRUCTOR&lowbar;ITERATIONS is
provided by the
CYGNUM&lowbar;POSIX&lowbar;PTHREAD&lowbar;DESTRUCTOR&lowbar;ITERATIONS
option. This controls the number of times that a key destructor
will be called while the data item remains non-NULL.
</para>
</listitem>
<listitem>
<para>
The value of PTHREAD&lowbar;KEYS&lowbar;MAX is provided
by the CYGNUM&lowbar;POSIX&lowbar;PTHREAD&lowbar;KEYS&lowbar;MAX
option. This defines the maximum number of per-thread data items
supported. The POSIX standard calls for this to be a minimum of
128, which is rather large for an embedded system. The default
value for this option is set to 128 for compatibility but it
should be reduced to a more usable value.
</para>
</listitem>
</itemizedlist>
 
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Thread Cancellation -->
 
<sect1 id="posix-thread-cancellation">
<title>Thread Cancellation &lsqb;POSIX Section 18&rsqb;</title>
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Implemented</title>
 
<screen>
int pthread&lowbar;cancel(pthread&lowbar;t thread);
int pthread&lowbar;setcancelstate(int state, int &ast;oldstate);
int pthread&lowbar;setcanceltype(int type, int &ast;oldtype);
void pthread&lowbar;testcancel(void);
void pthread&lowbar;cleanup&lowbar;push( void (&ast;routine)(void &ast;),
void &ast;arg);
void pthread&lowbar;cleanup&lowbar;pop( int execute);
</screen>
</sect2>
 
 
<!-- =================================================================== -->
 
<sect2>
<title>Functions Omitted</title>
<para>
&lt;none&gt;
</para>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<para>
Asynchronous cancellation is only partially implemented. In
particular, cancellation may occur in unexpected places in some
functions. It is strongly recommended that only synchronous
cancellation be used.
</para>
</sect2>
</sect1>
 
<!-- }}} -->
<!-- {{{ Non-POSIX Functions -->
 
<sect1 id="posix-non-posix-functions">
<title>Non-POSIX Functions</title>
<para>
In addition to the standard POSIX functions defined above, the
following non-POSIX functions are defined in the FILEIO package.
</para>
 
<!-- =================================================================== -->
 
<sect2>
<title>General I&sol;O Functions</title>
<screen>
int ioctl( int fd, CYG&lowbar;ADDRWORD com, CYG&lowbar;ADDRWORD data );
int select( int nfd, fd&lowbar;set &ast;in, fd&lowbar;set &ast;out, fd&lowbar;set &ast;ex, struct timeval &ast;tv);
</screen>
</sect2>
 
 
<!-- =================================================================== -->
 
<sect2>
<title>Socket Functions</title>
<screen>
int socket( int domain, int type, int protocol);
int bind( int s, const struct sockaddr &ast;sa, unsigned int len);
int listen( int s, int len);
int accept( int s, struct sockaddr &ast;sa, socklen&lowbar;t &ast;addrlen);
int connect( int s, const struct sockaddr &ast;sa, socklen&lowbar;t len);
int getpeername( int s, struct sockaddr &ast;sa, socklen&lowbar;t &ast;len);
int getsockname( int s, struct sockaddr &ast;sa, socklen&lowbar;t &ast;len);
int setsockopt( int s, int level, int optname, const void &ast;optval,
socklen&lowbar;t optlen);
int getsockopt( int s, int level, int optname, void &ast;optval,
socklen&lowbar;t &ast;optlen);
ssize&lowbar;t recvmsg( int s, struct msghdr &ast;msg, int flags);
ssize&lowbar;t recvfrom( int s, void &ast;buf, size&lowbar;t len, int flags,
struct sockaddr &ast;from, socklen&lowbar;t &ast;fromlen);
ssize&lowbar;t recv( int s, void &ast;buf, size&lowbar;t len, int flags);
ssize&lowbar;t sendmsg( int s, const struct msghdr &ast;msg, int flags);
ssize&lowbar;t sendto( int s, const void &ast;buf, size&lowbar;t len, int flags,
const struct sockaddr &ast;to, socklen&lowbar;t tolen);
ssize&lowbar;t send( int s, const void &ast;buf, size&lowbar;t len, int flags);
int shutdown( int s, int how);
</screen>
</sect2>
 
<!-- =================================================================== -->
 
<sect2>
<title>Notes</title>
<itemizedlist>
<listitem>
<para>
The precise behaviour of these functions depends mainly on the
functionality of the underlying filesystem or network stack to
which they are applied.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
 
<!-- }}} -->
 
</chapter>
 
<!-- {{{ Bibliography -->
 
<bibliography id="posix-references-and-bibliography">
<title>References and Bibliography</title>
 
<bibliomixed>
<bibliomisc>&lsqb;Lewine&rsqb;</bibliomisc>
<author>
<firstname>Donald</firstname>
<othername>A.</othername>
<surname>Lweine</surname>
</author>
<title>Posix Programmer&rsquo;s Guide: Writing Portable Unix
Programs With the POSIX.1 Standard O&rsquo;Reilly &amp;
Associates; ISBN: 0937175730.</title></bibliomixed>
 
<bibliomixed>
<bibliomisc>&lsqb;Lewis1&rsqb;</bibliomisc>
<author>
<firstname>Bil</firstname>
<surname>Lewis</surname>
</author>
<author>
<firstname>Daniel</firstname>
<othername>J.</othername>
<surname>Berg</surname>
</author>
<title>Threads Primer: A Guide to Multithreaded Programming</title>
<publishername>Prentice Hall</publishername>
<isbn>ISBN: 013443698</isbn>
</bibliomixed>
 
<bibliomixed>
<bibliomisc>&lsqb;Lewis2&rsqb;</bibliomisc>
<author>
<firstname>Bil</firstname>
<surname>Lewis</surname>
</author>
<author>
<firstname>Daniel</firstname>
<othername>J.</othername>
<surname>Berg</surname>
</author>
<title>Multithreaded Programming With Pthreads</title>
<publisher>
<publishername>Prentice Hall Computer Books</publishername>
</publisher>
<isbn>ISBN: 0136807291</isbn>
</bibliomixed>
 
<bibliomixed>
<bibliomisc>&lsqb;Nichols&rsqb;</bibliomisc>
<author>
<firstname>Bradford</firstname>
<surname>Nichols</surname>
</author>
<author>
<firstname>Dick</firstname>
<surname>Buttlar</surname>
</author>
<author>
<firstname>Jacqueline</firstname>
<othername>Proulx</othername>
<surname>Farrell</surname>
</author>
<title>Pthreads Programming: A POSIX Standard for Better
Multiprocessing (O&rsquo;Reilly Nutshell)</title>
<publisher><publishername>O&rsquo;Reilly &amp; Associates</publishername>
</publisher>
<isbn>ISBN: 1565921151</isbn>
</bibliomixed>
 
<bibliomixed>
<bibliomisc>&lsqb;Norton&rsqb;</bibliomisc>
<author>
<firstname>Scott</firstname>
<othername>J.</othername>
<surname>Norton</surname>
</author>
<author>
<firstname>Mark</firstname>
<othername>D.</othername>
<surname>Depasquale</surname>
</author>
<title>Thread Time: The MultiThreaded Programming Guide</title>
<publisher><publishername>Prentice Hall</publishername>
</publisher>
<isbn>ISBN: 0131900676</isbn></bibliomixed>
 
 
<bibliomixed>
<bibliomisc>&lsqb;POSIX&rsqb;</bibliomisc>
<title>Portable Operating System Interface(POSIX) -
Part 1: System Application Programming Interface (API)&lsqb;C
Language&rsqb;</title>
<corpauthor>ISO&sol;IEC 9945-1:1996, IEEE</corpauthor></bibliomixed>
 
<bibliomixed>
<bibliomisc>&lsqb;SUS2&rsqb;</bibliomisc>
<title>Open Group; Single Unix Specification, Version 2</title>
<bibliomisc><ulink
url="http://www.opengroup.org/public/pubs/online/7908799/index.html">http://www.opengroup.org/public/pubs/online/7908799/index.html</ulink></bibliomisc>
</bibliomixed>
 
</bibliography>
 
<!-- }}} -->
 
</part>
/v2_0/ChangeLog
0,0 → 1,1052
2003-03-03 Jonathan Larmour <jifl@eCosCentric.com>
 
* tests/signal2.c (cause_illegal_access): PowerPC only generates
alignment exceptions in little-endian mode, so make that a special
case.
 
* tests/mutex3.c: Include POSIX headers before feature tests to
prevent spurious CYG_TEST_NA.
 
2003-02-24 Jonathan Larmour <jifl@eCosCentric.com>
 
* doc/posix.sgml: Expunge EL/IX. Dead standard.
* cdl/posix.cdl: Add doc link.
 
2003-02-13 Jonathan Larmour <jifl@eCosCentric.com>
 
* src/mutex.cxx: Include sched.hxx for scheduler lock/unlock primitives.
Reported by Jani Monoses.
 
2003-02-10 Gary Thomas <gary@mlbassoc.com>
 
* tests/signal3.c (main): Reorg code so it builds with older GCC.
 
2003-01-31 Nick Garnett <nickg@calivar.com>
 
* src/time.cxx (alarm_action): Added call to
cyg_posix_signal_sigwait() to wake up any sigwait()ing threads.
 
* src/signal.cxx (cyg_posix_signal_sigwait): Added this function
to export access to signal_sigwait conditional variable.
(sigtimedwait): Added call to cyg_posix_timer_asr() to allow timer
signals to be delivered here.
 
* src/pprivate.h: Added prototype for cyg_posix_signal_sigwait().
 
* cdl/posix.cdl:
* tests/signal3.c: Added this program to test interaction of
timers and signals, particularly sigwait(). Based on a test
program from N.Suresh <nsuresh@cdotb.ernet.in>.
 
2003-01-20 Jonathan Larmour <jifl@eCosCentric.com>
 
* src/signal.cxx (cyg_posix_deliver_signals): silence warning.
 
* src/time.cxx (cyg_timespec_to_ticks): Remove use of default arg in
definition.
 
2003-01-18 Jonathan Larmour <jifl@eCosCentric.com>
 
* src/mqueue.cxx: Fix multi-line string literal warning.
 
2003-01-13 Jonathan Larmour <jifl@eCosCentric.com>
 
* doc/posix.sgml: Document them.
 
* src/mqueue.cxx (mq_timedreceive): Make fully compliant by dealing
with bogus timeouts.
(mq_timedsend): Ditto.
 
2003-01-13 Dmitriy Korovkin <dkorovkin@rambler.ru>
 
* src/mqueue.cxx (mq_timedsend): New function. Implementing POSIX
1003.1d draft definition.
(mq_timedreceive): Ditto.
 
2002-12-10 Wade Jensen <waj4news@cox.net>
2002-12-10 Jonathan Larmour <jifl@eCosCentric.com>
 
* src/mutex.cxx (pthread_cond_timedwait): Initialize clock converters
only once ever.
 
2002-11-26 Nick Garnett <nickg@ecoscentric.com>
 
* src/signal.cxx: Changed the three routines added in the last
change so that they can be called safely from non-POSIX threads.
 
2002-11-10 Nick Garnett <nickg@ecoscentric.com>
 
* src/signal.cxx: Added three exportable routines that may be used
by other packages to manipulate the signal mask, test for
deliverable signals, and have signals delivered at controlled
points.
 
* include/export.h: Added macros to export signal mask management,
detection and delivery to other packages.
 
2002-11-05 Jonathan Larmour <jifl@eCosCentric.com>
 
* tests/tm_basic.cxx: Use <cyg/infra/diag.h> for diag_printf
prototype.
 
2002-05-23 Jesper Skov <jskov@redhat.com>
 
* cdl/posix.cdl: Don't build tests using signals when posix
signals are disabled.
 
2002-05-21 Jesper Skov <jskov@redhat.com>
 
* tests/mutex3.c: Added an NA check.
 
2002-04-09 Jonathan Larmour <jlarmour@redhat.com>
 
* src/signal.cxx (cyg_deliver_signals): Don't assert here for an
unhandled signal (unless there's no _exit). Trace it though.
 
2002-04-08 Jonathan Larmour <jlarmour@redhat.com>
 
* src/sem.cxx (sem_getvalue): return 0, and put value in *sval.
 
2002-04-03 Jonathan Larmour <jlarmour@redhat.com>
 
* cdl/posix.cdl: Allow clocks to be configured again.
 
2002-03-05 Jesper Skov <jskov@redhat.com>
 
* src/pprivate.h: Correct conditional declaration of timespec
functions.
 
* src/sched.cxx (sched_rr_get_interval): Return ENOSYS when
CYGPKG_POSIX_CLOCKS disabled.
 
2002-02-27 Robin Farine <robin.farine@terminus.org>
 
* src/pthread.cxx (pthread_exit): While running thread static
storage destructors, set the thread's value associated with the
current key to NULL before invoking the destructor.
 
2002-02-14 Nick Garnett <nickg@redhat.com>
 
* doc/posix.sgml: Generally fixed up and reformatted to make this
file readable by mere humans. Some omissions and outdated
information fixed, but not substantially changed from the
original.
 
* cdl/posix.cdl: Changed some definitions and dependencies so that
disabling the timers does not disable threads too. This was
largely a consequence of trying to document the behaviour of these
options.
2002-02-14 Jonathan Larmour <jlarmour@redhat.com>
 
* doc/posix.sgml: New file, originally accompanied by this ChangeLog:
2001-12-22 Jonathan Larmour <jlarmour@redhat.com>
* ecos-elix.sgml: Do a minor cleanup of the function prototype
layouts.
Should be done better than this, but this is at least not
_completely_ wrong any more.
Also several more layout problems due to incorrect tags fixed.
2001-12-07 Jonathan Larmour <jlarmour@redhat.com>
* ecos-elix.sgml: Add getcwd as supported now.
2001-12-06 Jonathan Larmour <jlarmour@redhat.com>
* ecos-elix.sgml: Created from old framemaker version.
2002-01-21 Jonathan Larmour <jlarmour@redhat.com>
 
* src/sched.cxx (sched_get_priority_min): Don't allow idle thread
priority as a valid priority.
Case #106952.
 
2001-12-11 Nick Garnett <nickg@redhat.com>
 
* tests/mqueue2.c (cyg_user_start): Added CYG_TEST_INIT() to
NOTAPPLICABLE variant, otherwise the order of breakpoints are all
wrong and the testfarm registers a failure.
 
2001-11-06 Gary Thomas <gthomas@redhat.com>
 
* include/muttypes.h: Need <pkgconf/kernel.h> configuration info,
otherwise structures defined here could have the wrong size.
 
2001-10-25 I-Jui Sung <ijsung@csie.nctu.edu.tw>
 
* src/mqueue.cxx (do_mq_unlink): Nullify table entries' mq as this
is used by mq_open to see if the entry is used.
 
2001-10-11 Jesper Skov <jskov@redhat.com>
 
* tests/mutex3.c: Fixed warning.
(new_thread): Fixed allocation: increase counter
before starting threads which have been allocated resources.
 
* tests/signal2.c (cause_illegal_access): Fix warning.
 
2001-10-10 Jesper Skov <jskov@redhat.com>
 
* cdl/posix.cdl: Only build sem.cxx when the semaphores component
is enabled.
 
2001-10-09 Jonathan Larmour <jlarmour@redhat.com>
 
* src/pprivate.h (pthread_info): Conditionalize signal specific
members. Conditionalize declaration of
cyg_posix_pthread_release_thread().
 
* cdl/posix.cdl (CYGPKG_POSIX_CLOCKS): new option to separately
configure posix clocks from timers.
(CYGPKG_POSIX_TIMERS): require clocks and signals.
 
* include/time.h: Make proper ISO C. Conditionalize on
CYGPKG_POSIX_TIMERS correctly wrt the above change.
 
* src/pthread.cxx (posix_asr): Call signal and timer subsystems
conditionally.
 
* src/pthread.cxx (pthread_reap): Don't destroy signal handling
fields if there is no signal handling subsystem.
(cyg_posix_pthread_release_thread): Conditionalize on signals.
(pthread_create): Init signal subsys conditionally.
 
* src/signal.cxx (sleep): Move to...
 
* src/time.cxx: ...here.
Conditionalize throughout depending on whether it's POSIX clocks
or more specifically POSIX timers.
(nanosleep): Use PTHREAD_TESTCANCEL() not pthread_testcancel().
Get current thread from kernel not pthreads to remove pthread
dependency.
 
2001-10-09 Jesper Skov <jskov@redhat.com>
 
* tests/signal2.c: Also do NA check for signals.
 
2001-10-01 Jonathan Larmour <jlarmour@redhat.com>
 
* src/mqueue.cxx (mq_open): Conditionalize use of sigev correctly.
(mq_close): Similarly.
 
2001-09-28 Jonathan Larmour <jlarmour@redhat.com>
 
* cdl/pthread.cdl (CYGNUM_POSIX_MAIN_DEFAULT_PRIORITY): Clarify
POSIX thread priority description.
 
2001-09-28 Jesper Skov <jskov@redhat.com>
 
* cdl/pthread.cdl: Changed default priority of POSIX main to
16. This allows service threads (such as DHCP thread) to run when
started from main().
 
2001-09-10 Jonathan Larmour <jlarmour@redhat.com>
 
* include/pthread.h: Separate mutex and condvar API into separate
header file to fix configury problems.
* include/mutex.h: New file for the above.
* cdl/posix.cdl: provide the correct configury for the isoinfra
package to include the above file.
* cdl/pthread.cdl: Move _POSIX_PTHREAD_PRIO_INHERIT and
_POSIX_THREAD_PRIO_PROTECT to cdl/posix.cdl.
2001-09-07 Jonathan Larmour <jlarmour@redhat.com>
 
* src/sem.cxx (sem_trywait): Actually use the return value.
 
* src/sched.cxx (sched_get_priority_max): Use MAX not MIN
(sched_get_priority_min): Use MIN not MAX.
 
2001-09-06 Jesper Skov <jskov@redhat.com>
 
* cdl/posix.cdl: Moved signal implements statements to the
CYGPKG_POSIX_SIGNALS component.
 
2001-08-06 Jonathan Larmour <jlarmour@redhat.com>
 
* cdl/posix.cdl: Reorganize dependencies so that signals, timers
and pthreads really can be disabled, and the relevant files don't
get built.
Build new mutex.cxx file.
Remove duplicate CYGPKG_POSIX_SCHED dependency for pthreads.
 
* include/limits.h: Don't include irrelevant header dependencies.
 
* include/muttypes.h: New type defining mutex/cond var types separately
from other pthread types.
 
* include/types.h: Remove mutex/cond var types.
 
* include/signal.h: Conditionalize on CYGPKG_POSIX_SIGNALS
 
* include/sigsetjmp.h: Don't include irrelevant header dependencies.
Rewrite sigsetjmp in a much more compiler friendly (and readable)
way with less type punning.
 
* src/misc.cxx: Don't include sysconf cases when pthreads or
CYGPKG_POSIX_TIMERS not enabled.
 
* src/mutex.cxx: New file, broken out of pthreads.cxx, as most
of it is not fixed to the pthreads implementation, and I've fixed
the bits that were too tied to it.
 
* src/pprivate.h: Conditionalize definitions that are specific
to CYGPKG_POSIX_PTHREAD. Ditto for prototypes for CYGPKG_POSIX_SIGNALS
and CYGPKG_POSIX_TIMERS. Move PTHREAD_ENTRY/RETURN etc. macros
here so they can be used throughout the package.
 
* src/pthread.cxx: Remove mutex/cond var implementation, and
entry/return macros, as per above.
 
* src/signal.cxx (cyg_sigqueue): Don't just set non-queueable signals
pending - also forcibly wake up any blocked threads.
(siglongjmp): Use new layout of sigjmp_buf.
 
* tests/mutex3.c:
* tests/pthread1.c:
* tests/pthread2.c:
* tests/pthread3.c:
* tests/signal1.c:
* tests/sigsetjmp.c:
* tests/timer1.c:
* tests/tm_basic.cxx:
Correct configuration dependencies, and do NA appropriately.
2001-08-03 Nick Garnett <nickg@cygnus.co.uk>
 
Imported from a development branch:
2001-06-27 Nick Garnett <nickg@cygnus.co.uk>
 
* tests/pthread3.c:
Modified the loop that waits for the threads to get going so that
it will function correctly in an SMP system, where the threads
will run in parallel.
 
* tests/mutex3.c: Disabled this test for SMP systems. It depends
too much on predicting the priority-driven execution order of the
threads. In an SMP system, some threads will run in parallel and
falsify the assumptions.
 
2001-05-25 Nick Garnett <nickg@cygnus.co.uk>
 
* src/signal.cxx (siglongjmp): Minor change to satisfy latest C++
compiler.
 
2001-06-14 Jonathan Larmour <jlarmour@redhat.com>
 
* src/pthread.cxx (pthread_attr_setstacksize): Correct stack
size assertion.
 
2001-06-12 Jonathan Larmour <jlarmour@redhat.com>
 
* src/pthread.cxx (MAIN_DEFAULT_STACK_SIZE): Define to use at
least PTHREAD_STACK_MIN for main_stack.
 
2001-05-01 Nick Garnett <nickg@cygnus.co.uk>
 
[x86 branch]
* tests/signal2.c (cause_illegal_access): Added code for I386
architecture to provoke General Protection Fault.
 
* src/except.cxx: Removed some extraneous diag_printf()s.
 
2001-04-25 Bart Veer <bartv@redhat.com>
 
* tests/tm_basic.cxx:
This test is now functional on the synthetic target.
 
2001-04-20 Jonathan Larmour <jlarmour@redhat.com>
 
* src/time.cxx (cyg_ticks_to_timespec): Actually don't bother
with working out seconds using convertors. Instead just divide
down ns from a long long.
 
2001-04-19 Jonathan Larmour <jlarmour@redhat.com>
 
* src/time.cxx (cyg_ticks_to_timespec): Clock convertors round off,
so adjust timespec accordingly.
 
2001-02-14 Jonathan Larmour <jlarmour@redhat.com>
 
* include/pthread.h: Remove pthread_canceled() and
pthread_testcancel_unlock().
* src/pthread.cxx: Ditto.
(pthread_join): Restructure to have function exit only at function end
(pthread_cond_timedwait): Check for timeouts and return ETIMEDOUT
 
* src/signal.cxx (sigtimedwait): Restructure cancellation testing
 
* src/time.cxx (nanosleep): test for cancellation at the end of the
function to keep Nick happy ;).
 
2001-02-11 Jonathan Larmour <jlarmour@redhat.com>
 
* include/pthread.h: Add new pthread_testcancel_unlock and
pthread_canceled functions as eCos extensions.
Rename existing pthread_canceled variable to pthread_cancelled_dummy_var
* src/pthread.cxx (pthread_canceled): New function to interrogate if
current thread has deferred cancel pending
(pthread_testcancel_unlock): New function. Like testcancel, but unlocks
a mutex before exitting the thread.
(checkforcancel): New internal function
(pthread_join): Add thread cancellation checks.
(pthread_cond_wait): Ditto.
(pthread_cond_timedwait): Ditto.
(pthread_testcancel): Use checkforcancel()
* src/sem.cxx (sem_wait): Add thread cancellation checks
* src/signal.cxx (sigtimedwait): Ditto.
Also make compilation of this file conditional on CYGPKG_POSIX_SIGNALS
* src/time.cxx (nanosleep): Ditto.
Also make compilation of this file conditional on CYGPKG_POSIX_TIMERS
 
* cdl/posix.cdl (CYGPKG_POSIX_TIMERS): Implements POSIX timer ops.
Add explicit kernel and pthread dependencies.
 
* tests/sigsetjmp.c (pthread_entry1): Fix incorrect thread no. output
 
* tests/pthread3.c: Add deferred cancellation test.
 
2001-01-11 Nick Garnett <nickg@cygnus.co.uk>
 
* src/pthread.cxx (pthread_testcancel): Added test for self !=
NULL in case this gets called from a non-pthread.
 
2000-12-22 Jonathan Larmour <jlarmour@redhat.com>
 
* src/pthread.cxx (pthread_measure_stack_usage): New function
to measure stack usage.
 
* include/pthread.h: Prototype it.
 
* cdl/pthread.cdl: remove CYGNUM_POSIX_MAIN_DEFAULT_STACK_SIZE and
instead implement CYGINT_LIBC_STARTUP_EXTERNAL_INVOKE_MAIN_POSSIBLE
 
* src/pthread.cxx: Use stack size for main from libc_startup package
to prevent confusion
(cyg_posix_pthread_start): Likewise
 
2000-12-06 Jonathan Larmour <jlarmour@redhat.com>
 
* src/signal.cxx: include unistd.h for _exit
 
2000-11-20 Nick Garnett <nickg@cygnus.co.uk>
 
* src/signal.cxx (cyg_deliver_signals): Added else in code to
handle SIG_DFL. Otherwise if the SA_SIGINFO bit is set we call the
signal handler twice!
 
2000-11-07 Jonathan Larmour <jlarmour@redhat.com>
 
* src/signal.cxx (cyg_posix_thread_siginit): Add extra thread
argument so that threads can inherit parent's sigmask.
 
* src/pthread.cxx (pthread_create): Call with parent thread
 
* src/pprivate.h: Change cyg_posix_thread_siginit prototype to take
parent thread argument
 
* tests/signal1.c: Add more checking of sigwaits, and fix so that it's
only called when the signal is masked. Check errno values too
sometimes.
 
2000-11-02 Jonathan Larmour <jlarmour@redhat.com>
 
* src/signal.cxx (sigtimedwait): return signal number on success,
not 0
(SIGNAL_RETURN_VALUE): New macro for returning from functions with
valid non-zero returns
(sigwaitinfo): Pass on sigtimedwait result with SIGNAL_RETURN_VALUE
macro as it may return the signal number.
 
2000-11-01 Jonathan Larmour <jlarmour@redhat.com>
 
* src/signal.cxx (sigtimedwait): Check for SIGALRMs as a special
case when looping as it won't have been set pending if it was
masked.
(check_sigalarm): New function extracted from the posix signal ASR
(sigalrm_action): Unconditionally wake up threads waiting in sigwait
so that they can check for pending SIGALRMs even if they were
masked.
(cyg_deliver_signals): Handle SIG_DFL signals properly, and check
for bad signal handlers.
(cyg_posix_signal_start): Initialize default signal actions to SIG_DFL
 
2000-10-27 Jesper Skov <jskov@redhat.com>
 
* tests/signal2.c (cause_illegal_access): Don't loop forever.
 
2000-10-16 Jonathan Larmour <jlarmour@redhat.com>
 
* include/sigsetjmp.h (sigsetjmp): Various fixes to make portable
across all HALs (by avoiding CYGARC_JMP_BUF_SIZE) and remove warnings.
* src/signal.cxx (siglongjmp): Likewise
 
2000-10-12 Nick Garnett <nickg@cygnus.co.uk>
 
* include/sigsetjmp.h: Added this header to define
sigjmp_buf,sigsetjmp() and siglongjmp().
 
* cdl/posix.cdl:
Added support for providing sigsetjmp implementation and header.
Added sigsetjmp test.
 
* src/signal.cxx: Added siglongjmp().
 
* tests/sigsetjmp.c: Added this test for sigsetjmp(), siglongjmp()
functionality. This is also a test for longjmping out of signal
handlers.
 
* tests/signal2.c:
Ifdeffed around cause_* functions to avoid compiler warnings when
they are not needed.
Changed CYG_TEST_NA() calls to CYG_TEST_INFO() and changed
CYG_TEST_FINISH() to CYG_TEST_PASS_FINISH(). With the _NA's there,
the first unsupported exception just terminates the program, and
does not give any subsequent supported ones a chance to run.
 
2000-10-12 Jesper Skov <jskov@redhat.com>
 
* tests/timer1.c (main): Fix exit check.
 
2000-10-11 Nick Garnett <nickg@cygnus.co.uk>
 
* src/pthread.cxx: Fixed cyg_posix_pthread_release_thread() to
work for _DETACHED threads as well as for _RUNNING ones. Also
fixed a bug in test to decrement counter in this routine.
 
* src/pprivate.h: Added note about retaining numerical order of
PTHREAD_STATE_* defines.
 
* tests/timer1.c: Fixed some bugs of the how-did-it-ever-work
variety.
 
2000-10-05 Nick Garnett <nickg@cygnus.co.uk>
 
* src/misc.cxx:
Added a set of compatibility functions to aid portability and
improve standards compliance.
Added cyg_posix_function_[start|finish] to set up and terminate
POSIX API functionality wrt signal and cancellation behaviour.
(Lots more to do here).
 
* include/export.h:
Added this file to contain definitions that can be exported from
the POSIX package to others.
 
* src/pprivate.h: Added include of export.h
2000-09-11 Jonathan Larmour <jlarmour@redhat.com>
 
* include/limits.h (OPEN_MAX): Don't define here - let FS infra do
that.
(LINK_MAX): Ditto
(NAME_MAX): Ditto
(PATH_MAX): Ditto
 
2000-09-04 Nick Garnett <nickg@cygnus.co.uk>
 
* tests/pthread2.c:
* tests/pthread3.c:
Fixed bug in calculation of thread stack addresses.
 
* src/misc.cxx (sysconf): Change zero returns to -1 when a feature
is not supported.
 
2000-08-08 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* include/limits.h: Don't define SSIZE_MAX here, leave it to the
isoinfra default.
 
2000-07-27 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* tests/signal2.c: NA if no setjmp/longjmp
 
2000-07-26 Nick Garnett <nickg@cygnus.co.uk>
 
* include/pthread.h:
* src/pthread.cxx (pthread_testcancel): Reversed addition of cyg_
to this symbol.
 
2000-07-25 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* src/pthread.cxx: Define main_stack and main_thread as static
Rename pthread_canceled -> cyg_pthread_canceled - pthread_ may be
a reserved name space but this makes explicit it is implementation-
and not standard-defined
(PTHREAD_ENTRY_VOID): Define for funcs that take no args
(pthread_testcancel): Call PTHREAD_ENTRY_VOID()
 
* include/pthread.h: Rename pthread_canceled -> cyg_pthread_canceled
 
2000-07-20 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* src/pthread.cxx: Use isoinfra to determine presence of malloc()
Define pthread_malloc() and pthread_free() as inlines
 
* cdl/posix.cdl: Shouldn't define _POSIX_MESSAGE_PASSING at all - that
happens in isoinfra.
 
2000-07-20 Nick Garnett <nickg@cygnus.co.uk>
 
* cdl/posix.cdl: Added misc.cxx to compile list. Added option to
define _POSIX_MESSAGE_PASSING. Added configury for utsname
structure.
 
* include/utsname.h: Added this file to define struct utsname and
uname() function prototype.
 
* include/mqueue.h: Moved definition of _POSIX_MESSAGE_PASSING to
CDL.
 
* include/limits.h: Added NGROUPS_MAX definition.
 
* src/pthread.cxx:
Added support for malloced() thread stacks.
Added implementations of pthread_mutex_setprioceiling() and
pthread_mutex_getprioceiling().
Changed implementations of pthread_mutex_destroy(),
pthread_mutex_lock() and pthread_mutex_trylock() to conform more
closely to the standard.
Changed pthread_key_create() to assign NULL to all valid thread
slots that correspond to a newly allocated key.
 
* src/pprivate.h: Added freestack and stackmem members to manage
malloced thread stacks.
 
* src/misc.cxx: Added this file to contain functions that do not
belong in any other files. Currently contains uname() and
sysconf().
 
2000-07-19 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* src/startup.cxx: Remove unnecessary includes
Use dummy object constructor to do initialization
 
* cdl/posix.cdl:
Don't need main.cxx any more
Build startup.cxx into extras.o (via libextras.a)
 
* cdl/pthread.cdl (CYGPKG_POSIX_MAIN_THREAD):
Integrate with CYGPKG_LIBC_STARTUP - tell CYGPKG_LIBC_STARTUP to
let pthreads set up main thread
 
* src/pthread.cxx: Integrate with CYGPKG_LIBC_STARTUP rather than
calling main() directly.
Track number of threads waiting to be joined, so we can tell in
pthread_exit() if this is the last thread, and therefore whether
to call exit()
 
* src/main.cxx: obsolete, removed
 
2000-07-13 Nick Garnett <nickg@cygnus.co.uk>
 
* src/signal.cxx: Added ISO C compatibility functions signal() and
raise().
 
2000-06-21 Nick Garnett <nickg@cygnus.co.uk>
 
* src/pthread.cxx: Added for(;;) loop to end of pthread_exit().
pthread_exit() is marked with the noreturn attribute, and without
this some compilers generate a call to abort() here in case
Cyg_Thread::exit() returns. The loop avoids this.
 
2000-06-06 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* src/mqueue.cxx (mq_receive): Fix non-portable treatment of mode flags
(mq_send): Ditto
* tests/mqueue2.c (main): Ditto
 
2000-05-24 Nick Garnett <nickg@cygnus.co.uk>
 
* tests/pthread2.c: Added this program to test per-thread data
handling.
 
* tests/pthread3.c: Added this program to test execution of
cancellation handler.
 
* src/pthread.cxx: Fixed some bugs revealed by new test programs.
 
* cdl/posix.cdl: Added two new pthread tests.
 
2000-05-22 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* cdl/posix.cdl (CYGPKG_POSIX): Require
CYGIMP_KERNEL_SCHED_SORTED_QUEUES
 
2000-05-20 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* tests/mqueue1.c (cyg_user_start): Define correctly
* tests/mqueue2.c (cyg_user_start): Likewise
 
* src/pprivate.h (cyg_sigqueue): Make struct sigevent * arg const since
it is, and it prevents warnings elsewhere
* src/signal.cxx (cyg_sigqueue): ditto
 
* tests/signal2.c: Use CYG_TEST_NA, not CYG_TEST_INFO (otherwise
the test farm may fail the tests because there are no PASSes or NAs)
 
* cdl/posix.cdl (CYGPKG_POSIX): We need errno and error codes, so
require them
Move some of the package implements into the components
Add message queue configuration, build mqueue.cxx and the mqueue1 and
mqueue2 tests
Move some calculated options into isoinfra, implemented as interfaces
so that unistd.h and limits.h can get the values
 
* include/limits.h: Move _POSIX_* macros into isoinfra limits.h
since they are implementation independent
 
* src/mqueue.cxx: Add POSIX message queue implementation
* tests/mqueue1.c, tests/mqueue2.c: and tests
 
2000-05-18 Nick Garnett <nickg@cygnus.co.uk>
 
* src/pprivate.h:
* src/pthread.cxx:
* src/signal.cxx:
* src/time.cxx:
Added prioritization of static kernel objects.
 
2000-05-17 Nick Garnett <nickg@cygnus.co.uk>
 
* src/pthread.cxx:
To reduce the static memory required by this code, the
pthread_info structure for a pthread is now allocated in the stack
memory for that thread, and not in a static table. The table is
now just an array of pointers. The per-thread data array is now
also allocated onto the stack only when first required.
 
* include/pthread.h: Removed some redundant code.
 
* include/limits.h: Added PTHREAD_STACK_OVERHEAD to record
management overhead imposed on POSIX threads stacks. This is added
to the HAL minimum requirement to generate PTHREAD_STACK_MIN.
 
* src/pprivate.h (pthread_info):
* include/types.h (pthread_attr_t): Converted a number of integer
state and boolean fields to bitfields.
 
* cdl/pthread.cdl:
Added requirement for CYGFUN_KERNEL_THREADS_STACK_LIMIT.
 
2000-05-16 Nick Garnett <nickg@cygnus.co.uk>
 
* include/types.h: Added stacksize_valid to pthread_attr_t
structure.
 
* include/signal.h:
Added SI_EXCEPT to mark any signals that were caused by an
exception. Removed conditions around SIGBUS.
 
* src/startup.cxx (cyg_posix_start):
Added call to cyg_posix_exception_start().
 
* src/signal.cxx:
Rearranged cyg_deliver_signals() so that it is possible to
longjmp() out of a signal handler without leaving signal handling
code in an inconsistent state.
Added handling of SIG_IGN in sigaction().
 
* src/pthread.cxx: Added setting and checking of stacksize_valid.
 
* src/pprivate.h: Added cyg_deliver_signals() as an export of
signal system. Added exports from except.cxx.
 
* src/except.cxx: Added this file to handle delivery of exceptions
into the POSIX signal mechanism.
 
* cdl/posix.cdl: Added except.cxx to compile list, added signal2
to tests. Added requirement on kernel exception processing.
 
* tests/tm_basic.cxx: Tidied up a compilation warning.
 
* tests/signal2.c: Added this test for exception signal generation.
 
* tests/mutex3.c: Fixed stupid bug.
2000-05-10 Nick Garnett <nickg@cygnus.co.uk>
 
* src/pprivate.h: Added cyg_posix_clock_start() prototype.
 
* src/startup.cxx: Added call to cyg_posix_clock_start().
 
* src/time.cxx: Added startup routine to initialize
converters. Fixed error result bug in timer_delete().
 
* include/signal.h: Removed some configuration tests which are now
done in CDL.
 
* cdl/posix.cdl: Added configury for the signals component. Added
tm_basic to tests.
 
* tests/tm_basic.cxx:
Added this POSIXized version of the tm_basic test. Note that this
has not been entirely converted. While the code being tested is
POSIX, the timing infrastructure remains a mish-mash of kernel,
KAPI and HAL code.
 
2000-05-04 Nick Garnett <nickg@cygnus.co.uk>
 
* src/time.cxx:
Many changes to implement the delivery of signals on timer expiry.
Also added timer_delete().
 
* src/signal.cxx:
cyg_sigqueue() and cyg_deliver_signals() may now only be called
from within the context of a POSIX thread, either from an API call
or an ASR.
cyg_deliver_signals() can now cope with a signal that has
SA_SIGINFO set but no signals queued. It also determines
dynamically whether to lock the signal_mutex.
cyg_deliver_signals() is no longer called implicitly from
cyg_sigqueue() - so a number of expicit calls have been added.
* src/sched.cxx:
Added this file to implement scheduling API.
 
* src/pthread.cxx:
Moved priority translation macros to pprivate.h.
Removed errno handling, now done in isoinfra package.
Added iterative calls to per-thread data destructors.
 
* src/pprivate.h:
Removed error field from pthread_info structure.
Moved priority translation macros here.
Removed prototype for cyg_deliver_signals().
Added prototype for cyg_posix_timer_asr().
 
* include/time.h: Added timer_delete() which was mysteriously
omitted.
 
* cdl/posix.cdl: Added sched.cxx to compile list and timer1.c to
tests.
 
* tests/signal1.c:
* tests/pthread1.c:
Fixed bug in use of stack sizes.
 
* tests/timer1.c:
Added test for use of timers.
2000-05-02 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* include/sched.h: No longer needed - just use the default definition
in isoinfra
 
* include/errno.h: No longer needed - errno provision now comes from
CYGPKG_ERROR
* include/sys/types.h: Moved to include/types.h
* cdl/posix.cdl, cdl/pthread.cdl: Put include files in cyg/posix, and
configure CYGPKG_ISOINFRA to include the appropriate headers
* include/semaphore.h: Don't need to check kernel - including
pkgconf/kernel.h would already fail
Give SEM_FAILED a type so casting behaves in C++
* include/signal.h: This uses pid_t etc., so include <sys/types.h>
Add signal() and raise() prototypes (to allow libc compilation, even
though they aren't implemented yet)
* include/time.h: Remove unnecessary includes. Move clockid_t and
timer_t definitions here from sys/types.h since this is where the
standard says they must live.
* src/pprivate.h: Include signal.h and limits.h since their contents
are used later in the file.
 
2000-04-28 Nick Garnett <nickg@cygnus.co.uk>
 
* src/signal.cxx:
Added implementations of alarm(), pause() and sleep().
Modified cyg_sigqueue() so that it could be called from an ASR.
Added cyg_posix_signal_asr() to do signal processing in ASRs.
Miscellaneous bug fixes.
 
* src/pthread.cxx:
Added pthread_count to count number of threads created.
Added call to signal ASR function in main ASR.
Added cyg_posix_pthread_release_thread() to seek out and kick a
thread to which a given set of signals may be delivered.
 
* src/pprivate.h:
Added some more functions that are shared between POSIX
subsystems.
 
* include/signal.h:
Added alarm(), pause() and sleep() prototypes.
 
* tests/signal1.c: Added this test for various aspects of signal
handling.
 
* cdl/posix.cdl: Added signal1 test.
 
2000-04-20 Nick Garnett <nickg@cygnus.co.uk>
 
* src/signal.cxx: Added this file to contain signal handling code.
 
* src/time.cxx: Made tick<->timespec converters exported to
rest of POSIX subsystem. Enabled interface to signal mechanism for
notifying timer expiration.
 
* src/pthread.cxx:
Made pthread_mutex exported to rest of POSIX subsystem.
Exported pthread_info_id().
Added thread init and destroy functions for signal subsystem.
 
* src/startup.cxx: Added call to cyg_posix_signal_start().
 
* src/pprivate.h: Added signal handling fields support to
pthread_info structure. Added extra internal interfaces to support
signal handling code.
 
* include/signal.h: Added _how_ argument values for the sigmask
functions.
 
* cdl/posix.cdl: Added signal.cxx to compile list.
 
2000-04-13 Nick Garnett <nickg@cygnus.co.uk>
 
* include/time.h:
* src/time.cxx:
Added implementation of clock and timer functions. These are
currently untested since they need working signals.
 
2000-04-12 Nick Garnett <nickg@cygnus.co.uk>
 
* src/pprivate.h: Added cancellation support fields to
pthread_info structure. Made pthread_self_info() exported.
 
* include/semaphore.h: Added SEM_FAILED plus misc. tidies.
 
* include/pthread.h: Added PTHREAD_CANCELED.
 
* include/errno.h: Fixed cyg_pthread_errno_p() return type.
 
* src/pthread.cxx:
Added pthread_reap() to clean up exited threads.
Added support for cancellation.
Added cyg_posix_errno_p().
 
* src/time.cxx:
Added this file to implement time functionality. At present only
nanosleep() is actually implemented.
 
* src/sem.cxx:
Added this file to implement semaphore functionality.
 
* cdl/pthread.cdl:
Added some extra configuration requirements.
 
* cdl/posix.cdl:
Added some more files to compile.
Added semaphore configuration.
 
* tests/mutex3.c:
Added this test program. This is actually a POSIXized version of
Hugo's splendid kernel test of the same name. It exercises quite a
lot of the pthread infrastructure and is thus a good test to run.
 
* tests/pthread1.c:
Added proper comment headers and added full testing stuff.
2000-04-10 Nick Garnett <nickg@cygnus.co.uk>
 
* src/pprivate.h:
* src/pthread.cxx:
Added per-thread data support.
 
2000-04-06 Nick Garnett <nickg@cygnus.co.uk>
 
* src/pthread.cxx:
Filled in implementations of lots of functions.
 
* src/main.cxx:
Added this file to contain a default main. This is currenly just a
duplicate of the same file from the C library. Work is needed to
combine these.
 
* include/sys/types.h:
Modified pthread_mutex_t to conform to kernel structure.
 
* cdl/pthread.cdl:
Added support for main thread.
 
* cdl/posix.cdl:
Added main.cxx to compile list.
 
2000-03-31 Nick Garnett <nickg@cygnus.co.uk>
 
* cdl/pthread.cdl:
* cdl/posix.cdl:
Added CDL files to configure POSIX subsystem.
 
* src/pprivate.h:
* src/pthread.cxx:
* src/startup.cxx:
Added these files to begin implementation of POSIX package.
* include/pthread.h:
* include/sched.h:
* include/signal.h:
* include/time.h:
* include/sys/types.h:
Many changes needed by implementation work.
* include/limits.h:
* include/errno.h:
Added these header files.
2000-03-24 Nick Garnett <nickg@cygnus.co.uk>
 
* include/sys/types.h:
* include/time.h:
* include/sched.h:
* include/pthread.h:
* include/signal.h:
* include/semaphore.h:
* include/mqueue.h:
Roughed out (most of) the set of POSIX headers for the
functionality we are currently going to support. These files are
currently neither fully standard conformant nor implementation
ready. Much work is still needed to make them so. Watch this
space.
 
#####ECOSGPLCOPYRIGHTBEGIN####
## -------------------------------------------
## This file is part of eCos, the Embedded Configurable Operating System.
## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
##
## eCos is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free
## Software Foundation; either version 2 or (at your option) any later version.
##
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
## for more details.
##
## You should have received a copy of the GNU General Public License along
## with eCos; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
##
## As a special exception, if other files instantiate templates or use macros
## or inline functions from this file, or you compile this file and link it
## with other works to produce a work based on this file, this file does not
## by itself cause the resulting work to be covered by the GNU General Public
## License. However the source code for this file must still be made available
## in accordance with section (3) of the GNU General Public License.
##
## This exception does not invalidate any other reasons why a work based on
## this file might be covered by the GNU General Public License.
##
## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
## at http://sources.redhat.com/ecos/ecos-license/
## -------------------------------------------
#####ECOSGPLCOPYRIGHTEND####
/v2_0/src/time.cxx
0,0 → 1,700
//==========================================================================
//
// time.cxx
//
// POSIX time functions implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-27
// Purpose: POSIX time functions implementation
// Description: This file contains the implementation of the POSIX time
// functions.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/posix.h>
 
#ifdef CYGPKG_POSIX_CLOCKS
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include "pprivate.h" // POSIX private header
 
#include <time.h> // our header
 
#include <cyg/kernel/thread.hxx>
#include <cyg/kernel/clock.hxx>
 
#include <cyg/kernel/thread.inl>
#include <cyg/kernel/clock.inl>
 
// -------------------------------------------------------------------------
// Internal definitions
 
// Handle entry to a pthread package function.
#define TIME_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" );
 
// Do a time package defined return. This requires the error code
// to be placed in errno, and if it is non-zero, -1 returned as the
// result of the function. This also gives us a place to put any
// generic tidyup handling needed for things like signal delivery and
// cancellation.
#define TIME_RETURN(err) \
CYG_MACRO_START \
int __retval = 0; \
if( err != 0 ) __retval = -1, errno = err; \
CYG_REPORT_RETVAL( __retval ); \
return __retval; \
CYG_MACRO_END
 
//==========================================================================
// Timer control structures
 
#ifdef CYGPKG_POSIX_TIMERS
typedef struct
{
timer_t id; // id value for checking
Cyg_Alarm *alarm; // eCos alarm object
cyg_bool armed; // is alarm enabled?
cyg_bool pending; // is expiry pending?
int overrun; // Overrun count
struct sigevent sigev; // Sigevent to raise on expiry
// Space for alarm object
cyg_uint8 alarm_obj[sizeof(Cyg_Alarm)];
} posix_timer;
 
// Mutex for controlling access to shared data structures
static Cyg_Mutex timer_mutex CYGBLD_POSIX_INIT;
 
// Array of timer objects
static posix_timer timer_table[_POSIX_TIMER_MAX];
 
// Index of next timer to allocate from array
static int timer_next = 0;
 
// This is used to make timer_t values unique even when reusing
// a table slot. This allows _POSIX_TIMER_MAX to range
// up to 1024.
#define TIMER_ID_COOKIE_INC 0x00000400
#define TIMER_ID_COOKIE_MASK (TIMER_ID_COOKIE_INC-1)
static timer_t timer_id_cookie = TIMER_ID_COOKIE_INC;
 
#endif // ifdef CYGPKG_POSIX_TIMERS
 
//-----------------------------------------------------------------------------
// new operator to allow us to invoke the constructor on
// posix_timer.alarm_obj.
 
inline void *operator new(size_t size, cyg_uint8 *ptr) { return (void *)ptr; };
 
//==========================================================================
// Time conversion variables
// These are used to interconvert between ticks and POSIX timespecs.
 
// Converters from sec and ns to ticks
static struct Cyg_Clock::converter ns_converter, sec_converter;
 
// Converters from ticks to sec and ns
static struct Cyg_Clock::converter ns_inverter, sec_inverter;
 
// tickns is the number of nanoseconds per tick.
static cyg_tick_count tickns;
 
static cyg_bool converters_initialized = false;
 
//==========================================================================
// Local functions
 
static void init_converters()
{
if( !converters_initialized )
{
 
// Create the converters we need.
Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1, &ns_converter );
Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000000000, &sec_converter );
Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1, &ns_inverter );
Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1000000000, &sec_inverter );
 
tickns = Cyg_Clock::convert( 1, &ns_inverter );
converters_initialized = true;
}
}
 
static cyg_bool valid_timespec( const struct timespec *tp )
{
// Fail a NULL pointer
if( tp == NULL ) return false;
 
// Fail illegal nanosecond values
if( tp->tv_nsec < 0 || tp->tv_nsec > 1000000000 )
return false;
 
return true;
}
 
externC cyg_tick_count cyg_timespec_to_ticks( const struct timespec *tp,
cyg_bool roundup)
{
init_converters();
 
// Short circuit zero timespecs
if( tp->tv_sec == 0 && tp->tv_nsec == 0 )
{
return 0;
}
// Convert the seconds field to ticks.
cyg_tick_count ticks = Cyg_Clock::convert( tp->tv_sec, &sec_converter );
 
if( roundup )
{
// Convert the nanoseconds. We add (tickns-1) to round the value up
// to the next whole tick.
 
ticks += Cyg_Clock::convert( (cyg_tick_count)tp->tv_nsec+tickns-1, &ns_converter );
}
else
{
// Convert the nanoseconds. This will round down to nearest whole tick.
ticks += Cyg_Clock::convert( (cyg_tick_count)tp->tv_nsec, &ns_converter );
}
 
return ticks;
}
 
externC void cyg_ticks_to_timespec( cyg_tick_count ticks, struct timespec *tp )
{
init_converters();
 
// short circuit zero ticks values
if( ticks == 0 )
{
tp->tv_sec = 0;
tp->tv_nsec = 0;
return;
}
 
// Convert everything to nanoseconds with a long long. For 64-bits,
// this is safe for 544 years. We'll think about it more closer to
// the time...
 
unsigned long long nsecs = Cyg_Clock::convert( ticks, &ns_inverter );
 
tp->tv_sec = (long)(nsecs / 1000000000ll);
tp->tv_nsec = (long)(nsecs % 1000000000ll);
 
CYG_POSTCONDITION(valid_timespec(tp), "Failed to make valid timespec!");
}
 
//==========================================================================
// Startup routine.
 
externC void cyg_posix_clock_start()
{
init_converters();
}
 
#ifdef CYGPKG_POSIX_TIMERS
//==========================================================================
// Alarm action routine
// This is called each time an alarm set up by a timer expires.
 
static void alarm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data )
{
posix_timer *timer = (posix_timer *)data;
 
if( timer->pending )
{
// If the pending flag is already set, count an overrun and
// do not bother to try and deliver the expiry.
timer->overrun++;
}
else
{
if( timer->sigev.sigev_notify == SIGEV_SIGNAL )
{
// Set the expiry pending and wake a thread to
// deliver the signal.
timer->pending = true;
sigset_t mask;
sigemptyset( &mask );
sigaddset( &mask, timer->sigev.sigev_signo );
cyg_posix_signal_sigwait();
cyg_posix_pthread_release_thread( &mask );
}
else if( timer->sigev.sigev_notify == SIGEV_THREAD )
{
// Thread style notification
// FIXME: implement SIGEV_THREAD
}
// else do nothing
}
}
 
//==========================================================================
// Timer ASR routine
 
externC void cyg_posix_timer_asr( pthread_info *self )
{
 
// Loop over the timers looking for any that have an
// expiry pending and call cyg_sigqueue() for each.
for( int i = 0; i < _POSIX_TIMER_MAX; i++ )
{
posix_timer *timer = &timer_table[i];
 
if( timer->id != 0 && timer->pending )
{
timer->pending = false;
// Call into signal subsystem...
cyg_sigqueue( &timer->sigev, SI_TIMER );
 
timer->overrun = 0;
}
}
}
 
#endif // ifdef CYGPKG_POSIX_TIMERS
 
//==========================================================================
// Clock functions
 
//-----------------------------------------------------------------------------
// Set the clocks current time
 
externC int clock_settime( clockid_t clock_id, const struct timespec *tp)
{
TIME_ENTRY();
 
if( clock_id != CLOCK_REALTIME )
TIME_RETURN(EINVAL);
 
if( !valid_timespec( tp ) )
TIME_RETURN(EINVAL);
cyg_tick_count ticks = cyg_timespec_to_ticks( tp );
 
Cyg_Clock::real_time_clock->set_value( ticks );
TIME_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Get the clocks current time
 
externC int clock_gettime( clockid_t clock_id, struct timespec *tp)
{
TIME_ENTRY();
 
if( clock_id != CLOCK_REALTIME )
TIME_RETURN(EINVAL);
 
if( tp == NULL )
TIME_RETURN(EINVAL);
cyg_tick_count ticks = Cyg_Clock::real_time_clock->current_value();
 
cyg_ticks_to_timespec( ticks, tp );
 
TIME_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Get the clocks resolution
 
externC int clock_getres( clockid_t clock_id, struct timespec *tp)
{
TIME_ENTRY();
 
if( clock_id != CLOCK_REALTIME )
TIME_RETURN(EINVAL);
 
if( tp == NULL )
TIME_RETURN(EINVAL);
 
// Get the resolution of 1 tick
cyg_ticks_to_timespec( 1, tp );
TIME_RETURN(0);
}
 
//==========================================================================
// Timer functions
 
#ifdef CYGPKG_POSIX_TIMERS
 
//-----------------------------------------------------------------------------
// Create a timer based on the given clock.
 
externC int timer_create( clockid_t clock_id,
struct sigevent *evp,
timer_t *timer_id)
{
TIME_ENTRY();
 
if( clock_id != CLOCK_REALTIME )
TIME_RETURN(EINVAL);
 
timer_mutex.lock();
 
posix_timer *timer;
int next = timer_next;
 
// Look for an unused slot in the table
while( timer_table[next].id != 0 )
{
next++;
if( next >= _POSIX_TIMER_MAX )
next = 0;
 
if( next == timer_next )
{
timer_mutex.unlock();
TIME_RETURN(EAGAIN);
}
}
 
timer = &timer_table[next];
 
timer_next = next;
 
// Make sure we never allocate a zero timer id.
while( timer->id == 0 )
{
timer_id_cookie += TIMER_ID_COOKIE_INC;
timer->id = next+timer_id_cookie;
}
 
if( evp == NULL )
{
// If no evp is supplied, set up the timer
// to use a default set.
timer->sigev.sigev_notify = SIGEV_SIGNAL;
timer->sigev.sigev_signo = SIGALRM;
timer->sigev.sigev_value.sival_int = timer->id;
}
else timer->sigev = *evp;
timer->alarm = new( timer->alarm_obj )
Cyg_Alarm( Cyg_Clock::real_time_clock,
alarm_action,
(CYG_ADDRWORD)timer );
 
timer->armed = false;
timer->overrun = 0;
 
*timer_id = timer->id;
timer_mutex.unlock();
TIME_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Delete the timer
 
externC int timer_delete( timer_t timerid )
{
int err = EINVAL;
TIME_ENTRY();
posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
 
timer_mutex.lock();
 
if( timer->id == timerid )
{
// This is a valid timer, disable the kernel
// alarm and delete it.
 
// disable alarm
timer->alarm->disable();
 
// destroy it
timer->alarm->~Cyg_Alarm();
 
// Mark POSIX timer free
timer->id = 0;
 
err = 0;
}
 
timer_mutex.unlock();
TIME_RETURN( err );
}
 
//-----------------------------------------------------------------------------
// Set the expiration time of the timer.
 
externC int timer_settime( timer_t timerid, int flags,
const struct itimerspec *value,
struct itimerspec *ovalue )
{
int err = EINVAL;
TIME_ENTRY();
if( value == NULL )
TIME_RETURN(EINVAL);
 
// convert trigger and interval values to ticks.
cyg_tick_count trigger = cyg_timespec_to_ticks( &value->it_value, true );
cyg_tick_count interval = cyg_timespec_to_ticks( &value->it_interval, true );
posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
 
timer_mutex.lock();
 
if( timer->id == timerid )
{
// disable the timer
timer->alarm->disable();
if( ovalue != NULL )
{
cyg_tick_count otrigger, ointerval;
 
timer->alarm->get_times( &otrigger, &ointerval );
 
if( timer->armed )
{
// convert absolute trigger time to interval until next trigger
otrigger -= Cyg_Clock::real_time_clock->current_value();
}
else otrigger = 0;
 
// convert ticks to timespecs
cyg_ticks_to_timespec( otrigger, &ovalue->it_value );
cyg_ticks_to_timespec( ointerval, &ovalue->it_interval );
}
if( trigger == 0 )
{
// Mark timer disarmed
timer->armed = false;
}
else
{
// If the ABSTIME flag is not set, add the current time
if( (flags & TIMER_ABSTIME) == 0 )
trigger += Cyg_Clock::real_time_clock->current_value();
 
// Set the alarm running.
timer->alarm->initialize( trigger, interval );
 
// Mark timer armed
timer->armed = true;
 
}
err = 0;
}
timer_mutex.unlock();
TIME_RETURN(err);
}
 
//-----------------------------------------------------------------------------
// Get current timer values
 
externC int timer_gettime( timer_t timerid, struct itimerspec *value )
{
int err = EINVAL;
 
TIME_ENTRY();
if( value == NULL )
TIME_RETURN(EINVAL);
posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
 
timer_mutex.lock();
 
if( timer->id == timerid )
{
cyg_tick_count trigger, interval;
 
timer->alarm->get_times( &trigger, &interval );
 
if( timer->armed )
{
// convert absolute trigger time to interval until next trigger
trigger -= Cyg_Clock::real_time_clock->current_value();
}
else trigger = 0;
 
// convert ticks to timespecs
cyg_ticks_to_timespec( trigger, &value->it_value );
cyg_ticks_to_timespec( interval, &value->it_interval );
err = 0;
}
timer_mutex.unlock();
TIME_RETURN(err);
}
 
//-----------------------------------------------------------------------------
// Get number of missed triggers
 
externC int timer_getoverrun( timer_t timerid )
{
int overrun = 0;
TIME_ENTRY();
 
posix_timer *timer = &timer_table[timerid & TIMER_ID_COOKIE_MASK];
 
timer_mutex.lock();
 
if( timer->id == timerid )
{
overrun = timer->overrun;
}
timer_mutex.unlock();
CYG_REPORT_RETVAL(overrun);
return overrun;
}
 
#endif // ifdef CYGPKG_POSIX_TIMERS
 
//==========================================================================
// Nanosleep
// Sleep for the given time.
 
externC int nanosleep( const struct timespec *rqtp,
struct timespec *rmtp)
{
cyg_tick_count ticks, now, then;
 
TIME_ENTRY();
 
// check for cancellation first.
PTHREAD_TESTCANCEL();
 
// Fail an invalid timespec
if( !valid_timespec( rqtp ) )
TIME_RETURN(EINVAL);
 
// Return immediately for a zero delay.
if( rqtp->tv_sec == 0 && rqtp->tv_nsec == 0 )
TIME_RETURN(0);
 
// Convert timespec to ticks
ticks = cyg_timespec_to_ticks( rqtp, true );
 
CYG_ASSERT( ticks != 0, "Zero tick count");
Cyg_Thread *self = Cyg_Thread::self();
// Do the delay, keeping track of how long we actually slept for.
then = Cyg_Clock::real_time_clock->current_value();
 
self->delay( ticks );
 
now = Cyg_Clock::real_time_clock->current_value();
 
if( rmtp != NULL && (then+ticks) > now )
{
// We woke up early, return the time left.
// FIXME: strictly we only need to do this if we were woken
// by a signal.
 
// Calculate remaining number of ticks.
ticks -= (now-then);
 
cyg_ticks_to_timespec( ticks, rmtp );
}
// check if we were woken up because we were cancelled.
PTHREAD_TESTCANCEL();
 
TIME_RETURN(0);
}
 
// -------------------------------------------------------------------------
// Wait for a signal, or the given number of seconds
 
externC unsigned int sleep( unsigned int seconds )
{
TIME_ENTRY();
 
struct timespec timeout;
 
timeout.tv_sec = seconds;
timeout.tv_nsec = 0;
 
if( nanosleep( &timeout, &timeout ) != 0 )
{
CYG_REPORT_RETVAL(timeout.tv_sec);
return timeout.tv_sec;
}
 
TIME_RETURN(0);
}
 
#endif // ifdef CYGPKG_POSIX_CLOCKS
 
// -------------------------------------------------------------------------
// EOF time.cxx
/v2_0/src/pprivate.h
0,0 → 1,271
#ifndef CYGONCE_PPRIVATE_H
#define CYGONCE_PPRIVATE_H
//=============================================================================
//
// pprivate.h
//
// POSIX types header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-17
// Purpose: POSIX private header
// Description: This header contains various POSIX type definitions that are
// shared between the various parts of the POSIX package.
//
// Usage: #include <pprivate.h>
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <stddef.h> // NULL, size_t
 
#include <sys/types.h>
#include <sched.h>
#include <pthread.h>
#include <errno.h> // error codes
#include <signal.h> // sigset_t
#include <limits.h> // PTHREAD_KEYS_MAX
 
#include <cyg/posix/export.h> // POSIX exports header
 
#include <cyg/kernel/thread.hxx> // thread definitions
#include <cyg/kernel/mutex.hxx> // mutex definitions
 
//=============================================================================
// Constructor prioritization
 
// Prioritization for POSIX library support objects
#define CYGBLD_POSIX_INIT CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_COMPAT)
 
// Prioritization for POSIX library startup initialization. This must
// come after CYGBLD_POSIX_INIT constructors.
#define CYGBLD_POSIX_START CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_COMPAT+5)
 
//=============================================================================
// Thread control data structure
 
// Per-thread information needed by POSIX
// This is pointed to by the CYGNUM_KERNEL_THREADS_DATA_POSIX entry of the
// per-thread data.
 
#ifdef CYGPKG_POSIX_PTHREAD
typedef struct
{
unsigned int state:4, // Thread state
cancelstate:2, // Cancel state of thread
canceltype:2, // Cancel type of thread
cancelpending:1, // pending cancel flag
freestack:1; // stack malloced, must be freed
 
pthread_t id; // My thread ID
Cyg_Thread *thread; // pointer to eCos thread object
pthread_attr_t attr; // Current thread attributes
void *retval; // return value
void *(*start_routine)(void *); // start routine
void *start_arg; // argument to start routine
char name[20]; // name string for debugging
Cyg_Condition_Variable *joiner; // joining threads wait here
CYG_ADDRWORD stackmem; // base of stack memory area
// only valid if freestack == true
 
struct pthread_cleanup_buffer *cancelbuffer; // stack of cleanup buffers
 
#ifdef CYGPKG_POSIX_SIGNALS
sigset_t sigpending; // Set of pending signals
sigset_t sigmask; // Thread's signal mask
#endif
// The following is space for the eCos thread object that underlies
// this POSIX thread. It is allocated like this to avoid constructing
// it on startup.
cyg_uint8 thread_obj[sizeof(Cyg_Thread)];
 
// And the same for the joiner condition variable.
cyg_uint8 joiner_obj[sizeof(Cyg_Condition_Variable)];
 
// Per-thread data table pointer
void **thread_data;
} pthread_info;
 
 
// Values for the state field. These are solely concerned with the
// states visible to POSIX. The thread's run state is stored in the
// eCos thread object.
// Note: numerical order here is important, do not rearrange.
 
#define PTHREAD_STATE_FREE 0 // This structure is free for reuse
#define PTHREAD_STATE_DETACHED 1 // The thread is running but detached
#define PTHREAD_STATE_RUNNING 2 // The thread is running and will wait
// to join when it exits
#define PTHREAD_STATE_JOIN 3 // The thread has exited and is waiting
// to be joined
#define PTHREAD_STATE_EXITED 4 // The thread has exited and is ready to
// be reaped
#endif // ifdef CYGPKG_POSIX_PTHREAD
//-----------------------------------------------------------------------------
// Internal definitions
 
// Handle entry to a pthread package function.
#define PTHREAD_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" )
 
// Handle entry to a pthread package function with no args.
#define PTHREAD_ENTRY_VOID() CYG_REPORT_FUNCTION()
 
// Do a pthread package defined return. This requires the error code to be
// returned as the result of the function. This also gives us a place to
// put any generic tidyup handling needed for things like signal delivery
// and cancellation.
#define PTHREAD_RETURN(err) \
CYG_MACRO_START \
CYG_REPORT_RETVAL( err ); \
return err; \
CYG_MACRO_END
 
// A void variant of the above.
#define PTHREAD_RETURN_VOID \
CYG_MACRO_START \
CYG_REPORT_RETURN(); \
return; \
CYG_MACRO_END
 
// Check that a pointer passed in as an argument is valid and return
// EINVAL if it is not. This should be used to check pointers that are
// required to be valid. Pointers that may optionally be NULL should
// be checked within the function.
#define PTHREAD_CHECK(ptr) if( (ptr) == NULL ) PTHREAD_RETURN(EINVAL);
 
#ifdef CYGPKG_POSIX_PTHREAD
# define PTHREAD_TESTCANCEL() pthread_testcancel()
#else
# define PTHREAD_TESTCANCEL()
#endif
 
//-----------------------------------------------------------------------------
// Priority translation.
// eCos priorities run from 0 as the highest to 31 as the lowest. POSIX priorities
// run in the opposite direction. The following macros translate between the two
// priority ranges.
 
#define PTHREAD_ECOS_PRIORITY(pri) (CYG_THREAD_MIN_PRIORITY-(pri))
 
#define PTHREAD_POSIX_PRIORITY(pri) (CYG_THREAD_MIN_PRIORITY-(pri))
 
//-----------------------------------------------------------------------------
// Global data structures
 
// Mutex for locking access to pthread_info structures
extern Cyg_Mutex pthread_mutex;
 
//-----------------------------------------------------------------------------
// Functions exported by pthread.cxx to the other parts of the POSIX subsystem.
 
#ifdef CYGPKG_POSIX_PTHREAD
externC void cyg_posix_pthread_start( void );
 
externC pthread_info *pthread_self_info(void);
 
externC pthread_info *pthread_info_id( pthread_t id );
 
# ifdef CYGPKG_POSIX_SIGNALS
externC void cyg_posix_pthread_release_thread( sigset_t *mask );
# endif
#endif
 
//-----------------------------------------------------------------------------
// Functions exported by signal.cxx to the other parts of the POSIX subsystem.
 
#ifdef CYGPKG_POSIX_SIGNALS
externC void cyg_posix_signal_start();
 
externC void cyg_posix_signal_asr(pthread_info *self);
 
externC cyg_bool cyg_sigqueue( const struct sigevent *sev, int code,
pthread_info *thread = NULL );
 
externC cyg_bool cyg_deliver_signals();
 
externC void cyg_posix_signal_sigwait();
 
externC void cyg_posix_thread_siginit( pthread_info *thread,
pthread_info *parentthread );
 
externC void cyg_posix_thread_sigdestroy( pthread_info *thread );
#endif
 
//-----------------------------------------------------------------------------
// Functions exported by time.cxx to other parts of the POSIX subsystem.
 
#ifdef CYGPKG_POSIX_CLOCKS
externC void cyg_posix_clock_start();
 
externC cyg_tick_count cyg_timespec_to_ticks( const struct timespec *tp,
cyg_bool roundup = false);
 
externC void cyg_ticks_to_timespec( cyg_tick_count ticks, struct timespec *tp );
 
#endif
 
#ifdef CYGPKG_POSIX_TIMERS
 
externC void cyg_posix_timer_asr( pthread_info *self );
 
#endif
 
//-----------------------------------------------------------------------------
// Functions exported by except.cxx
 
#ifdef CYGPKG_POSIX_SIGNALS
externC void cyg_posix_exception_start();
 
externC void cyg_pthread_exception_init(pthread_info *thread);
 
externC void cyg_pthread_exception_destroy(pthread_info *thread);
#endif
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_PPRIVATE_H
// End of pprivate.h
/v2_0/src/mqueue.cxx
0,0 → 1,982
/*========================================================================
//
// mqueue.cxx
//
// Message queues tests
//
//========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jlarmour
// Contributors:
// Date: 2000-05-14
// Purpose: This file provides the implementation for POSIX message
// queues
// Description: It uses eCos kernel mqueues as the underlying
// implementation
// Usage:
//
//####DESCRIPTIONEND####
//
//======================================================================
*/
 
/* CONFIGURATION */
 
#include <pkgconf/posix.h>
 
#ifdef CYGPKG_POSIX_MQUEUES
 
#include <pkgconf/kernel.h>
 
/* INCLUDES */
 
#include <cyg/infra/cyg_type.h> // common types etc.
#include <cyg/infra/cyg_ass.h> // Assertion support
#include <cyg/infra/cyg_trac.h> // Tracing support
#include <cyg/kernel/mqueue.hxx> // eCos Mqueue Header
#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::lock()
#include <cyg/kernel/sched.inl> // inlines for above
#include <mqueue.h> // Standard POSIX mqueue header
#include <sys/types.h> // mode_t, ssize_t
#include <limits.h> // PATH_MAX
#include <stdlib.h> // malloc, etc.
#include <errno.h> // errno
#include <fcntl.h> // O_*
#include <stdarg.h> // varargs
#include <pthread.h> // mutexes
#include <string.h> // strncpy
#include <new> // C++ new
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
# include <signal.h>
# include "pprivate.h" // cyg_sigqueue()
#endif
#ifdef CYGFUN_KERNEL_THREADS_TIMER
# include <time.h>
# include "pprivate.h" // cyg_timespec_to_ticks()
#endif
 
/* CONSTANTS */
 
#define MQ_VALID_MAGIC 0x6db256c1
 
/* TYPE DEFINITIONS */
 
struct mqtabent;
 
// this is a queue user - each one of these corresponds to a mqd_t
struct mquser {
int flags; // O_RDONLY, O_WRONLY, O_RDWR, O_NONBLOCK
struct mqtabent *tabent; // back pointer to table entry
struct mquser *next;
bool notifieruser; // POSIX sucks so bad. It requires a mq_close
// to only deregister the notification if it
// was done via this descriptor. So we have to
// know if it was this one
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
cyg_uint32 magic; // magic number: MQ_VALID_MAGIC if valid
#endif
};
 
struct mqtabent {
char name[ PATH_MAX ]; // ascii name - set to "" when unused
Cyg_Mqueue *mq; // the underlying queue object
long maxmsg; // as set on creation
long msgsize; // as set on creation
bool unlinkme; // unlink when final user closes?
struct mquser *users; // each user
 
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
const struct sigevent *sigev; // notification event
#endif
};
 
/* GLOBALS */
 
static struct mqtabent mqtab[ CYGNUM_POSIX_MQUEUE_OPEN_MAX ];
static pthread_mutex_t mqtab_mut = PTHREAD_MUTEX_INITIALIZER;
 
/* LOCAL FUNCTIONS */
 
//------------------------------------------------------------------------
 
// Deallocation callback from Cyg_Mqueue
static void
my_free( void *ptr, size_t )
{
free( ptr );
}
 
//------------------------------------------------------------------------
 
// Do the actual "unlink" of a queue, i.e. mark it invalid in the table.
// The table mutex is assumed to be locked
static void
do_mq_unlink( struct mqtabent *tabent )
{
CYG_REPORT_FUNCTION();
CYG_CHECK_DATA_PTRC( tabent );
 
tabent->name[0] = '\0'; // won't match anything the user sends now
tabent->mq->~Cyg_Mqueue();
free( tabent->mq );
tabent->mq=NULL;
 
CYG_REPORT_RETURN();
}
 
//------------------------------------------------------------------------
 
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
 
static void
notifyme( Cyg_Mqueue &q, CYG_ADDRWORD data )
{
CYG_REPORT_FUNCTION();
struct mquser *user = (struct mquser *)data;
CYG_CHECK_DATA_PTRC( user );
struct mqtabent *tabent = user->tabent;
CYG_CHECK_DATA_PTRC( tabent );
 
Cyg_Scheduler::lock();
// we may have been pre-empted before this, so check there's still a
// notification to do
 
if ( NULL == tabent->sigev ) {
Cyg_Scheduler::unlock();
CYG_REPORT_RETURN();
return;
} // if
 
const struct sigevent *ev = tabent->sigev;
// first deregister
q.setnotify( NULL, 0 );
tabent->sigev = NULL;
user->notifieruser = false; // not any more
// now the rest of the world can go
Cyg_Scheduler::unlock();
// queue event. If it fails... nothing we can do :-( so ignore return code
cyg_sigqueue( ev, SI_MESGQ );
 
cyg_deliver_signals();
CYG_REPORT_RETURN();
}
 
#endif // ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
 
//------------------------------------------------------------------------
 
/* EXPORTED FUNCTIONS */
 
externC mqd_t
mq_open( const char *name, int oflag, ... )
{
CYG_REPORT_FUNCTYPE( "returning %08x" );
CYG_REPORT_FUNCARG2( "name=%08x, oflag=%d", name, oflag );
CYG_CHECK_DATA_PTRC( name );
 
if ( ((oflag & O_RDONLY) != O_RDONLY) &&
((oflag & O_WRONLY) != O_WRONLY) &&
((oflag & O_RDWR) != O_RDWR)) {
// user didn't specify mode
errno = EINVAL;
CYG_REPORT_RETVAL( -1 );
return (mqd_t)-1;
} // if
 
mqd_t retval;
cyg_ucount32 i;
struct mqtabent *qtabent=NULL;
int interr;
 
interr = pthread_mutex_lock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
// find if a matching entry exists first
// FIXME: Should check for length and return ENAMETOOLONG
for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
if ( 0 == strncmp(name, mqtab[i].name, PATH_MAX) ) {
qtabent = &mqtab[i];
break;
} // if
} // for
if ( (NULL != qtabent) && (O_EXCL == (oflag & O_EXCL)) ) {
errno = EEXIST;
retval = (mqd_t)-1;
goto exit_unlock;
}
if ( (NULL == qtabent) && (O_CREAT != (oflag & O_CREAT)) ) {
errno = ENOENT;
retval = (mqd_t)-1;
goto exit_unlock;
}
 
// so if we didn't find something, we must be being asked to create it
if (NULL == qtabent) {
mode_t mode; // FIXME: mode ignored for now
const struct mq_attr *attr;
const struct mq_attr default_attr = { 0, MQ_OPEN_MAX, 128 };
va_list args;
va_start( args, oflag );
mode = va_arg( args, mode_t );
attr = va_arg( args, struct mq_attr * );
va_end( args );
 
// find an empty table entry
for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
if ( NULL == mqtab[i].mq )
break;
}
 
// if not found, table is full
if ( i == CYGNUM_POSIX_MQUEUE_OPEN_MAX ) {
errno = ENFILE;
retval = (mqd_t)-1;
goto exit_unlock;
}
 
Cyg_Mqueue::qerr_t qerr;
 
// user can specify NULL attr, which means arbitrary message queue
// size! Duh.
if ( NULL == attr )
attr = &default_attr;
else {
// if they do supply one, POSIX says we're meant to check it
if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) {
errno = EINVAL;
retval = (mqd_t)-1;
goto exit_unlock;
}
} // else
 
// allocate the underlying queue
Cyg_Mqueue *mqholder = (Cyg_Mqueue *)malloc( sizeof(Cyg_Mqueue) );
if ( NULL == mqholder ) {
errno = ENOSPC;
retval = (mqd_t)-1;
goto exit_unlock;
}
// construct it with placement new
mqtab[i].mq = new (mqholder) Cyg_Mqueue( attr->mq_maxmsg,
attr->mq_msgsize,
&malloc, &my_free, &qerr );
switch (qerr) {
case Cyg_Mqueue::OK:
break;
case Cyg_Mqueue::NOMEM:
free( mqholder );
errno = ENOSPC;
retval = (mqd_t)-1;
goto exit_unlock;
default:
CYG_FAIL("Unhandled Cyg_Mqueue constructor return error");
break;
} // switch
 
mqtab[i].users = (struct mquser *) malloc( sizeof(struct mquser) );
if ( NULL == mqtab[i].users ) {
mqtab[i].mq->~Cyg_Mqueue();
free( mqholder );
errno = ENOSPC;
retval = (mqd_t)-1;
goto exit_unlock;
}
 
// initialize mqtab[i]
mqtab[i].maxmsg = attr->mq_maxmsg;
mqtab[i].msgsize = attr->mq_msgsize;
mqtab[i].unlinkme = false;
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
mqtab[i].sigev = NULL;
#endif
strncpy( mqtab[i].name, name, PATH_MAX );
 
// initialize first mqtab[i].users
mqtab[i].users->next = NULL;
// set the mode for later, but also note that O_NONBLOCK can
// be set in oflags *or* the attr the user passed
mqtab[i].users->flags = oflag | (attr->mq_flags & O_NONBLOCK);
 
// set back pointer so that message queue handle can find actual queue
mqtab[i].users->tabent = &mqtab[i];
mqtab[i].users->notifieruser = false;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
mqtab[i].users->magic = MQ_VALID_MAGIC; // now valid
#endif
retval=(mqd_t)mqtab[i].users;
 
goto exit_unlock;
} // if (NULL == qtabent)
 
// so we're not creating, and we have a valid qtabent
 
// But this qtabent may be being unlinked. If so, we are permitted
// to return an error, so we will. (see under mq_unlink() in POSIX)
// Which error though? EINVAL seems best, but POSIX doesn't say :-/
 
if (true == qtabent->unlinkme) {
errno = EINVAL;
retval = (mqd_t)-1;
goto exit_unlock;
}
// now we have a usable qtabent
 
struct mquser *user;
user = (struct mquser *) malloc( sizeof(struct mquser) );
if ( NULL == user ) {
errno = ENOSPC;
retval = (mqd_t)-1;
goto exit_unlock;
}
 
// prepend to qtab user list
user->next = qtabent->users;
qtabent->users = user;
 
// set back pointer so that message queue handle can find actual queue
user->tabent = qtabent;
 
user->flags = oflag;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
user->magic = MQ_VALID_MAGIC; // now valid
#endif
 
retval=(mqd_t)user;
 
exit_unlock:
interr = pthread_mutex_unlock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
CYG_REPORT_RETVAL( retval );
return retval;
} // mq_open()
 
//------------------------------------------------------------------------
 
// NOTE: It is the *user*'s responsibility to ensure that nothing is
// blocked in mq_send() or mq_receive() when closing the queue with
// that descriptor. The standard does not specify the behaviour, so that's
// what I am assuming
 
externC int
mq_close( mqd_t mqdes )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG1XV( mqdes );
struct mquser *user = (struct mquser *)mqdes;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
#endif
int interr;
 
interr = pthread_mutex_lock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
 
struct mqtabent *tabent = user->tabent;
struct mquser *usertmp;
// perhaps should return EBADF instead of assert?
CYG_ASSERT( tabent->users != NULL, "Null message queue user list" );
 
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
// deregister notification iff this was the message queue descriptor
// that was used to register it (POSIX says)
if ( true == user->notifieruser ) {
tabent->mq->setnotify( NULL, 0 );
tabent->sigev = NULL;
// not worth clearing notifieruser
}
#endif
 
// find in the list for this queue and remove - sucks a bit, but seems
// best over all - the list shouldn't be too long
if ( tabent->users == user ) {
tabent->users = user->next; // remove
} else {
for ( usertmp=tabent->users;
NULL != usertmp->next;
usertmp = usertmp->next ) {
if ( usertmp->next == user )
break;
} // for
 
// perhaps should return EBADF instead of assert?
CYG_ASSERT( usertmp->next != NULL, "Couldn't find message queue user" );
 
usertmp->next = user->next; // remove
} // else
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
user->magic = 0; // invalidate
#endif
 
// free it up
free( user );
 
if ( (true == tabent->unlinkme) && (NULL == tabent->users) ) {
do_mq_unlink( tabent );
} // if
 
interr = pthread_mutex_unlock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
CYG_REPORT_RETVAL( 0 );
return 0;
} // mq_close()
 
 
//------------------------------------------------------------------------
 
externC int
mq_unlink( const char *name )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG1( "name=%s", name );
 
int retval, interr;
cyg_ucount32 i;
struct mqtabent *qtabent=NULL;
 
interr = pthread_mutex_lock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
 
// find the entry first
// FIXME: Should check for length and return ENAMETOOLONG
for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
if ( 0 == strncmp(name, mqtab[i].name, PATH_MAX) ) {
qtabent = &mqtab[i];
break;
} // if
} // for
 
if ( NULL == qtabent ) { // not found
errno = ENOENT;
retval = -1;
goto exit_unlock;
}
 
if ( NULL != qtabent->users ) { // still in use
qtabent->unlinkme = true; // so mark it as pending deletion
} else {
do_mq_unlink( qtabent );
} // else
 
retval = 0;
 
exit_unlock:
interr = pthread_mutex_unlock( &mqtab_mut );
// should never fail
CYG_ASSERT( interr == 0, "internal lock failed!" );
CYG_REPORT_RETVAL( retval );
return retval;
} // mq_unlink()
 
//------------------------------------------------------------------------
 
externC int
mq_send( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
unsigned int msg_prio )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%u",
mqdes, msg_ptr, msg_len, msg_prio );
CYG_CHECK_DATA_PTRC( msg_ptr );
struct mquser *user = (struct mquser *)mqdes;
struct mqtabent *tabent = user->tabent;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
#endif
if ( msg_len > (size_t)tabent->msgsize ) {
errno = EMSGSIZE;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
if ( msg_prio > MQ_PRIO_MAX ) {
errno = EINVAL;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
if ( (O_WRONLY != (user->flags & O_WRONLY)) &&
(O_RDWR != (user->flags & O_RDWR)) ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
// go for it
Cyg_Mqueue::qerr_t err;
err = tabent->mq->put( msg_ptr, msg_len, msg_prio,
((user->flags & O_NONBLOCK) != O_NONBLOCK) );
switch (err) {
 
case Cyg_Mqueue::INTR:
errno = EINTR;
CYG_REPORT_RETVAL( -1 );
return -1;
 
case Cyg_Mqueue::WOULDBLOCK:
CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
"Message queue assumed non-blocking when blocking requested"
);
errno = EAGAIN;
CYG_REPORT_RETVAL( -1 );
return -1;
case Cyg_Mqueue::OK:
CYG_REPORT_RETVAL( 0 );
return 0;
 
default:
CYG_FAIL( "unhandled message queue return code" );
return -1; // keep compiler happy
} // switch
} // mq_send()
 
//------------------------------------------------------------------------
 
 
externC ssize_t
mq_receive( mqd_t mqdes, char *msg_ptr, size_t msg_len,
unsigned int *msg_prio )
{
CYG_REPORT_FUNCTYPE( "returning %ld" );
CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%08x",
mqdes, msg_ptr, msg_len, msg_prio );
CYG_CHECK_DATA_PTRC( msg_ptr );
CYG_CHECK_DATA_PTRC( msg_ptr+msg_len-1 );
if ( NULL != msg_prio )
CYG_CHECK_DATA_PTRC( msg_prio );
struct mquser *user = (struct mquser *)mqdes;
struct mqtabent *tabent = user->tabent;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
}
#endif
if ( (O_RDONLY != (user->flags & O_RDONLY)) &&
(O_RDWR != (user->flags & O_RDWR)) ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
}
 
if ( msg_len < (size_t)tabent->msgsize ) {
errno = EMSGSIZE;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
}
 
// go for it
Cyg_Mqueue::qerr_t err;
err = tabent->mq->get( msg_ptr, &msg_len, msg_prio,
((user->flags & O_NONBLOCK) != O_NONBLOCK) );
switch (err) {
 
case Cyg_Mqueue::INTR:
errno = EINTR;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
 
case Cyg_Mqueue::WOULDBLOCK:
CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
"Message queue assumed non-blocking when blocking requested"
);
errno = EAGAIN;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
case Cyg_Mqueue::OK:
CYG_ASSERT( msg_len <= (size_t)tabent->msgsize,
"returned message too long" );
if ( NULL != msg_prio )
CYG_ASSERT( *msg_prio <= MQ_PRIO_MAX,
"returned message has invalid priority" );
CYG_REPORT_RETVAL( msg_len );
return (ssize_t)msg_len;
 
default:
CYG_FAIL( "unhandled message queue return code" );
return (ssize_t)-1; // keep compiler happy
} // switch
} // mq_receive()
 
 
//------------------------------------------------------------------------
#ifdef CYGFUN_KERNEL_THREADS_TIMER
externC int
mq_timedsend( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
unsigned int msg_prio, const struct timespec *abs_timeout)
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG6( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%u, "
"abs_timeout = %lu, %ld",
mqdes, msg_ptr, msg_len, msg_prio,
abs_timeout->tv_sec, abs_timeout->tv_nsec);
CYG_CHECK_DATA_PTRC( msg_ptr );
struct mquser *user = (struct mquser *)mqdes;
struct mqtabent *tabent = user->tabent;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
#endif
if ( msg_len > (size_t)tabent->msgsize ) {
errno = EMSGSIZE;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
if ( msg_prio > MQ_PRIO_MAX ) {
errno = EINVAL;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
if ( (O_WRONLY != (user->flags & O_WRONLY)) &&
(O_RDWR != (user->flags & O_RDWR)) ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
// go for it
Cyg_Mqueue::qerr_t err;
bool nonblocking = ((user->flags & O_NONBLOCK) == O_NONBLOCK);
bool badtimespec = (abs_timeout->tv_nsec < 0) ||
(abs_timeout->tv_nsec > 999999999l);
err = tabent->mq->put( msg_ptr, msg_len, msg_prio,
!nonblocking && !badtimespec,
cyg_timespec_to_ticks(abs_timeout));
switch (err) {
 
case Cyg_Mqueue::INTR:
errno = EINTR;
CYG_REPORT_RETVAL( -1 );
return -1;
 
case Cyg_Mqueue::WOULDBLOCK:
if (badtimespec) {
errno = EINVAL;
CYG_REPORT_RETVAL( -1 );
return -1;
}
CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
"Message queue assumed non-blocking when blocking requested"
);
errno = EAGAIN;
CYG_REPORT_RETVAL( -1 );
return -1;
 
case Cyg_Mqueue::TIMEOUT:
errno = ETIMEDOUT;
CYG_REPORT_RETVAL( -1 );
return -1;
case Cyg_Mqueue::OK:
CYG_REPORT_RETVAL( 0 );
return 0;
 
default:
CYG_FAIL( "unhandled message queue return code" );
return -1; // keep compiler happy
} // switch
} // mq_timedsend()
 
//------------------------------------------------------------------------
 
 
externC ssize_t
mq_timedreceive( mqd_t mqdes, char *msg_ptr, size_t msg_len,
unsigned int *msg_prio, const struct timespec *abs_timeout)
{
CYG_REPORT_FUNCTYPE( "returning %ld" );
CYG_REPORT_FUNCARG6( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%08x, "
"abs_timeout = %lu, %ld",
mqdes, msg_ptr, msg_len, msg_prio,
abs_timeout->tv_sec, abs_timeout->tv_nsec );
CYG_CHECK_DATA_PTRC( msg_ptr );
CYG_CHECK_DATA_PTRC( msg_ptr+msg_len-1 );
if ( NULL != msg_prio )
CYG_CHECK_DATA_PTRC( msg_prio );
struct mquser *user = (struct mquser *)mqdes;
struct mqtabent *tabent = user->tabent;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
}
#endif
if ( (O_RDONLY != (user->flags & O_RDONLY)) &&
(O_RDWR != (user->flags & O_RDWR)) ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
}
 
if ( msg_len < (size_t)tabent->msgsize ) {
errno = EMSGSIZE;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
}
 
// go for it
Cyg_Mqueue::qerr_t err;
bool nonblocking = ((user->flags & O_NONBLOCK) == O_NONBLOCK);
bool badtimespec = (abs_timeout->tv_nsec < 0) ||
(abs_timeout->tv_nsec > 999999999l);
err = tabent->mq->get( msg_ptr, &msg_len, msg_prio,
!nonblocking && !badtimespec,
cyg_timespec_to_ticks(abs_timeout) );
switch (err) {
 
case Cyg_Mqueue::INTR:
errno = EINTR;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
 
case Cyg_Mqueue::WOULDBLOCK:
if (badtimespec) {
errno = EINVAL;
CYG_REPORT_RETVAL( -1 );
return -1;
}
CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
"Message queue assumed non-blocking when blocking requested"
);
errno = EAGAIN;
CYG_REPORT_RETVAL( -1 );
return (ssize_t)-1;
 
case Cyg_Mqueue::TIMEOUT:
errno = ETIMEDOUT;
CYG_REPORT_RETVAL( -1 );
return -1;
case Cyg_Mqueue::OK:
CYG_ASSERT( msg_len <= (size_t)tabent->msgsize,
"returned message too long" );
if ( NULL != msg_prio )
CYG_ASSERT( *msg_prio <= MQ_PRIO_MAX,
"returned message has invalid priority" );
CYG_REPORT_RETVAL( msg_len );
return (ssize_t)msg_len;
 
default:
CYG_FAIL( "unhandled message queue return code" );
return (ssize_t)-1; // keep compiler happy
} // switch
} // mq_timedreceive()
 
//------------------------------------------------------------------------
#endif
 
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
 
externC int
mq_notify( mqd_t mqdes, const struct sigevent *notification )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG2( "mqdes=%08x, notification=%08x", mqdes, notification );
if ( NULL != notification )
CYG_CHECK_DATA_PTRC( notification );
struct mquser *user = (struct mquser *)mqdes;
struct mqtabent *tabent = user->tabent;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
#endif
// lock scheduler since we test and set non-atomically
Cyg_Scheduler::lock();
// we are being told to clear the notification function
if ( NULL == notification ) {
tabent->mq->setnotify( NULL, 0 );
tabent->sigev = NULL;
Cyg_Scheduler::unlock();
CYG_REPORT_RETVAL( 0 );
return 0;
} // if
if ( NULL != tabent->sigev ) { // already registered
Cyg_Scheduler::unlock();
errno = EBUSY;
CYG_REPORT_RETVAL( -1 );
return -1;
} // if
 
tabent->sigev = notification;
user->notifieruser = true; // Used for deciding about whether to
// deregister in mq_close()
tabent->mq->setnotify( &notifyme, (CYG_ADDRWORD) user );
Cyg_Scheduler::unlock();
CYG_REPORT_RETVAL( 0 );
return 0;
} // mq_notify()
 
#endif // ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
 
//------------------------------------------------------------------------
 
externC int
mq_setattr( mqd_t mqdes, const struct mq_attr *mqstat,
struct mq_attr *omqstat )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG3( "mqdes=%08x, mqstat=%08x, omqstat=%08x",
mqdes, mqstat, omqstat );
CYG_CHECK_DATA_PTRC( mqstat );
 
struct mquser *user = (struct mquser *)mqdes;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
#endif
if ( NULL != omqstat ) {
CYG_CHECK_DATA_PTRC( omqstat );
mq_getattr( mqdes, omqstat );
} // if
 
// Two-stage update, so lock sched since it's quick
Cyg_Scheduler::lock();
user->flags &= ~O_NONBLOCK; // clear
if ( (mqstat->mq_flags & O_NONBLOCK) == O_NONBLOCK ) {
user->flags |= O_NONBLOCK;
} // if
Cyg_Scheduler::unlock();
 
CYG_REPORT_RETVAL( 0 );
return 0;
} // mq_setattr()
 
//------------------------------------------------------------------------
 
externC int
mq_getattr( mqd_t mqdes, struct mq_attr *mqstat )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
CYG_REPORT_FUNCARG2( "mqdes=%08x, mqstat=%08x", mqdes, mqstat );
CYG_CHECK_DATA_PTRC( mqstat );
 
struct mquser *user = (struct mquser *)mqdes;
struct mqtabent *tabent = user->tabent;
 
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
if ( user->magic != MQ_VALID_MAGIC ) {
errno = EBADF;
CYG_REPORT_RETVAL( -1 );
return -1;
}
#endif
mqstat->mq_flags = user->flags;
mqstat->mq_maxmsg = tabent->maxmsg;
mqstat->mq_msgsize = tabent->msgsize;
mqstat->mq_curmsgs = tabent->mq->count();
CYG_REPORT_RETVAL( 0 );
return 0;
} // mq_getattr()
 
 
//------------------------------------------------------------------------
 
#endif // ifdef CYGPKG_POSIX_MQUEUES
 
/* EOF mqueue.cxx */
/v2_0/src/mutex.cxx
0,0 → 1,551
//==========================================================================
//
// pthread.cxx
//
// POSIX pthreads implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg, jlarmour, Wade Jensen
// Date: 2000-03-27
// Purpose: POSIX pthread implementation
// Description: This file contains the implementation of the POSIX pthread
// functions.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/posix.h>
 
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include "pprivate.h" // POSIX private header
 
#include <cyg/kernel/thread.hxx> // thread definitions
#include <cyg/kernel/mutex.hxx> // mutex definitions
#include <cyg/kernel/clock.hxx> // clock definitions
#include <cyg/kernel/sched.hxx> // scheduler primitives
#include <pthread.h>
 
#include <cyg/kernel/thread.inl> // thread inlines
#include <cyg/kernel/sched.inl> // scheduler inlines
 
//-----------------------------------------------------------------------------
// new operator to allow us to construct mutex objects
 
inline void *operator new(size_t size, cyg_uint8 *ptr) { return (void *)ptr; };
 
//=============================================================================
// Mutexes
 
//-----------------------------------------------------------------------------
// Mutex attributes manipulation functions
 
//-----------------------------------------------------------------------------
// Initialize attribute object
 
externC int pthread_mutexattr_init ( pthread_mutexattr_t *attr)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
attr->protocol = PTHREAD_PRIO_NONE;
#ifdef _POSIX_THREAD_PRIO_PROTECT
attr->prioceiling = 0;
#endif
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Destroy attribute object
 
externC int pthread_mutexattr_destroy ( pthread_mutexattr_t *attr)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
// Nothing to do here...
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Optional functions depending on priority inversion protection options.
 
#if defined(_POSIX_THREAD_PRIO_INHERIT) || defined(_POSIX_THREAD_PRIO_PROTECT)
 
// Set priority inversion protection protocol
externC int pthread_mutexattr_setprotocol ( pthread_mutexattr_t *attr,
int protocol)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
switch( protocol )
{
case PTHREAD_PRIO_NONE:
#if defined(_POSIX_THREAD_PRIO_INHERIT)
case PTHREAD_PRIO_INHERIT:
#endif
#if defined(_POSIX_THREAD_PRIO_PROTECT)
case PTHREAD_PRIO_PROTECT:
#endif
attr->protocol = protocol;
PTHREAD_RETURN(0);
 
default:
PTHREAD_RETURN(EINVAL);
}
PTHREAD_RETURN(0);
}
 
// Get priority inversion protection protocol
externC int pthread_mutexattr_getprotocol ( pthread_mutexattr_t *attr,
int *protocol)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( protocol != NULL )
*protocol = attr->protocol;
PTHREAD_RETURN(0);
}
 
#if defined(_POSIX_THREAD_PRIO_PROTECT)
 
// Set priority for priority ceiling protocol
externC int pthread_mutexattr_setprioceiling ( pthread_mutexattr_t *attr,
int prioceiling)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
attr->prioceiling = prioceiling;
PTHREAD_RETURN(0);
}
 
// Get priority for priority ceiling protocol
externC int pthread_mutexattr_getprioceiling ( pthread_mutexattr_t *attr,
int *prioceiling)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( prioceiling != NULL )
*prioceiling = attr->prioceiling;
PTHREAD_RETURN(0);
}
 
// Set priority ceiling of given mutex, returning old ceiling.
externC int pthread_mutex_setprioceiling( pthread_mutex_t *mutex,
int prioceiling,
int *old_ceiling)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(mutex);
 
pthread_mutex_lock( mutex );
 
Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
 
if( old_ceiling != NULL )
*old_ceiling = mx->get_ceiling();
mx->set_ceiling( prioceiling );
pthread_mutex_unlock( mutex );
 
PTHREAD_RETURN(0);
}
 
// Get priority ceiling of given mutex
externC int pthread_mutex_getprioceiling( pthread_mutex_t *mutex,
int *prioceiling)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(mutex);
 
Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
 
if( prioceiling != NULL )
*prioceiling = mx->get_ceiling();
PTHREAD_RETURN(0);
}
 
#endif // defined(_POSIX_THREAD_PRIO_PROTECT)
 
#endif // defined(_POSIX_THREAD_PRIO_INHERIT) || defined(_POSIX_THREAD_PRIO_PROTECT)
 
//-----------------------------------------------------------------------------
// Mutex functions
 
//-----------------------------------------------------------------------------
// Initialize mutex. If mutex_attr is NULL, use default attributes.
 
externC int pthread_mutex_init (pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutex_attr)
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK( mutex );
pthread_mutexattr_t use_attr;
 
// Set up the attributes we are going to use
if( mutex_attr == NULL )
pthread_mutexattr_init( &use_attr );
else use_attr = *mutex_attr;
 
// Now translate the POSIX protocol identifier into the eCos one.
Cyg_Mutex::cyg_protcol protocol;
switch( use_attr.protocol )
{
#if defined(_POSIX_THREAD_PRIO_PROTECT)
case PTHREAD_PRIO_PROTECT:
protocol = Cyg_Mutex::CEILING;
break;
#endif
#if defined(_POSIX_THREAD_PRIO_INHERIT)
case PTHREAD_PRIO_INHERIT:
protocol = Cyg_Mutex::INHERIT;
break;
#endif
case PTHREAD_PRIO_NONE:
protocol = Cyg_Mutex::NONE;
break;
 
default:
PTHREAD_RETURN(EINVAL);
}
 
Cyg_Mutex *mx = new((cyg_uint8 *)mutex) Cyg_Mutex( protocol );
 
mx = mx; // silence compiler warning
#if defined(_POSIX_THREAD_PRIO_PROTECT)
if ( protocol == Cyg_Mutex::CEILING )
mx->set_ceiling( use_attr.prioceiling );
#endif
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Destroy mutex.
 
externC int pthread_mutex_destroy (pthread_mutex_t *mutex)
{
PTHREAD_ENTRY();
 
int err = ENOERR;
PTHREAD_CHECK( mutex );
 
Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
if( mx->get_owner() != NULL )
err = EBUSY;
else mx->~Cyg_Mutex();
PTHREAD_RETURN(err);
}
 
//-----------------------------------------------------------------------------
// Lock mutex, waiting for it if necessary.
 
externC int pthread_mutex_lock (pthread_mutex_t *mutex)
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK( mutex );
 
Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
 
if( mx->get_owner() == Cyg_Thread::self() )
PTHREAD_RETURN(EDEADLK);
// Loop here until we acquire the mutex. Even if we are kicked out
// of the wait by a signal or release we must retry.
while( !mx->lock() )
continue;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Try to lock mutex.
 
externC int pthread_mutex_trylock (pthread_mutex_t *mutex)
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK( mutex );
Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
 
if( mx->get_owner() == Cyg_Thread::self() )
PTHREAD_RETURN(EDEADLK);
if( mx->trylock() )
PTHREAD_RETURN(0);
 
PTHREAD_RETURN(EBUSY);
}
 
 
//-----------------------------------------------------------------------------
// Unlock mutex.
 
externC int pthread_mutex_unlock (pthread_mutex_t *mutex)
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK( mutex );
Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
 
mx->unlock();
PTHREAD_RETURN(0);
}
 
 
//=============================================================================
// Condition Variables
 
//-----------------------------------------------------------------------------
// Attribute manipulation functions
// We do not actually support any attributes at present, so these do nothing.
 
//-----------------------------------------------------------------------------
// Initialize condition variable attributes
 
externC int pthread_condattr_init (pthread_condattr_t *attr)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
// There are no condition variable attributes at present
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Destroy condition variable attributes
 
externC int pthread_condattr_destroy (pthread_condattr_t *attr)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
// nothing to do here...
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Condition variable functions
 
//-----------------------------------------------------------------------------
// Initialize condition variable.
 
externC int pthread_cond_init (pthread_cond_t *cond,
const pthread_condattr_t *attr)
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK( cond );
 
Cyg_Condition_Variable *cv =
new((cyg_uint8 *)cond) Cyg_Condition_Variable();
 
cv = cv;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Destroy condition variable.
 
externC int pthread_cond_destroy (pthread_cond_t *cond)
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK( cond );
 
((Cyg_Condition_Variable *)cond)->~Cyg_Condition_Variable();
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Wake up one thread waiting for condition variable
 
externC int pthread_cond_signal (pthread_cond_t *cond)
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK( cond );
 
((Cyg_Condition_Variable *)cond)->signal();
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Wake up all threads waiting for condition variable
 
externC int pthread_cond_broadcast (pthread_cond_t *cond)
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK( cond );
 
((Cyg_Condition_Variable *)cond)->broadcast();
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Block on condition variable until signalled. The mutex is
// assumed to be locked before this call, will be unlocked
// during the wait, and will be re-locked on wakeup.
 
externC int pthread_cond_wait (pthread_cond_t *cond,
pthread_mutex_t *mutex)
{
PTHREAD_ENTRY();
 
// check for cancellation first.
PTHREAD_TESTCANCEL();
 
PTHREAD_CHECK( cond );
PTHREAD_CHECK( mutex );
 
((Cyg_Condition_Variable *)cond)->wait( *(Cyg_Mutex *)mutex );
// check if we were woken because we were being cancelled
PTHREAD_TESTCANCEL();
 
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Block on condition variable until signalled, or the timeout expires.
 
externC int pthread_cond_timedwait (pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec *abstime)
{
PTHREAD_ENTRY();
 
// check for cancellation first.
PTHREAD_TESTCANCEL();
 
PTHREAD_CHECK( cond );
PTHREAD_CHECK( mutex );
PTHREAD_CHECK( abstime );
 
// Only initialize the converters once or they will consume a huge
// amount or runtime.
 
static struct Cyg_Clock::converter ns_converter;
static struct Cyg_Clock::converter sec_converter;
static volatile cyg_atomic conv_init;
if (!conv_init)
{
 
// Try to avoid unnecessarily locking the scheduler when we are not
// initializing the converters. Check the conv_init flag again to
// avoid race conditions.
 
struct Cyg_Clock::converter temp_ns_converter, temp_sec_converter;
Cyg_Clock::real_time_clock
->get_other_to_clock_converter( 1, &temp_ns_converter );
Cyg_Clock::real_time_clock
->get_other_to_clock_converter( 1000000000, &temp_sec_converter );
 
Cyg_Scheduler::lock();
if (!conv_init)
{
ns_converter = temp_ns_converter;
sec_converter = temp_sec_converter;
conv_init=1;
}
Cyg_Scheduler::unlock();
}
 
cyg_tick_count ticks;
ticks = Cyg_Clock::convert( abstime->tv_sec, &sec_converter );
ticks += Cyg_Clock::convert( abstime->tv_nsec, &ns_converter );
((Cyg_Condition_Variable *)cond)->wait( *(Cyg_Mutex *)mutex, ticks );
// check if we were woken because we were being cancelled
PTHREAD_TESTCANCEL();
 
if ( Cyg_Thread::self()->get_wake_reason() == Cyg_Thread::TIMEOUT )
PTHREAD_RETURN(ETIMEDOUT);
else
PTHREAD_RETURN(0);
}
 
// -------------------------------------------------------------------------
// EOF mutex.cxx
/v2_0/src/startup.cxx
0,0 → 1,87
//==========================================================================
//
// startup.cxx
//
// POSIX startup code
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg, jlarmour
// Contributors: nickg, jlarmour
// Date: 2000-03-27
// Purpose: POSIX startup code
// Description: This file contains code that must be run when the
// POSIX subsystem is started.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/posix.h>
 
#include <cyg/infra/cyg_type.h>
#include "pprivate.h" // POSIX private header
 
// -------------------------------------------------------------------------
 
// define an object that will automatically initialize the POSIX subsystem
 
class cyg_posix_startup_dummy_constructor_class {
public:
cyg_posix_startup_dummy_constructor_class() {
 
#ifdef CYGPKG_POSIX_PTHREAD
cyg_posix_pthread_start();
#endif
#ifdef CYGPKG_POSIX_SIGNALS
cyg_posix_signal_start();
cyg_posix_exception_start();
#endif
#ifdef CYGPKG_POSIX_TIMERS
cyg_posix_clock_start();
#endif
 
}
};
 
static cyg_posix_startup_dummy_constructor_class cyg_posix_startup_obj
CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_COMPAT);
 
// -------------------------------------------------------------------------
// EOF startup.cxx
/v2_0/src/sem.cxx
0,0 → 1,244
//==========================================================================
//
// sem.cxx
//
// POSIX semaphore implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-27
// Purpose: POSIX semaphore implementation
// Description: This file contains the implementation of the POSIX semaphore
// functions.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <semaphore.h> // our header
 
#include "pprivate.h" // POSIX private header
 
#include <cyg/kernel/thread.hxx> // Kernel threads
 
#include <cyg/kernel/thread.inl> // Cyg_ThreadQueue::empty()
 
#include <cyg/kernel/sema.hxx> // Kernel semaphores
 
// -------------------------------------------------------------------------
// Internal definitions
 
// Handle entry to a pthread package function.
#define SEMA_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" );
 
// Do a semaphore package defined return. This requires the error code
// to be placed in errno, and if it is non-zero, -1 returned as the
// result of the function. This also gives us a place to put any
// generic tidyup handling needed for things like signal delivery and
// cancellation.
#define SEMA_RETURN(err) \
CYG_MACRO_START \
int __retval = 0; \
if( err != 0 ) __retval = -1, errno = err; \
CYG_REPORT_RETVAL( __retval ); \
return __retval; \
CYG_MACRO_END
 
//-----------------------------------------------------------------------------
// new operator to allow us to invoke the Cyg_Thread constructor on the
// user's semaphore object.
 
inline void *operator new(size_t size, void *ptr) { return (void *)ptr; };
 
// -------------------------------------------------------------------------
// Initialize semaphore to value.
// pshared is not supported under eCos.
 
externC int sem_init (sem_t *sem, int pshared, unsigned int value)
{
SEMA_ENTRY();
 
if( value > SEM_VALUE_MAX )
SEMA_RETURN(EINVAL);
 
Cyg_Counting_Semaphore *sema;
 
sema = new((void *)sem) Cyg_Counting_Semaphore(value);
 
sema=sema;
SEMA_RETURN(0);
}
 
// -------------------------------------------------------------------------
// Destroy the semaphore.
 
externC int sem_destroy (sem_t *sem)
{
SEMA_ENTRY();
 
Cyg_Counting_Semaphore *sema = (Cyg_Counting_Semaphore *)sem;
 
// Check that the semaphore has no waiters
if( sema->waiting() )
SEMA_RETURN(EBUSY);
 
// Call the destructor
sema->~Cyg_Counting_Semaphore();
SEMA_RETURN(0);
}
 
// -------------------------------------------------------------------------
// Decrement value if >0 or wait for a post.
 
externC int sem_wait (sem_t *sem)
{
int retval = 0;
SEMA_ENTRY();
 
#ifdef CYGPKG_POSIX_PTHREAD
// check for cancellation first.
pthread_testcancel();
#endif
 
Cyg_Counting_Semaphore *sema = (Cyg_Counting_Semaphore *)sem;
 
if( !sema->wait() ) retval = EINTR;
#ifdef CYGPKG_POSIX_PTHREAD
// check if we were woken because we were being cancelled
pthread_testcancel();
#endif
 
SEMA_RETURN(retval);
}
 
// -------------------------------------------------------------------------
// Decrement value if >0, return -1 if not.
 
externC int sem_trywait (sem_t *sem)
{
int retval = 0;
SEMA_ENTRY();
 
Cyg_Counting_Semaphore *sema = (Cyg_Counting_Semaphore *)sem;
 
if( !sema->trywait() ) retval = EAGAIN;
SEMA_RETURN(retval);
}
 
// -------------------------------------------------------------------------
// Increment value and wake a waiter if one is present.
 
externC int sem_post (sem_t *sem)
{
SEMA_ENTRY();
 
Cyg_Counting_Semaphore *sema = (Cyg_Counting_Semaphore *)sem;
 
sema->post();
SEMA_RETURN(0);
}
 
// -------------------------------------------------------------------------
// Get current value
 
externC int sem_getvalue (sem_t *sem, int *sval)
{
SEMA_ENTRY();
 
Cyg_Counting_Semaphore *sema = (Cyg_Counting_Semaphore *)sem;
 
*sval = sema->peek();
 
CYG_REPORT_RETVAL( 0 );
return 0;
}
 
// -------------------------------------------------------------------------
// Open an existing named semaphore, or create it.
 
externC sem_t *sem_open (const char *name, int oflag, ...)
{
SEMA_ENTRY();
 
errno = ENOSYS;
 
CYG_REPORT_RETVAL( SEM_FAILED );
return SEM_FAILED;
}
 
// -------------------------------------------------------------------------
// Close descriptor for semaphore.
 
externC int sem_close (sem_t *sem)
{
SEMA_ENTRY();
 
SEMA_RETURN(ENOSYS);
}
 
// -------------------------------------------------------------------------
// Remove named semaphore
 
externC int sem_unlink (const char *name)
{
SEMA_ENTRY();
 
SEMA_RETURN(ENOSYS);
}
 
// -------------------------------------------------------------------------
// EOF sem.cxx
/v2_0/src/sched.cxx
0,0 → 1,242
//==========================================================================
//
// sched.cxx
//
// POSIX scheduler API implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-27
// Purpose: POSIX scheduler API implementation
// Description: This file contains the implementation of the POSIX scheduler
// functions.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include "pprivate.h" // POSIX private header
 
#include <cyg/kernel/sched.hxx> // scheduler definitions
#include <cyg/kernel/thread.hxx> // thread definitions
 
#include <cyg/kernel/sched.inl> // scheduler inlines
#include <cyg/kernel/thread.inl> // thread inlines
 
//==========================================================================
// Process scheduling functions.
 
//--------------------------------------------------------------------------
// Set scheduling parameters for given process.
 
int sched_setparam (pid_t pid, const struct sched_param *param)
{
CYG_REPORT_FUNCTYPE( "returning %d" );
 
if( pid != 0 )
{
errno = ESRCH;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
errno = ENOSYS;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
//--------------------------------------------------------------------------
// Get scheduling parameters for given process.
 
int sched_getparam (pid_t pid, struct sched_param *param)
{
CYG_REPORT_FUNCTYPE( "returning %d" );
 
if( pid != 0 )
{
errno = ESRCH;
CYG_REPORT_RETVAL( -1 );
return -1;
}
errno = ENOSYS;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
//--------------------------------------------------------------------------
// Set scheduling policy and/or parameters for given process.
int sched_setscheduler (pid_t pid,
int policy,
const struct sched_param *param)
{
CYG_REPORT_FUNCTYPE( "returning %d" );
 
if( pid != 0 )
{
errno = ESRCH;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
errno = ENOSYS;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
//--------------------------------------------------------------------------
// Get scheduling policy for given process.
 
int sched_getscheduler (pid_t pid)
{
CYG_REPORT_FUNCTYPE( "returning %d" );
 
if( pid != 0 )
{
errno = ESRCH;
CYG_REPORT_RETVAL( 0 );
return -1;
}
errno = ENOSYS;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
//--------------------------------------------------------------------------
// Force current thread to relinquish the processor.
 
int sched_yield (void)
{
CYG_REPORT_FUNCTYPE( "returning %d" );
 
Cyg_Thread::yield();
CYG_REPORT_RETVAL( 0 );
return 0;
}
 
//==========================================================================
// Scheduler parameter limits.
 
//--------------------------------------------------------------------------
// Get maximum priority value for a policy.
 
int sched_get_priority_max (int policy)
{
CYG_REPORT_FUNCTYPE( "returning %d" );
 
if( policy != SCHED_FIFO &&
policy != SCHED_RR &&
policy != SCHED_OTHER )
{
errno = EINVAL;
CYG_REPORT_RETVAL( -1 );
return -1;
}
int pri = PTHREAD_POSIX_PRIORITY( CYG_THREAD_MAX_PRIORITY );
CYG_REPORT_RETVAL( pri );
return pri;
}
 
//--------------------------------------------------------------------------
// Get minimum priority value for a policy.
 
int sched_get_priority_min (int policy)
{
CYG_REPORT_FUNCTYPE( "returning %d" );
 
if( policy != SCHED_FIFO &&
policy != SCHED_RR &&
policy != SCHED_OTHER )
{
errno = EINVAL;
CYG_REPORT_RETVAL( -1 );
return -1;
}
 
// idle thread priority isn't valid for general use, so subtract 1
int pri = PTHREAD_POSIX_PRIORITY( CYG_THREAD_MIN_PRIORITY-1 );
CYG_REPORT_RETVAL( pri );
return pri;
}
 
//--------------------------------------------------------------------------
// Get the SCHED_RR interval for the given process.
 
int sched_rr_get_interval (pid_t pid, struct timespec *t)
{
CYG_REPORT_FUNCTYPE( "returning %d" );
 
#ifdef CYGPKG_POSIX_CLOCKS
if( pid != 0 )
{
errno = ESRCH;
CYG_REPORT_RETVAL( -1 );
return -1;
}
cyg_ticks_to_timespec( CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS, t );
CYG_REPORT_RETVAL( 0 );
return 0;
#else
errno = ENOSYS;
CYG_REPORT_RETVAL( -1 );
return -1;
#endif
}
 
// -------------------------------------------------------------------------
// EOF sched.cxx
/v2_0/src/pthread.cxx
0,0 → 1,1644
//==========================================================================
//
// pthread.cxx
//
// POSIX pthreads implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg, jlarmour
// Date: 2000-03-27
// Purpose: POSIX pthread implementation
// Description: This file contains the implementation of the POSIX pthread
// functions.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
#include <pkgconf/isoinfra.h>
#include <pkgconf/libc_startup.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include "pprivate.h" // POSIX private header
 
#include <stdlib.h> // malloc(), free()
 
#include <cyg/kernel/sched.hxx> // scheduler definitions
#include <cyg/kernel/thread.hxx> // thread definitions
#include <cyg/kernel/clock.hxx> // clock definitions
 
#include <cyg/kernel/sched.inl> // scheduler inlines
 
//-----------------------------------------------------------------------------
// First check that the configuration contains the elements we need
 
#ifndef CYGPKG_KERNEL
#error POSIX pthread need eCos kernel
#endif
 
#ifndef CYGSEM_KERNEL_SCHED_MLQUEUE
#error POSIX pthreads need MLQ scheduler
#endif
 
#ifndef CYGSEM_KERNEL_SCHED_TIMESLICE
#error POSIX pthreads need timeslicing
#endif
 
#ifndef CYGVAR_KERNEL_THREADS_DATA
#error POSIX pthreads need per-thread data
#endif
 
//=============================================================================
// Internal data structures
 
// Mutex for controlling access to shared data structures
Cyg_Mutex pthread_mutex CYGBLD_POSIX_INIT;
 
// Array of pthread control structures. A pthread_t object is
// "just" an index into this array.
static pthread_info *thread_table[CYGNUM_POSIX_PTHREAD_THREADS_MAX];
 
// Count of number of threads in table.
static int pthread_count = 0;
 
// Count of number of threads that have exited and not been reaped.
static int pthreads_exited;
 
// Count of number of threads that are waiting to be joined
static int pthreads_tobejoined;
 
// Per-thread key allocation. This key map has a 1 bit set for each
// key that is free, zero if it is allocated.
#define KEY_MAP_TYPE cyg_uint32
#define KEY_MAP_TYPE_SIZE (sizeof(KEY_MAP_TYPE)*8) // in BITS!
static KEY_MAP_TYPE thread_key[PTHREAD_KEYS_MAX/KEY_MAP_TYPE_SIZE];
static void (*key_destructor[PTHREAD_KEYS_MAX]) (void *);
// Index of next pthread_info to allocate from thread_table array.
static int thread_info_next = 0;
 
// This is used to make pthread_t values unique even when reusing
// a table slot. This allows CYGNUM_POSIX_PTHREAD_THREADS_MAX to range
// up to 1024.
#define THREAD_ID_COOKIE_INC 0x00000400
#define THREAD_ID_COOKIE_MASK (THREAD_ID_COOKIE_INC-1)
static pthread_t thread_id_cookie = THREAD_ID_COOKIE_INC;
 
//-----------------------------------------------------------------------------
// Main thread.
 
#define MAIN_DEFAULT_STACK_SIZE \
(CYGNUM_LIBC_MAIN_DEFAULT_STACK_SIZE < PTHREAD_STACK_MIN \
? PTHREAD_STACK_MIN : CYGNUM_LIBC_MAIN_DEFAULT_STACK_SIZE)
 
static char main_stack[MAIN_DEFAULT_STACK_SIZE];
 
// Thread ID of main thread.
static pthread_t main_thread;
 
//=============================================================================
// Exported variables
 
int pthread_canceled_dummy_var; // pointed to by PTHREAD_CANCELED
 
//=============================================================================
// Internal functions
 
//-----------------------------------------------------------------------------
// Private version of pthread_self() that returns a pointer to our internal
// control structure.
 
pthread_info *pthread_self_info(void)
{
Cyg_Thread *thread = Cyg_Thread::self();
 
CYG_CHECK_DATA_PTR(thread, "Illegal current thread");
pthread_info *info = (pthread_info *)thread->get_data(CYGNUM_KERNEL_THREADS_DATA_POSIX);
 
// CYG_CHECK_DATA_PTR(info, "Not a POSIX thread!!!");
 
return info;
}
 
externC pthread_info *pthread_info_id( pthread_t id )
{
pthread_t index = id & THREAD_ID_COOKIE_MASK;
 
pthread_info *info = thread_table[index];
 
// Check for a valid entry
if( info == NULL )
return NULL;
// Check that this is a valid entry
if ( info->state == PTHREAD_STATE_FREE ||
info->state == PTHREAD_STATE_EXITED )
return NULL;
 
// Check that the entry matches the id
if( info->id != id ) return NULL;
 
// Return the pointer
return info;
}
 
//-----------------------------------------------------------------------------
// new operator to allow us to invoke the Cyg_Thread constructor on the
// pthread_info.thread_obj array.
 
inline void *operator new(size_t size, cyg_uint8 *ptr) { return (void *)ptr; };
 
//-----------------------------------------------------------------------------
// Optional memory allocation functions for pthread stacks.
// If there is an implementation of malloc() available, define pthread_malloc()
// and pthread_free() to use it. Otherwise define them to do nothing.
// In the future we may want to add configuration here to permit thread stacks
// to be allocated in a nominated memory pool separate from the standard malloc()
// pool. Hence the (currently redundant) encapsulation of these functions.
 
#if CYGINT_ISO_MALLOC
 
static __inline__ CYG_ADDRWORD pthread_malloc( CYG_ADDRWORD size )
{
return (CYG_ADDRWORD)malloc( size );
}
 
static __inline__ void pthread_free( CYG_ADDRWORD m )
{
free( (void *)m );
}
 
#define PTHREAD_MALLOC
 
#else
 
#define pthread_malloc(_x_) (0)
 
#define pthread_free(_x_)
 
#endif
 
//-----------------------------------------------------------------------------
// pthread entry function.
// does some housekeeping and then calls the user's start routine.
 
static void pthread_entry(CYG_ADDRWORD data)
{
pthread_info *self = (pthread_info *)data;
 
void *retval = self->start_routine(self->start_arg);
 
pthread_exit( retval );
}
 
//-----------------------------------------------------------------------------
// Main entry function.
// This is set as the start_routine of the main thread. It invokes main()
// and if it returns, shuts down the system.
 
externC void cyg_libc_invoke_main( void );
 
static void *call_main( void * )
{
cyg_libc_invoke_main();
return NULL; // placate compiler
}
 
//-----------------------------------------------------------------------------
// Check whether there is a cancel pending and if so, whether
// cancellations are enabled. We do it in this order to reduce the
// number of tests in the common case - when no cancellations are
// pending.
// We make this inline so it can be called directly below for speed
 
static __inline__ int
checkforcancel( void )
{
pthread_info *self = pthread_self_info();
 
if( self != NULL &&
self->cancelpending &&
self->cancelstate == PTHREAD_CANCEL_ENABLE )
return 1;
else
return 0;
}
 
 
//-----------------------------------------------------------------------------
// POSIX ASR
// This is installed as the ASR for all POSIX threads.
 
static void posix_asr( CYG_ADDRWORD data )
{
pthread_info *self = (pthread_info *)data;
 
#ifdef CYGPKG_POSIX_TIMERS
// Call into timer subsystem to deliver any pending
// timer expirations.
cyg_posix_timer_asr(self);
#endif
#ifdef CYGPKG_POSIX_SIGNALS
// Call signal subsystem to deliver any signals
cyg_posix_signal_asr(self);
#endif
// Check for cancellation
if( self->cancelpending &&
self->cancelstate == PTHREAD_CANCEL_ENABLE &&
self->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS )
{
// If we have a pending cancellation, cancellations are
// enabled and we are in asynchronous mode, then we can do the
// cancellation processing. Since pthread_exit() does
// everything we need to do, we just call that here.
pthread_exit(PTHREAD_CANCELED);
}
}
 
//-----------------------------------------------------------------------------
// The (Grim) Reaper.
// This function is called to tidy up and dispose of any threads that have
// exited. This work must be done from a thread other than the one exiting.
// Note: this function _must_ be called with pthread_mutex locked.
 
static void pthread_reap()
{
int i;
 
// Loop over the thread table looking for exited threads. The
// pthreads_exited counter springs us out of this once we have
// found them all (and keeps us out if there are none to do).
for( i = 0; pthreads_exited && i < CYGNUM_POSIX_PTHREAD_THREADS_MAX ; i++ )
{
pthread_info *thread = thread_table[i];
 
if( thread != NULL && thread->state == PTHREAD_STATE_EXITED )
{
// The thread has exited, so it is a candidate for being
// reaped. We have to make sure that the eCos thread has
// also reached EXITED state before we can tidy it up.
 
while( thread->thread->get_state() != Cyg_Thread::EXITED )
{
// The eCos thread has not yet exited. This is
// probably because its priority is too low to allow
// it to complete. We fix this here by raising its
// priority to equal ours and then yielding. This
// should eventually get it into exited state.
 
Cyg_Thread *self = Cyg_Thread::self();
 
// Set thread's priority to our current dispatching priority.
thread->thread->set_priority( self->get_current_priority() );
 
// Yield, yield
self->yield();
// and keep looping until he exits.
}
 
// At this point we have a thread that we can reap.
 
// destroy the eCos thread
thread->thread->~Cyg_Thread();
 
// destroy the joiner condvar
thread->joiner->~Cyg_Condition_Variable();
 
#ifdef CYGPKG_POSIX_SIGNALS
// Destroy signal handling fields
cyg_posix_thread_sigdestroy( thread );
#endif
// Free the stack if we allocated it
if( thread->freestack )
pthread_free( thread->stackmem );
 
// Finally, set the thread table entry to NULL so that it
// may be reused.
thread_table[i] = NULL;
 
pthread_count--;
pthreads_exited--;
}
}
}
 
//=============================================================================
// Functions exported to rest of POSIX subsystem.
 
//-----------------------------------------------------------------------------
// Create the main() thread.
 
externC void cyg_posix_pthread_start( void )
{
 
// Initialize the per-thread data key map.
 
for( cyg_ucount32 i = 0; i < (PTHREAD_KEYS_MAX/KEY_MAP_TYPE_SIZE); i++ )
{
thread_key[i] = ~0;
}
// Create the main thread
pthread_attr_t attr;
struct sched_param schedparam;
 
schedparam.sched_priority = CYGNUM_POSIX_MAIN_DEFAULT_PRIORITY;
 
pthread_attr_init( &attr );
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setstackaddr( &attr, &main_stack[sizeof(main_stack)] );
pthread_attr_setstacksize( &attr, sizeof(main_stack) );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
pthread_attr_setschedparam( &attr, &schedparam );
pthread_create( &main_thread, &attr, call_main, NULL );
}
 
#ifdef CYGPKG_POSIX_SIGNALS
//-----------------------------------------------------------------------------
// Look for a thread that can accept delivery of any of the signals in
// the mask and release it from any wait it is in. Since this may be
// called from a DSR, it cannot use any locks internally - any locking
// should be done before the call.
 
externC void cyg_posix_pthread_release_thread( sigset_t *mask )
{
int i;
int count = pthread_count;
// Loop over the thread table looking for a thread that has a
// signal mask that does not mask all the signals in mask.
// FIXME: find a more efficient way of doing this.
for( i = 0; count > 0 && i < CYGNUM_POSIX_PTHREAD_THREADS_MAX ; i++ )
{
pthread_info *thread = thread_table[i];
 
if( (thread != NULL) &&
(thread->state <= PTHREAD_STATE_RUNNING) &&
((*mask & ~thread->sigmask) != 0) )
{
// This thread can service at least one of the signals in
// *mask. Knock it out of its wait and make its ASR pending.
 
thread->thread->set_asr_pending();
thread->thread->release();
break;
}
 
// Decrement count for each valid thread we find.
if( thread != NULL && thread->state != PTHREAD_STATE_FREE )
count--;
}
}
#endif
 
//=============================================================================
// General thread operations
 
//-----------------------------------------------------------------------------
// Thread creation and management.
 
// Create a thread.
externC int pthread_create ( pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg)
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK(thread);
PTHREAD_CHECK(start_routine);
 
pthread_info *self = pthread_self_info();
pthread_attr_t use_attr;
 
// Set use_attr to the set of attributes we are going to
// actually use. Either those passed in, or the default set.
if( attr == NULL )
pthread_attr_init( &use_attr );
else use_attr = *attr;
 
// Adjust the attributes to cope with the setting of inheritsched.
 
if( use_attr.inheritsched == PTHREAD_INHERIT_SCHED )
{
use_attr.schedpolicy = self->attr.schedpolicy;
use_attr.schedparam = self->attr.schedparam;
}
 
CYG_ADDRWORD stackbase, stacksize;
cyg_bool freestack = false;
CYG_ADDRWORD stackmem = 0;
// If the stack size is not valid, we can assume that it is at
// least PTHREAD_STACK_MIN bytes.
if( use_attr.stacksize_valid )
stacksize = use_attr.stacksize;
else stacksize = PTHREAD_STACK_MIN;
 
if( use_attr.stackaddr_valid )
{
// Set up stack base and size from supplied arguments.
 
// Calculate stack base from address and size.
// FIXME: Falling stack assumed in pthread_create().
stackmem = stackbase = (CYG_ADDRWORD)use_attr.stackaddr-stacksize;
}
else
{
#ifdef PTHREAD_MALLOC
 
stackmem = stackbase = pthread_malloc( stacksize );
 
if( stackmem == 0 )
PTHREAD_RETURN( EAGAIN );
 
freestack = true;
#else
PTHREAD_RETURN(EINVAL);
#endif
}
 
// Get sole access to data structures
pthread_mutex.lock();
// Dispose of any dead threads
pthread_reap();
// Find a free slot in the thread table
pthread_info *nthread;
int thread_next = thread_info_next;
while( thread_table[thread_next] != NULL )
{
thread_next++;
if( thread_next >= CYGNUM_POSIX_PTHREAD_THREADS_MAX )
thread_next = 0;
 
// check for wrap, and return error if no slots left
if( thread_next == thread_info_next )
{
pthread_mutex.unlock();
if( freestack )
pthread_free( stackmem );
PTHREAD_RETURN(ENOMEM);
}
}
 
nthread = (pthread_info *)stackbase;
 
stackbase += sizeof(pthread_info);
stacksize -= sizeof(pthread_info);
thread_table[thread_next] = nthread;
 
// Set new next index
thread_info_next = thread_next;
// step the cookie
thread_id_cookie += THREAD_ID_COOKIE_INC;
 
// Initialize the table entry
nthread->state = use_attr.detachstate == PTHREAD_CREATE_JOINABLE ?
PTHREAD_STATE_RUNNING : PTHREAD_STATE_DETACHED;
nthread->id = thread_next+thread_id_cookie;
nthread->attr = use_attr;
nthread->retval = 0;
nthread->start_routine = start_routine;
nthread->start_arg = arg;
 
nthread->freestack = freestack;
nthread->stackmem = stackmem;
nthread->cancelstate = PTHREAD_CANCEL_ENABLE;
nthread->canceltype = PTHREAD_CANCEL_DEFERRED;
nthread->cancelbuffer = NULL;
nthread->cancelpending = false;
 
nthread->thread_data = NULL;
#ifdef CYGVAR_KERNEL_THREADS_NAME
// generate a name for this thread
 
char *name = nthread->name;
static char *name_template = "pthread.00000000";
pthread_t id = nthread->id;
for( int i = 0; name_template[i]; i++ ) name[i] = name_template[i];
 
// dump the id, in hex into the name.
for( int i = 15; i >= 8; i-- )
{
name[i] = "0123456789ABCDEF"[id&0xF];
id >>= 4;
}
 
#endif
 
// Initialize the joiner condition variable
 
nthread->joiner = new(nthread->joiner_obj) Cyg_Condition_Variable( pthread_mutex );
 
#ifdef CYGPKG_POSIX_SIGNALS
// Initialize signal specific fields.
cyg_posix_thread_siginit( nthread, self );
#endif
 
// create the underlying eCos thread
 
nthread->thread = new(&nthread->thread_obj[0])
Cyg_Thread ( PTHREAD_ECOS_PRIORITY(use_attr.schedparam.sched_priority),
pthread_entry,
(CYG_ADDRWORD)nthread,
name,
stackbase,
stacksize);
 
// Put pointer to pthread_info into eCos thread's per-thread data.
nthread->thread->set_data( CYGNUM_KERNEL_THREADS_DATA_POSIX, (CYG_ADDRWORD)nthread );
 
// Set timeslice enable according to scheduling policy.
if( use_attr.schedpolicy == SCHED_FIFO )
nthread->thread->timeslice_disable();
else nthread->thread->timeslice_enable();
 
// set up ASR and data
nthread->thread->set_asr( posix_asr, (CYG_ADDRWORD)nthread, NULL, NULL );
// return thread ID
*thread = nthread->id;
 
pthread_count++;
pthread_mutex.unlock();
 
// finally, set the thread going
nthread->thread->resume();
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Get current thread id.
 
externC pthread_t pthread_self ( void )
{
PTHREAD_ENTRY();
pthread_info *info = pthread_self_info();
 
CYG_CHECK_DATA_PTR(info, "Not a POSIX thread!!!");
return info->id;
}
 
//-----------------------------------------------------------------------------
// Compare two thread identifiers.
 
externC int pthread_equal (pthread_t thread1, pthread_t thread2)
{
PTHREAD_ENTRY();
return thread1 == thread2;
}
 
//-----------------------------------------------------------------------------
// Terminate current thread.
 
externC void exit(int) CYGBLD_ATTRIB_NORET;
 
externC void pthread_exit (void *retval)
{
PTHREAD_ENTRY();
pthread_info *self = pthread_self_info();
 
// Call cancellation handlers. We eat up the buffers as we go in
// case any of the routines calls pthread_exit() itself.
while( self->cancelbuffer != NULL )
{
struct pthread_cleanup_buffer *buffer = self->cancelbuffer;
 
self->cancelbuffer = buffer->prev;
 
buffer->routine(buffer->arg);
}
 
if( self->thread_data != NULL )
{
// Call per-thread key destructors.
// The specification of this is that we must continue to call the
// destructor functions until all the per-thread data values are NULL or
// we have done it PTHREAD_DESTRUCTOR_ITERATIONS times.
cyg_bool destructors_called;
int destructor_iterations = 0;
 
do
{
destructors_called = false;
for( cyg_ucount32 key = 0; key < PTHREAD_KEYS_MAX; key++ )
{
// Skip unallocated keys
if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
continue;
 
// Skip NULL destructors
if( key_destructor[key] == NULL ) continue;
 
// Skip NULL data values
if( self->thread_data[key] == NULL ) continue;
 
// If it passes all that, call the destructor.
// Note that NULLing the data value here is new
// behaviour in the 2001 POSIX standard.
{
void* value = self->thread_data[key];
self->thread_data[key] = NULL;
key_destructor[key](value);
}
 
// Record that we called a destructor
destructors_called = true;
}
 
// Count the iteration
destructor_iterations++;
} while( destructors_called &&
(destructor_iterations <= PTHREAD_DESTRUCTOR_ITERATIONS));
 
}
pthread_mutex.lock();
 
// Set the retval for any joiner
self->retval = retval;
 
// If we are already detached, go to EXITED state, otherwise
// go into JOIN state.
if ( PTHREAD_STATE_DETACHED == self->state ) {
self->state = PTHREAD_STATE_EXITED;
pthreads_exited++;
} else {
self->state = PTHREAD_STATE_JOIN;
pthreads_tobejoined++;
}
 
// Kick any waiting joiners
self->joiner->broadcast();
 
cyg_bool call_exit=false;
 
// if this is the last thread (other than threads waiting to be joined)
// then we need to call exit() later
if ( pthreads_exited + pthreads_tobejoined == pthread_count )
call_exit=true;
 
pthread_mutex.unlock();
// Finally, call the exit function; this will not return.
if ( call_exit )
::exit(0);
else
self->thread->exit();
 
// This loop keeps some compilers happy. pthread_exit() is marked
// with the noreturn attribute, and without this they generate a
// call to abort() here in case Cyg_Thread::exit() returns.
for(;;) continue;
}
 
//-----------------------------------------------------------------------------
// Wait for the thread to terminate. If thread_return is not NULL then
// the retval from the thread's call to pthread_exit() is stored at
// *thread_return.
 
externC int pthread_join (pthread_t thread, void **thread_return)
{
int err = 0;
 
PTHREAD_ENTRY();
// check for cancellation first.
pthread_testcancel();
 
pthread_mutex.lock();
// Dispose of any dead threads
pthread_reap();
pthread_info *self = pthread_self_info();
pthread_info *joinee = pthread_info_id( thread );
 
if( joinee == NULL )
{
err = ESRCH;
}
 
if( !err && joinee == self )
{
err = EDEADLK;
}
 
if ( !err ) {
switch ( joinee->state )
{
case PTHREAD_STATE_RUNNING:
// The thread is still running, we must wait for it.
while( joinee->state == PTHREAD_STATE_RUNNING ) {
if ( !joinee->joiner->wait() )
// check if we were woken because we were being cancelled
if ( checkforcancel() ) {
err = EAGAIN; // value unimportant, just some error
break;
}
}
 
// check that the thread is still joinable
if( joinee->state == PTHREAD_STATE_JOIN )
break;
 
// The thread has become unjoinable while we waited, so we
// fall through to complain.
case PTHREAD_STATE_FREE:
case PTHREAD_STATE_DETACHED:
case PTHREAD_STATE_EXITED:
// None of these may be joined.
err = EINVAL;
break;
case PTHREAD_STATE_JOIN:
break;
}
}
 
if ( !err ) {
// here, we know that joinee is a thread that has exited and is
// ready to be joined.
 
// Get the retval
if( thread_return != NULL )
*thread_return = joinee->retval;
// set state to exited.
joinee->state = PTHREAD_STATE_EXITED;
pthreads_exited++;
pthreads_tobejoined--;
// Dispose of any dead threads
pthread_reap();
}
 
pthread_mutex.unlock();
// check for cancellation before returning
pthread_testcancel();
 
PTHREAD_RETURN(err);
}
 
//-----------------------------------------------------------------------------
// Set the detachstate of the thread to "detached". The thread then does not
// need to be joined and its resources will be freed when it exits.
 
externC int pthread_detach (pthread_t thread)
{
PTHREAD_ENTRY();
int ret = 0;
pthread_mutex.lock();
 
pthread_info *detachee = pthread_info_id( thread );
if( detachee == NULL )
ret = ESRCH; // No such thread
else if( detachee->state == PTHREAD_STATE_DETACHED )
ret = EINVAL; // Already detached!
else
{
// Set state to detached and kick any joinees to
// make them return.
detachee->state = PTHREAD_STATE_DETACHED;
detachee->joiner->broadcast();
}
// Dispose of any dead threads
pthread_reap();
pthread_mutex.unlock();
 
PTHREAD_RETURN(ret);
}
 
 
//-----------------------------------------------------------------------------
// Thread attribute handling.
 
//-----------------------------------------------------------------------------
// Initialize attributes object with default attributes:
// detachstate == PTHREAD_CREATE_JOINABLE
// scope == PTHREAD_SCOPE_SYSTEM
// inheritsched == PTHREAD_INHERIT_SCHED
// schedpolicy == SCHED_OTHER
// schedparam == unset
// stackaddr == unset
// stacksize == 0
//
 
externC int pthread_attr_init (pthread_attr_t *attr)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
attr->detachstate = PTHREAD_CREATE_JOINABLE;
attr->scope = PTHREAD_SCOPE_SYSTEM;
attr->inheritsched = PTHREAD_INHERIT_SCHED;
attr->schedpolicy = SCHED_OTHER;
attr->schedparam.sched_priority = 0;
attr->stackaddr_valid = 0;
attr->stackaddr = NULL;
attr->stacksize_valid = 0;
attr->stacksize = 0;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Destroy thread attributes object
 
externC int pthread_attr_destroy (pthread_attr_t *attr)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
// Nothing to do here...
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Set the detachstate attribute
 
externC int pthread_attr_setdetachstate (pthread_attr_t *attr,
int detachstate)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( detachstate == PTHREAD_CREATE_JOINABLE ||
detachstate == PTHREAD_CREATE_DETACHED )
{
attr->detachstate = detachstate;
PTHREAD_RETURN(0);
}
PTHREAD_RETURN(EINVAL);
}
 
//-----------------------------------------------------------------------------
// Get the detachstate attribute
externC int pthread_attr_getdetachstate (const pthread_attr_t *attr,
int *detachstate)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( detachstate != NULL )
*detachstate = attr->detachstate;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Set scheduling contention scope
 
externC int pthread_attr_setscope (pthread_attr_t *attr, int scope)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( scope == PTHREAD_SCOPE_SYSTEM ||
scope == PTHREAD_SCOPE_PROCESS )
{
if( scope == PTHREAD_SCOPE_PROCESS )
PTHREAD_RETURN(ENOTSUP);
 
attr->scope = scope;
 
PTHREAD_RETURN(0);
}
PTHREAD_RETURN(EINVAL);
}
 
//-----------------------------------------------------------------------------
// Get scheduling contention scope
 
externC int pthread_attr_getscope (const pthread_attr_t *attr, int *scope)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( scope != NULL )
*scope = attr->scope;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Set scheduling inheritance attribute
 
externC int pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( inherit == PTHREAD_INHERIT_SCHED ||
inherit == PTHREAD_EXPLICIT_SCHED )
{
attr->inheritsched = inherit;
 
PTHREAD_RETURN(0);
}
 
PTHREAD_RETURN(EINVAL);
}
 
//-----------------------------------------------------------------------------
// Get scheduling inheritance attribute
 
externC int pthread_attr_getinheritsched (const pthread_attr_t *attr,
int *inherit)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( inherit != NULL )
*inherit = attr->inheritsched;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Set scheduling policy
 
externC int pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( policy == SCHED_OTHER ||
policy == SCHED_FIFO ||
policy == SCHED_RR )
{
attr->schedpolicy = policy;
 
PTHREAD_RETURN(0);
}
PTHREAD_RETURN(EINVAL);
}
 
//-----------------------------------------------------------------------------
// Get scheduling policy
 
externC int pthread_attr_getschedpolicy (const pthread_attr_t *attr,
int *policy)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( policy != NULL )
*policy = attr->schedpolicy;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Set scheduling parameters
externC int pthread_attr_setschedparam (pthread_attr_t *attr,
const struct sched_param *param)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
PTHREAD_CHECK(param);
 
attr->schedparam = *param;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Get scheduling parameters
 
externC int pthread_attr_getschedparam (const pthread_attr_t *attr,
struct sched_param *param)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( param != NULL )
*param = attr->schedparam;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Set starting address of stack. Whether this is at the start or end of
// the memory block allocated for the stack depends on whether the stack
// grows up or down.
 
externC int pthread_attr_setstackaddr (pthread_attr_t *attr, void *stackaddr)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
attr->stackaddr = stackaddr;
attr->stackaddr_valid = 1;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Get any previously set stack address.
 
externC int pthread_attr_getstackaddr (const pthread_attr_t *attr,
void **stackaddr)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
if( stackaddr != NULL )
{
if( attr->stackaddr_valid )
{
*stackaddr = attr->stackaddr;
PTHREAD_RETURN(0);
}
// Stack address not set, return EINVAL.
else PTHREAD_RETURN(EINVAL);
}
 
PTHREAD_RETURN(0);
}
 
 
//-----------------------------------------------------------------------------
// Set minimum creation stack size.
 
externC int pthread_attr_setstacksize (pthread_attr_t *attr,
size_t stacksize)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
CYG_ASSERT( stacksize >= PTHREAD_STACK_MIN, "Inadequate stack size supplied");
// Reject inadequate stack sizes
if( stacksize < PTHREAD_STACK_MIN )
PTHREAD_RETURN(EINVAL);
attr->stacksize_valid = 1;
attr->stacksize = stacksize;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Get current minimal stack size.
 
externC int pthread_attr_getstacksize (const pthread_attr_t *attr,
size_t *stacksize)
{
PTHREAD_ENTRY();
PTHREAD_CHECK(attr);
 
// Reject attempts to get a stack size when one has not been set.
if( !attr->stacksize_valid )
PTHREAD_RETURN(EINVAL);
if( stacksize != NULL )
*stacksize = attr->stacksize;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Thread scheduling controls
 
//-----------------------------------------------------------------------------
// Set scheduling policy and parameters for the thread
 
externC int pthread_setschedparam (pthread_t thread_id,
int policy,
const struct sched_param *param)
{
PTHREAD_ENTRY();
 
if( policy != SCHED_OTHER &&
policy != SCHED_FIFO &&
policy != SCHED_RR )
PTHREAD_RETURN(EINVAL);
 
PTHREAD_CHECK(param);
 
// The parameters seem OK, change the thread...
pthread_mutex.lock();
 
pthread_info *thread = pthread_info_id( thread_id );
 
if( thread == NULL )
{
pthread_mutex.unlock();
PTHREAD_RETURN(ESRCH);
}
thread->attr.schedpolicy = policy;
thread->attr.schedparam = *param;
 
if ( policy == SCHED_FIFO )
thread->thread->timeslice_disable();
else thread->thread->timeslice_enable();
 
thread->thread->set_priority( PTHREAD_ECOS_PRIORITY( param->sched_priority ));
 
pthread_mutex.unlock();
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Get scheduling policy and parameters for the thread
 
externC int pthread_getschedparam (pthread_t thread_id,
int *policy,
struct sched_param *param)
{
PTHREAD_ENTRY();
 
pthread_mutex.lock();
 
pthread_info *thread = pthread_info_id( thread_id );
 
if( thread == NULL )
{
pthread_mutex.unlock();
PTHREAD_RETURN(ESRCH);
}
 
if( policy != NULL )
*policy = thread->attr.schedpolicy;
 
if( param != NULL )
*param = thread->attr.schedparam;
pthread_mutex.unlock();
PTHREAD_RETURN(0);
}
 
 
//=============================================================================
// Dynamic package initialization
// Call init_routine just the once per control variable.
 
externC int pthread_once (pthread_once_t *once_control,
void (*init_routine) (void))
{
PTHREAD_ENTRY();
 
PTHREAD_CHECK( once_control );
PTHREAD_CHECK( init_routine );
 
pthread_once_t old;
 
// Do a test and set on the once_control object.
pthread_mutex.lock();
 
old = *once_control;
*once_control = 1;
 
pthread_mutex.unlock();
 
// If the once_control was zero, call the init_routine().
if( !old ) init_routine();
PTHREAD_RETURN(0);
}
 
 
//=============================================================================
//Thread specific data
 
//-----------------------------------------------------------------------------
// Create a key to identify a location in the thread specific data area.
// Each thread has its own distinct thread-specific data area but all are
// addressed by the same keys. The destructor function is called whenever a
// thread exits and the value associated with the key is non-NULL.
 
externC int pthread_key_create (pthread_key_t *key,
void (*destructor) (void *))
{
PTHREAD_ENTRY();
 
pthread_key_t k = -1;
pthread_mutex.lock();
 
// Find a key to allocate
for( cyg_ucount32 i = 0; i < (PTHREAD_KEYS_MAX/KEY_MAP_TYPE_SIZE); i++ )
{
if( thread_key[i] != 0 )
{
// We have a table slot with space available
 
// Get index of ls set bit.
HAL_LSBIT_INDEX( k, thread_key[i] );
 
// clear it
thread_key[i] &= ~(1<<k);
 
// Add index of word
k += i * KEY_MAP_TYPE_SIZE;
 
// Install destructor
key_destructor[k] = destructor;
// break out with key found
break;
}
}
 
if( k != -1 )
{
// plant a NULL in all the valid thread data slots for this
// key in case we are reusing a key we used before.
for( cyg_ucount32 i = 0; i < CYGNUM_POSIX_PTHREAD_THREADS_MAX ; i++ )
{
pthread_info *thread = thread_table[i];
 
if( thread != NULL && thread->thread_data != NULL )
thread->thread_data[k] = NULL;
}
}
pthread_mutex.unlock();
 
if( k == -1 ) PTHREAD_RETURN(EAGAIN);
 
*key = k;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Delete key.
 
externC int pthread_key_delete (pthread_key_t key)
{
PTHREAD_ENTRY();
 
pthread_mutex.lock();
 
// Set the key bit to 1 to indicate it is free.
thread_key[key/KEY_MAP_TYPE_SIZE] |= 1<<(key%(KEY_MAP_TYPE_SIZE));
 
pthread_mutex.unlock();
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Store the pointer value in the thread-specific data slot addressed
// by the key.
 
externC int pthread_setspecific (pthread_key_t key, const void *pointer)
{
PTHREAD_ENTRY();
 
if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
PTHREAD_RETURN(EINVAL);
 
pthread_info *self = pthread_self_info();
 
if( self->thread_data == NULL )
{
// Allocate the per-thread data table
self->thread_data =
(void **)self->thread->increment_stack_limit(
PTHREAD_KEYS_MAX * sizeof(void *) );
 
// Clear out all entries
for( int i = 0; i < PTHREAD_KEYS_MAX; i++ )
self->thread_data[i] = NULL;
}
self->thread_data[key] = (void *)pointer;
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Retrieve the pointer value in the thread-specific data slot addressed
// by the key.
 
externC void *pthread_getspecific (pthread_key_t key)
{
void *val;
PTHREAD_ENTRY();
 
if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
PTHREAD_RETURN(NULL);
 
pthread_info *self = pthread_self_info();
 
if( self->thread_data == NULL )
val = NULL;
else val = self->thread_data[key];
 
PTHREAD_RETURN(val);
}
 
//=============================================================================
// Thread Cancellation Functions
 
//-----------------------------------------------------------------------------
// Set cancel state of current thread to ENABLE or DISABLE.
// Returns old state in *oldstate.
 
externC int pthread_setcancelstate (int state, int *oldstate)
{
PTHREAD_ENTRY();
 
if( state != PTHREAD_CANCEL_ENABLE &&
state != PTHREAD_CANCEL_DISABLE )
PTHREAD_RETURN(EINVAL);
pthread_mutex.lock();
 
pthread_info *self = pthread_self_info();
 
if( oldstate != NULL ) *oldstate = self->cancelstate;
self->cancelstate = state;
pthread_mutex.unlock();
// Note: This function may have made it possible for a pending
// cancellation to now be delivered. However the standard does not
// list this function as a cancellation point, so for now we do
// nothing. In future we might call pthread_testcancel() here.
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Set cancel type of current thread to ASYNCHRONOUS or DEFERRED.
// Returns old type in *oldtype.
 
externC int pthread_setcanceltype (int type, int *oldtype)
{
PTHREAD_ENTRY();
 
if( type != PTHREAD_CANCEL_ASYNCHRONOUS &&
type != PTHREAD_CANCEL_DEFERRED )
PTHREAD_RETURN(EINVAL);
pthread_mutex.lock();
 
pthread_info *self = pthread_self_info();
if( oldtype != NULL ) *oldtype = self->canceltype;
 
self->canceltype = type;
pthread_mutex.unlock();
 
// Note: This function may have made it possible for a pending
// cancellation to now be delivered. However the standard does not
// list this function as a cancellation point, so for now we do
// nothing. In future we might call pthread_testcancel() here.
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Cancel the thread.
 
externC int pthread_cancel (pthread_t thread)
{
PTHREAD_ENTRY();
 
pthread_mutex.lock();
 
pthread_info *th = pthread_info_id(thread);
 
if( th == NULL )
{
pthread_mutex.unlock();
PTHREAD_RETURN(ESRCH);
}
 
th->cancelpending = true;
 
if ( th->cancelstate == PTHREAD_CANCEL_ENABLE )
{
if ( th->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS )
{
// If the thread has cancellation enabled, and it is in
// asynchronous mode, set the eCos thread's ASR pending to
// deal with it when the thread wakes up. We also release the
// thread out of any current wait to make it wake up.
th->thread->set_asr_pending();
th->thread->release();
}
else if ( th->canceltype == PTHREAD_CANCEL_DEFERRED )
{
// If the thread has cancellation enabled, and it is in
// deferred mode, wake the thread up so that cancellation
// points can test for cancellation.
th->thread->release();
}
else
CYG_FAIL("Unknown cancellation type");
}
 
// Otherwise the thread has cancellation disabled, in which case
// it is up to the thread to enable cancellation
pthread_mutex.unlock();
PTHREAD_RETURN(0);
}
 
//-----------------------------------------------------------------------------
// Test for a pending cancellation for the current thread and terminate
// the thread if there is one.
 
externC void pthread_testcancel (void)
{
PTHREAD_ENTRY_VOID();
 
if( checkforcancel() )
{
// If we have cancellation enabled, and there is a cancellation
// pending, then go ahead and do the deed.
// Exit now with special retval. pthread_exit() calls the
// cancellation handlers implicitly.
pthread_exit(PTHREAD_CANCELED);
}
PTHREAD_RETURN_VOID;
}
 
//-----------------------------------------------------------------------------
// These two functions actually implement the cleanup push and pop functionality.
 
externC void pthread_cleanup_push_inner (struct pthread_cleanup_buffer *buffer,
void (*routine) (void *),
void *arg)
{
PTHREAD_ENTRY();
 
pthread_info *self = pthread_self_info();
 
buffer->routine = routine;
buffer->arg = arg;
buffer->prev = self->cancelbuffer;
 
self->cancelbuffer = buffer;
 
return;
}
 
externC void pthread_cleanup_pop_inner (struct pthread_cleanup_buffer *buffer,
int execute)
{
PTHREAD_ENTRY();
 
pthread_info *self = pthread_self_info();
CYG_ASSERT( self->cancelbuffer == buffer, "Stacking error in cleanup buffers");
if( self->cancelbuffer == buffer )
{
// Remove the buffer from the stack
self->cancelbuffer = buffer->prev;
}
else
{
// If the top of the stack is not the buffer we expect, do not
// execute it.
execute = 0;
}
 
if( execute ) buffer->routine(buffer->arg);
return;
}
 
 
// -------------------------------------------------------------------------
// eCos-specific function to measure stack usage of the supplied thread
 
#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
externC size_t pthread_measure_stack_usage (pthread_t thread)
{
pthread_info *th = pthread_info_id(thread);
 
if ( NULL == th )
return (size_t)-1;
 
return (size_t)th->thread->measure_stack_usage();
}
#endif
 
// -------------------------------------------------------------------------
// EOF pthread.cxx
/v2_0/src/except.cxx
0,0 → 1,343
//==========================================================================
//
// except.cxx
//
// POSIX exception translation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-27
// Purpose: POSIX exception translation
// Description: This file contains code to translate eCos hardware
// exceptions into POSIX signals.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <cyg/infra/diag.h>
 
#include "pprivate.h" // POSIX private header
 
#include <signal.h> // our header
 
#include <cyg/kernel/thread.inl>
 
//==========================================================================
// Translation table from eCos exceptions to POSIX signals.
 
static const struct
{
cyg_code exception;
int signal;
} exception_signal_mapping[] =
{
#ifdef CYGNUM_HAL_EXCEPTION_DATA_ACCESS
{CYGNUM_HAL_EXCEPTION_DATA_ACCESS, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_WRITE
{CYGNUM_HAL_EXCEPTION_DATA_WRITE, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_CODE_ACCESS
{CYGNUM_HAL_EXCEPTION_CODE_ACCESS, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_CODE_WRITE
{CYGNUM_HAL_EXCEPTION_CODE_WRITE, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_CODE_EXECUTE
{CYGNUM_HAL_EXCEPTION_CODE_EXECUTE, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_IO_ACCESS
{CYGNUM_HAL_EXCEPTION_IO_ACCESS, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_IO_WRITE
{CYGNUM_HAL_EXCEPTION_IO_ACCESS, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS
{CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_WRITE
{CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_WRITE, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_CODE_TLBMISS_ACCESS
{CYGNUM_HAL_EXCEPTION_CODE_TLBMISS_ACCESS, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_CODE_TLBMISS_WRITE
{CYGNUM_HAL_EXCEPTION_CODE_TLBMISS_WRITE, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_TLBERROR_ACCESS
{CYGNUM_HAL_EXCEPTION_DATA_TLBERROR_ACCESS, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_TLBERROR_WRITE
{CYGNUM_HAL_EXCEPTION_DATA_TLBERROR_WRITE, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_CODE_TLBERROR_ACCESS
{CYGNUM_HAL_EXCEPTION_CODE_TLBERROR_ACCESS, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_CODE_TLBERROR_WRITE
{CYGNUM_HAL_EXCEPTION_CODE_TLBERROR_WRITE, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS
{CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_WRITE
{CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_WRITE, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_IO_UNALIGNED_ACCESS
{CYGNUM_HAL_EXCEPTION_IO_UNALIGNED_ACCESS, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_IO_UNALIGNED_WRITE
{CYGNUM_HAL_EXCEPTION_IO_UNALIGNED_WRITE, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION
{CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION, SIGILL},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_INTERRUPT
{CYGNUM_HAL_EXCEPTION_INTERRUPT, SIGINT},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_TRAP
{CYGNUM_HAL_EXCEPTION_TRAP, SIGTRAP},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO
{CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO, SIGFPE},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_OVERFLOW
{CYGNUM_HAL_EXCEPTION_OVERFLOW, SIGFPE},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_BOUNDS
{CYGNUM_HAL_EXCEPTION_BOUNDS, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_SINGLE_STEP
{CYGNUM_HAL_EXCEPTION_SINGLE_STEP, SIGTRAP},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_INSTRUCTION_BP
{CYGNUM_HAL_EXCEPTION_INSTRUCTION_BP, SIGTRAP},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_PERIPHERAL_BP
{CYGNUM_HAL_EXCEPTION_PERIPHERAL_BP, SIGTRAP},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DATA_BP
{CYGNUM_HAL_EXCEPTION_DATA_BP, SIGTRAP},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_DEVELOPMENT_BP
{CYGNUM_HAL_EXCEPTION_DEVELOPMENT_BP, SIGTRAP},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_STACK_OVERFLOW
{CYGNUM_HAL_EXCEPTION_STACK_OVERFLOW, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_STACK_FAULT
{CYGNUM_HAL_EXCEPTION_STACK_FAULT, SIGSEGV},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_PARITY
{CYGNUM_HAL_EXCEPTION_PARITY, SIGBUS},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_FPU
{CYGNUM_HAL_EXCEPTION_FPU, SIGFPE},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_FPU_NOT_AVAIL
{CYGNUM_HAL_EXCEPTION_FPU_NOT_AVAIL, SIGFPE},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_FPU_OVERFLOW
{CYGNUM_HAL_EXCEPTION_FPU_OVERFLOW, SIGFPE},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_FPU_UNDERFLOW
{CYGNUM_HAL_EXCEPTION_FPU_UNDERFLOW, SIGFPE},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO
{CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO, SIGFPE},
#endif
#ifdef CYGNUM_HAL_EXCEPTION_SYSTEM_CALL
{CYGNUM_HAL_EXCEPTION_SYSTEM_CALL, SIGSYS},
#endif
{0, 0} // dummy value to ensure compiler is happy
};
 
//==========================================================================
// POSIX exception handler
 
static void cyg_posix_exception_handler(
CYG_ADDRWORD data, // user supplied data == signal number
cyg_code exception_number, // exception being raised
CYG_ADDRWORD exception_info // any exception specific info
)
{
int signo = 0;
 
pthread_info *self = pthread_self_info();
 
if( self == NULL )
{
// Not a POSIX thread, just return
return;
}
#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
 
signo = data;
 
#else
 
for( int i = 0; exception_signal_mapping[i].signal != 0; i++ )
{
if( exception_signal_mapping[i].exception == exception_number )
{
signo = exception_signal_mapping[i].signal;
break;
}
}
 
#endif
 
if( sigismember( &self->sigmask, signo ) )
{
// The signal is masked in the current thread. POSIX says that
// the behaviour is undefined here. We choose to ignore it.
 
return;
}
 
// The kernel exception handler may have disabled interrupts, so
// we (re-)enable them here. From this point on we are running in
// a context that is effectively just pushed onto the stack of the
// current thread. If we return we will unwind and resume
// execution from the excepting code. We can also, in theory,
// longjump out of the signal handler, and although that is
// deprecated, we make sure in cyg_deliver_signals() that it is
// possible to do it.
HAL_ENABLE_INTERRUPTS();
struct sigevent sev;
 
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = signo;
sev.sigev_value.sival_ptr = (void *)exception_info;
 
// Generate the signal
cyg_sigqueue( &sev, SI_EXCEPT );
 
// And try to deliver it
cyg_deliver_signals();
}
 
//==========================================================================
// Install all the exception handlers
 
static void install_handlers( Cyg_Thread *thread)
{
#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
 
// With decoded exceptions, we must install a separate exception
// handler for each supported exception.
 
for( int i = 0; exception_signal_mapping[i].signal != 0; i++ )
{
thread->register_exception( exception_signal_mapping[i].exception,
cyg_posix_exception_handler,
exception_signal_mapping[i].signal,,
NULL,
NULL);
}
#else
 
// Otherwise there is just one exception handler for all exceptions.
thread->register_exception( CYGNUM_HAL_EXCEPTION_MIN,
cyg_posix_exception_handler,
0,
NULL,
NULL);
#endif
}
 
//==========================================================================
// Initialization
 
externC void cyg_posix_exception_start()
{
#ifdef CYGSEM_KERNEL_EXCEPTIONS_GLOBAL
 
// With global exceptions, we only need to install a single static
// set of exception handlers. Note that by this point in system
// initialization the idle thread should be installed as the
// current thread, so we pass a pointer to that to
// install_handlers(). The identity of the thread passed is
// actually irrelevant in this case and is just used as a handle
// into the thread class.
 
install_handlers( Cyg_Thread::self() );
#endif
}
 
//==========================================================================
// Per thread exception initialization and destruction
 
externC void cyg_pthread_exception_init(pthread_info *thread)
{
#ifndef CYGSEM_KERNEL_EXCEPTIONS_GLOBAL
 
// With non-global exceptions we must install a new set of handlers
// for each thread.
 
install_handlers( thread->thread );
#endif
}
 
externC void cyg_pthread_exception_destroy(pthread_info *thread)
{
// Nothing to do at present.
}
 
// -------------------------------------------------------------------------
// EOF except.cxx
/v2_0/src/misc.cxx
0,0 → 1,386
//==========================================================================
//
// misc.cxx
//
// POSIX misc function implementations
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-07-18
// Purpose: POSIX misc function implementation
// Description: This file contains the implementation of miscellaneous POSIX
// functions that do not belong elsewhere.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/system.h>
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/posix.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include "pprivate.h" // POSIX private header
 
#include <unistd.h>
#include <sys/utsname.h> // My header
#include <string.h> // strcpy
#include <limits.h>
#include <time.h>
 
#include <cyg/kernel/sched.hxx>
 
#include <cyg/kernel/sched.inl>
 
// -------------------------------------------------------------------------
// Supply some suitable values for constants that may not be present
// in all configurations.
 
#ifndef MQ_OPEN_MAX
#define MQ_OPEN_MAX 0
#endif
#ifndef MQ_PRIO_MAX
#define MQ_PRIO_MAX 0
#endif
 
// -------------------------------------------------------------------------
 
#define __string(_x) #_x
#define __xstring(_x) __string(_x)
 
// -------------------------------------------------------------------------
// uname()
 
__externC int uname( struct utsname *name )
{
CYG_REPORT_FUNCTYPE( "returning %d" );
 
strcpy( name->sysname, "eCos" );
strcpy( name->nodename, "" ); // should use gethostname()
strcpy( name->release, __xstring( CYGNUM_KERNEL_VERSION_MAJOR ) );
strcpy( name->version, __xstring( CYGNUM_KERNEL_VERSION_MINOR ) );
strcpy( name->machine, "" );
 
CYG_REPORT_RETVAL(0);
return 0;
}
 
// -------------------------------------------------------------------------
// sysconf()
 
#define SC_CASE( _name, _val ) case _name: return _val
 
__externC long sysconf( int name )
{
 
switch( name )
{
SC_CASE( _SC_AIO_LISTIO_MAX, AIO_LISTIO_MAX );
SC_CASE( _SC_AIO_MAX, AIO_MAX );
SC_CASE( _SC_AIO_PRIO_DELTA_MAX, AIO_PRIO_DELTA_MAX );
SC_CASE( _SC_ARG_MAX, ARG_MAX );
SC_CASE( _SC_CHILD_MAX, CHILD_MAX );
SC_CASE( _SC_DELAYTIMER_MAX, DELAYTIMER_MAX );
SC_CASE( _SC_GETGR_R_SIZE_MAX, 0 );
SC_CASE( _SC_GETPW_R_SIZE_MAX, 0 );
SC_CASE( _SC_LOGIN_NAME_MAX, LOGIN_NAME_MAX );
SC_CASE( _SC_MQ_OPEN_MAX, MQ_OPEN_MAX );
SC_CASE( _SC_MQ_PRIO_MAX, MQ_PRIO_MAX );
SC_CASE( _SC_NGROUPS_MAX, NGROUPS_MAX );
SC_CASE( _SC_OPEN_MAX, OPEN_MAX );
SC_CASE( _SC_PAGESIZE, PAGESIZE );
SC_CASE( _SC_RTSIG_MAX, RTSIG_MAX );
SC_CASE( _SC_SEM_NSEMS_MAX, SEM_NSEMS_MAX );
SC_CASE( _SC_SEM_VALUE_MAX, SEM_VALUE_MAX );
SC_CASE( _SC_SIGQUEUE_MAX, SIGQUEUE_MAX );
SC_CASE( _SC_STREAM_MAX, STREAM_MAX );
#ifdef CYGPKG_POSIX_PTHREAD
SC_CASE( _SC_THREAD_DESTRUCTOR_ITERATIONS, PTHREAD_DESTRUCTOR_ITERATIONS );
SC_CASE( _SC_THREAD_KEYS_MAX, PTHREAD_KEYS_MAX );
SC_CASE( _SC_THREAD_STACK_MIN, PTHREAD_STACK_MIN );
SC_CASE( _SC_THREAD_THREADS_MAX, PTHREAD_THREADS_MAX );
#endif
SC_CASE( _SC_TIMER_MAX, TIMER_MAX );
SC_CASE( _SC_TTY_NAME_MAX, TTY_NAME_MAX );
SC_CASE( _SC_TZNAME_MAX, TZNAME_MAX );
SC_CASE( _SC_VERSION, _POSIX_VERSION );
 
#ifdef CYGPKG_POSIX_TIMERS
case _SC_CLK_TCK:
{
struct timespec ts;
ts.tv_sec = 1;
ts.tv_nsec = 0;
cyg_tick_count ticks = cyg_timespec_to_ticks( &ts );
return ticks;
}
#endif
 
case _SC_ASYNCHRONOUS_IO:
#ifdef _POSIX_ASYNCHRONOUS_IO
return 1;
#else
return -1;
#endif
case _SC_FSYNC:
#ifdef _POSIX_FSYNC
return 1;
#else
return -1;
#endif
case _SC_JOB_CONTROL:
#ifdef _POSIX_JOB_CONTROL
return 1;
#else
return -1;
#endif
case _SC_MAPPED_FILES:
#ifdef _POSIX_MAPPED_FILES
return 1;
#else
return -1;
#endif
case _SC_MEMLOCK:
#ifdef _POSIX_MEMLOCK
return 1;
#else
return -1;
#endif
case _SC_MEMLOCK_RANGE:
#ifdef _POSIX_MEMLOCK_RANGE
return 1;
#else
return -1 ;
#endif
case _SC_MEMORY_PROTECTION:
#ifdef _POSIX_MEMORY_PROTECTION
return 1;
#else
return -1;
#endif
case _SC_MESSAGE_PASSING:
#ifdef _POSIX_MESSAGE_PASSING
return 1;
#else
return -1;
#endif
case _SC_PRIORITIZED_IO:
#ifdef _POSIX_PRIORITIZED_IO
return 1;
#else
return -1;
#endif
case _SC_PRIORITY_SCHEDULING:
#ifdef _POSIX_PRIORITY_SCHEDULING
return 1;
#else
return -1;
#endif
case _SC_REALTIME_SIGNALS:
#ifdef _POSIX_REALTIME_SIGNALS
return 1;
#else
return -1;
#endif
case _SC_SAVED_IDS:
#ifdef _POSIX_SAVED_IDS
return 1;
#else
return -1;
#endif
case _SC_SEMAPHORES:
#ifdef _POSIX_SEMAPHORES
return 1;
#else
return -1;
#endif
case _SC_SHARED_MEMORY_OBJECTS:
#ifdef _POSIX_SHARED_MEMORY_OBJECTS
return 1;
#else
return -1;
#endif
case _SC_SYNCHRONIZED_IO:
#ifdef _POSIX_SYNCHRONIZED_IO
return 1;
#else
return -1;
#endif
case _SC_THREADS:
#ifdef _POSIX_THREADS
return 1;
#else
return -1;
#endif
case _SC_THREAD_ATTR_STACKADDR:
#ifdef _POSIX_THREAD_ATTR_STACKADDR
return 1;
#else
return -1;
#endif
case _SC_THREAD_ATTR_STACKSIZE:
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
return 1;
#else
return -1;
#endif
case _SC_THREAD_PRIO_INHERIT:
#ifdef _POSIX_THREAD_PRIO_INHERIT
return 1;
#else
return -1;
#endif
case _SC_THREAD_PRIO_PROTECT:
#ifdef _POSIX_THREAD_PRIO_PROTECT
return 1;
#else
return -1;
#endif
case _SC_THREAD_PRIORITY_SCHEDULING:
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
return 1;
#else
return -1;
#endif
case _SC_THREAD_PROCESS_SHARED:
#ifdef _POSIX_THREAD_PROCESS_SHARED
return 1;
#else
return -1;
#endif
case _SC_THREAD_SAFE_FUNCTIONS:
#ifdef _POSIX_THREAD_SAFE_FUNCTIONS
return 1;
#else
return -1;
#endif
case _SC_TIMERS:
#ifdef _POSIX_TIMERS
return 1;
#else
return -1;
#endif
 
default:
errno = EINVAL;
return -1;
}
}
 
//==========================================================================
// Some trivial compatibility functions.
// These are merely present to permit existing code to be ported a little
// more easily, and to provide adequate standards compatibility.
 
__externC pid_t getpid ( void ) { return 42; }
__externC pid_t getppid ( void ) { return 41; }
__externC uid_t getuid ( void ) { return 666; }
__externC uid_t geteuid ( void ) { return 666; }
__externC gid_t getgid ( void ) { return 88; }
__externC gid_t getegid ( void ) { return 88; }
__externC int setuid ( uid_t uid ) { errno = EPERM; return -1; }
__externC int setgid ( uid_t gid ) { errno = EPERM; return -1; }
__externC int getgroups ( int gidsetsize, gid_t grouplist[] ) { return 0; };
__externC pid_t getpgrp ( void ) { return 42; }
__externC pid_t setsid ( void ) { errno = EPERM; return -1; }
__externC int setpgid ( pid_t pid, pid_t pgid ) { errno = ENOSYS; return -1; }
 
//==========================================================================
// Exports to other packages
 
// -------------------------------------------------------------------------
// POSIX API function entry
 
__externC void cyg_posix_function_start()
{
Cyg_Thread *self = Cyg_Scheduler::get_current_thread();
 
// Inhibit ASR delivery in this function until it returns.
self->set_asr_inhibit();
}
 
// -------------------------------------------------------------------------
 
__externC void cyg_posix_function_finish()
{
Cyg_Thread *self = Cyg_Scheduler::get_current_thread();
 
// Re-allow ASR delivery.
self->clear_asr_inhibit();
 
// After clearing the inhibit flag, blip the scheduler lock
// to get any pending ASRs delivered.
Cyg_Scheduler::lock();
Cyg_Scheduler::unlock();
}
 
// -------------------------------------------------------------------------
// EOF misc.cxx
/v2_0/src/signal.cxx
0,0 → 1,1236
//==========================================================================
//
// signal.cxx
//
// POSIX signal functions implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Nick Garnett
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-03-27
// Purpose: POSIX signal functions implementation
// Description: This file contains the implementation of the POSIX signal
// functions.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/posix.h>
 
#ifdef CYGPKG_POSIX_SIGNALS
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/isoinfra.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include "pprivate.h" // POSIX private header
 
#include <signal.h> // our header
#include <setjmp.h>
#include <unistd.h> // _exit
 
#include <cyg/kernel/clock.hxx>
#include <cyg/kernel/thread.hxx>
#include <cyg/kernel/clock.inl>
#include <cyg/kernel/thread.inl>
 
// -------------------------------------------------------------------------
// Internal definitions
 
// Handle entry to a signal package function.
#define SIGNAL_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" );
 
// Do a signal package defined return. This requires the error code
// to be placed in errno, and if it is non-zero, -1 returned as the
// result of the function. This also gives us a place to put any
// generic tidyup handling needed for things like signal delivery and
// cancellation.
#define SIGNAL_RETURN(err) \
CYG_MACRO_START \
int __retval = 0; \
if( err != 0 ) __retval = -1, errno = err; \
CYG_REPORT_RETVAL( __retval ); \
return __retval; \
CYG_MACRO_END
 
// Similarly for functions that have valid non-zero returns
#define SIGNAL_RETURN_VALUE(val) \
CYG_MACRO_START \
CYG_REPORT_RETVAL( val ); \
return val; \
CYG_MACRO_END
 
// Range check on a signal value.
#define SIGNAL_VALID(_sig_) (((_sig_) > 0) && ((_sig_) < ((int)sizeof(sigset_t)*8)))
 
//==========================================================================
// Signal management structures
 
typedef struct signal_info
{
struct signal_info *next; // link in list of pending signals
siginfo_t si; // siginfo to pass to handler
} signal_info;
 
typedef struct
{
struct sigaction sa; // Sigaction defining what to do
signal_info *pending; // List of pending signals - this is
// a circular list with pending pointing
// to the tail element (or NULL if empty).
} signal_state;
 
//==========================================================================
// Signal management variables
 
// Lock used to protect signal management structures
Cyg_Mutex signal_mutex CYGBLD_POSIX_INIT;
 
// Condition variable for all threads in sigsuspend() and sigwait()
// to wait on.
Cyg_Condition_Variable signal_sigwait( signal_mutex ) CYGBLD_POSIX_INIT;
 
// Global pending signal set
sigset_t sig_pending;
 
// Array controlling signal states
static signal_state sigstate[sizeof(sigset_t)*8];
 
// Array of available signal_info objects for queueing signals
static signal_info siginfo[SIGQUEUE_MAX];
 
// List of free signal_info objects
static signal_info *siginfo_next = NULL;
 
//==========================================================================
// Variables used to support alarm()
 
// Forward def of action function
static void sigalrm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data );
 
// Kernel alarm object
static Cyg_Alarm sigalrm_alarm( Cyg_Clock::real_time_clock, sigalrm_action, 0 ) CYGBLD_POSIX_INIT;
 
// Set true when alarm is armed
volatile cyg_bool sigalrm_armed = false;
 
// Set true when alarm has fired and is waiting to be delivered
volatile cyg_bool sigalrm_pending = false;
 
//==========================================================================
// Implementation functions.
// These are where the real work of the signal mechanism gets done.
 
externC void cyg_posix_signal_start()
{
// Chain all free signal_info objects together
for( int i = 0; i < SIGQUEUE_MAX; i++ )
{
siginfo[i].next = siginfo_next;
siginfo_next = &siginfo[i];
}
// initialize all signal actions to SIG_DFL
for ( unsigned int i=0; i<(sizeof(sigstate)/sizeof(signal_state)); i++ )
{
sigstate[i].sa.sa_handler = SIG_DFL;
}
 
// Clear the pending signal set
sigemptyset( &sig_pending );
}
 
// -------------------------------------------------------------------------
// Generate a signal
 
cyg_bool cyg_sigqueue( const struct sigevent *sev, int code,
pthread_info *thread )
{
if( sev->sigev_notify == SIGEV_NONE )
{
// Do nothing
return true;
}
 
if( sev->sigev_notify == SIGEV_THREAD )
{
// create a thread to run the notification
// function.
// FIXME: implement SIGEV_THREAD
return true;
}
 
// Otherwise we must have a SIGEV_SIGNAL notification
 
// Find out whether the current thread already has the mutex
// locked. This is a distinct possibility if this function is
// called from the ASR while exiting the signal_sigwait condvar in
// pause() and sigtimedwait().
pthread_info *self = pthread_self_info();
cyg_bool locked = (self != NULL) && (signal_mutex.get_owner() == self->thread);
// Lock the mutex only if we do not already own it
if( !locked ) signal_mutex.lock();
int signo = sev->sigev_signo;
signal_state *ss = &sigstate[signo];
 
if( ss->sa.sa_flags & SA_SIGINFO )
{
// We have a queuable signal, allocate a signal_info
// object and add it to the queue.
 
if( siginfo_next == NULL )
{
if( !locked ) signal_mutex.unlock();
return false;
}
 
signal_info *si = siginfo_next;
siginfo_next = si->next;
 
si->si.si_signo = signo;
si->si.si_code = code;
si->si.si_value = sev->sigev_value;
 
if( ss->pending == NULL )
{
si->next = si;
}
else
{
si->next = ss->pending->next;
ss->pending->next = si;
}
ss->pending = si;
}
// else A non-queuable signal, just set it pending
 
if( thread != NULL )
{
sigaddset( &thread->sigpending, signo );
// just wake the thread up now if it's blocked somewhere
if ((thread->sigpending & ~thread->sigmask) != 0)
{
thread->thread->set_asr_pending();
thread->thread->release();
}
}
else
{
sigaddset( &sig_pending, signo );
// Wake up any threads in sigsuspend() and sigwait().
if (!signal_sigwait.get_queue()->empty())
{
signal_sigwait.broadcast();
}
else
{
cyg_posix_pthread_release_thread( &sig_pending );
}
}
 
if( !locked ) signal_mutex.unlock();
return true;
}
 
// -------------------------------------------------------------------------
// Deliver any pending unblocked signals to the current thread
// Returns true if a signal handler was called.
 
cyg_bool cyg_deliver_signals()
{
cyg_bool res = false;
pthread_info *self = pthread_self_info();
 
// If there is no pthread_info pointer for this thread then
// it is not a POSIX thread and cannot have signals delivered
// to it.
if( self == NULL ) return false;
// If there are no pending signals our work is done
if( sig_pending == 0 && self->sigpending == 0 )
return false;
 
// If there are no unmasked pending signals our
// work is also done
if( ((sig_pending | self->sigpending) & ~self->sigmask) == 0 )
return false;
 
// As with cyg_sigqueue(), this function can get called from an
// ASR where the signal_mutex is already locked. Check here to
// avoid relocking...
cyg_bool locked = signal_mutex.get_owner() == self->thread;
if( !locked ) signal_mutex.lock();
sigset_t todo;
 
// Since a signal handler may raise another signal, or unmask an existing
// signal, we loop here while there are no more unblocked signals pending.
while( (todo = ((sig_pending | self->sigpending) & ~self->sigmask)) != 0 )
{
// Here todo is a mask of the signals available for delivery
int signo = 0;
 
// This prioritizes low numbered signals
HAL_LSBIT_INDEX( signo, todo );
 
signal_state *ss = &sigstate[signo];
sigset_t sigbit = 1L<<signo;
 
if( ss->sa.sa_handler != SIG_IGN )
{
sigset_t oldmask = self->sigmask;
siginfo_t lsi;
 
if(ss->pending != NULL)
{
// There is a queued signal. Dequeue it and copy the
// siginfo object to a local copy.
signal_info *si = ss->pending->next;
// Make a local copy of the siginfo object
lsi = si->si;
// Remove the head signal_info object from the
// circular list.
if( ss->pending == si )
ss->pending = NULL;
else
ss->pending->next = si->next;
 
// Return it to the free list
si->next = siginfo_next;
siginfo_next = si;
}
else
{
// There are no signals queued. Set up the local siginfo_t
// object with default values.
 
lsi.si_signo = signo;
lsi.si_code = SI_USER;
lsi.si_value.sival_int = 0;
}
// Clear the bit from the pending masks. If the pending
// queue is not empty, leave the bits set, otherwise clear
// them. Do this now so that if the signal handler longjumps
// out, the signal subsystem is clean.
if( ss->pending == NULL )
{
// Clear the bit in both masks regardless of which
// one it actually came from. This is cheaper than
// trying to find out.
sig_pending &= ~sigbit;
self->sigpending &= ~sigbit;
}
 
// Add the mask set and the signal itself to the
// mask while we call the signal handler
self->sigmask = oldmask | ss->sa.sa_mask | sigbit;
// Unlock now so that a longjmp out of the handler
// does the right thing. We do this even if we did not
// lock the mutex since it will only recently have been
// relocked and thus all data is still consistent.
signal_mutex.unlock();
if( ss->sa.sa_flags & SA_SIGINFO )
{
// A sigaction delivery
CYG_CHECK_FUNC_PTR( ss->sa.sa_sigaction,
"Bad sa_sigaction signal handler" );
ss->sa.sa_sigaction( signo, &lsi, NULL );
}
else if ( ss->sa.sa_handler == SIG_DFL )
{
CYG_TRACE2( true,
"Unhandled POSIX signal: sig=%d, mask=%08x",
signo, oldmask );
 
// FIXME: should do something better here
#if CYGINT_ISO_EXIT
_exit( -signo );
#endif
CYG_FAIL("Unhandled POSIX signal");
}
else
{
// This is a standard signal delivery.
CYG_CHECK_FUNC_PTR( ss->sa.sa_handler,
"Bad sa_handler signal handler" );
 
ss->sa.sa_handler( signo );
}
 
// Relock the mutex
signal_mutex.lock();
 
// Restore original signal mask
self->sigmask = oldmask;
 
// return that we have handled a signal
res = true;
}
}
 
if( !locked ) signal_mutex.unlock();
return res;
}
 
// -------------------------------------------------------------------------
// Utility routine to signal any threads waiting in sigwait*().
 
void cyg_posix_signal_sigwait()
{
signal_sigwait.broadcast();
}
 
// -------------------------------------------------------------------------
// Action routine called from kernel alarm to deliver the SIGALRM signal.
// We cannot call any signal delivery functions directly here, so we simply
// set a flag and schedule an ASR to be called.
 
static void sigalrm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data )
{
sigset_t mask;
sigalrm_armed = false;
sigalrm_pending = true;
sigemptyset( &mask );
sigaddset( &mask, SIGALRM );
// Wake up any threads in sigsuspend() and sigwait() in case they
// are waiting for an alarm, and would have SIGALRM masked
signal_sigwait.broadcast();
cyg_posix_pthread_release_thread( &mask );
}
 
// -------------------------------------------------------------------------
// Check for SIGALRMs. This is called from the ASR and sigtimedwait()
// as alarms need to be handled as a special case.
 
static __inline__ void check_sigalarm(void)
{
// If there is a pending SIGALRM, generate it
if( sigalrm_pending )
{
sigalrm_pending = false;
struct sigevent sev;
 
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGALRM;
sev.sigev_value.sival_int = 0;
 
// generate the signal
cyg_sigqueue( &sev, SI_USER );
}
}
 
// -------------------------------------------------------------------------
// signal ASR function. This is called from the general POSIX ASR to
// deal with any signal related issues.
 
externC void cyg_posix_signal_asr(pthread_info *self)
{
check_sigalarm();
 
// Now call cyg_deliver_signals() to see if we can
// handle any signals now.
cyg_deliver_signals();
}
 
//==========================================================================
// Per-thread initialization and destruction
 
externC void cyg_posix_thread_siginit( pthread_info *thread,
pthread_info *parentthread )
{
// Clear out signal masks
sigemptyset( &thread->sigpending );
// but threads inherit signal masks
if ( NULL == parentthread )
sigemptyset( &thread->sigmask );
else
thread->sigmask = parentthread->sigmask;
cyg_pthread_exception_init( thread );
}
 
externC void cyg_posix_thread_sigdestroy( pthread_info *thread )
{
cyg_pthread_exception_destroy( thread );
}
 
//==========================================================================
// Functions to generate signals
 
// -------------------------------------------------------------------------
// Deliver sig to a process.
// eCos only supports the value 0 for pid.
 
externC int kill (pid_t pid, int sig)
{
SIGNAL_ENTRY();
 
if( !SIGNAL_VALID(sig) )
SIGNAL_RETURN(EINVAL);
if( pid != 0 )
SIGNAL_RETURN(ESRCH);
 
struct sigevent sev;
 
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = sig;
sev.sigev_value.sival_int = 0;
cyg_sigqueue( &sev, SI_USER );
 
cyg_deliver_signals();
SIGNAL_RETURN(0);
}
 
// -------------------------------------------------------------------------
 
externC int pthread_kill (pthread_t threadid, int sig)
{
SIGNAL_ENTRY();
 
if( !SIGNAL_VALID(sig) )
SIGNAL_RETURN(EINVAL);
struct sigevent sev;
 
pthread_info *thread = pthread_info_id(threadid);
 
if( thread == NULL )
SIGNAL_RETURN(ESRCH);
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = sig;
sev.sigev_value.sival_int = 0;
cyg_sigqueue( &sev, SI_USER, thread );
 
cyg_deliver_signals();
SIGNAL_RETURN(0);
}
 
//==========================================================================
// Functions to catch signals
 
// -------------------------------------------------------------------------
// Install signal handler for sig.
 
externC int sigaction (int sig, const struct sigaction *act,
struct sigaction *oact)
{
SIGNAL_ENTRY();
 
if( !SIGNAL_VALID(sig) )
SIGNAL_RETURN(EINVAL);
signal_state *ss = &sigstate[sig];
signal_mutex.lock();
 
if( oact != NULL )
*oact = ss->sa;
 
ss->sa = *act;
 
if( ss->sa.sa_handler == SIG_IGN )
{
// Setting the handler to SIG_IGN causes any pending
// signals to be discarded and any queued values to also
// be removed.
 
pthread_info *self = pthread_self_info();
sigset_t sigbit = 1<<sig;
 
if( (sig_pending | self->sigpending) & sigbit )
{
// This signal is pending, clear it
 
sig_pending &= ~sigbit;
self->sigpending &= ~sigbit;
 
// Clean out any queued signal_info objects
while( ss->pending != NULL )
{
signal_info *si = ss->pending->next;
// Remove the head signal_info object from the
// circular list.
if( ss->pending == si )
ss->pending = NULL;
else
ss->pending->next = si->next;
 
// Return it to the free list
si->next = siginfo_next;
siginfo_next = si;
}
}
}
cyg_deliver_signals();
signal_mutex.unlock();
SIGNAL_RETURN(0);
}
 
// -------------------------------------------------------------------------
// Queue signal to process with value.
 
externC int sigqueue (pid_t pid, int sig, const union sigval value)
{
SIGNAL_ENTRY();
 
if( !SIGNAL_VALID(sig) )
SIGNAL_RETURN(EINVAL);
struct sigevent sev;
 
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = sig;
sev.sigev_value = value;
cyg_sigqueue( &sev, SI_QUEUE );
 
cyg_deliver_signals();
SIGNAL_RETURN(0);
}
//==========================================================================
// Functions to deal with current blocked and pending masks
 
// -------------------------------------------------------------------------
// Set process blocked signal mask
// Map this onto pthread_sigmask().
 
externC int sigprocmask (int how, const sigset_t *set, sigset_t *oset)
{
return pthread_sigmask( how, set, oset);
}
 
// -------------------------------------------------------------------------
// Set calling thread's blocked signal mask
 
externC int pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
{
int err = 0;
SIGNAL_ENTRY();
 
pthread_info *self = pthread_self_info();
// Save old set
if( oset != NULL )
*oset = self->sigmask;
 
if( set != NULL )
{
switch( how )
{
case SIG_BLOCK:
self->sigmask |= *set;
break;
case SIG_UNBLOCK:
self->sigmask &= ~*set;
break;
case SIG_SETMASK:
self->sigmask = *set;
break;
 
default:
err = EINVAL;
break;
}
}
 
// Deliver any newly unblocked signals
cyg_deliver_signals();
SIGNAL_RETURN(err);
}
 
// -------------------------------------------------------------------------
// Exported routine to set calling thread's blocked signal mask
//
// Optionally set and return the current thread's signal mask. This is
// exported to other packages so that they can manipulate the signal
// mask without necessarily having them delivered (as calling
// pthread_sigmask() would). Signals can be delivered by calling
// cyg_posix_deliver_signals().
 
externC void cyg_pthread_sigmask_set (const sigset_t *set, sigset_t *oset)
{
pthread_info *self = pthread_self_info();
 
if( self != NULL )
{
if( oset != NULL )
*oset = self->sigmask;
 
if( set != NULL )
self->sigmask = *set;
}
}
 
// -------------------------------------------------------------------------
// Exported routine to test for any pending signals.
//
// This routine tests for any pending undelivered, unmasked
// signals. If there are any it returns true. This is exported to
// other packages, such as FILEIO, so that they can detect whether to
// abort a current API call with an EINTR result.
 
externC cyg_bool cyg_posix_sigpending(void)
{
pthread_info *self = pthread_self_info();
 
if( self == NULL )
return false;
return ( ((sig_pending | self->sigpending) & ~self->sigmask) != 0 );
}
 
// -------------------------------------------------------------------------
// Exported routine to deliver selected signals
//
// This routine optionally sets the given mask and then tries to
// deliver any pending signals that have been unmasked. This is
// exported to other packages so that they can cause signals to be
// delivered at controlled points during execution.
 
externC void cyg_posix_deliver_signals( const sigset_t *mask )
{
sigset_t oldmask;
pthread_info *self = pthread_self_info();
 
if( self != NULL )
{
if( mask != NULL )
{
oldmask = self->sigmask;
self->sigmask = *mask;
}
else
oldmask = 0; // silence warning
 
cyg_deliver_signals();
 
if( mask != NULL )
self->sigmask = oldmask;
}
}
 
// -------------------------------------------------------------------------
// Get set of pending signals for this process
 
externC int sigpending (sigset_t *set)
{
SIGNAL_ENTRY();
 
if( set == NULL )
SIGNAL_RETURN(EINVAL);
pthread_info *self = pthread_self_info();
*set = self->sigpending | sig_pending;
SIGNAL_RETURN(0);
}
 
//==========================================================================
// Wait for or accept signals
 
// -------------------------------------------------------------------------
// Block signals in set and wait for a signal
 
externC int sigsuspend (const sigset_t *set)
{
SIGNAL_ENTRY();
 
pthread_info *self = pthread_self_info();
 
signal_mutex.lock();
 
// Save the old mask and set the current mask to
// the one supplied.
sigset_t old = self->sigmask;
self->sigmask = *set;
 
// Loop until a signal gets delivered
while( !cyg_deliver_signals() )
signal_sigwait.wait();
 
self->sigmask = old;
signal_mutex.unlock();
SIGNAL_RETURN(EINTR);
}
 
// -------------------------------------------------------------------------
// Wait for a signal in set to arrive
// Implement this as a variant on sigtimedwait().
 
externC int sigwait (const sigset_t *set, int *sig)
{
SIGNAL_ENTRY();
 
siginfo_t info;
int ret = sigtimedwait( set, &info, NULL );
 
if( ret == -1 )
SIGNAL_RETURN(errno);
 
*sig = ret;
SIGNAL_RETURN(0);
}
 
// -------------------------------------------------------------------------
// Do the same as sigwait() except return a siginfo_t object too.
// Implement this as a variant on sigtimedwait().
 
externC int sigwaitinfo (const sigset_t *set, siginfo_t *info)
{
SIGNAL_ENTRY();
 
int ret = sigtimedwait( set, info, NULL );
SIGNAL_RETURN_VALUE(ret);
}
 
// -------------------------------------------------------------------------
// Wait either for a signal in the given set to become pending, or
// for the timeout to expire. If timeout is NULL, wait for ever.
 
externC int sigtimedwait (const sigset_t *set, siginfo_t *info,
const struct timespec *timeout)
{
SIGNAL_ENTRY();
 
// check for cancellation first.
pthread_testcancel();
 
int err = 0;
cyg_tick_count ticks;
 
if( timeout == NULL ) ticks = 0;
else ticks = cyg_timespec_to_ticks( timeout ) +
Cyg_Clock::real_time_clock->current_value();
 
pthread_info *self = pthread_self_info();
signal_mutex.lock();
 
sigset_t todo;
 
// Wait for a signal in the set to become pending
while( (todo = (*set & (sig_pending | self->sigpending))) == 0 )
{
// If timeout is not NULL, do a timed wait on the
// sigwait condition variable. If it is NULL - wait
// until we are woken.
if( timeout )
{
if( ticks == 0 || !signal_sigwait.wait(ticks) )
{
// If the timeout is actually zero, or we have waited and
// timed out, then we must quit with an error.
err = EAGAIN;
break;
}
}
else {
if ( !signal_sigwait.wait() ) {
// check we weren't woken up forcibly (e.g. to be cancelled)
// if so, pretend it's an error
err = EAGAIN;
break;
}
}
// Special case check for SIGALRM since the fact SIGALRM is masked
// would have prevented it being set pending in the alarm handler.
check_sigalarm();
 
cyg_posix_timer_asr(self);
}
 
if( err == 0 )
{
// There is a signal in the set that is pending: deliver
// it. todo contains a mask of all the signals that could be
// delivered now, but we only want to deliver one of them.
 
int signo = 0;
 
// Select the lowest numbered signal from the todo mask
HAL_LSBIT_INDEX( signo, todo );
 
signal_state *ss = &sigstate[signo];
sigset_t sigbit = 1L<<signo;
 
if( (ss->sa.sa_flags & SA_SIGINFO) && (ss->pending != NULL) )
{
// If the SA_SIGINFO bit is set, then there
// will be a signal_info object queued on the
// pending field.
 
signal_info *si = ss->pending->next;
*info = si->si;
 
// Remove the head signal_info object from the
// circular list.
if( ss->pending == si )
ss->pending = NULL;
else
ss->pending->next = si->next;
si->next = siginfo_next;
siginfo_next = si;
}
else
{
// Not a queued signal, or there is no signal_info object
// on the pending queue: fill in info structure with
// default values.
info->si_signo = signo;
info->si_code = SI_USER;
info->si_value.sival_int = 0;
}
 
// Clear the bit from the pending masks. If the pending
// queue is not empty, leave the bits set, otherwise clear
// them.
if( ss->pending == NULL )
{
// Clear the bit in both masks regardless of which
// one it actually came from. This is cheaper than
// trying to find out.
sig_pending &= ~sigbit;
self->sigpending &= ~sigbit;
}
 
// all done
}
signal_mutex.unlock();
 
pthread_testcancel();
 
if (err)
SIGNAL_RETURN(err);
else
SIGNAL_RETURN_VALUE( info->si_signo );
}
 
//==========================================================================
// alarm, pause and sleep
 
// -------------------------------------------------------------------------
// Generate SIGALRM after some number of seconds
 
externC unsigned int alarm( unsigned int seconds )
{
int res = 0;
struct timespec tv;
cyg_tick_count trigger, interval;
 
SIGNAL_ENTRY();
 
signal_mutex.lock();
 
if( sigalrm_armed )
{
sigalrm_alarm.disable();
 
sigalrm_alarm.get_times( &trigger, &interval );
 
// Convert trigger time back to interval
trigger -= Cyg_Clock::real_time_clock->current_value();
cyg_ticks_to_timespec( trigger, &tv );
 
res = tv.tv_sec;
sigalrm_armed = false;
}
 
if( seconds != 0 )
{
// Here we know that the sigalrm_alarm is unarmed, set it up
// to trigger in the required number of seconds.
 
tv.tv_sec = seconds;
tv.tv_nsec = 0;
 
trigger = cyg_timespec_to_ticks( &tv );
 
// Convert trigger interval to absolute time
trigger += Cyg_Clock::real_time_clock->current_value();
sigalrm_alarm.initialize( trigger, 0 );
 
sigalrm_armed = true;
}
signal_mutex.unlock();
 
CYG_REPORT_RETVAL(res);
return res;
}
 
// -------------------------------------------------------------------------
// Wait for a signal to be delivered.
 
externC int pause( void )
{
SIGNAL_ENTRY();
 
signal_mutex.lock();
 
// Check for any pending signals that can be delivered and
// if there are none, wait for a signal to be generated
if( !cyg_deliver_signals() )
signal_sigwait.wait();
 
// Now check again for some signals to deliver
cyg_deliver_signals();
signal_mutex.unlock();
SIGNAL_RETURN(EINTR);
}
 
//==========================================================================
// Signal sets
 
// -------------------------------------------------------------------------
// Clear all signals from set.
 
externC int sigemptyset (sigset_t *set)
{
SIGNAL_ENTRY();
 
*set = 0;
SIGNAL_RETURN(0);
}
 
// -------------------------------------------------------------------------
// Set all signals in set.
 
externC int sigfillset (sigset_t *set)
{
SIGNAL_ENTRY();
 
*set = ~0;
SIGNAL_RETURN(0);
}
 
// -------------------------------------------------------------------------
// Add signo to set.
 
externC int sigaddset (sigset_t *set, int signo)
{
SIGNAL_ENTRY();
 
int err = 0;
if( !SIGNAL_VALID(signo) )
err = EINVAL;
else *set |= 1<<signo;
SIGNAL_RETURN(err);
}
 
// -------------------------------------------------------------------------
// Remove signo from set.
 
externC int sigdelset (sigset_t *set, int signo)
{
SIGNAL_ENTRY();
 
int err = 0;
if( !SIGNAL_VALID(signo) )
err = EINVAL;
else *set &= ~(1<<signo);
SIGNAL_RETURN(err);
}
 
// -------------------------------------------------------------------------
// Test whether signo is in set
 
externC int sigismember (const sigset_t *set, int signo)
{
SIGNAL_ENTRY();
 
int ret = 0;
if( !SIGNAL_VALID(signo) )
SIGNAL_RETURN(EINVAL);
 
if( *set & (1<<signo) ) ret = 1;
 
CYG_REPORT_RETVAL( ret );
return ret;
}
 
//==========================================================================
// ISO C compatibility functions
 
// -------------------------------------------------------------------------
// Installs a new signal handler for the specified signal, and returns
// the old handler
 
externC sa_sighandler_t signal(int sig, sa_sighandler_t handler)
{
SIGNAL_ENTRY();
 
int err;
sa_sighandler_t ret;
struct sigaction new_action;
struct sigaction old_action;
 
sigemptyset( &new_action.sa_mask );
new_action.sa_flags = 0;
new_action.sa_handler = handler;
 
err = sigaction( sig, &new_action, &old_action );
 
if( err < 0 )
ret = SIG_ERR;
else ret = old_action.sa_handler;
CYG_REPORT_RETVAL( ret );
return ret;
}
 
// -------------------------------------------------------------------------
// raise() - ISO C 7.7.2 //
//
// Raises the signal, which will cause the current signal handler for
// that signal to be called
 
externC int raise(int sig)
{
return kill( 0, sig );
}
 
// -------------------------------------------------------------------------
// siglongjmp()
// Restores signal mask and longjumps.
 
__externC void siglongjmp( sigjmp_buf env, int val )
{
CYG_REPORT_FUNCNAME( "siglongjmp" );
CYG_REPORT_FUNCARG2( "&env=%08x, val=%d", &env, val );
 
// ISO C says that if we are passed val == 0, then we change it to 1
if( val == 0 )
val = 1;
 
if( env[0].__savemask )
pthread_sigmask( SIG_SETMASK, &env[0].__sigsavemask, NULL );
HAL_REORDER_BARRIER(); // prevent any chance of optimisation re-ordering
hal_longjmp( env[0].__jmp_buf, val );
HAL_REORDER_BARRIER(); // prevent any chance of optimisation re-ordering
 
#ifdef CYGDBG_USE_ASSERTS
CYG_ASSERT( 0, "siglongjmp should not have reached this point!" );
#else
for (;;)
CYG_EMPTY_STATEMENT;
#endif
}
 
#endif // ifdef CYGPKG_POSIX_SIGNALS
 
// -------------------------------------------------------------------------
// EOF signal.cxx

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.