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

📄 pthread.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 4 页
字号:
    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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -