Files
epics-base/src/libCom/osi/os/vxWorks/osdThread.c
Andrew Johnson 12dc840eda Don't print anything from epicsThreadShow() when tid=0.
Also don't pass level > 1 to vxWorks taskShow() routine.
2010-05-03 17:28:04 -05:00

401 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* osi/os/vxWorks/epicsThread.c */
/* Author: Marty Kraimer Date: 25AUG99 */
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <vxWorks.h>
#include <taskLib.h>
#include <taskVarLib.h>
#include <sysLib.h>
#include "errlog.h"
#include "ellLib.h"
#include "epicsThread.h"
#include "cantProceed.h"
#include "epicsAssert.h"
#include "vxLib.h"
#include "epicsExit.h"
#if CPU_FAMILY == MC680X0
#define ARCH_STACK_FACTOR 1
#elif CPU_FAMILY == SPARC
#define ARCH_STACK_FACTOR 2
#else
#define ARCH_STACK_FACTOR 2
#endif
static const unsigned stackSizeTable[epicsThreadStackBig+1] =
{4000*ARCH_STACK_FACTOR, 6000*ARCH_STACK_FACTOR, 11000*ARCH_STACK_FACTOR};
/*The following forces atReboot to be loaded*/
extern int atRebootExtern;
static struct pext {
int *pExtern;
struct pext *pext;
} pext = {&atRebootExtern, &pext};
/* definitions for implementation of epicsThreadPrivate */
static void **papTSD = 0;
static int nepicsThreadPrivate = 0;
static SEM_ID epicsThreadOnceMutex = 0;
/* Just map osi 0 to 99 into vx 100 to 199 */
/* remember that for vxWorks lower number means higher priority */
/* vx = 100 + (99 -osi) = 199 - osi*/
/* osi = 199 - vx */
static unsigned int getOsiPriorityValue(int ossPriority)
{
if ( ossPriority < 100 ) {
return epicsThreadPriorityMax;
}
else if ( ossPriority > 199 ) {
return epicsThreadPriorityMin;
}
else {
return ( 199u - (unsigned int) ossPriority );
}
}
static int getOssPriorityValue(unsigned int osiPriority)
{
if ( osiPriority > 99 ) {
return 100;
}
else {
return ( 199 - (signed int) osiPriority );
}
}
static void epicsThreadInit(void)
{
static int lock = 0;
while(!vxTas(&lock)) taskDelay(1);
if(epicsThreadOnceMutex==0) {
epicsThreadOnceMutex = semMCreate(
SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);
assert(epicsThreadOnceMutex);
}
lock = 0;
}
unsigned int epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
{
if (stackSizeClass<epicsThreadStackSmall) {
errlogPrintf("epicsThreadGetStackSize illegal argument (too small)");
return stackSizeTable[epicsThreadStackBig];
}
if (stackSizeClass>epicsThreadStackBig) {
errlogPrintf("epicsThreadGetStackSize illegal argument (too large)");
return stackSizeTable[epicsThreadStackBig];
}
return stackSizeTable[stackSizeClass];
}
struct epicsThreadOSD {};
/* Strictly speaking this should be a WIND_TCB, but we only need it to
* be able to create an epicsThreadId that is guaranteed never to be
* the same as any current TID, and since TIDs are pointers this works.
*/
void epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
{
static struct epicsThreadOSD threadOnceComplete;
#define EPICS_THREAD_ONCE_DONE &threadOnceComplete
int result;
epicsThreadInit();
result = semTake(epicsThreadOnceMutex, WAIT_FOREVER);
assert(result == OK);
if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
*id = epicsThreadGetIdSelf(); /* mark active */
semGive(epicsThreadOnceMutex);
func(arg);
result = semTake(epicsThreadOnceMutex, WAIT_FOREVER);
assert(result == OK);
*id = EPICS_THREAD_ONCE_DONE; /* mark done */
} else if (*id == epicsThreadGetIdSelf()) {
semGive(epicsThreadOnceMutex);
cantProceed("Recursive epicsThreadOnce() initialization\n");
} else
while (*id != EPICS_THREAD_ONCE_DONE) {
/* Another thread is in the above func(arg) call. */
semGive(epicsThreadOnceMutex);
epicsThreadSleep(epicsThreadSleepQuantum());
result = semTake(epicsThreadOnceMutex, WAIT_FOREVER);
assert(result == OK);
}
semGive(epicsThreadOnceMutex);
}
static void createFunction(EPICSTHREADFUNC func, void *parm)
{
int tid = taskIdSelf();
taskVarAdd(tid,(int *)(char *)&papTSD);
/*Make sure that papTSD is still 0 after that call to taskVarAdd*/
papTSD = 0;
(*func)(parm);
epicsExitCallAtThreadExits ();
free(papTSD);
taskVarDelete(tid,(int *)(char *)&papTSD);
}
#ifdef ALTIVEC
#define TASK_FLAGS (VX_FP_TASK | VX_ALTIVEC_TASK)
#else
#define TASK_FLAGS (VX_FP_TASK)
#endif
epicsThreadId epicsThreadCreate(const char *name,
unsigned int priority, unsigned int stackSize,
EPICSTHREADFUNC funptr,void *parm)
{
int tid;
if(epicsThreadOnceMutex==0) epicsThreadInit();
if(stackSize<100) {
errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n",name,stackSize);
return(0);
}
tid = taskSpawn((char *)name,getOssPriorityValue(priority),
TASK_FLAGS, stackSize,
(FUNCPTR)createFunction,(int)funptr,(int)parm,
0,0,0,0,0,0,0,0);
if(tid==ERROR) {
errlogPrintf("epicsThreadCreate %s failure %s\n",
name,strerror(errno));
return(0);
}
return((epicsThreadId)tid);
}
void epicsThreadSuspendSelf()
{
STATUS status;
status = taskSuspend(taskIdSelf());
if(status) errlogPrintf("epicsThreadSuspendSelf failed\n");
}
void epicsThreadResume(epicsThreadId id)
{
int tid = (int)id;
STATUS status;
status = taskResume(tid);
if(status) errlogPrintf("epicsThreadResume failed\n");
}
void epicsThreadExitMain(void)
{
errlogPrintf("epicsThreadExitMain was called for vxWorks. Why?\n");
}
unsigned int epicsThreadGetPriority(epicsThreadId id)
{
int tid = (int)id;
STATUS status;
int priority = 0;
status = taskPriorityGet(tid,&priority);
if(status) errlogPrintf("epicsThreadGetPriority failed\n");
return(getOsiPriorityValue(priority));
}
unsigned int epicsThreadGetPrioritySelf(void)
{
return(epicsThreadGetPriority(epicsThreadGetIdSelf()));
}
void epicsThreadSetPriority(epicsThreadId id,unsigned int osip)
{
int tid = (int)id;
STATUS status;
int priority = 0;
priority = getOssPriorityValue(osip);
status = taskPrioritySet(tid,priority);
if(status) errlogPrintf("epicsThreadSetPriority failed\n");
}
epicsThreadBooleanStatus epicsThreadHighestPriorityLevelBelow(
unsigned int priority, unsigned *pPriorityJustBelow)
{
unsigned newPriority = priority - 1;
if (newPriority <= 99) {
*pPriorityJustBelow = newPriority;
return epicsThreadBooleanStatusSuccess;
}
return epicsThreadBooleanStatusFail;
}
epicsThreadBooleanStatus epicsThreadLowestPriorityLevelAbove(
unsigned int priority, unsigned *pPriorityJustAbove)
{
unsigned newPriority = priority + 1;
newPriority = priority + 1;
if (newPriority <= 99) {
*pPriorityJustAbove = newPriority;
return epicsThreadBooleanStatusSuccess;
}
return epicsThreadBooleanStatusFail;
}
int epicsThreadIsEqual(epicsThreadId id1, epicsThreadId id2)
{
return((id1==id2) ? 1 : 0);
}
int epicsThreadIsSuspended(epicsThreadId id)
{
int tid = (int)id;
return((int)taskIsSuspended(tid));
}
void epicsThreadSleep(double seconds)
{
STATUS status;
int ticks;
if(seconds<=0.0) {
ticks = 0;
} else {
ticks = seconds*sysClkRateGet() + 0.5;
if(ticks<=0) ticks = 1;
}
status = taskDelay(ticks);
if(status) errlogPrintf("epicsThreadSleep\n");
}
epicsThreadId epicsThreadGetIdSelf(void)
{
return((epicsThreadId)taskIdSelf());
}
epicsThreadId epicsThreadGetId(const char *name)
{
int tid = taskNameToId((char *)name);
return((epicsThreadId)(tid==ERROR?0:tid));
}
const char *epicsThreadGetNameSelf(void)
{
return taskName(taskIdSelf());
}
void epicsThreadGetName (epicsThreadId id, char *name, size_t size)
{
int tid = (int)id;
strncpy(name,taskName(tid),size-1);
name[size-1] = '\0';
}
void epicsThreadShowAll(unsigned int level)
{
taskShow(0,2);
}
void epicsThreadShow(epicsThreadId id, unsigned int level)
{
int tid = (int)id;
if (level > 1) level = 1;
if (tid)
taskShow(tid, level);
}
/* The following algorithm was thought of by Andrew Johnson APS/ASD .
* The basic idea is to use a single vxWorks task variable.
* The task variable is papTSD, which is an array of pointers to the TSD
* The array size is equal to the number of epicsThreadPrivateIds created + 1
* when epicsThreadPrivateSet is called.
* Until the first call to epicsThreadPrivateCreate by a application papTSD=0
* After first call papTSD[0] is value of nepicsThreadPrivate when
* epicsThreadPrivateSet was last called by the thread. This is also
* the value of epicsThreadPrivateId.
* The algorithm allows for epicsThreadPrivateCreate being called after
* the first call to epicsThreadPrivateSet.
*/
epicsThreadPrivateId epicsThreadPrivateCreate()
{
static int lock = 0;
epicsThreadPrivateId id;
epicsThreadInit();
/*lock is necessary because ++nepicsThreadPrivate may not be indivisible*/
while(!vxTas(&lock)) taskDelay(1);
id = (epicsThreadPrivateId)++nepicsThreadPrivate;
lock = 0;
return(id);
}
void epicsThreadPrivateDelete(epicsThreadPrivateId id)
{
/*nothing to delete */
return;
}
/*
* No mutex is necessary here because by definition
* thread variables are local to a single thread.
*/
void epicsThreadPrivateSet (epicsThreadPrivateId id, void *pvt)
{
int int_id = (int)id;
int nepicsThreadPrivateOld = 0;
if (papTSD) nepicsThreadPrivateOld = (int)papTSD[0];
if (!papTSD || nepicsThreadPrivateOld < int_id) {
void **papTSDold = papTSD;
int i;
papTSD = callocMustSucceed(int_id + 1,sizeof(void *),
"epicsThreadPrivateSet");
papTSD[0] = (void *)(int_id);
for (i = 1; i <= nepicsThreadPrivateOld; i++) {
papTSD[i] = papTSDold[i];
}
free (papTSDold);
}
papTSD[int_id] = pvt;
}
void *epicsThreadPrivateGet(epicsThreadPrivateId id)
{
int int_id = (int)id;
/*
* If epicsThreadPrivateGet() is called before epicsThreadPrivateSet()
* for any particular thread, the value returned is always NULL.
*/
if ( papTSD && int_id <= (int) papTSD[0] ) {
return papTSD[int_id];
}
return NULL;
}
double epicsThreadSleepQuantum ()
{
double HZ = sysClkRateGet ();
return 1.0 / HZ;
}