pthread.cxx

来自「eCos操作系统源码」· CXX 代码 · 共 1,680 行 · 第 1/4 页

CXX
1,680
字号
    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 )    {        CYG_ASSERT( NULL != self,                    "Attempt to inherit sched policy from non-POSIX thread" );#ifdef CYGDBG_USE_ASSERTS        // paranoia check        int i;        for (i=(sizeof(thread_table)/sizeof(*thread_table))-1; i>=0; i--) {            if (thread_table[i] == self)                break;        }        CYG_ASSERT( i>=0, "Current pthread not found in table" );#endif        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.    if (NULL != self) {        CYG_CHECK_DATA_PTR( self,                            "Attempt to inherit signal mask from bogus pthread" );#ifdef CYGDBG_USE_ASSERTS        // paranoia check        int i;        for (i=(sizeof(thread_table)/sizeof(*thread_table))-1; i>=0; i--) {            if (thread_table[i] == self)                break;        }        CYG_ASSERT( i>=0, "Current pthread not found in table" );#endif    }    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();    // Disable cancellation requests for this thread.  If cleanup    // handlers exist, they will generally be issuing system calls    // to clean up resources.  We want these system calls to run    // without cancelling, and we also want to prevent being    // re-cancelled.    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);    // 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 ) {

⌨️ 快捷键说明

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