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

📄 task.c

📁 linux环境支持psos的操作系统。非常适合进行移植的朋友。
💻 C
📖 第 1 页 / 共 4 页
字号:
/*****************************************************************************
 * task.c - defines the wrapper functions and data structures needed
 *          to implement a Wind River pSOS+ (R) task control API 
 *          in a POSIX Threads environment.
 ****************************************************************************/

#include <errno.h>
#include <unistd.h>
#include <sched.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>
#include "p2pthread.h"

#undef DIAG_PRINTFS

#define T_NOPREEMPT  0x01
#define T_TSLICE     0x02

#define ERR_TIMEOUT  0x01
#define ERR_NODENO   0x04
#define ERR_OBJDEL   0x05
#define ERR_OBJTFULL 0x08
#define ERR_OBJNF    0x09

#define ERR_PRIOR    0x11
#define ERR_ACTIVE   0x12
#define ERR_SUSP     0x14
#define ERR_NOTSUSP  0x15
#define ERR_REGNUM   0x17

/*
**  user_sysroot is a user-defined function.  It contains all initialization
**               calls to create any tasks and other objects reqired for
**               startup of the user's RTOS system environment.  It is called
**               from (and runs in) the system initialization pthread context.
**               It may optionally wait for some condition, shut down the
**               user's RTOS system environment, clean up the resources used
**               by the various RTOS objects, and return to the initialization
**               pthread.  The system initialization pthread will then
**               terminate, as will the parent process.
*/
// extern void user_sysroot( void );

/*****************************************************************************
**  p2pthread Global Data Structures
*****************************************************************************/

/*
**  task_list is a linked list of pthread task control blocks.
**            It is used to perform en-masse operations on all p2pthread
**            tasks at once.
*/
static p2pthread_cb_t *
    task_list = (p2pthread_cb_t *)NULL;

/*
**  task_list_lock is a mutex used to serialize access to the task list
*/
static pthread_mutex_t
    task_list_lock = PTHREAD_MUTEX_INITIALIZER;

/*
**  p2pt_sched_lock is a mutex used to make sched_lock exclusive to one thread
**                  at a time.
*/
pthread_mutex_t
    p2pt_sched_lock = PTHREAD_MUTEX_INITIALIZER;

/*
**  scheduler_locked contains the pthread ID of the thread which currently
**                   has the scheduler locked (or NULL if it is unlocked).
*/
static pthread_t
    scheduler_locked = (pthread_t)NULL;

/*
**  sched_lock_level tracks recursive nesting levels of sched_lock/unlock calls
**                   so the scheduler is only unlocked at the outermost
**                   sched_unlock call.
*/
static unsigned long
    sched_lock_level = 0;

/*
**  sched_lock_change is a condition variable which signals a change from
**                    locked to unlocked or vice-versa.
*/
static pthread_cond_t
    sched_lock_change = PTHREAD_COND_INITIALIZER;

/*****************************************************************************
**  thread-safe malloc
*****************************************************************************/
void *ts_malloc( size_t blksize )
{
    void *blkaddr;
    static pthread_mutex_t
        malloc_lock = PTHREAD_MUTEX_INITIALIZER;

    pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
                          (void *)&malloc_lock );
    pthread_mutex_lock( &malloc_lock );

    blkaddr = malloc( blksize );

    pthread_mutex_unlock( &malloc_lock );
    pthread_cleanup_pop( 0 );

    return( blkaddr );
}
    
/*****************************************************************************
**  thread-safe free
*****************************************************************************/
void ts_free( void *blkaddr )

{
    static pthread_mutex_t
        free_lock = PTHREAD_MUTEX_INITIALIZER;

    pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
                          (void *)&free_lock );
    pthread_mutex_lock( &free_lock );

    free( blkaddr );

    pthread_mutex_unlock( &free_lock );
    pthread_cleanup_pop( 0 );
}
    
/*****************************************************************************
**  my_tcb - returns a pointer to the task control block for the calling task
*****************************************************************************/
p2pthread_cb_t *
   my_tcb( void )
{
    pthread_t my_pthrid;
    p2pthread_cb_t *current_tcb;

    /*
    **  Get caller's pthread ID
    */
    my_pthrid = pthread_self();

    /*
    **  If the task_list contains tasks, scan it for the tcb
    **  whose thread id matches the one to be deleted.  No locking
    **  of the task list is done here since the access is read-only.
    **  NOTE that a tcb being appended to the task_list MUST have its
    **  nxt_task member initialized to NULL before being linked into
    **  the list. 
    */
    if ( task_list != (p2pthread_cb_t *)NULL )
    {
        for ( current_tcb = task_list;
              current_tcb != (p2pthread_cb_t *)NULL;
              current_tcb = current_tcb->nxt_task )
        {
            if ( my_pthrid == current_tcb->pthrid )
            {
                /*
                **  Found the task control_block.
                */
                return( current_tcb );
            }
        }
    }

    /*
    **  No matching task found... return NULL
    */
    return( (p2pthread_cb_t *)NULL );
}

/*****************************************************************************
** tcb_for - returns the address of the task control block for the task
**           idenified by taskid
*****************************************************************************/
p2pthread_cb_t *
   tcb_for( ULONG taskid )
{
    p2pthread_cb_t *current_tcb;
    int found_taskid;

        if ( task_list != (p2pthread_cb_t *)NULL )
        {
            /*
            **  One or more tasks already exist in the task list...
            **  Scan the existing tasks for a matching ID.
            */
            found_taskid = FALSE;
            for ( current_tcb = task_list; 
                  current_tcb != (p2pthread_cb_t *)NULL;
                  current_tcb = current_tcb->nxt_task )
            {
                if ( current_tcb->taskid == taskid )
                {
                    found_taskid = TRUE;
                    break;
                }
            }
            if ( found_taskid == FALSE )
                /*
                **  No matching ID found
                */
                current_tcb = (p2pthread_cb_t *)NULL;
        }
        else
            current_tcb = (p2pthread_cb_t *)NULL;
 
    return( current_tcb );
}

/*****************************************************************************
** sched_lock - 'locks the scheduler' to prevent preemption of the current task
**           by other task-level code.  Because we cannot actually lock the
**           scheduler in a pthreads environment, we temporarily set the
**           dynamic priority of the calling thread above that of any other
**           thread, thus guaranteeing that no other tasks preempt it.
*****************************************************************************/
void
   sched_lock( void )
{
    pthread_t my_pthrid;
    p2pthread_cb_t *tcb;
    int max_priority, sched_policy, got_lock;

    /*
    **  p2pt_sched_lock ensures that only one p2pthread pthread at a time gets
    **  to run at max_priority (effectively locking out all other p2pthread
    **  pthreads).  Due to the semantics of the pthread_cleanup push/pop
    **  pairs (which protect against deadlocks in the event a thread gets
    **  terminated while holding the mutex lock), we cannot safely leave
    **  the mutex itself locked until sched_unlock() is called.  Therefore,
    **  we instead use the mutex to provide 'atomic access' to a global
    **  flag indicating if the scheduler is currently locked.  We will
    **  'spin' and briefly suspend until the scheduler is unlocked, and
    **  will then lock it ourselves before proceeding.
    */
    got_lock = FALSE;
    my_pthrid = pthread_self();

    /*
    **  'Spin' here until scheduler_locked == NULL or our pthread ID
    **  This effectively prevents more than one pthread at a time from
    **  setting its priority to max_priority.
    */
    do {
        /*
        **  The pthread_cleanup_push/pop pair ensure the mutex will be
        **  unlocked if the calling thread gets killed within this loop.
        */
        pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
                              (void *)&p2pt_sched_lock );
        /*
        **  The mutex lock/unlock guarantees 'atomic' access to the
        **  scheduler_locked flag.  Locking via pthread ID allows recursive
        **  locking by the same pthread while excluding all other pthreads.
        */
        pthread_mutex_lock( &p2pt_sched_lock );
        if ( (scheduler_locked == (pthread_t)NULL) ||
             (scheduler_locked == my_pthrid) )
        {
            scheduler_locked = my_pthrid;
            sched_lock_level++;
			/* 
			**  Note: since the type of 'sched_lock_level is defined as

			**	'unsigned', so the condition below is only occur when 
			**  sched_lock_level exceed it's maxium value. It's a bug 
			**  although it is right in most of time.
            */
            if ( sched_lock_level == 0L )
                sched_lock_level--;
            got_lock = TRUE;
			/* 
			**  Note: i think maybe the statement below is useless.
			*/
			pthread_cond_broadcast( &sched_lock_change );
#ifdef DIAG_PRINTFS 
            printf( "\r\nsched_lock sched_lock_level %lu locking tid %ld",
                sched_lock_level,  scheduler_locked );
#endif
        }
        else
        {
#ifdef DIAG_PRINTFS 
            printf( "\r\nsched_lock locking tid %ld my tid %ld",
                    scheduler_locked, my_pthrid );
#endif
            pthread_cond_wait( &sched_lock_change, &p2pt_sched_lock );
        }
        pthread_mutex_unlock( &p2pt_sched_lock );

        /*
        **  Add a cancellation point to this loop, since there are no others.
        */
        pthread_testcancel();
        pthread_cleanup_pop( 0 );
    } while ( got_lock == FALSE );

    /*
    **  task_list_lock prevents other p2pthread pthreads from modifying
    **  the p2pthread pthread task list while we're searching it and modifying
    **  the calling task's priority level.
    */
    pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
                          (void *)&task_list_lock );
    pthread_mutex_lock( &task_list_lock );
    tcb = my_tcb();
    if ( tcb != (p2pthread_cb_t *)NULL )
    {
        pthread_attr_getschedpolicy( &(tcb->attr), &sched_policy );
        max_priority = sched_get_priority_max( sched_policy );
        ((tcb->attr).__schedparam).sched_priority = max_priority;
		/*
		** Note: here we set the priority for the given pthread.
		*/
        pthread_setschedparam( tcb->pthrid, sched_policy,
                          (struct sched_param *)&((tcb->attr).__schedparam) );
    }
    pthread_mutex_unlock( &task_list_lock );
    pthread_cleanup_pop( 0 );
}

/*****************************************************************************
** sched_unlock - 'unlocks the scheduler' to allow preemption of the current
**             task by other task-level code.  Because we cannot actually lock
**             the scheduler in a pthreads environment, the dynamic priority of
**             the calling thread was temporarily raised above that of any
**             other thread.  Therefore, we now restore the priority of the
**             calling thread to its original value to 'unlock' the task
**             scheduler.
*****************************************************************************/
void
   sched_unlock( void )
{
    p2pthread_cb_t *tcb;
    int sched_policy;

    /*
    **  scheduler_locked ensures that only one p2pthread pthread at a time gets
    **  to run at max_priority (effectively locking out all other p2pthread
    **  pthreads).  Unlock it here to complete 'unlocking' of the scheduler.
    */
    pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
                          (void *)&p2pt_sched_lock );
    pthread_mutex_lock( &p2pt_sched_lock );

    if ( scheduler_locked == pthread_self() )
    {
        if ( sched_lock_level > 0L )
            sched_lock_level--;
        if ( sched_lock_level < 1L )
        {
            /*
            **  task_list_lock prevents other p2pthread pthreads from modifying
            **  the p2pthread pthread task list while we're searching it and
            **  modifying the calling task's priority level.
            */
            pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,
                                  (void *)&task_list_lock );
            pthread_mutex_lock( &task_list_lock );
            tcb = my_tcb();
            if ( tcb != (p2pthread_cb_t *)NULL )
            {
                pthread_attr_getschedpolicy( &(tcb->attr), &sched_policy );
                ((tcb->attr).__schedparam).sched_priority = 
                                           tcb->prv_priority.sched_priority;
                pthread_setschedparam( tcb->pthrid, sched_policy,
                          (struct sched_param *)&((tcb->attr).__schedparam) );
            }
            pthread_mutex_unlock( &task_list_lock );
            pthread_cleanup_pop( 0 );

            scheduler_locked = (pthread_t)NULL;
            pthread_cond_broadcast( &sched_lock_change );
        }
#ifdef DIAG_PRINTFS 
        printf( "\r\nsched_unlock sched_lock_level %lu locking tid %ld",
                sched_lock_level,  scheduler_locked );
#endif
    }
#ifdef DIAG_PRINTFS 
    else
        printf( "\r\nsched_unlock locking tid %ld my tid %ld", scheduler_locked,
                pthread_self() );
#endif

    pthread_mutex_unlock( &p2pt_sched_lock );
    pthread_cleanup_pop( 0 );
}

/*****************************************************************************
** link_susp_tcb - appends a new tcb pointer to a linked list of tcb pointers
**                 for tasks suspended on the object owning the list.
*****************************************************************************/
void
   link_susp_tcb( p2pthread_cb_t **list_head, p2pthread_cb_t *new_entry )
{
    p2pthread_cb_t *nxt_entry;

    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 );
        new_entry->nxt_susp = (p2pthread_cb_t *)NULL;
        if ( *list_head != (p2pthread_cb_t *)NULL )
        {
            for ( nxt_entry = *list_head; 
                  nxt_entry->nxt_susp != (p2pthread_cb_t *)NULL;
                  nxt_entry = nxt_entry->nxt_susp ) ;
            nxt_entry->nxt_susp = new_entry;
#ifdef DIAG_PRINTFS 
            printf( "\r\nadd susp_tcb @ %p to list @ %p", new_entry,
                    nxt_entry );
#endif
        }
        else
        {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -