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