📄 pthread.cxx
字号:
// The parameters seem OK, change the thread...
pthread_mutex.lock();
pthread_info *thread = pthread_info_id( thread_id );
if( thread == NULL )
{
pthread_mutex.unlock();
PTHREAD_RETURN(ESRCH);
}
thread->attr.schedpolicy = policy;
thread->attr.schedparam = *param;
if ( policy == SCHED_FIFO )
thread->thread->timeslice_disable();
else thread->thread->timeslice_enable();
thread->thread->set_priority( PTHREAD_ECOS_PRIORITY( param->sched_priority ));
pthread_mutex.unlock();
PTHREAD_RETURN(0);
}
//-----------------------------------------------------------------------------
// Get scheduling policy and parameters for the thread
externC int pthread_getschedparam (pthread_t thread_id,
int *policy,
struct sched_param *param)
{
PTHREAD_ENTRY();
pthread_mutex.lock();
pthread_info *thread = pthread_info_id( thread_id );
if( thread == NULL )
{
pthread_mutex.unlock();
PTHREAD_RETURN(ESRCH);
}
if( policy != NULL )
*policy = thread->attr.schedpolicy;
if( param != NULL )
*param = thread->attr.schedparam;
pthread_mutex.unlock();
PTHREAD_RETURN(0);
}
//=============================================================================
// Dynamic package initialization
// Call init_routine just the once per control variable.
externC int pthread_once (pthread_once_t *once_control,
void (*init_routine) (void))
{
PTHREAD_ENTRY();
PTHREAD_CHECK( once_control );
PTHREAD_CHECK( init_routine );
pthread_once_t old;
// Do a test and set on the once_control object.
pthread_mutex.lock();
old = *once_control;
*once_control = 1;
pthread_mutex.unlock();
// If the once_control was zero, call the init_routine().
if( !old ) init_routine();
PTHREAD_RETURN(0);
}
//=============================================================================
//Thread specific data
//-----------------------------------------------------------------------------
// Create a key to identify a location in the thread specific data area.
// Each thread has its own distinct thread-specific data area but all are
// addressed by the same keys. The destructor function is called whenever a
// thread exits and the value associated with the key is non-NULL.
externC int pthread_key_create (pthread_key_t *key,
void (*destructor) (void *))
{
PTHREAD_ENTRY();
pthread_key_t k = -1;
pthread_mutex.lock();
// Find a key to allocate
for( cyg_ucount32 i = 0; i < (PTHREAD_KEYS_MAX/KEY_MAP_TYPE_SIZE); i++ )
{
if( thread_key[i] != 0 )
{
// We have a table slot with space available
// Get index of ls set bit.
HAL_LSBIT_INDEX( k, thread_key[i] );
// clear it
thread_key[i] &= ~(1<<k);
// Add index of word
k += i * KEY_MAP_TYPE_SIZE;
// Install destructor
key_destructor[k] = destructor;
// break out with key found
break;
}
}
if( k != -1 )
{
// plant a NULL in all the valid thread data slots for this
// key in case we are reusing a key we used before.
for( cyg_ucount32 i = 0; i < CYGNUM_POSIX_PTHREAD_THREADS_MAX ; i++ )
{
pthread_info *thread = thread_table[i];
if( thread != NULL && thread->thread_data != NULL )
thread->thread_data[k] = NULL;
}
}
pthread_mutex.unlock();
if( k == -1 ) PTHREAD_RETURN(EAGAIN);
*key = k;
PTHREAD_RETURN(0);
}
//-----------------------------------------------------------------------------
// Delete key.
externC int pthread_key_delete (pthread_key_t key)
{
PTHREAD_ENTRY();
pthread_mutex.lock();
// Set the key bit to 1 to indicate it is free.
thread_key[key/KEY_MAP_TYPE_SIZE] |= 1<<(key%(KEY_MAP_TYPE_SIZE));
pthread_mutex.unlock();
PTHREAD_RETURN(0);
}
//-----------------------------------------------------------------------------
// Store the pointer value in the thread-specific data slot addressed
// by the key.
externC int pthread_setspecific (pthread_key_t key, const void *pointer)
{
PTHREAD_ENTRY();
if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
PTHREAD_RETURN(EINVAL);
pthread_info *self = pthread_self_info();
if( self->thread_data == NULL )
{
// Allocate the per-thread data table
self->thread_data =
(void **)self->thread->increment_stack_limit(
PTHREAD_KEYS_MAX * sizeof(void *) );
// Clear out all entries
for( int i = 0; i < PTHREAD_KEYS_MAX; i++ )
self->thread_data[i] = NULL;
}
self->thread_data[key] = (void *)pointer;
PTHREAD_RETURN(0);
}
//-----------------------------------------------------------------------------
// Retrieve the pointer value in the thread-specific data slot addressed
// by the key.
externC void *pthread_getspecific (pthread_key_t key)
{
void *val;
PTHREAD_ENTRY();
if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
PTHREAD_RETURN(NULL);
pthread_info *self = pthread_self_info();
if( self->thread_data == NULL )
val = NULL;
else val = self->thread_data[key];
PTHREAD_RETURN(val);
}
//=============================================================================
// Thread Cancellation Functions
//-----------------------------------------------------------------------------
// Set cancel state of current thread to ENABLE or DISABLE.
// Returns old state in *oldstate.
externC int pthread_setcancelstate (int state, int *oldstate)
{
PTHREAD_ENTRY();
if( state != PTHREAD_CANCEL_ENABLE &&
state != PTHREAD_CANCEL_DISABLE )
PTHREAD_RETURN(EINVAL);
pthread_mutex.lock();
pthread_info *self = pthread_self_info();
if( oldstate != NULL ) *oldstate = self->cancelstate;
self->cancelstate = state;
pthread_mutex.unlock();
// Note: This function may have made it possible for a pending
// cancellation to now be delivered. However the standard does not
// list this function as a cancellation point, so for now we do
// nothing. In future we might call pthread_testcancel() here.
PTHREAD_RETURN(0);
}
//-----------------------------------------------------------------------------
// Set cancel type of current thread to ASYNCHRONOUS or DEFERRED.
// Returns old type in *oldtype.
externC int pthread_setcanceltype (int type, int *oldtype)
{
PTHREAD_ENTRY();
if( type != PTHREAD_CANCEL_ASYNCHRONOUS &&
type != PTHREAD_CANCEL_DEFERRED )
PTHREAD_RETURN(EINVAL);
pthread_mutex.lock();
pthread_info *self = pthread_self_info();
if( oldtype != NULL ) *oldtype = self->canceltype;
self->canceltype = type;
pthread_mutex.unlock();
// Note: This function may have made it possible for a pending
// cancellation to now be delivered. However the standard does not
// list this function as a cancellation point, so for now we do
// nothing. In future we might call pthread_testcancel() here.
PTHREAD_RETURN(0);
}
//-----------------------------------------------------------------------------
// Cancel the thread.
externC int pthread_cancel (pthread_t thread)
{
PTHREAD_ENTRY();
pthread_mutex.lock();
pthread_info *th = pthread_info_id(thread);
if( th == NULL )
{
pthread_mutex.unlock();
PTHREAD_RETURN(ESRCH);
}
th->cancelpending = true;
if ( th->cancelstate == PTHREAD_CANCEL_ENABLE )
{
if ( th->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS )
{
// If the thread has cancellation enabled, and it is in
// asynchronous mode, set the eCos thread's ASR pending to
// deal with it when the thread wakes up. We also release the
// thread out of any current wait to make it wake up.
th->thread->set_asr_pending();
th->thread->release();
}
else if ( th->canceltype == PTHREAD_CANCEL_DEFERRED )
{
// If the thread has cancellation enabled, and it is in
// deferred mode, wake the thread up so that cancellation
// points can test for cancellation.
th->thread->release();
}
else
CYG_FAIL("Unknown cancellation type");
}
// Otherwise the thread has cancellation disabled, in which case
// it is up to the thread to enable cancellation
pthread_mutex.unlock();
PTHREAD_RETURN(0);
}
//-----------------------------------------------------------------------------
// Test for a pending cancellation for the current thread and terminate
// the thread if there is one.
externC void pthread_testcancel (void)
{
PTHREAD_ENTRY_VOID();
if( checkforcancel() )
{
// If we have cancellation enabled, and there is a cancellation
// pending, then go ahead and do the deed.
// Exit now with special retval. pthread_exit() calls the
// cancellation handlers implicitly.
pthread_exit(PTHREAD_CANCELED);
}
PTHREAD_RETURN_VOID;
}
//-----------------------------------------------------------------------------
// These two functions actually implement the cleanup push and pop functionality.
externC void pthread_cleanup_push_inner (struct pthread_cleanup_buffer *buffer,
void (*routine) (void *),
void *arg)
{
PTHREAD_ENTRY();
pthread_info *self = pthread_self_info();
buffer->routine = routine;
buffer->arg = arg;
buffer->prev = self->cancelbuffer;
self->cancelbuffer = buffer;
return;
}
externC void pthread_cleanup_pop_inner (struct pthread_cleanup_buffer *buffer,
int execute)
{
PTHREAD_ENTRY();
pthread_info *self = pthread_self_info();
CYG_ASSERT( self->cancelbuffer == buffer, "Stacking error in cleanup buffers");
if( self->cancelbuffer == buffer )
{
// Remove the buffer from the stack
self->cancelbuffer = buffer->prev;
}
else
{
// If the top of the stack is not the buffer we expect, do not
// execute it.
execute = 0;
}
if( execute ) buffer->routine(buffer->arg);
return;
}
// -------------------------------------------------------------------------
// eCos-specific function to measure stack usage of the supplied thread
#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
externC size_t pthread_measure_stack_usage (pthread_t thread)
{
pthread_info *th = pthread_info_id(thread);
if ( NULL == th )
return (size_t)-1;
return (size_t)th->thread->measure_stack_usage();
}
#endif
// -------------------------------------------------------------------------
// EOF pthread.cxx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -