Experimental Physics and Industrial Control System

1994  1995  1996  1997  1998  <19992000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  Index 1994  1995  1996  1997  1998  <19992000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019 
<== Date ==> <== Thread ==>

Subject: iocCore port
From: Marty Kraimer <mrk@aps.anl.gov>
To: tech-talk@aps.anl.gov
Date: Fri, 10 Sep 1999 15:05:34 -0500
Work on porting iocCore to other operating systems besides vxWorks is

The following has been accomplised

Almost all of base except Channel Access, the sequencer, and hardware support
has been changed to use the new osi routines rather than vxWorks specific calls.
I have not touched Channel Access becuse this needs help from Jeff Hill. William
Lupton is already working on a version of the sequencer that is independent of
vxWorks. The hardware dependent code will be unbundled from base.

Janet Anderson has modified the make system so that it works for non vxWorks IOC
targets. The new system is actually easier than the old.

Using the new osi independent code the example application generated by
makeBaseApp has been run successfully. This was a major milestone.

A document describing the iocCore port is attached. Note that to port to other
systems only the libraries osiSem and osiThread need to be implemented. It
should be possible to implement these using posix calls. If this is done we
should be able to run iocCore on many platforms.

Marty Kraimer

Porting iocCore

Sept 10, 1999

iocCore includes the following components of epics base:

The port is based on the following assumptions:

Overview of Changes

Replacements for existing vxWorks and epics components

The following Operating System Independent libraries replace vxWorks specific libraries. In addition the following new base components are provided


It is not possible to expect every environment to supply an environment that makes it easy to implement  vxWorks symFindByName. Instead a facility to register and find pointers to functions and structures is provided. This leaves the problem of registering everything currently located via calls to symFindByName. The following solves the problem:

Build Environment (Everyone's favorite subject :-)

The build environment is different. The principal features are:

UNRESOLVED ISSUE: Should we have the ability to distinguish building for a single vw multithreaded environment? My guess is YES.


This will go away.

vxWorks shell

If the target is not for vxWorks, the vxWorks target shell is not available. IocInit, dbLoadRecords, etc  must be  called directly by main or the equivalent. The "nice" vxWorks debugging environment is not available although a nicer one using xgdb may be available.

How do we run dbpr, dbgf, etc?

Interrupt Level

The vxWorks intLock/intUnlock routines are an essential part of base. For example any code, including interrupt routines, can call callbackRequest. osiInterrupt is provided to solve this problem. For operating systems like vxWorks, in which everything runs in a shared memory, multithreaded kernel environment, an osi specific version must be provided. For other operating systems, e.g. winxx, Unix, Linux, a generic version is provided. The only restriction is that kernel code MUST not call any of the osi routines.

Status Of Port

The following has been done: This section contains prototype definitions of what needs to be implemented for each port of iocCore.

A particular implementation may implement each function as desired BUT the final result must appear to user code like the definitions in this section. For example  functions can be implemented via macros defined in a header file that replace the generic header file.


unsigned long clockGetCurrentTick();
int clockGetRate();
int clockGetEventTime(int event_number,TS_STAMP *ts);
int clockGetCurrentTime(TS_STAMP* ts);
A vxWorks specific version is provided that provides exactly the same semantics as 3.13.

A generic version is provided that should work on most platforms.

Perhaps it should be implemented via libCom/osiTime.


void * osiFindGlobalSymbol(const char *name);
A vxWorks version is provided that calls symFindByName. It is called by the registry if a name is not found in the registry itself.

A generic version is provided that always returns failure. If the generic version is used then all external symbols must be registered, See the registry for details.


int interruptLock();
void interruptUnlock(int key);
int interruptIsInterruptContext();
void interruptContextMessage(const char *message);
A vxWorks specific version is provided. It maps directly to intLib calls.

A generic version is provided that uses a global semaphore to lock. This version is intended for operating systems in which iocCore will run as a multithreaded process. The global semaphore is thus only global within the process.


ringId  ringCreate(int nbytes);
void    ringDelete(ringId id);
int     ringGet(ringId id, char *value,int nbytes);
int     ringPut(ringId id, char *value,int nbytes);
void    ringFlush(ringId id);
int     ringFreeBytes(ringId id);
int     ringUsedBytes(ringId id);
int     ringSize(ringId id);
int     ringIsEmpty(ringId id);
int     ringIsFull(ringId id);
A vxWorks specific version is provided that maps directly to rngLib calls.

A generic version is provided that works on all platforms.  This version is currently 1.5 times slower than the vxWorks specific version. Perhaps some clever thought can make it as fast as rngLib.

osiRing has the following properties.


typedef void *semId;
typedef enum {semTakeOK,semTakeTimeout} semTakeStatus;
typedef enum {semEmpty,semFull} semInitialState;

semId semBinaryCreate(int initialState);
void semBinaryDestroy(semId id);
void semBinaryGive(semId id);
semTakeStatus semBinaryTake(semId id);
void semBinaryTakeAssert(semId id);
semTakeStatus semBinaryTakeTimeout(semId id, double timeOut);
semTakeStatus semBinaryTakeNoWait(semId id);
void semBinaryFlush(semId id);

semId semMutexCreate(void);
void semMutexDestroy(semId id);
void semMutexGive(semId id);
semTakeStatus semMutexTake(semId id);
void semMutexTakeAssert(semId id);
semTakeStatus semMutexTakeTimeout(semId id, double timeOut);
semTakeStatus semMutexTakeNoWait(semId id);
void semMutexFlush(semId id);

Mutual exclusion semaphores

For POSIX For vxWorks

On a single threaded environment


#define threadPriorityMax 99
#define threadPriorityMin  0

/*some generic values */
#define threadPriorityLow 10
#define threadPriorityMedium 50
#define threadPriorityHigh 90

/*some iocCore specific values */
#define threadPriorityChannelAccessClient 10
#define threadPriorityChannelAccessServer 20
#define threadPriorityScanLow 60
#define threadPriorityScanHigh 70

 *The following functions convert to/from osi (operating system independent)
 * and oss (operating system specific) priority values
 * NOTE THAT ALL OTHER CALLS USE osi priority values

int threadGetOsiPriorityValue(int ossPriority);
int threadGetOssPriorityValue(int osiPriority);

/* stack sizes for each stackSizeClass are implementation and CPU dependent */
typedef enum {
    threadStackSmall, threadStackMedium, threadStackBig
} threadStackSizeClass;

unsigned int threadGetStackSize(threadStackSizeClass size);

typedef void *threadId;
threadId threadCreate(const char *name,
    unsigned int priority, unsigned int stackSize,
    THREADFUNC funptr,void *parm);
void threadDestroy(threadId id);
void threadSuspend(threadId id);
void threadResume(threadId id);
int threadGetPriority(threadId id);
void threadSetPriority(threadId id,int priority);
void threadSetDestroySafe(threadId id);
void threadSetDestroyUnsafe(threadId id);
const char *threadGetName(threadId id);
int threadIsEqual(threadId id1, threadId id2);
int threadIsReady(threadId id);
int threadIsSuspended(threadId id);
void threadSleep(double seconds);
threadId threadGetIdSelf(void);
void threadLockContextSwitch(void);
void threadUnlockContextSwitch(void);
threadId threadNameToId(const char *name);
Thread priorities are assigned a value from 0 to 99. A higher value means higher priority

Thread stack values are handled as follows:

For vxWorks osiThread is implement via calls to taskLib

For posix it should be possible (I hope)  to implement thread via a combination of:

Thread is not implemented for a single threaded environment.


typedef void *watchdogId;
typedef void (*WATCHDOGFUNC)(void *parm);

watchdogId watchdogCreate ();
void watchdogDestroy (watchdogId id);
void watchdogStart(watchdogId id, int delaySeconds,WATCHDOGFUNC funptr,*parm);
void watchdogCancel(watchdogId id);
A vxWorks version is provided that maps directly into mwdLib calls.

I think a generic version can be implemented via base/srcf/libCom/osiTimer. This has not yet been implemented.

New base supplied component


void cantProceed(const char *errorMessage);
void *callocMustSucceed(size_t count, size_t size, const char *errorMessage);
void *mallocMustSucceed(size_t size, const char *errorMessage);
cantProceed prints error message and then callocMustSucceed is like calloc except that it does not return if storage is not available. A lot of iocCore is initialized by iocInit. If memory allocation fails during iocInit it is not possible to recover. mallocMustSucceed is like malloc except that it does not return if storage is not available.


iocCore currently uses symFindByName to dynamically bind the following: This only the first two items need a solution. The existing implementation solves the first problem. No solution has been provided for the subroutine records but it will not be hard implement.


The basic idea is to provide a registration facility. Any storage meant to be "globally" accessable must be registered before it can be accessed by other code.

A perl script is provided that reads the xxxApp.dbd file and produces a c file containing a routine registerRecordDeviceDriver, which registers all record/device/driver support defined in the xxxApp.dbd file.


int registryAdd(void *registryID,const char *name,void *data);
void *registryFind(void *registryID,const char *name);
int registrySetTableSize(int size);
void registryFree();
int registryDump(void);
This is the code which does the work. Each different set of things to register must have it's own unique ID. Everything to be registered is stored in the same gpHash table.

Routine registrySetTableSize is provided in case the default hash table size (1024 entries)  is not sufficient.


typedef int (*computeSizeOffset)(dbRecordType *pdbRecordType);

typedef struct recordTypeLocation {
    struct rset *prset;
    computeSizeOffset sizeOffset;

int registryRecordTypeAdd(const char *name,recordTypeLocation *prtl);
recordTypeLocation *registryRecordTypeFind(const char *name);
Some features:


int registryDeviceSupportAdd(const char *name,struct dset *pdset)
struct dset *registryDeviceSupportFind(const char *name);
This provides access to the device support entry table.


int registryDriverSupportAdd(const char *name,struct drvet *pdrvet);
struct drvet *registryDriverSupportFind(const char *name);

/* The following function is generated by registerRecordDeviceDriver/pl */
int registerRecordDeviceDriver(DBBASE *pdbbase);
This provides access to the driver support entry table.


This is the perl script which creates a c source file that registers record/device/driver support. Make rules are provided that


A version of this is provided for vxWorks. This version makes it unnecessary to use registerRecordDeviceDriver.pl or register other external names. Thus for vxWorks everything can work almost exactly like it did in release 3.13.x
Navigate by Date:
Prev: problems with downloading EPICS Lifang Zheng
Next: Unix sequencer William Lupton
Index: 1994  1995  1996  1997  1998  <19992000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019 
Navigate by Thread:
Prev: problems with downloading EPICS Lifang Zheng
Next: RE: iocCore port Peregrine McGehee
Index: 1994  1995  1996  1997  1998  <19992000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019