pthread.cxx

来自「ecos实时嵌入式操作系统」· CXX 代码 · 共 1,645 行 · 第 1/4 页

CXX
1,645
字号
//==========================================================================////      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 structuresCyg_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 joinedstatic 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 variablesint 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_MALLOCstatic __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 speedstatic __inline__ intcheckforcancel( 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

⌨️ 快捷键说明

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