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

📄 task.c

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