📄 linuxucos.c
字号:
/* linuxucos.c v0.2.0 01-Jan-02 David Poole davep@mbuf.com * * Portions copyright as follows: * * (c) Copyright 2001, Jean J. Labrosse, Weston, FL * All Rights Reserved * * Simple wrapper around SysV and POSIX threads functions to mimic uCOS-II * features. Has only been tested on RedHat Linux 7 and 7.2. * * Currently supported features are: * * Semaphores: * none * * Mutual Exclusion Semaphores: * OSMutexAccept() * OSMutexCreate() * OSMutexDel() * OSMutexPend() * OSMutexPost() * * Event Flags: * OSFlagAccept() * OSFlagCreate() * OSFlagPend() * OSFlagPost() * * Message Mailboxes: * none * * Message Queues: * OSQAccept() * OSQCreate() * OSQDel() * OSQPend() * OSQPost() * * Memory Management: * none * * Task Management: * OSTaskCreate() * OSTaskCreateExt() * * Time Management: * OSTimeDly() * OSTimeGet() * * Miscellaneous: * OSInit(); * OSStart(); * * * uCOS-II specific information: I'm using a 1ms "tick" on Linux so * OS_TICKS_PER_SEC must be 1000. * */#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <sys/sem.h>#include <sys/time.h>#include <errno.h>#include <unistd.h>#include <pthread.h>#include <time.h>#include <assert.h>#define LINUX_UCOS#include "includes.h"// using a 1 ms tick on Linux#define NANOSECONDS_PER_TICK 1000000l#define SECONDS 1000// Table of EVENT control blocks #define OS_EVENT_COUNT 99OS_EVENT lnxOSEventTbl[OS_EVENT_COUNT]; // mutex to protect the lnxOSEventTbl listpthread_mutex_t oseventtbl_mutex = PTHREAD_MUTEX_INITIALIZER;// Table of available OS_FLAG_GRP #define OS_MAX_FLAGS 99OS_FLAG_GRP lnxOSFlagTbl[OS_MAX_FLAGS];// mutex to protect the lnxOSFlagTbl listpthread_mutex_t osflagtbl_mutex = PTHREAD_MUTEX_INITIALIZER;// uCOS-II flags are implemented using pthread's condition variables;struct pthread_flag { pthread_mutex_t mutex; pthread_cond_t cond;};// "blank" mutex and condition for initializing struct pthread_flag memberspthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;// for debugging #define PRINTF printf#define PERROR perror#define ASSERT assert// returned when an interface function encounters// an error; this should never happen#define OS_ERR_INTERNAL -1// there are a few places where a lack of a timeout// on SysV IPC mechanisms means a poll #define POLL_DELAY 10 // ticks// sigh#ifndef min#define min(x,y) ((x)<(y)?(x):(y))#endifstruct sembuf sem_release = { 0, 1, IPC_NOWAIT };struct sembuf sem_claim = { 0, -1, IPC_NOWAIT };// convert a uCOS-II 'prio' (used as a task ID as of 2.51)// into the pthread_t id// 64 is the maximum number of tasks in the current version// of ucOS-II; could change in a future version so beware#define MAX_TASKS 64pthread_t pthread_to_prio[MAX_TASKS];// time is measure from when the system "booted", ie// when the program was started (see epoch_init())struct timeval epoch;void epoch_init( void ){ gettimeofday( &epoch, NULL );}INT32U get_ms_time( void ){ INT32U ms; struct timeval now; gettimeofday( &now, NULL ); ms = now.tv_sec * 1000 + now.tv_sec / NANOSECONDS_PER_TICK; return ms;}OS_EVENT *get_free_event( INT8U evttype ){ int i, perr; // lock the table perr = pthread_mutex_lock( &oseventtbl_mutex ); ASSERT( perr == 0 ); // get a free OS_EVENT for( i=0 ; i<OS_EVENT_COUNT ; i++ ) { if( lnxOSEventTbl[i].OSEventType == OS_EVENT_TYPE_UNUSED ) { lnxOSEventTbl[i].OSEventType = evttype; // unlock the table perr = pthread_mutex_unlock( &oseventtbl_mutex ); ASSERT( perr == 0 ); return &lnxOSEventTbl[i]; } } // unlock the table perr = pthread_mutex_unlock( &oseventtbl_mutex ); ASSERT( perr == 0 ); return NULL;}// *****************//// Time Functions//// *****************void OSTimeDly( INT16U ticks ){ int ret; struct timespec req, rem; ldiv_t nanotime; // using a 1ms "tick" on Linux nanotime = ldiv( ticks, SECONDS ); req.tv_sec = nanotime.quot; req.tv_nsec = (nanotime.rem) * NANOSECONDS_PER_TICK; while( 1 ) { ret = nanosleep( &req, &rem ); if( ret == 0 ) { // successfully finished the sleep break; } assert( errno == EINTR ); // at this point, we were interrupted by a signal // recalculate how much we needed to sleep and do it again memcpy( &req, &rem, sizeof(struct timespec) ); }}INT32U OSTimeGet( void ){ // get_ms_time() returns ms since program start return get_ms_time();}// *****************//// Flag Functions// // *****************OS_FLAGS OS_FlagTest( OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, INT8U *err ){ OS_FLAGS flags_cur; OS_FLAGS flags_rdy; BOOLEAN consume; int perr; struct pthread_flag *pflag; struct timeval now; struct timespec sleeptime; ldiv_t nanotime; if( pgrp == NULL ) { *err = OS_FLAG_INVALID_PGRP; return 0; } if( pgrp->OSFlagType != OS_EVENT_TYPE_FLAG ) { *err = OS_ERR_EVENT_TYPE; return 0; } // wait_type can be // OS_FLAG_WAIT_CLR_ALL -- all bits in 'flags' will be clear // OS_FLAG_WAIT_CLR_ANY -- any bits in 'flags' will be clear // OS_FLAG_WAIT_SET_ALL -- all bits in 'flags' will be set // OS_FLAG_WAIT_SET_ANY -- any bits in 'flags' will be clear // test the flags pflag = (struct pthread_flag *)pgrp->OSFlagWaitList; // lock the pthread condition perr = pthread_mutex_lock( &(pflag->mutex) ); ASSERT( perr == 0 ); // test if (wait_type & OS_FLAG_CONSUME) { /* See if we need to consume the flags */ wait_type &= ~OS_FLAG_CONSUME; consume = TRUE; } else { consume = FALSE; } *err = OS_NO_ERR; /* timeout of 1 => no wait */ /* timeout of 0 => wait forever */ if( timeout > 1 ) { // our timeout is in 1ms "ticks" so convert to system nanoseconds nanotime = ldiv( timeout, SECONDS ); gettimeofday( &now, NULL ); sleeptime.tv_sec = now.tv_sec + nanotime.quot; sleeptime.tv_nsec = now.tv_usec + nanotime.rem * NANOSECONDS_PER_TICK; } *err = OS_NO_ERR; flags_cur = 0; switch( wait_type ) { case OS_FLAG_WAIT_SET_ALL : flags_rdy = pgrp->OSFlagFlags & flags; /* Extract only the bits we want */ perr = 0; while (flags_rdy != flags && perr != ETIMEDOUT ) { if( timeout == 0 ) { /* wait forever */ perr = pthread_cond_wait( &(pflag->cond), &(pflag->mutex) ); } else if( timeout > 1 ) { perr = pthread_cond_timedwait( &(pflag->cond), &(pflag->mutex), &sleeptime ); } else { *err = OS_FLAG_ERR_NOT_RDY; goto fail; } flags_rdy = pgrp->OSFlagFlags & flags; } if( perr == ETIMEDOUT ) { *err = OS_TIMEOUT; goto fail; } if (consume == TRUE) { /* See if we need to consume the flags */ pgrp->OSFlagFlags &= ~flags_rdy; /* Clear ONLY the flags that we wanted */ } flags_cur = pgrp->OSFlagFlags; /* Will return the state of the group */ break; case OS_FLAG_WAIT_SET_ANY : flags_rdy = pgrp->OSFlagFlags & flags; /* Extract only the bits we want */ perr = 0; while(flags_rdy == (OS_FLAGS)0 && perr != ETIMEDOUT ) { if( timeout == 0 ) { /* wait forever */ perr = pthread_cond_wait( &(pflag->cond), &(pflag->mutex) ); } else if( timeout > 1 ) { perr = pthread_cond_timedwait( &(pflag->cond), &(pflag->mutex), &sleeptime ); } else { *err = OS_FLAG_ERR_NOT_RDY; goto fail; } flags_rdy = pgrp->OSFlagFlags & flags; } if( perr == ETIMEDOUT ) { *err = OS_TIMEOUT; goto fail; } if (consume == TRUE) { /* See if we need to consume the flags */ pgrp->OSFlagFlags &= ~flags_rdy; /* Clear ONLY the flags that we got */ } flags_cur = pgrp->OSFlagFlags; /* Will return the state of the group */ break; case OS_FLAG_WAIT_CLR_ALL : flags_rdy = ~pgrp->OSFlagFlags & flags; /* Extract only the bits we want */ perr = 0; while( flags_rdy != flags && perr != ETIMEDOUT ) { if( timeout == 0 ) { /* wait forever */ perr = pthread_cond_wait( &(pflag->cond), &(pflag->mutex) ); } else if( timeout > 1 ) { perr = pthread_cond_timedwait( &(pflag->cond), &(pflag->mutex), &sleeptime ); } else { *err = OS_FLAG_ERR_NOT_RDY; goto fail; } flags_rdy = ~pgrp->OSFlagFlags & flags; } if( perr == ETIMEDOUT ) { *err = OS_TIMEOUT; goto fail; } if (consume == TRUE) { /* See if we need to consume the flags */ pgrp->OSFlagFlags |= flags_rdy; /* Set ONLY the flags that we wanted */ } flags_cur = pgrp->OSFlagFlags; /* Will return the state of the group */ break; case OS_FLAG_WAIT_CLR_ANY : flags_rdy = ~pgrp->OSFlagFlags & flags; /* Extract only the bits we want */ perr = 0; while(flags_rdy == (OS_FLAGS)0 && perr != ETIMEDOUT ) { if( timeout == 0 ) { /* wait forever */ perr = pthread_cond_wait( &(pflag->cond), &(pflag->mutex) ); } else if( timeout > 1 ) { perr = pthread_cond_timedwait( &(pflag->cond), &(pflag->mutex), &sleeptime ); } else { *err = OS_FLAG_ERR_NOT_RDY; goto fail; } flags_rdy = ~pgrp->OSFlagFlags & flags; } if( perr == ETIMEDOUT ) { *err = OS_TIMEOUT; goto fail; } if (consume == TRUE) { /* See if we need to consume the flags */ pgrp->OSFlagFlags |= flags_rdy; /* Set ONLY the flags that we got */ } flags_cur = pgrp->OSFlagFlags; /* Will return the state of the group */ break; default : ASSERT(0); flags_cur = (OS_FLAGS)0; *err = OS_FLAG_ERR_WAIT_TYPE; }fail: // unlock the pthread condition perr = pthread_mutex_unlock( &(pflag->mutex) ); ASSERT( perr == 0 ); return flags_cur;}OS_FLAGS OSFlagAccept( OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT8U *err ){ OS_FLAGS flags_cur; /* timeout == 0 => wait forever so use 1 to indicate no wait. * If a caller passes in 1 deliberately to OSFlagPend(), the system * will (supposedly) only delay for 1 tick which is pretty much nothing * anyway. */ flags_cur = OS_FlagTest( pgrp, flags, wait_type, 1/* no wait */, err ); return flags_cur;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -