📄 task.c
字号:
*list_head = new_entry;
#ifdef DIAG_PRINTFS
printf( "\r\nadd susp_tcb @ %p to list @ %p", new_entry,
list_head );
#endif
}
/*
** Initialize the suspended task's pointer back to suspend list
** This is used for cleanup during task deletion by t_delete().
*/
new_entry->suspend_list = list_head;
pthread_mutex_unlock( &task_list_lock );
pthread_cleanup_pop( 0 );
}
}
/*****************************************************************************
** unlink_susp_tcb - removes tcb pointer from a linked list of tcb pointers
** for tasks suspended on the object owning the list.
*****************************************************************************/
void
unlink_susp_tcb( p2pthread_cb_t **list_head, p2pthread_cb_t *entry )
{
p2pthread_cb_t *current_tcb;
if ( list_head != (p2pthread_cb_t **)NULL )
{
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&task_list_lock );
pthread_mutex_lock( &task_list_lock );
if ( *list_head == entry )
{
*list_head = entry->nxt_susp;
#ifdef DIAG_PRINTFS
printf( "\r\ndel susp_tcb @ %p from list @ %p - newlist head %p",
entry, list_head, *list_head );
#endif
}
else
{
for ( current_tcb = *list_head;
current_tcb != (p2pthread_cb_t *)NULL;
current_tcb = current_tcb->nxt_susp )
{
if ( current_tcb->nxt_susp == entry )
{
current_tcb->nxt_susp = entry->nxt_susp;
#ifdef DIAG_PRINTFS
printf( "\r\ndel susp_tcb @ %p from list @ %p", entry,
current_tcb );
#endif
}
}
}
entry->nxt_susp = (p2pthread_cb_t *)NULL;
pthread_mutex_unlock( &task_list_lock );
pthread_cleanup_pop( 0 );
}
}
/*****************************************************************************
** signal_for_my_task - searches the specified 'pended task list' for the
** task to be selected according to the specified
** pend order. If the selected task is the currently
** executing task, the task is deleted from the
** specified pended task list and returns a non-zero
** result... otherwise the pended task list is not
** modified and a zero result is returned.
*****************************************************************************/
int
signal_for_my_task( p2pthread_cb_t **list_head, int pend_order )
{
p2pthread_cb_t *signalled_task;
p2pthread_cb_t *current_tcb;
int result;
result = FALSE;
#ifdef DIAG_PRINTFS
printf( "\r\nsignal_for_my_task - list head = %p", *list_head );
#endif
if ( list_head != (p2pthread_cb_t **)NULL )
{
signalled_task = *list_head;
/*
** First determine which task is being signalled
*/
if ( pend_order != 0 )
{
/*
** Tasks pend in priority order... locate the highest priority
** task in the pended list.
*/
for ( current_tcb = *list_head;
current_tcb != (p2pthread_cb_t *)NULL;
current_tcb = current_tcb->nxt_susp )
{
if ( (current_tcb->prv_priority).sched_priority >
(signalled_task->prv_priority).sched_priority )
signalled_task = current_tcb;
#ifdef DIAG_PRINTFS
printf( "\r\nsignal_for_my_task - tcb @ %p priority %d",
current_tcb,
(current_tcb->prv_priority).sched_priority );
#endif
}
} /*
else
**
** Tasks pend in FIFO order... signal is for task at list head.
*/
/*
** Signalled task located... see if it's the currently executing task.
*/
if ( signalled_task == my_tcb() )
{
/*
** The currently executing task is being signalled...
*/
result = TRUE;
}
#ifdef DIAG_PRINTFS
printf( "\r\nsignal_for_my_task - signalled tcb @ %p my tcb @ %p",
signalled_task, my_tcb() );
#endif
}
return( result );
}
/*****************************************************************************
** new_tid - assigns the next unused task ID for the caller's task
*****************************************************************************/
static ULONG
new_tid( void )
{
p2pthread_cb_t *current_tcb;
ULONG new_taskid;
/*
** Note: since we only read the task_list, so no locking of
** task_list_lock is needed, and you can't only go to the
** last member in task_list to get it's task_id and plus 1.
*/
/*
** Get the highest previously assigned task id and add one.
*/
if ( task_list != (p2pthread_cb_t *)NULL )
{
/*
** One or more tasks already exist in the task list...
** Find the highest task ID number in the existing list.
*/
new_taskid = task_list->taskid;
for ( current_tcb = task_list;
current_tcb->nxt_task != (p2pthread_cb_t *)NULL;
current_tcb = current_tcb->nxt_task )
{
if ( (current_tcb->nxt_task)->taskid > new_taskid )
{
new_taskid = (current_tcb->nxt_task)->taskid;
}
}
/*
** Add one to the highest existing task ID
*/
new_taskid++;
}
else
{
/*
** this is the first task being added to the task list.
*/
new_taskid = 1;
}
return( new_taskid );
}
/*****************************************************************************
** translate_priority - translates a p2pthread priority into a pthreads priority
*****************************************************************************/
static int
translate_priority( ULONG p2pt_priority, int sched_policy, ULONG *errp )
{
int max_priority, min_priority, pthread_priority;
/*
** Validate the range of the user's task priority.
*/
if ( (p2pt_priority < MIN_P2PT_PRIORITY) |
(p2pt_priority > MAX_P2PT_PRIORITY) )
*errp = ERR_PRIOR;
/*
** Translate the p2pthread priority into a pthreads priority.
*/
pthread_priority = (int)p2pt_priority;
/*
** Next get the allowable priority range for the scheduling policy.
*/
min_priority = sched_get_priority_min( sched_policy );
max_priority = sched_get_priority_max( sched_policy );
/*
** Now 'clip' the new priority level to within priority range.
** Reserve max_priority level for temporary use during system calls.
** NOTE that relative p2pthread priorities may not translate properly
** if the p2pthread priorities used span several multiples of max_priority.
*/
pthread_priority %= max_priority;
if ( pthread_priority < min_priority )
pthread_priority = min_priority;
return( pthread_priority );
}
/*****************************************************************************
** tcb_delete - deletes a pthread task control block from the task_list
** and frees the memory allocated for the tcb
*****************************************************************************/
static void
tcb_delete( p2pthread_cb_t *tcb )
{
p2pthread_cb_t *current_tcb;
/*
** If the task_list contains tasks, scan it for a link to the tcb
** being deleted.
*/
if ( task_list != (p2pthread_cb_t *)NULL )
{
/*
** Remove the task from the suspend list for any object it
** is pending on.
*/
unlink_susp_tcb( tcb->suspend_list, tcb );
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&task_list_lock );
pthread_mutex_lock( &task_list_lock );
if ( tcb == task_list )
{
task_list = tcb->nxt_task;
}
else
{
for ( current_tcb = task_list;
current_tcb->nxt_task != (p2pthread_cb_t *)NULL;
current_tcb = current_tcb->nxt_task )
{
if ( tcb == current_tcb->nxt_task )
{
/*
** Found the tcb just prior to the one being deleted.
** Unlink the tcb being deleted from the task_list.
*/
current_tcb->nxt_task = tcb->nxt_task;
break;
}
}
}
pthread_mutex_unlock( &task_list_lock );
pthread_cleanup_pop( 0 );
}
/* Release the memory occupied by the tcb being deleted. */
ts_free( (void *)tcb );
}
/*****************************************************************************
** t_delete - removes the specified task(s) from the task list,
** frees the memory occupied by the task control block(s),
** and kills the pthread(s) associated with the task(s).
*****************************************************************************/
ULONG
t_delete( ULONG tid )
{
p2pthread_cb_t *current_tcb;
p2pthread_cb_t *self_tcb;
ULONG error;
error = ERR_NO_ERROR;
sched_lock();
self_tcb = my_tcb();
if ( tid == 0 )
{
/*
** Delete currently executing task... get its pthread ID
*/
if ( self_tcb != (p2pthread_cb_t *)NULL )
{
/*
** Kill the currently executing task's pthread and
** then de-allocate its data structures.
*/
/* POSIX threads can exist in either the ‘joinable’ state
** or the ‘detached’ state. A given pthread or process
** can wait for a joinable pthread to terminate. At this time,
** the process or pthread waiting on the terminating pthread
** obtains an exit status from the pthread and then the terminating
** pthread’s resources are released. A ‘detached’pthread has
** effectively been told that no other process or pthread cares when
** it terminates. This means that when the ‘detached’ pthread
** terminates, its resources are released immediately and no other
** process or pthread can receive termination notice or an exit status.
** If the pthread is deleting itself it must be ‘detached’ in order
** to free its Linux resources upon termination.
*/
pthread_detach( self_tcb->pthrid );
pthread_cleanup_push( (void(*)(void *))tcb_delete,
(void *)self_tcb );
pthread_exit( ( void *)NULL );
/*
** Because pthread_exit is also a termination point func,
** so the arg of pthread_cleanup_pop is 0, and it's still
** that the function tcb_delete() will be called.
*/
pthread_cleanup_pop( 0 );
}
else
error = ERR_OBJDEL;
}
else
{
/*
** Delete the task whose taskid matches tid.
** If the task_list contains tasks, scan it for the tcb
** whose task id matches the one to be deleted.
*/
current_tcb = tcb_for( tid );
if ( current_tcb != (p2pthread_cb_t *)NULL )
{
/*
** Found the task being deleted... delete it.
*/
if ( current_tcb != self_tcb )
{
/*
** Task being deleted is not the current task.
** Kill the task pthread and wait for it to die.
** Then de-allocate its data structures.
*/
pthread_cancel( current_tcb->pthrid );
pthread_join( current_tcb->pthrid, (void **)NULL );
tcb_delete( current_tcb );
}
else
{
/*
** Kill the currently executing task's pthread
** and then de-allocate its data structures.
*/
pthread_detach( self_tcb->pthrid );
pthread_cleanup_push( (void(*)(void *))tcb_delete,
(void *)self_tcb );
pthread_exit( ( void *)NULL );
pthread_cleanup_pop( 0 );
}
}
else
error = ERR_OBJDEL;
}
sched_unlock();
return( error );
}
/*****************************************************************************
** cleanup_scheduler_lock ensures that a killed pthread releases the
** scheduler lock if it owned it.
*****************************************************************************/
static void
cleanup_scheduler_lock( void *tcb )
{
p2pthread_cb_t *mytcb;
mytcb = (p2pthread_cb_t *)tcb;
pthread_mutex_lock( &p2pt_sched_lock );
if ( scheduler_locked == pthread_self() )
{
sched_lock_level = 0;
scheduler_locked = (pthread_t)NULL;
}
pthread_mutex_unlock( &p2pt_sched_lock );
}
/*****************************************************************************
** task_wrapper is a pthread used to 'contain' a p2pthread task.
*****************************************************************************/
static void *
task_wrapper( void *arg )
{
p2pthread_cb_t *tcb;
p2pthread_pb_t *parmblk;
void (*task_ptr)( ULONG, ULONG, ULONG, ULONG );
/*
** Make a parameter block pointer from the caller's argument
** Then extract the needed info from the parameter block and
** free its memory before beginning the p2pthread task
*/
parmblk = (p2pthread_pb_t *)arg;
tcb = parmblk->tcb;
task_ptr = parmblk->task_ptr;
/*
** Note: ensure that this pthread will release the scheduler lock if killed.
*/
pthread_cleanup_push( cleanup_scheduler_lock, (void *)tcb );
/*
** Call the p2pthread task. Normally this is an endless loop and doesn't
** return here.
*/
#ifdef DIAG_PRINTFS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -