📄 task.c
字号:
printf( "\r\ntask_wrapper starting task @ %p tcb @ %p:", task_ptr, tcb );
sleep( 1 );
#endif
(*task_ptr)( parmblk->parms[0], parmblk->parms[1], parmblk->parms[2],
parmblk->parms[3] );
/*
** Note: here the arg is '1'.
** If for some reason the task above DOES return, clean up the
** pthread and task resources and kill the pthread.
*/
pthread_cleanup_pop( 1 );
/*
** NOTE t_delete takes no action if the task has already been deleted.
*/
t_delete( tcb->taskid );
return( (void *)NULL );
}
/*****************************************************************************
** t_create - creates a pthread to contain the specified p2pthread task and
** initializes the requisite data structures to support p2pthread
** task behavior not directly supported by Posix threads.
*****************************************************************************/
ULONG
t_create( char name[4], ULONG pri, ULONG sstack, ULONG ustack, ULONG mode,
ULONG *tid )
{
p2pthread_cb_t *tcb;
p2pthread_cb_t *current_tcb;
int i, new_priority;
ULONG error, my_tid;
error = ERR_NO_ERROR;
/*
** Establish task identifier
*/
my_tid = new_tid();
if ( tid != (ULONG *)NULL )
*tid = my_tid;
/* First allocate memory for a new pthread task control block */
tcb = ts_malloc( sizeof( p2pthread_cb_t ) );
if ( tcb != (p2pthread_cb_t *)NULL )
{
pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
(void *)&task_list_lock );
pthread_mutex_lock( &task_list_lock );
/*
** Got a new task control block. Initialize it.
*/
tcb->pthrid = (pthread_t)NULL;
tcb->taskid = my_tid;
/*
** Copy the task name
*/
for ( i = 0; i < 4; i++ )
tcb->taskname[i] = name[i];
/*
** Initialize the thread attributes to default values.
** Then modify the attributes to make a real-time thread.
*/
pthread_attr_init( &(tcb->attr) );
/*
** Get the default scheduling priority & init prv_priority member
*/
pthread_attr_getschedparam( &(tcb->attr), &(tcb->prv_priority) );
/*
** Translate the p2pthread priority into a pthreads priority
** and set the new scheduling priority.
*/
pthread_attr_setschedpolicy( &(tcb->attr), SCHED_FIFO );
new_priority = translate_priority( pri, SCHED_FIFO, &error );
(tcb->prv_priority).sched_priority = new_priority;
pthread_attr_setschedparam( &(tcb->attr), &(tcb->prv_priority) );
/*
** 'Registers' for task
*/
for ( i = 1; i < 8; i++ )
tcb->registers[i] = (ULONG)NULL;
/*
** Mutex and Condition variable for task events
*/
pthread_mutex_init( &(tcb->event_lock), (pthread_mutexattr_t *)NULL );
pthread_cond_init( &(tcb->event_change), (pthread_condattr_t *)NULL );
/*
** Event state to awaken task (if suspended)
*/
tcb->event_mask = (ULONG)NULL;
/*
** Current state of captured event flags for task
*/
tcb->events_captured = (ULONG)NULL;
/*
** Current state of pending event flags for task
*/
tcb->events_pending = (ULONG)NULL;
/*
** The task is initially created in a suspended state
*/
tcb->suspend_reason = WAIT_TSTRT;
tcb->suspend_list = (p2pthread_cb_t **)NULL;
tcb->nxt_susp = (p2pthread_cb_t *)NULL;
tcb->nxt_task = (p2pthread_cb_t *)NULL;
/*
** If everything's okay thus far, we have a valid TCB ready to go.
*/
if ( error == ERR_NO_ERROR )
{
/*
** Insert the task control block into the task list.
** First see if the task list contains any tasks yet.
*/
if ( task_list == (p2pthread_cb_t *)NULL )
{
task_list = tcb;
}
else
{
/*
** Append the new tcb to the task list.
*/
for ( current_tcb = task_list;
current_tcb->nxt_task != (p2pthread_cb_t *)NULL;
current_tcb = current_tcb->nxt_task );
current_tcb->nxt_task = tcb;
}
}
else
{
/*
** OOPS! Something went wrong... clean up & exit.
*/
ts_free( (void *)tcb );
}
pthread_mutex_unlock( &task_list_lock );
pthread_cleanup_pop( 0 );
}
else /* malloc failed */
{
error = ERR_OBJTFULL;
}
return( error );
}
/*****************************************************************************
** t_start - creates a pthread to contain the specified p2pthread task and
** initializes the requisite data structures to support p2pthread
** task behavior not directly supported by Posix threads.
*****************************************************************************/
ULONG
t_start( ULONG tid, ULONG mode,
void (*task)( ULONG, ULONG, ULONG, ULONG ), ULONG parms[4] )
{
p2pthread_cb_t *tcb;
p2pthread_pb_t *parmblk;
int sched_policy;
ULONG error;
error = ERR_NO_ERROR;
/*
** 'Lock the p2pthread scheduler' to defer any context switch to a higher
** priority task until after this call has completed its work.
*/
sched_lock();
tcb = tcb_for( tid );
if ( tcb != (p2pthread_cb_t *)NULL )
{
/*
** Found our task control block.
** Init the parameter block for the task wrapper function and
** start a new real-time pthread for the task.
*/
if ( tcb->suspend_reason == WAIT_TSTRT )
{
tcb->suspend_reason = WAIT_READY;
tcb->entry_point = task;
/*
** Mode flags for task
*/
tcb->flags = mode;
pthread_attr_init(&(tcb->attr));
/*
** Determine whether round-robin time-slicing is to be used or not
*/
if ( mode & T_TSLICE )
sched_policy = SCHED_RR;
else
sched_policy = SCHED_FIFO;
pthread_attr_setschedpolicy( &(tcb->attr), sched_policy);
parmblk =
(p2pthread_pb_t *)ts_malloc( sizeof( p2pthread_pb_t ) );
if ( parmblk != (p2pthread_pb_t *)NULL )
{
parmblk->tcb = tcb;
parmblk->task_ptr = task;
if ( parms != (ULONG *)NULL )
{
parmblk->parms[0] = parms[0];
parmblk->parms[1] = parms[1];
parmblk->parms[2] = parms[2];
parmblk->parms[3] = parms[3];
}
else
{
parmblk->parms[0] = (ULONG)NULL;
parmblk->parms[1] = (ULONG)NULL;
parmblk->parms[2] = (ULONG)NULL;
parmblk->parms[3] = (ULONG)NULL;
}
#ifdef DIAG_PRINTFS
printf( "\r\nt_start task @ %p tcb @ %p:", task, tcb );
#endif
if ( pthread_create( &(tcb->pthrid), &(tcb->attr),
task_wrapper, (void *)parmblk ) != 0 )
{
#ifdef DIAG_PRINTFS
perror( "\r\nt_start pthread_create returned error:" );
#endif
error = ERR_OBJDEL;
tcb_delete( tcb );
}
}
else
{
#ifdef DIAG_PRINTFS
printf( "\r\nt_start unable to allocate parameter block" );
#endif
error = ERR_OBJDEL;
tcb_delete( tcb );
}
}
else
{
/*
** task already made runnable
*/
error = ERR_ACTIVE;
#ifdef DIAG_PRINTFS
printf( "\r\nt_start task @ tcb %p already active", tcb );
#endif
}
}
else
error = ERR_OBJDEL;
/*
** 'Unlock the p2pthread scheduler' to enable a possible context switch
** to a task made runnable by this call.
*/
sched_unlock();
return( error );
}
/*****************************************************************************
** t_suspend - suspends the specified p2pthread task
*****************************************************************************/
ULONG
t_suspend( ULONG tid )
{
p2pthread_cb_t *current_tcb;
p2pthread_cb_t *self_tcb;
ULONG error;
error = ERR_NO_ERROR;
self_tcb = my_tcb();
if ( tid == 0 )
{
/*
** Suspend currently executing task... get its pthread ID
*/
if ( self_tcb != (p2pthread_cb_t *)NULL )
{
/*
** Don't suspend if currently executing task has the
** scheduler locked!
*/
pthread_mutex_lock( &p2pt_sched_lock );
if ( scheduler_locked == pthread_self() )
{
if ( sched_lock_level < 1L )
{
/*
** Suspend the currently executing task's pthread
*/
pthread_mutex_unlock( &p2pt_sched_lock );
self_tcb->suspend_reason = WAIT_TSUSP;
pthread_kill( self_tcb->pthrid, SIGSTOP );
}
else
/*
** Note: it seems that this condition did not suspend
** the task and no errno returned.
*/
pthread_mutex_unlock( &p2pt_sched_lock );
}
else
{
/*
** Suspend the currently executing task's pthread
*/
pthread_mutex_unlock( &p2pt_sched_lock );
self_tcb->suspend_reason = WAIT_TSUSP;
pthread_kill( self_tcb->pthrid, SIGSTOP );
}
}
}
else
{
/*
** Suspend 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 suspended.
*/
current_tcb = tcb_for( tid );
if ( current_tcb != (p2pthread_cb_t *)NULL )
{
/*
** Suspend task if task not already suspended.
*/
if ( current_tcb->suspend_reason != WAIT_TSUSP )
{
/*
** set this pthread as the hignest priority, so
that the tid task are not locked.
*/
sched_lock();
/*
** Found the task being suspended... suspend it.
*/
if ( current_tcb != self_tcb )
{
/*
** Task being suspended is not the current task.
*/
current_tcb->suspend_reason = WAIT_TSUSP;
pthread_kill( current_tcb->pthrid, SIGSTOP );
sched_unlock();
}
else
{
/*
** Suspend the currently executing task's pthread
** if it doesn't have the scheduler locked.
*/
sched_unlock();
pthread_mutex_lock( &p2pt_sched_lock );
if ( scheduler_locked == pthread_self() )
{
pthread_mutex_unlock( &p2pt_sched_lock );
}
else
{
/*
** Suspend the currently executing pthread
*/
pthread_mutex_unlock( &p2pt_sched_lock );
self_tcb->suspend_reason = WAIT_TSUSP;
pthread_kill( self_tcb->pthrid, SIGSTOP );
}
}
}
else
{
error = ERR_SUSP;
}
}
else
error = ERR_OBJDEL;
}
return( error );
}
/*****************************************************************************
** t_resume - resume the specified p2pthread task
*****************************************************************************/
ULONG
t_resume( ULONG tid )
{
p2pthread_cb_t *current_tcb;
p2pthread_cb_t *self_tcb;
ULONG error;
error = ERR_NO_ERROR;
sched_lock();
self_tcb = my_tcb();
/*
** Resume 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 resumed.
*/
current_tcb = tcb_for( tid );
if ( current_tcb != (p2pthread_cb_t *)NULL )
{
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -