⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pthread.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 4 页
字号:
//==========================================================================
//
//      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);

    // This assertion mustn't be enabled because sometimes we can legitimately
    // carefully call this as long as we realise the value can be NULL.
    // e.g. consider the use of this when inheriting sigmasks when in the
    // context of creating the main() thread.
//    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 )
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -