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/IEC |
9945-1)[POSIX]. |
</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/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 |
[POSIX]. Online, the Open Group Single Unix |
Specification [SUS2] 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. |
[Lewine] covers the process, signal, file and I/O |
functions, while [Lewis1], [Lewis2], |
[Nichols] and [Norton] 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 “// TBA” |
are potential candidates for later implementation. |
</para> |
|
<!-- }}} --> |
<!-- {{{ Process Primitives --> |
|
<sect1 id="posix-process-primitives"> |
<title>Process Primitives [POSIX Section 3]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
int kill(pid_t pid, int sig); |
int pthread_kill(pthread_t thread, int sig); |
int sigaction(int sig, const struct sigaction *act, |
struct sigaction *oact); |
int sigqueue(pid_t pid, int sig, const union sigval value); |
int sigprocmask(int how, const sigset_t *set, |
sigset_t *oset); |
int pthread_sigmask(int how, const sigset_t *set, |
sigset_t *oset); |
int sigpending(sigset_t *set); |
int sigsuspend(const sigset_t *set); |
int sigwait(const sigset_t *set, int *sig); |
int sigwaitinfo(const sigset_t *set, siginfo_t *info); |
int sigtimedwait(const sigset_t *set, siginfo_t *info, |
const struct timespec *timeout); |
int sigemptyset(sigset_t *set); |
int sigfillset(sigset_t *set); |
int sigaddset(sigset_t *set, int signo); |
int sigdelset(sigset_t *set, int signo); |
int sigismember(const sigset_t *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_t fork(void); |
int execl( const char *path, const char *arg, ... ); |
int execv( const char *path, char *const argv[] ); |
int execle( const char *path, const char *arg, ... ); |
int execve( const char *path, char *const argv[], |
char *const envp[] ); |
int execlp( const char *path, const char *arg, ... ); |
int execvp( const char *path, char *const argv[] ); |
int pthread_atfork( void(*prepare)(void), |
void (*parent)(void), |
void (*child)() ); |
pid_t wait( int *stat_loc ); |
pid_t waitpid( pid_t pid, int *stat_loc, |
int options ); |
void _exit( int status ); |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Notes</title> |
<itemizedlist> |
<listitem> |
<para> |
Signal handling may be enabled or disabled with the |
CYGPKG_POSIX_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_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_code</emphasis> value, |
<emphasis>SI_EXCEPT</emphasis>, is defined to |
distinguish hardware generated exceptions from |
others. |
</para> |
</listitem> |
|
<listitem> |
<para> |
Extra signals are defined: |
_SIGTRAP_,_SIGIOT_, |
_SIGEMT_, and _SIGSYS_. 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 [POSIX Section 4]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
int uname( struct utsname *name ); |
time_t time( time_t *tloc ); |
char *getenv( const char *name ); |
int isatty( int fd ); |
long sysconf( int name ); |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
<screen> |
pid_t getpid( void ); |
pid_t getppid( void ); |
uid_t getuid( void ); |
uid_t geteuid( void ); |
gid_t getgid( void ); |
gid_t getegid( void ); |
int setuid( uid_t uid ); |
int setgid( gid_t gid ); |
int getgroups( int gidsetsize, gid_t grouplist[] ); |
char *getlogin( void ); |
int getlogin_r( char *name, size_t namesize ); |
pid_t getpgrp( void ); |
pid_t setsid( void ); |
int setpgid( pid_t pid, pid_t pgid ); |
char *ctermid( char *s); |
char *ttyname( int fd ); // TBA |
int ttyname_r( int fd, char *name, size_t namesize); // TBA |
clock_t times( struct tms *buffer ); // TBA |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Notes</title> |
<itemizedlist> |
<listitem> |
<para>The fields of the <emphasis>utsname</emphasis> |
structure are initialized as follows: |
<screen> |
sysname “eCos” |
nodename “” (gethostname() is currently not available) |
|
release Major version number of the kernel |
version Minor version number of the kernel |
machine “” (Requires some config tool changes) |
</screen> |
</para> |
<para> |
The sizes of these strings are defined by |
CYG_POSIX_UTSNAME_LENGTH and |
CYG_POSIX_UTSNAME_NODENAME_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_LIBC_DEFAULT_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><limits.h></filename>, |
or zero. |
</para> |
</listitem> |
</itemizedlist> |
|
</sect2> |
</sect1> |
|
<!-- }}} --> |
<!-- {{{ Files and Directories --> |
|
<sect1 id="posix-files-and-directories"> |
<title>Files and Directories [POSIX Section 5]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
DIR *opendir( const char *dirname ); |
struct dirent *readdir( DIR *dirp ); |
int readdir_r( DIR *dirp, struct dirent *entry, |
struct dirent **result ); |
void rewinddir( DIR *dirp ); |
int closedir( DIR *dirp ); |
int chdir( const char *path ); |
char *getcwd( char *buf, size_t size ); |
int open( const char * path , int oflag , ... ); |
int creat( const char * path, mode_t mode ); |
int link( const char *existing, const char *new ); |
int mkdir( const char *path, mode_t mode ); |
int unlink( const char *path ); |
int rmdir( const char *path ); |
int rename( const char *old, const char *new ); |
int stat( const char *path, struct stat *buf ); |
int fstat( int fd, struct stat *buf ); |
int access( const char *path, int amode ); |
long pathconf(const char *path, int name); |
long fpathconf(int fd, int name); |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
|
<screen> |
mode_t umask( mode_t cmask ); |
int mkfifo( const char *path, mode_t mode ); |
int chmod( const char *path, mode_t mode ); // TBA |
int fchmod( int fd, mode_t mode ); // TBA |
int chown( const char *path, uid_t owner, gid_t group ); |
int utime( const char *path, const struct utimbuf *times ); // TBA |
int ftruncate( int fd, off_t length ); // TBA |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Notes</title> |
|
<itemizedlist> |
<listitem> |
<para> |
If a call to <function>open()</function> or <function>creat()</function> supplies |
the third _mode_ 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_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_FILEIO_NFILE option. The maximum number |
of file descriptors is supplied by the CYGNUM_FILEIO_NFD |
option. |
</para> |
</listitem> |
</itemizedlist> |
</sect2> |
</sect1> |
|
<!-- }}} --> |
<!-- {{{ Input and Output --> |
|
<sect1 id="posix-input-and-output"> |
<title>Input and Output [POSIX Section 6]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
int dup( int fd ); |
int dup2( int fd, int fd2 ); |
int close(int fd); |
ssize_t read(int fd, void *buf, size_t nbyte); |
ssize_t write(int fd, const void *buf, size_t nbyte); |
int fcntl( int fd, int cmd, ... ); |
off_t lseek(int fd, off_t offset, int whence); |
int fsync( int fd ); |
int fdatasync( int fd );</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
<screen> |
int pipe( int fildes[2] ); |
int aio_read( struct aiocb *aiocbp ); // TBA |
int aio_write( struct aiocb *aiocbp ); // TBA |
int lio_listio( int mode, struct aiocb *const list[], |
int nent, struct sigevent *sig); // TBA |
int aio_error( struct aiocb *aiocbp ); // TBA |
int aio_return( struct aiocb *aiocbp ); // TBA |
int aio_cancel( int fd, struct aiocb *aiocbp ); // TBA |
int aio_suspend( const struct aiocb *const list[], |
int nent, const struct timespec *timeout ); // TBA |
int aio_fsync( int op, struct aiocb *aiocbp ); |
// TBA |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Notes</title> |
<itemizedlist> |
<listitem> |
<para> |
Only the <emphasis>F_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 [POSIX Section 7]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
<screen> |
speed_t cfgetospeed( const struct termios *termios_p ); |
int cfsetospeed( struct termios *termios_p, speed_t speed ); |
speed_t cfgetispeed( const struct termios *termios_p ); |
int cfsetispeed( struct termios *termios_p, speed_t speed ); |
int tcgetattr( int fd, struct termios *termios_p ); |
int tcsetattr( int fd, int optional_actions, |
const struct termios *termios_p ); |
int tcsendbreak( int fd, int duration ); |
int tcdrain( int fd ); |
int tcflush( int fd, int queue_selector ); |
int tcsendbreak( int fd, int action ); |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
|
<screen> |
pid_t tcgetpgrp( int fd ); |
int tcsetpgrp( int fd, pid_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 |
“tty” devices, not the “serial” |
devices. None of the functionality relevant to job |
control, controlling terminals and sessions is |
implemented. |
</para> |
</listitem> |
<listitem> |
<para> |
Only <emphasis>MIN</emphasis> = 0 and |
<emphasis>TIME</emphasis> = 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 [POSIX Section 8]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
<screen> |
char *setlocale( int category, const char *locale ); |
int fileno( FILE *stream ); |
FILE *fdopen( int fd, const char *type ); |
int getc_unlocked( FILE *stream); |
int getchar_unlocked( void ); |
int putc_unlocked( FILE *stream ); |
int putchar_unlocked( void ); |
char *strtok_r( char *s, const char *sep, |
char **lasts ); |
char *asctime_r( const struct tm *tm, char *buf ); |
char *ctime_r( const time_t *clock, char *buf ); |
struct tm *gmtime_r( const time_t *clock, |
struct tm *result ); |
struct tm *localtime_r( const time_t *clock, |
struct tm *result ); |
int rand_r( unsigned int *seed ); |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
<screen> |
void flockfile( FILE *file ); |
int ftrylockfile( FILE *file ); |
void funlockfile( FILE *file ); |
int sigsetjmp( sigjmp_buf env, int savemask ); // TBA |
void siglongjmp( sigjmp_buf env, int val ); // TBA |
void tzset(void); // 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_unlocked()</emphasis>, |
<emphasis>getchar_unlocked()</emphasis>, |
<emphasis>putc_unlocked()</emphasis> and |
<emphasis>putchar_unlocked()</emphasis> are defined |
but are currently identical to their non-unlocked |
equivalents. |
</para> |
</listitem> |
<listitem> |
<para> |
<emphasis>strtok_r()</emphasis>, <emphasis>asctime_r()</emphasis>, |
<emphasis>ctime_r()</emphasis>, <emphasis>gmtime_r()</emphasis>, |
<emphasis>localtime_r()</emphasis> and |
<emphasis>rand_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 [POSIX Section 9]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<para> |
<none> |
</para> |
|
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
|
<screen> |
struct group *getgrgid( gid_t gid ); |
int getgrgid( gid_t gid, struct group *grp, char *buffer, |
size_t bufsize, struct group **result ); |
struct group *getgrname( const char *name ); |
int getgrname_r( const char *name, struct group *grp, |
char *buffer, size_t bufsize, struct group **result ); |
struct passwd *getpwuid( uid_t uid ); |
int getpwuid_r( uid_t uid, struct passwd *pwd, |
char *buffer, size_t bufsize, struct passwd **result ); |
struct passwd *getpwnam( const char *name ); |
int getpwnam_r( const char *name, struct passwd *pwd, |
char *buffer, size_t bufsize, struct passwd **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 [POSIX Section 10]</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 [POSIX Section 11]</title> |
|
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
int sem_init(sem_t *sem, int pshared, unsigned int value); |
int sem_destroy(sem_t *sem); |
int sem_wait(sem_t *sem); |
int sem_trywait(sem_t *sem); |
int sem_post(sem_t *sem); |
int sem_getvalue(sem_t *sem, int *sval); |
int pthread_mutexattr_init( pthread_mutexattr_t *attr); |
int pthread_mutexattr_destroy( pthread_mutexattr_t *attr); |
int pthread_mutex_init(pthread_mutex_t *mutex, |
const pthread_mutexattr_t *mutex_attr); |
int pthread_mutex_destroy(pthread_mutex_t *mutex); |
int pthread_mutex_lock(pthread_mutex_t *mutex); |
int pthread_mutex_trylock(pthread_mutex_t *mutex); |
int pthread_mutex_unlock(pthread_mutex_t *mutex); |
int pthread_condattr_init(pthread_condattr_t *attr); |
int pthread_condattr_destroy(pthread_condattr_t *attr); |
int pthread_cond_init(pthread_cond_t *cond, |
const pthread_condattr_t *attr); |
int pthread_cond_destroy(pthread_cond_t *cond); |
int pthread_cond_signal(pthread_cond_t *cond); |
int pthread_cond_broadcast(pthread_cond_t *cond); |
int pthread_cond_wait(pthread_cond_t *cond, |
pthread_mutex_t *mutex); |
int pthread_cond_timedwait(pthread_cond_t *cond, |
pthread_mutex_t *mutex, |
const struct timespec *abstime); |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
|
<screen> |
sem_t *sem_open(const char *name, int oflag, ...); // TBA |
int sem_close(sem_t *sem); // TBA |
int sem_unlink(const char *name); // TBA |
int pthread_mutexattr_getpshared( const pthread_mutexattr_t *attr, |
int *pshared ); |
int pthread_mutexattr_setpshared( const pthread_mutexattr_t *attr, |
int pshared ); |
int pthread_condattr_getpshared( const pthread_condattr_t *attr, |
int *pshared); |
int pthread_condattr_setpshared( const pthread_condattr_t *attr, |
int pshared);</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Notes</title> |
<itemizedlist> |
<listitem> |
<para> |
The presence of semaphores is controlled by the |
CYGPKG_POSIX_SEMAPHORES option. This in turn |
causes the _POSIX_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_init()</emphasis> is not implemented, |
its value is ignored. |
</para> |
</listitem> |
|
<listitem> |
<para> |
Functions <emphasis>sem_open()</emphasis>, |
<emphasis>sem_close()</emphasis> and |
<emphasis>sem_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 |
_POSIX_THREAD_PRIO_INHERIT and |
_POSIX_THREAD_PRIO_PROTECT |
configuration options. |
</para> |
</listitem> |
|
<listitem> |
<para> |
{_POSIX_THREAD_PROCESS_SHARED} 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_mutexattr_getpshared()</emphasis>, |
<emphasis>pthread_mutexattr_setpshared()</emphasis>, |
<emphasis>pthread_condattr_getpshared()</emphasis> and |
<emphasis>pthread_condattr_setpshared()</emphasis>. |
</para> |
</listitem> |
|
<listitem> |
<para> |
Condition variables do not become bound to a particular |
mutex when |
<emphasis>pthread_cond_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 [POSIX Section 12]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<para> |
<none> |
</para> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
|
<screen> |
int mlockall( int flags ); |
int munlockall( void ); |
int mlock( const void *addr, size_t len ); |
int munlock( const void *addr, size_t len ); |
void mmap( void *addr, size_t len, int prot, int flags, |
int fd, off_t off ); |
int munmap( void *addr, size_t len ); |
int mprotect( const void *addr, size_t len, int prot ); |
int msync( void *addr, size_t len, int flags ); |
int shm_open( const char *name, int oflag, mode_t mode ); |
int shm_unlink( const char *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 [POSIX Section 13]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
int sched_yield(void); |
int sched_get_priority_max(int policy); |
int sched_get_priority_min(int policy); |
int sched_rr_get_interval(pid_t pid, struct timespec *t); |
int pthread_attr_setscope(pthread_attr_t *attr, int scope); |
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope); |
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit); |
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit); |
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); |
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy); |
int pthread_attr_setschedparam( pthread_attr_t *attr, const struct sched_param *param); |
int pthread_attr_getschedparam( const pthread_attr_t *attr, |
struct sched_param *param); |
int pthread_setschedparam(pthread_t thread, int policy, |
const struct sched_param *param); |
int pthread_getschedparam(pthread_t thread, int *policy, |
struct sched_param *param); |
int pthread_mutexattr_setprotocol( pthread_mutexattr_t *attr, |
int protocol); |
int pthread_mutexattr_getprotocol( pthread_mutexattr_t *attr, |
int *protocol); |
int pthread_mutexattr_setprioceiling( pthread_mutexattr_t *attr, |
int prioceiling); |
int pthread_mutexattr_getprioceiling( pthread_mutexattr_t *attr, |
int *prioceiling); |
int pthread_mutex_setprioceiling( pthread_mutex_t *mutex, |
int prioceiling, |
int *old_ceiling); |
int pthread_mutex_getprioceiling( pthread_mutex_t *mutex, |
int *prioceiling); |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
|
<screen> |
int sched_setparam(pid_t pid, const struct sched_param *param); |
int sched_getparam(pid_t pid, struct sched_param *param); |
int sched_setscheduler(pid_t pid, int policy, |
const struct sched_param *param); |
int sched_getscheduler(pid_t pid); |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Notes</title> |
<itemizedlist> |
<listitem> |
<para> |
The functions <emphasis>sched_setparam()</emphasis>, |
<emphasis>sched_getparam()</emphasis>, |
<emphasis>sched_setscheduler()</emphasis> and |
<emphasis>sched_getscheduler()</emphasis> are present |
but always return an error. |
</para> |
</listitem> |
<listitem> |
<para> |
The scheduler policy <emphasis>SCHED_OTHER</emphasis> is |
equivalent to <emphasis>SCHED_RR</emphasis>. |
</para> |
</listitem> |
<listitem> |
<para> |
Only <emphasis>PTHREAD_SCOPE_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_SCOPE_SYSTEM |
inheritsched PTHREAD_INHERIT_SCHED |
schedpolicy SCHED_OTHER |
schedparam.sched 0 |
</screen> |
</para> |
</listitem> |
<listitem> |
<para> |
Mutex priority inversion protection is controlled by a |
number of kernel configuration options. |
If CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
is defined then |
{_POSIX_THREAD_PRIO_INHERIT} |
will be defined and PTHREAD_PRIO_INHERIT may |
be set as the protocol in a |
<emphasis>pthread_mutexattr_t</emphasis> |
object. |
If CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
is defined then |
{_POSIX_THREAD_PRIO_PROTECT} |
will be defined and PTHREAD_PRIO_PROTECT may |
be set as the protocol in a |
<emphasis>pthread_mutexattr_t</emphasis> object. |
</para> |
</listitem> |
<listitem> |
<para> |
The default attribute values set by |
<emphasis>pthread_mutexattr_init()</emphasis> |
is to set the protocol attribute to |
PTHREAD_PRIO_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 [POSIX Section 14]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
int clock_settime( clockid_t clock_id, |
const struct timespec *tp); |
int clock_gettime( clockid_t clock_id, struct timespec *tp); |
int clock_getres( clockid_t clock_id, struct timespec *tp); |
int timer_create( clockid_t clock_id, struct sigevent *evp, |
timer_t *timer_id); |
int timer_delete( timer_t timer_id ); |
int timer_settime( timer_t timerid, int flags, |
const struct itimerspec *value, |
struct itimerspec *ovalue ); |
int timer_gettime( timer_t timerid, struct itimerspec *value ); |
int timer_getoverrun( timer_t timerid ); |
int nanosleep( const struct timespec *rqtp, struct timespec *rmtp); |
</screen> |
|
</sect2> |
|
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
|
<para> |
<none> |
</para> |
|
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Notes</title> |
|
<itemizedlist> |
<listitem> |
<para> |
Currently <emphasis>timer_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_POSIX_TIMERS allows the timer support to be |
enabled or disabled, and causes _POSIX_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 [POSIX Section 15]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
mqd_t mq_open( const char *name, int oflag, ... ); |
int mq_close( mqd_t mqdes ); |
int mq_unlink( const char *name ); |
int mq_send( mqd_t mqdes, const char *msg_ptr, |
size_t msg_len, unsigned int msg_prio ); |
ssize_t mq_receive( mqd_t mqdes, char *msg_ptr, |
size_t msg_len, unsigned int *msg_prio ); |
int mq_setattr( mqd_t mqdes, const struct mq_attr *mqstat, |
struct mq_attr *omqstat ); |
int mq_getattr( mqd_t mqdes, struct mq_attr *mqstat ); |
int mq_notify( mqd_t mqdes, const struct sigevent *notification ); |
</screen> |
<para>From POSIX 1003.1d draft: </para> |
<screen> |
int mq_send( mqd_t mqdes, const char *msg_ptr, |
size_t msg_len, unsigned int msg_prio, |
const struct timespec *abs_timeout ); |
ssize_t mq_receive( mqd_t mqdes, char *msg_ptr, |
size_t msg_len, unsigned int *msg_prio, |
const struct timespec *abs_timeout ); |
</screen> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
|
<para> |
<none> |
</para> |
|
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Notes</title> |
|
<itemizedlist> |
<listitem> |
<para> |
The presence of message queues is controlled by the |
CYGPKG_POSIX_MQUEUES option. Setting this will |
cause [_POSIX_MESSAGE_PASSING] 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 [POSIX Section 16]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
int pthread_attr_init(pthread_attr_t *attr); |
int pthread_attr_destroy(pthread_attr_t *attr); |
int pthread_attr_setdetachstate(pthread_attr_t *attr, |
int detachstate); |
int pthread_attr_getdetachstate(const pthread_attr_t *attr, |
int *detachstate); |
int pthread_attr_setstackaddr(pthread_attr_t *attr, |
void *stackaddr); |
int pthread_attr_getstackaddr(const pthread_attr_t *attr, |
void **stackaddr); |
int pthread_attr_setstacksize(pthread_attr_t *attr, |
size_t stacksize); |
int pthread_attr_getstacksize(const pthread_attr_t *attr, |
size_t *stacksize); |
int pthread_create( pthread_t *thread, |
const pthread_attr_t *attr, |
void *(*start_routine)(void *), |
void *arg); |
pthread_t pthread_self( void ); |
int pthread_equal(pthread_t thread1, pthread_t thread2); |
void pthread_exit(void *retval); |
int pthread_join(pthread_t thread, void **thread_return); |
int pthread_detach(pthread_t thread); |
int pthread_once(pthread_once_t *once_control, |
void (*init_routine)(void)); |
</screen> |
|
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
|
<para> |
<none> |
</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_CREATE_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_MEMALLOC_MALLOC_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_STACK_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_THREADS_MAX is supplied by |
the CYGNUM_POSIX_PTHREAD_THREADS_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_POSIX_MAIN_DEFAULT_PRIORITY option. |
</para> |
</listitem> |
</itemizedlist> |
|
</sect2> |
</sect1> |
|
<!-- }}} --> |
<!-- {{{ Thread-Specific Data --> |
|
<sect1 id="posix-thread-specific-data"> |
<title>Thread-Specific Data [POSIX Section 17]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
int pthread_key_create(pthread_key_t *key, |
void (*destructor)(void *)); |
int pthread_setspecific(pthread_key_t key, const void *pointer); |
void *pthread_getspecific(pthread_key_t key); |
int pthread_key_delete(pthread_key_t key); |
</screen> |
|
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
<para> |
<none> |
</para> |
</sect2> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Notes</title> |
|
<itemizedlist> |
<listitem> |
<para> |
The value of PTHREAD_DESTRUCTOR_ITERATIONS is |
provided by the |
CYGNUM_POSIX_PTHREAD_DESTRUCTOR_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_KEYS_MAX is provided |
by the CYGNUM_POSIX_PTHREAD_KEYS_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 [POSIX Section 18]</title> |
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Implemented</title> |
|
<screen> |
int pthread_cancel(pthread_t thread); |
int pthread_setcancelstate(int state, int *oldstate); |
int pthread_setcanceltype(int type, int *oldtype); |
void pthread_testcancel(void); |
void pthread_cleanup_push( void (*routine)(void *), |
void *arg); |
void pthread_cleanup_pop( int execute); |
</screen> |
</sect2> |
|
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Functions Omitted</title> |
<para> |
<none> |
</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/O Functions</title> |
<screen> |
int ioctl( int fd, CYG_ADDRWORD com, CYG_ADDRWORD data ); |
int select( int nfd, fd_set *in, fd_set *out, fd_set *ex, struct timeval *tv); |
</screen> |
</sect2> |
|
|
<!-- =================================================================== --> |
|
<sect2> |
<title>Socket Functions</title> |
<screen> |
int socket( int domain, int type, int protocol); |
int bind( int s, const struct sockaddr *sa, unsigned int len); |
int listen( int s, int len); |
int accept( int s, struct sockaddr *sa, socklen_t *addrlen); |
int connect( int s, const struct sockaddr *sa, socklen_t len); |
int getpeername( int s, struct sockaddr *sa, socklen_t *len); |
int getsockname( int s, struct sockaddr *sa, socklen_t *len); |
int setsockopt( int s, int level, int optname, const void *optval, |
socklen_t optlen); |
int getsockopt( int s, int level, int optname, void *optval, |
socklen_t *optlen); |
ssize_t recvmsg( int s, struct msghdr *msg, int flags); |
ssize_t recvfrom( int s, void *buf, size_t len, int flags, |
struct sockaddr *from, socklen_t *fromlen); |
ssize_t recv( int s, void *buf, size_t len, int flags); |
ssize_t sendmsg( int s, const struct msghdr *msg, int flags); |
ssize_t sendto( int s, const void *buf, size_t len, int flags, |
const struct sockaddr *to, socklen_t tolen); |
ssize_t send( int s, const void *buf, size_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>[Lewine]</bibliomisc> |
<author> |
<firstname>Donald</firstname> |
<othername>A.</othername> |
<surname>Lweine</surname> |
</author> |
<title>Posix Programmer’s Guide: Writing Portable Unix |
Programs With the POSIX.1 Standard O’Reilly & |
Associates; ISBN: 0937175730.</title></bibliomixed> |
|
<bibliomixed> |
<bibliomisc>[Lewis1]</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>[Lewis2]</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>[Nichols]</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’Reilly Nutshell)</title> |
<publisher><publishername>O’Reilly & Associates</publishername> |
</publisher> |
<isbn>ISBN: 1565921151</isbn> |
</bibliomixed> |
|
<bibliomixed> |
<bibliomisc>[Norton]</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>[POSIX]</bibliomisc> |
<title>Portable Operating System Interface(POSIX) - |
Part 1: System Application Programming Interface (API)[C |
Language]</title> |
<corpauthor>ISO/IEC 9945-1:1996, IEEE</corpauthor></bibliomixed> |
|
<bibliomixed> |
<bibliomisc>[SUS2]</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( ¬ifyme, (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 |