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 + -
显示快捷键?