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

📄 tasklib.c

📁 如何将基于vxworks的应用程序移植到LINUX操作系统。
💻 C
📖 第 1 页 / 共 5 页
字号:
/***************************************************************************** * taskLib.c - defines the wrapper functions and data structures needed *             to implement a VxWorks task control API in a POSIX Threads *             environment. *   * Copyright (C) 2000  Monta Vista Software Inc. * * Author : Gary S. Robertson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU Lesser General Public License for more details. ****************************************************************************/#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 "vxwk2pthread.h"#include "vxwkdefs.h"#undef DIAG_PRINTFS/***  selfRestart is a system function used by a task to restart itself.**              The function creates a temporary watchdog timer which restarts **              the terminated task and then deletes itself. */extern void   selfRestart( vxwk2pthread_cb_t *restart_tcb );extern BOOL   roundRobinIsEnabled( void );/*******************************************************************************  VxWorks-to-pthread Global Data Structures*****************************************************************************//***  task_list is a linked list of pthread task control blocks.**            It is used to perform en-masse operations on all VxWorks pthread**            tasks at once.*/vxwk2pthread_cb_t *    task_list = (vxwk2pthread_cb_t *)NULL;/***  task_list_lock is a mutex used to serialize access to the task list*/pthread_mutex_t    task_list_lock = PTHREAD_MUTEX_INITIALIZER;/***  vxworks_task_lock is a mutex used to make taskLock exclusive to one**                    thread at a time.*/pthread_mutex_t    vxworks_task_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;/***  taskLock_level tracks recursive nesting levels of taskLock/unlock calls**                 so the scheduler is only unlocked at the outermost**                 taskUnlock call.*/static unsigned long    taskLock_level = 0;/***  taskLock_change is a condition variable which signals a change from**                  locked to unlocked or vice-versa.*/static pthread_cond_t    taskLock_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_cleanup_pop( 1 );    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_cleanup_pop( 1 );}    /*******************************************************************************  my_tcb - returns a pointer to the task control block for the calling task*****************************************************************************/vxwk2pthread_cb_t *   my_tcb( void ){    pthread_t my_pthrid;    vxwk2pthread_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 != (vxwk2pthread_cb_t *)NULL )    {        for ( current_tcb = task_list;              current_tcb != (vxwk2pthread_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( (vxwk2pthread_cb_t *)NULL );}/******************************************************************************* tcb_for - returns the address of the task control block for the task**           idenified by taskid*****************************************************************************/vxwk2pthread_cb_t *   tcb_for( int taskid ){    vxwk2pthread_cb_t *current_tcb;    int found_taskid;        if ( task_list != (vxwk2pthread_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 != (vxwk2pthread_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 = (vxwk2pthread_cb_t *)NULL;        }        else            current_tcb = (vxwk2pthread_cb_t *)NULL;     return( current_tcb );}/******************************************************************************* taskLock - '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   taskLock( void ){    pthread_t my_pthrid;    vxwk2pthread_cb_t *tcb;    int max_priority, sched_policy, got_lock;    /*    **  vxworks_task_lock ensures that only one VxWorks pthread at a time gets    **  to run at max_priority (effectively locking out all other VxWorks    **  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 taskUnlock() 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 *)&vxworks_task_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( &vxworks_task_lock );        if ( (scheduler_locked == (pthread_t)NULL) ||             (scheduler_locked == my_pthrid) )        {            scheduler_locked = my_pthrid;            taskLock_level++;            if ( taskLock_level == 0L )                taskLock_level--;            got_lock = TRUE;            pthread_cond_broadcast( &taskLock_change );#ifdef DIAG_PRINTFS             printf( "\r\ntaskLock taskLock_level %lu locking tid %ld",                taskLock_level,  scheduler_locked );#endif        }        else        {#ifdef DIAG_PRINTFS             printf( "\r\ntaskLock locking tid %ld my tid %ld",                    scheduler_locked, my_pthrid );#endif            pthread_cond_wait( &taskLock_change, &vxworks_task_lock );        }        pthread_mutex_unlock( &vxworks_task_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 VxWorks pthreads from modifying    **  the VxWorks 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 != (vxwk2pthread_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;        pthread_setschedparam( tcb->pthrid, sched_policy,                          (struct sched_param *)&((tcb->attr).__schedparam) );    }    pthread_cleanup_pop( 1 );}/******************************************************************************* taskUnlock - '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   taskUnlock( void ){    vxwk2pthread_cb_t *tcb;    int sched_policy;    /*    **  scheduler_locked ensures that only one VxWorks pthread at a time gets    **  to run at max_priority (effectively locking out all other VxWorks    **  pthreads).  Unlock it here to complete 'unlocking' of the scheduler.    */    pthread_cleanup_push( (void(*)(void *))pthread_mutex_unlock,                          (void *)&vxworks_task_lock );    pthread_mutex_lock( &vxworks_task_lock );    if ( scheduler_locked == pthread_self() )    {        if ( taskLock_level > 0L )            taskLock_level--;        if ( taskLock_level < 1L )        {            /*            **  task_list_lock prevents other VxWorks pthreads from modifying            **  the VxWorks 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 != (vxwk2pthread_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_cleanup_pop( 1 );            scheduler_locked = (pthread_t)NULL;            pthread_cond_broadcast( &taskLock_change );        }#ifdef DIAG_PRINTFS         printf( "\r\ntaskUnlock taskLock_level %lu locking tid %ld",                taskLock_level,  scheduler_locked );#endif    }#ifdef DIAG_PRINTFS     else        printf( "\r\ntaskUnlock locking tid %ld my tid %ld", scheduler_locked,                pthread_self() );#endif    pthread_cleanup_pop( 1 );}/******************************************************************************* 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( vxwk2pthread_cb_t **list_head, vxwk2pthread_cb_t *new_entry ){    vxwk2pthread_cb_t *nxt_entry;    if ( list_head != (vxwk2pthread_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 = (vxwk2pthread_cb_t *)NULL;        if ( *list_head != (vxwk2pthread_cb_t *)NULL )        {            for ( nxt_entry = *list_head;                   nxt_entry->nxt_susp != (vxwk2pthread_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        {            *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.        */

⌨️ 快捷键说明

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