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

📄 task.c

📁 linux环境支持psos的操作系统。非常适合进行移植的朋友。
💻 C
📖 第 1 页 / 共 4 页
字号:
            *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 + -