Merge branch 'PSI-3.14' of git.psi.ch:epics_base/base-3-14-12 into PSI-3.14
This commit is contained in:
@@ -964,6 +964,7 @@ static void event_task (void *pParm)
|
||||
} while( ! pendexit );
|
||||
|
||||
epicsMutexDestroy(evUser->firstque.writelock);
|
||||
evUser->firstque.writelock = (epicsMutexId)0xdeadbeef;
|
||||
|
||||
{
|
||||
struct event_que *nextque;
|
||||
@@ -972,6 +973,7 @@ static void event_task (void *pParm)
|
||||
while(ev_que){
|
||||
nextque = ev_que->nextque;
|
||||
epicsMutexDestroy(ev_que->writelock);
|
||||
ev_que->writelock = (epicsMutexId)0xdeadbeef;
|
||||
freeListFree(dbevEventQueueFreeList, ev_que);
|
||||
ev_que = nextque;
|
||||
}
|
||||
@@ -980,6 +982,7 @@ static void event_task (void *pParm)
|
||||
epicsEventDestroy(evUser->ppendsem);
|
||||
epicsEventDestroy(evUser->pflush_sem);
|
||||
epicsMutexDestroy(evUser->lock);
|
||||
evUser->lock = (epicsMutexId)0xdeadbeef;
|
||||
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
|
||||
|
||||
@@ -558,6 +558,186 @@ static MAC_ENTRY *create( MAC_HANDLE *handle, const char *name, int special )
|
||||
return entry;
|
||||
}
|
||||
|
||||
#define SUCCESS 0
|
||||
#define NOVALUE 1
|
||||
#define UNTERMINATED 2
|
||||
#define DIVZERO 3
|
||||
|
||||
static int parseExpr( const char** pp, int* v, int level );
|
||||
|
||||
/* Value is a number or an expression in () */
|
||||
static int parseValue( const char** pp, int* v )
|
||||
{
|
||||
int status;
|
||||
int val;
|
||||
const char *p = *pp;
|
||||
int neg = 0;
|
||||
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p == '+' || *p == '-') neg = *p++ == '-';
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p == '(')
|
||||
{
|
||||
p++;
|
||||
if ((status = parseExpr(&p, &val, 0)) != SUCCESS) return status;
|
||||
if (*p++ != ')')
|
||||
{
|
||||
printf("macLib: missing ) after '%s'\n", *pp);
|
||||
return UNTERMINATED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char* e;
|
||||
val = strtol(p, &e, 0);
|
||||
if (e == p) return NOVALUE;
|
||||
p = e;
|
||||
}
|
||||
if (neg) val = -val;
|
||||
*pp = p;
|
||||
*v = val;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* Expr is a sum or product of Values or a conditional */
|
||||
static int parseExpr( const char** pp, int* v, int level )
|
||||
{
|
||||
const char *p = *pp;
|
||||
int o = 0;
|
||||
int val0, val1, val2;
|
||||
int status = SUCCESS;
|
||||
int stat1, stat2;
|
||||
|
||||
val0 = 0;
|
||||
/* handle sums and differences */
|
||||
do {
|
||||
if ((stat1 = parseValue(&p, &val1)) != SUCCESS)
|
||||
{
|
||||
if (o && stat1 == NOVALUE)
|
||||
printf ("macLib: missing operand after '%c'\n", o);
|
||||
return stat1;
|
||||
}
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
o = *p;
|
||||
/* handle products and quotients */
|
||||
while (o == '*' || o == '/' || o == '%')
|
||||
{
|
||||
p++;
|
||||
if ((stat2 = parseValue(&p, &val2)) != SUCCESS)
|
||||
{
|
||||
if (stat2 == NOVALUE)
|
||||
printf ("macLib: missing operand after '%c'\n", o);
|
||||
return stat2;
|
||||
}
|
||||
if (o == '*') val1 *= val2;
|
||||
else if (val2 == 0)
|
||||
{
|
||||
status = DIVZERO;
|
||||
val1 = 1;
|
||||
}
|
||||
else if (o == '/') val1 /= val2;
|
||||
else val1 %= val2;
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
o = *p;
|
||||
}
|
||||
val0 += val1;
|
||||
} while (o == '+' || o == '-');
|
||||
|
||||
/* handle comparisons */
|
||||
o = *p;
|
||||
if (o == '<' || o == '>')
|
||||
{
|
||||
p++;
|
||||
if ((stat1 = parseExpr(&p, &val1, 1)) != SUCCESS)
|
||||
{
|
||||
if (stat1 == NOVALUE)
|
||||
printf ("macLib: missing expression after '%c'\n", o);
|
||||
return stat1;
|
||||
}
|
||||
if (o == '<')
|
||||
val0 = (val0 < val1);
|
||||
else
|
||||
val0 = (val0 > val1);
|
||||
}
|
||||
|
||||
/* handle conditionals */
|
||||
if (*p == '?' && level == 0)
|
||||
{
|
||||
p++;
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p != ':')
|
||||
{
|
||||
stat1 = parseExpr(&p, &val1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
val1 = val0;
|
||||
stat1 = status;
|
||||
}
|
||||
if (*p != ':')
|
||||
{
|
||||
printf("macLib: missing : after '%s'\n", *pp);
|
||||
return UNTERMINATED;
|
||||
}
|
||||
p++;
|
||||
stat2 = parseExpr(&p, &val2, 0);
|
||||
status = val0 ? stat1 : stat2;
|
||||
val0 = val0 ? val1 : val2;
|
||||
}
|
||||
|
||||
*v = val0;
|
||||
*pp = p;
|
||||
return status;
|
||||
}
|
||||
|
||||
static MAC_ENTRY *evalExpr( MAC_HANDLE *handle, const char *expr )
|
||||
{
|
||||
MAC_ENTRY *entry = NULL;
|
||||
int status;
|
||||
const char* p = expr;
|
||||
int value;
|
||||
char valuestr[40];
|
||||
char format[20] = "%d";
|
||||
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p == '%')
|
||||
{
|
||||
int i = 1;
|
||||
p++;
|
||||
while (i < sizeof(format) && strchr(" #-+0", *p))
|
||||
format[i++] = *p++;
|
||||
while (i < sizeof(format) && strchr("0123456789", *p))
|
||||
format[i++] = *p++;
|
||||
if (i < sizeof(format) && strchr("diouxXc", *p))
|
||||
{
|
||||
format[i++] = *p++;
|
||||
format[i] = 0;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
status = parseExpr(&p, &value, 0);
|
||||
if (status == DIVZERO)
|
||||
printf ("macLib: division by zero\n");
|
||||
if (status != SUCCESS)
|
||||
return NULL;
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p)
|
||||
{
|
||||
printf("macLib: rubbish at end of expression: %s\n", p);
|
||||
return NULL;
|
||||
}
|
||||
sprintf(valuestr, format, value);
|
||||
entry = create( handle, expr, TRUE );
|
||||
if ( entry )
|
||||
{
|
||||
entry->type = "calculation";
|
||||
if ( rawval( handle, entry, valuestr ) == NULL )
|
||||
return NULL;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up macro entry with matching "special" attribute by name
|
||||
*/
|
||||
@@ -569,6 +749,10 @@ static MAC_ENTRY *lookup( MAC_HANDLE *handle, const char *name, int special )
|
||||
printf( "lookup-> level = %d, name = %s, special = %d\n",
|
||||
handle->level, name, special );
|
||||
|
||||
if ( (special == FALSE) ) {
|
||||
entry = evalExpr( handle, name );
|
||||
if (entry) return entry;
|
||||
}
|
||||
/* search backwards so scoping works */
|
||||
for ( entry = last( handle ); entry != NULL; entry = previous( entry ) ) {
|
||||
if ( entry->special != special )
|
||||
@@ -688,6 +872,7 @@ static void trans( MAC_HANDLE *handle, MAC_ENTRY *entry, int level,
|
||||
/* return immediately if raw value is NULL */
|
||||
if ( *rawval == NULL ) return;
|
||||
|
||||
|
||||
/* discard quotes and escapes if level is > 0 (i.e. if these aren't
|
||||
the user's quotes and escapes) */
|
||||
discard = ( level > 0 );
|
||||
|
||||
876
src/libCom/osi/os/Linux/osdThread.c
Normal file
876
src/libCom/osi/os/Linux/osdThread.c
Normal file
@@ -0,0 +1,876 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* epicsThread.c */
|
||||
|
||||
/* Author: Marty Kraimer Date: 18JAN2000 */
|
||||
|
||||
/* This is a posix implementation of epicsThread */
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsStdio.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsThread.h"
|
||||
#include "cantProceed.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsExit.h"
|
||||
|
||||
static int mutexLock(pthread_mutex_t *id)
|
||||
{
|
||||
int status;
|
||||
|
||||
while(1) {
|
||||
status = pthread_mutex_lock(id);
|
||||
if(status!=EINTR) return status;
|
||||
fprintf(stderr,"pthread_mutex_lock returned EINTR. Violates SUSv3\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined DONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING
|
||||
#undef _POSIX_THREAD_PRIORITY_SCHEDULING
|
||||
#endif
|
||||
|
||||
typedef struct commonAttr{
|
||||
pthread_attr_t attr;
|
||||
struct sched_param schedParam;
|
||||
int maxPriority;
|
||||
int minPriority;
|
||||
int schedPolicy;
|
||||
int usePolicy;
|
||||
} commonAttr;
|
||||
|
||||
typedef struct epicsThreadOSD {
|
||||
ELLNODE node;
|
||||
pthread_t tid;
|
||||
pid_t lwpId;
|
||||
pthread_attr_t attr;
|
||||
struct sched_param schedParam;
|
||||
EPICSTHREADFUNC createFunc;
|
||||
void *createArg;
|
||||
epicsEventId suspendEvent;
|
||||
int isSuspended;
|
||||
int isEpicsThread;
|
||||
int isFifoScheduled;
|
||||
int isOnThreadList;
|
||||
unsigned int osiPriority;
|
||||
char *name;
|
||||
} epicsThreadOSD;
|
||||
|
||||
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
|
||||
typedef struct {
|
||||
int min_pri, max_pri;
|
||||
int policy;
|
||||
int ok;
|
||||
} priAvailable;
|
||||
#endif
|
||||
|
||||
static pthread_key_t getpthreadInfo;
|
||||
static pthread_mutex_t onceLock;
|
||||
static pthread_mutex_t listLock;
|
||||
static ELLLIST pthreadList = ELLLIST_INIT;
|
||||
static commonAttr *pcommonAttr = 0;
|
||||
static int epicsThreadOnceCalled = 0;
|
||||
|
||||
static epicsThreadOSD *createImplicit(void);
|
||||
|
||||
#define checkStatus(status,message) \
|
||||
if((status)) {\
|
||||
errlogPrintf("%s error %s\n",(message),strerror((status))); \
|
||||
}
|
||||
|
||||
#define checkStatusQuit(status,message,method) \
|
||||
if(status) { \
|
||||
errlogPrintf("%s error %s\n",(message),strerror((status))); \
|
||||
cantProceed((method)); \
|
||||
}
|
||||
|
||||
/* The following are for use by once, which is only invoked from epicsThreadInit*/
|
||||
/* Until epicsThreadInit completes errlogInit will not work */
|
||||
/* It must also be used by init_threadInfo otherwise errlogInit could get */
|
||||
/* called recursively */
|
||||
#define checkStatusOnce(status,message) \
|
||||
if((status)) {\
|
||||
fprintf(stderr,"%s error %s\n",(message),strerror((status))); }
|
||||
|
||||
#define checkStatusOnceQuit(status,message,method) \
|
||||
if(status) { \
|
||||
fprintf(stderr,"%s error %s",(message),strerror((status))); \
|
||||
fprintf(stderr," %s\n",method); \
|
||||
fprintf(stderr,"epicsThreadInit cant proceed. Program exiting\n"); \
|
||||
exit(-1);\
|
||||
}
|
||||
|
||||
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
static int getOssPriorityValue(epicsThreadOSD *pthreadInfo)
|
||||
{
|
||||
double maxPriority,minPriority,slope,oss;
|
||||
|
||||
if(pcommonAttr->maxPriority==pcommonAttr->minPriority)
|
||||
return(pcommonAttr->maxPriority);
|
||||
maxPriority = (double)pcommonAttr->maxPriority;
|
||||
minPriority = (double)pcommonAttr->minPriority;
|
||||
slope = (maxPriority - minPriority)/100.0;
|
||||
oss = (double)pthreadInfo->osiPriority * slope + minPriority;
|
||||
return((int)oss);
|
||||
}
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
static void setSchedulingPolicy(epicsThreadOSD *pthreadInfo,int policy)
|
||||
{
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
int status;
|
||||
|
||||
if(!pcommonAttr->usePolicy) return;
|
||||
|
||||
status = pthread_attr_getschedparam(
|
||||
&pthreadInfo->attr,&pthreadInfo->schedParam);
|
||||
checkStatusOnce(status,"pthread_attr_getschedparam");
|
||||
pthreadInfo->schedParam.sched_priority = getOssPriorityValue(pthreadInfo);
|
||||
status = pthread_attr_setschedpolicy(
|
||||
&pthreadInfo->attr,policy);
|
||||
checkStatusOnce(status,"pthread_attr_setschedpolicy");
|
||||
status = pthread_attr_setschedparam(
|
||||
&pthreadInfo->attr,&pthreadInfo->schedParam);
|
||||
checkStatusOnce(status,"pthread_attr_setschedparam");
|
||||
status = pthread_attr_setinheritsched(
|
||||
&pthreadInfo->attr,PTHREAD_EXPLICIT_SCHED);
|
||||
checkStatusOnce(status,"pthread_attr_setinheritsched");
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
}
|
||||
|
||||
static epicsThreadOSD * create_threadInfo(const char *name)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
pthreadInfo = callocMustSucceed(1,sizeof(*pthreadInfo),"create_threadInfo");
|
||||
pthreadInfo->suspendEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
pthreadInfo->name = epicsStrDup(name);
|
||||
return pthreadInfo;
|
||||
}
|
||||
|
||||
static epicsThreadOSD * init_threadInfo(const char *name,
|
||||
unsigned int priority, unsigned int stackSize,
|
||||
EPICSTHREADFUNC funptr,void *parm)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
|
||||
pthreadInfo = create_threadInfo(name);
|
||||
pthreadInfo->createFunc = funptr;
|
||||
pthreadInfo->createArg = parm;
|
||||
status = pthread_attr_init(&pthreadInfo->attr);
|
||||
checkStatusOnce(status,"pthread_attr_init");
|
||||
if(status) return 0;
|
||||
status = pthread_attr_setdetachstate(
|
||||
&pthreadInfo->attr, PTHREAD_CREATE_DETACHED);
|
||||
checkStatusOnce(status,"pthread_attr_setdetachstate");
|
||||
#if defined (_POSIX_THREAD_ATTR_STACKSIZE)
|
||||
#if ! defined (OSITHREAD_USE_DEFAULT_STACK)
|
||||
status = pthread_attr_setstacksize( &pthreadInfo->attr,(size_t)stackSize);
|
||||
checkStatusOnce(status,"pthread_attr_setstacksize");
|
||||
#endif /*OSITHREAD_USE_DEFAULT_STACK*/
|
||||
#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
|
||||
status = pthread_attr_setscope(&pthreadInfo->attr,PTHREAD_SCOPE_PROCESS);
|
||||
if(errVerbose) checkStatusOnce(status,"pthread_attr_setscope");
|
||||
pthreadInfo->osiPriority = priority;
|
||||
return(pthreadInfo);
|
||||
}
|
||||
|
||||
static void free_threadInfo(epicsThreadOSD *pthreadInfo)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","free_threadInfo");
|
||||
if(pthreadInfo->isOnThreadList) ellDelete(&pthreadList,&pthreadInfo->node);
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","free_threadInfo");
|
||||
epicsEventDestroy(pthreadInfo->suspendEvent);
|
||||
status = pthread_attr_destroy(&pthreadInfo->attr);
|
||||
checkStatusQuit(status,"pthread_attr_destroy","free_threadInfo");
|
||||
free(pthreadInfo->name);
|
||||
free(pthreadInfo);
|
||||
}
|
||||
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
/*
|
||||
* The actually available range priority range (at least under linux)
|
||||
* may be restricted by resource limitations (but that is ignored
|
||||
* by sched_get_priority_max()). See bug #835138 which is fixed by
|
||||
* this code.
|
||||
*/
|
||||
|
||||
static int try_pri(int pri, int policy)
|
||||
{
|
||||
struct sched_param schedp;
|
||||
|
||||
schedp.sched_priority = pri;
|
||||
return pthread_setschedparam(pthread_self(), policy, &schedp);
|
||||
}
|
||||
|
||||
static void*
|
||||
find_pri_range(void *arg)
|
||||
{
|
||||
priAvailable *prm = arg;
|
||||
int min = sched_get_priority_min(prm->policy);
|
||||
int max = sched_get_priority_max(prm->policy);
|
||||
int low, try;
|
||||
|
||||
if ( -1 == min || -1 == max ) {
|
||||
/* something is very wrong; maintain old behavior
|
||||
* (warning message if sched_get_priority_xxx() fails
|
||||
* and use default policy's sched_priority [even if
|
||||
* that is likely to cause epicsThreadCreate to fail
|
||||
* because that priority is not suitable for SCHED_FIFO]).
|
||||
*/
|
||||
prm->min_pri = prm->max_pri = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if ( try_pri(min, prm->policy) ) {
|
||||
/* cannot create thread at minimum priority;
|
||||
* probably no permission to use SCHED_FIFO
|
||||
* at all. However, we still must return
|
||||
* a priority range accepted by the SCHED_FIFO
|
||||
* policy. Otherwise, epicsThreadCreate() cannot
|
||||
* detect the unsufficient permission (EPERM)
|
||||
* and fall back to a non-RT thread (because
|
||||
* pthread_attr_setschedparam would fail with
|
||||
* EINVAL due to the bad priority).
|
||||
*/
|
||||
prm->min_pri = prm->max_pri = min;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Binary search through available priorities.
|
||||
* The actually available range may be restricted
|
||||
* by resource limitations (but that is ignored
|
||||
* by sched_get_priority_max() [linux]).
|
||||
*/
|
||||
low = min;
|
||||
|
||||
while ( low < max ) {
|
||||
try = (max+low)/2;
|
||||
if ( try_pri(try, prm->policy) ) {
|
||||
max = try;
|
||||
} else {
|
||||
low = try + 1;
|
||||
}
|
||||
}
|
||||
|
||||
prm->min_pri = min;
|
||||
prm->max_pri = try_pri(max, prm->policy) ? max-1 : max;
|
||||
prm->ok = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void findPriorityRange(commonAttr *a_p)
|
||||
{
|
||||
priAvailable arg;
|
||||
pthread_t id;
|
||||
void *dummy;
|
||||
int status;
|
||||
|
||||
arg.policy = a_p->schedPolicy;
|
||||
arg.ok = 0;
|
||||
|
||||
status = pthread_create(&id, 0, find_pri_range, &arg);
|
||||
checkStatusQuit(status, "pthread_create","epicsThreadInit");
|
||||
|
||||
status = pthread_join(id, &dummy);
|
||||
checkStatusQuit(status, "pthread_join","epicsThreadInit");
|
||||
|
||||
a_p->minPriority = arg.min_pri;
|
||||
a_p->maxPriority = arg.max_pri;
|
||||
a_p->usePolicy = arg.ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void once(void)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
|
||||
pthread_key_create(&getpthreadInfo,0);
|
||||
status = pthread_mutex_init(&onceLock,0);
|
||||
checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
|
||||
status = pthread_mutex_init(&listLock,0);
|
||||
checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
|
||||
pcommonAttr = calloc(1,sizeof(commonAttr));
|
||||
if(!pcommonAttr) checkStatusOnceQuit(errno,"calloc","epicsThreadInit");
|
||||
status = pthread_attr_init(&pcommonAttr->attr);
|
||||
checkStatusOnceQuit(status,"pthread_attr_init","epicsThreadInit");
|
||||
status = pthread_attr_setdetachstate(
|
||||
&pcommonAttr->attr, PTHREAD_CREATE_DETACHED);
|
||||
checkStatusOnce(status,"pthread_attr_setdetachstate");
|
||||
status = pthread_attr_setscope(&pcommonAttr->attr,PTHREAD_SCOPE_PROCESS);
|
||||
if(errVerbose) checkStatusOnce(status,"pthread_attr_setscope");
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
status = pthread_attr_setschedpolicy(
|
||||
&pcommonAttr->attr,SCHED_FIFO);
|
||||
checkStatusOnce(status,"pthread_attr_setschedpolicy");
|
||||
status = pthread_attr_getschedpolicy(
|
||||
&pcommonAttr->attr,&pcommonAttr->schedPolicy);
|
||||
checkStatusOnce(status,"pthread_attr_getschedpolicy");
|
||||
status = pthread_attr_getschedparam(
|
||||
&pcommonAttr->attr,&pcommonAttr->schedParam);
|
||||
checkStatusOnce(status,"pthread_attr_getschedparam");
|
||||
|
||||
findPriorityRange(pcommonAttr);
|
||||
|
||||
if(pcommonAttr->maxPriority == -1) {
|
||||
pcommonAttr->maxPriority = pcommonAttr->schedParam.sched_priority;
|
||||
fprintf(stderr,"sched_get_priority_max failed set to %d\n",
|
||||
pcommonAttr->maxPriority);
|
||||
}
|
||||
if(pcommonAttr->minPriority == -1) {
|
||||
pcommonAttr->minPriority = pcommonAttr->schedParam.sched_priority;
|
||||
fprintf(stderr,"sched_get_priority_min failed set to %d\n",
|
||||
pcommonAttr->maxPriority);
|
||||
}
|
||||
#else
|
||||
if(errVerbose) fprintf(stderr,"task priorities are not implemented\n");
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0);
|
||||
pthreadInfo->lwpId = syscall(SYS_gettid);
|
||||
status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
|
||||
checkStatusOnceQuit(status,"pthread_setspecific","epicsThreadInit");
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsThreadInit");
|
||||
ellAdd(&pthreadList,&pthreadInfo->node);
|
||||
pthreadInfo->isOnThreadList = 1;
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadInit");
|
||||
status = atexit(epicsExitCallAtExits);
|
||||
checkStatusOnce(status,"atexit");
|
||||
epicsThreadOnceCalled = 1;
|
||||
}
|
||||
|
||||
static void * start_routine(void *arg)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo = (epicsThreadOSD *)arg;
|
||||
int status;
|
||||
sigset_t blockAllSig;
|
||||
char comm[16];
|
||||
|
||||
/* Set the name of the thread's process. Limited to 16 characters. */
|
||||
snprintf(comm, sizeof(comm), "%s", pthreadInfo->name);
|
||||
prctl(PR_SET_NAME, comm, 0l, 0l, 0l);
|
||||
pthreadInfo->lwpId = syscall(SYS_gettid);
|
||||
|
||||
sigfillset(&blockAllSig);
|
||||
pthread_sigmask(SIG_SETMASK,&blockAllSig,NULL);
|
||||
status = pthread_setspecific(getpthreadInfo,arg);
|
||||
checkStatusQuit(status,"pthread_setspecific","start_routine");
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","start_routine");
|
||||
ellAdd(&pthreadList,&pthreadInfo->node);
|
||||
pthreadInfo->isOnThreadList = 1;
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","start_routine");
|
||||
|
||||
(*pthreadInfo->createFunc)(pthreadInfo->createArg);
|
||||
|
||||
epicsExitCallAtThreadExits ();
|
||||
|
||||
free_threadInfo(pthreadInfo);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void epicsThreadInit(void)
|
||||
{
|
||||
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
|
||||
int status = pthread_once(&once_control,once);
|
||||
checkStatusQuit(status,"pthread_once","epicsThreadInit");
|
||||
}
|
||||
|
||||
|
||||
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
|
||||
{
|
||||
#if ! defined (_POSIX_THREAD_ATTR_STACKSIZE)
|
||||
return 0;
|
||||
#elif defined (OSITHREAD_USE_DEFAULT_STACK)
|
||||
return 0;
|
||||
#else
|
||||
#define STACK_SIZE(f) (f * 0x10000 * sizeof(void *))
|
||||
static const unsigned stackSizeTable[epicsThreadStackBig+1] = {
|
||||
STACK_SIZE(1), STACK_SIZE(2), STACK_SIZE(4)
|
||||
};
|
||||
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];
|
||||
#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
|
||||
{
|
||||
static struct epicsThreadOSD threadOnceComplete;
|
||||
#define EPICS_THREAD_ONCE_DONE &threadOnceComplete
|
||||
int status;
|
||||
|
||||
epicsThreadInit();
|
||||
status = mutexLock(&onceLock);
|
||||
if(status) {
|
||||
fprintf(stderr,"epicsThreadOnce: pthread_mutex_lock returned %s.\n",
|
||||
strerror(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (*id != EPICS_THREAD_ONCE_DONE) {
|
||||
if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
|
||||
*id = epicsThreadGetIdSelf(); /* mark active */
|
||||
status = pthread_mutex_unlock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
|
||||
func(arg);
|
||||
status = mutexLock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
|
||||
*id = EPICS_THREAD_ONCE_DONE; /* mark done */
|
||||
} else if (*id == epicsThreadGetIdSelf()) {
|
||||
status = pthread_mutex_unlock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
|
||||
cantProceed("Recursive epicsThreadOnce() initialization\n");
|
||||
} else
|
||||
while (*id != EPICS_THREAD_ONCE_DONE) {
|
||||
/* Another thread is in the above func(arg) call. */
|
||||
status = pthread_mutex_unlock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
|
||||
epicsThreadSleep(epicsThreadSleepQuantum());
|
||||
status = mutexLock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
|
||||
}
|
||||
}
|
||||
status = pthread_mutex_unlock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadOnce");
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate(const char *name,
|
||||
unsigned int priority, unsigned int stackSize,
|
||||
EPICSTHREADFUNC funptr,void *parm)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
sigset_t blockAllSig, oldSig;
|
||||
|
||||
epicsThreadInit();
|
||||
assert(pcommonAttr);
|
||||
sigfillset(&blockAllSig);
|
||||
pthread_sigmask(SIG_SETMASK,&blockAllSig,&oldSig);
|
||||
pthreadInfo = init_threadInfo(name,priority,stackSize,funptr,parm);
|
||||
if(pthreadInfo==0) return 0;
|
||||
pthreadInfo->isEpicsThread = 1;
|
||||
setSchedulingPolicy(pthreadInfo,SCHED_FIFO);
|
||||
pthreadInfo->isFifoScheduled = 1;
|
||||
status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr,
|
||||
start_routine,pthreadInfo);
|
||||
if(status==EPERM){
|
||||
/* Try again without SCHED_FIFO*/
|
||||
free_threadInfo(pthreadInfo);
|
||||
pthreadInfo = init_threadInfo(name,priority,stackSize,funptr,parm);
|
||||
if(pthreadInfo==0) return 0;
|
||||
pthreadInfo->isEpicsThread = 1;
|
||||
status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr,
|
||||
start_routine,pthreadInfo);
|
||||
}
|
||||
checkStatusOnce(status,"pthread_create");
|
||||
if(status) {
|
||||
free_threadInfo(pthreadInfo);
|
||||
return 0;
|
||||
}
|
||||
status = pthread_sigmask(SIG_SETMASK,&oldSig,NULL);
|
||||
checkStatusOnce(status,"pthread_sigmask");
|
||||
return(pthreadInfo);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup routine for threads not created by epicsThreadCreate().
|
||||
*/
|
||||
/* static void nonEPICSthreadCleanup(void *arg)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo = (epicsThreadOSD *)arg;
|
||||
|
||||
free(pthreadInfo->name);
|
||||
free(pthreadInfo);
|
||||
} */
|
||||
|
||||
/*
|
||||
* Create dummy context for threads not created by epicsThreadCreate().
|
||||
*/
|
||||
static epicsThreadOSD *createImplicit(void)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
char name[64];
|
||||
pthread_t tid;
|
||||
int status;
|
||||
|
||||
tid = pthread_self();
|
||||
sprintf(name, "non-EPICS_%ld", (long)tid);
|
||||
pthreadInfo = create_threadInfo(name);
|
||||
pthreadInfo->tid = tid;
|
||||
pthreadInfo->osiPriority = 0;
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
{
|
||||
struct sched_param param;
|
||||
int policy;
|
||||
if(pthread_getschedparam(tid,&policy,¶m) == 0)
|
||||
pthreadInfo->osiPriority =
|
||||
(param.sched_priority - pcommonAttr->minPriority) * 100.0 /
|
||||
(pcommonAttr->maxPriority - pcommonAttr->minPriority + 1);
|
||||
}
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
|
||||
checkStatusQuit(status,"pthread_setspecific","createImplicit");
|
||||
/* pthread_cleanup_push(nonEPICSthreadCleanup, pthreadInfo); */
|
||||
return pthreadInfo;
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
epicsThreadInit();
|
||||
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
|
||||
if(pthreadInfo==NULL)
|
||||
pthreadInfo = createImplicit();
|
||||
pthreadInfo->isSuspended = 1;
|
||||
epicsEventMustWait(pthreadInfo->suspendEvent);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadOSD *pthreadInfo)
|
||||
{
|
||||
assert(epicsThreadOnceCalled);
|
||||
pthreadInfo->isSuspended = 0;
|
||||
epicsEventSignal(pthreadInfo->suspendEvent);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadExitMain(void)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
epicsThreadInit();
|
||||
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
|
||||
if(pthreadInfo==NULL)
|
||||
pthreadInfo = createImplicit();
|
||||
if(pthreadInfo->createFunc) {
|
||||
errlogPrintf("called from non-main thread\n");
|
||||
cantProceed("epicsThreadExitMain");
|
||||
}
|
||||
else {
|
||||
free_threadInfo(pthreadInfo);
|
||||
pthread_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority(epicsThreadId pthreadInfo)
|
||||
{
|
||||
assert(epicsThreadOnceCalled);
|
||||
return(pthreadInfo->osiPriority);
|
||||
}
|
||||
|
||||
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPrioritySelf(void)
|
||||
{
|
||||
epicsThreadInit();
|
||||
return(epicsThreadGetPriority(epicsThreadGetIdSelf()));
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadSetPriority(epicsThreadId pthreadInfo,unsigned int priority)
|
||||
{
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
int status;
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
assert(pthreadInfo);
|
||||
if(!pthreadInfo->isEpicsThread) {
|
||||
fprintf(stderr,"epicsThreadSetPriority called by non epics thread\n");
|
||||
return;
|
||||
}
|
||||
pthreadInfo->osiPriority = priority;
|
||||
if(!pthreadInfo->isFifoScheduled) return;
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
if(!pcommonAttr->usePolicy) return;
|
||||
pthreadInfo->schedParam.sched_priority = getOssPriorityValue(pthreadInfo);
|
||||
status = pthread_attr_setschedparam(
|
||||
&pthreadInfo->attr,&pthreadInfo->schedParam);
|
||||
if(errVerbose) checkStatus(status,"pthread_attr_setschedparam");
|
||||
status = pthread_setschedparam(
|
||||
pthreadInfo->tid,pcommonAttr->schedPolicy,&pthreadInfo->schedParam);
|
||||
if(errVerbose) checkStatus(status,"pthread_setschedparam");
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadHighestPriorityLevelBelow(
|
||||
unsigned int priority, unsigned *pPriorityJustBelow)
|
||||
{
|
||||
unsigned newPriority = priority - 1;
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
int diff;
|
||||
diff = pcommonAttr->maxPriority - pcommonAttr->minPriority;
|
||||
if(diff<0) diff = -diff;
|
||||
if(diff>1 && diff <100) newPriority -= 100/(diff+1);
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
if (newPriority <= 99) {
|
||||
*pPriorityJustBelow = newPriority;
|
||||
return epicsThreadBooleanStatusSuccess;
|
||||
}
|
||||
return epicsThreadBooleanStatusFail;
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadLowestPriorityLevelAbove(
|
||||
unsigned int priority, unsigned *pPriorityJustAbove)
|
||||
{
|
||||
unsigned newPriority = priority + 1;
|
||||
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
int diff;
|
||||
diff = pcommonAttr->maxPriority - pcommonAttr->minPriority;
|
||||
if(diff<0) diff = -diff;
|
||||
if(diff>1 && diff <100) newPriority += 100/(diff+1);
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
if (newPriority <= 99) {
|
||||
*pPriorityJustAbove = newPriority;
|
||||
return epicsThreadBooleanStatusSuccess;
|
||||
}
|
||||
return epicsThreadBooleanStatusFail;
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsThreadIsEqual(epicsThreadId p1, epicsThreadId p2)
|
||||
{
|
||||
assert(epicsThreadOnceCalled);
|
||||
assert(p1);
|
||||
assert(p2);
|
||||
return(pthread_equal(p1->tid,p2->tid));
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsThreadIsSuspended(epicsThreadId pthreadInfo) {
|
||||
assert(epicsThreadOnceCalled);
|
||||
assert(pthreadInfo);
|
||||
return(pthreadInfo->isSuspended ? 1 : 0);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadSleep(double seconds)
|
||||
{
|
||||
struct timespec delayTime;
|
||||
struct timespec remainingTime;
|
||||
double nanoseconds;
|
||||
|
||||
if (seconds > 0) {
|
||||
delayTime.tv_sec = seconds;
|
||||
nanoseconds = (seconds - delayTime.tv_sec) *1e9;
|
||||
delayTime.tv_nsec = nanoseconds;
|
||||
}
|
||||
else {
|
||||
delayTime.tv_sec = 0;
|
||||
delayTime.tv_nsec = 0;
|
||||
}
|
||||
while (nanosleep(&delayTime, &remainingTime) == -1 &&
|
||||
errno == EINTR)
|
||||
delayTime = remainingTime;
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetIdSelf(void) {
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
epicsThreadInit();
|
||||
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
|
||||
if(pthreadInfo==NULL)
|
||||
pthreadInfo = createImplicit();
|
||||
assert ( pthreadInfo );
|
||||
return(pthreadInfo);
|
||||
}
|
||||
|
||||
epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId ( epicsThreadId threadId )
|
||||
{
|
||||
return threadId->tid;
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId(const char *name) {
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsThreadGetId");
|
||||
pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
|
||||
while(pthreadInfo) {
|
||||
if(strcmp(name,pthreadInfo->name) == 0) break;
|
||||
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
|
||||
}
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadGetId");
|
||||
|
||||
return(pthreadInfo);
|
||||
}
|
||||
|
||||
epicsShareFunc const char epicsShareAPI *epicsThreadGetNameSelf()
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
epicsThreadInit();
|
||||
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
|
||||
if(pthreadInfo==NULL)
|
||||
pthreadInfo = createImplicit();
|
||||
return(pthreadInfo->name);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadGetName(epicsThreadId pthreadInfo, char *name, size_t size)
|
||||
{
|
||||
assert(epicsThreadOnceCalled);
|
||||
strncpy(name, pthreadInfo->name, size-1);
|
||||
name[size-1] = '\0';
|
||||
}
|
||||
|
||||
static void showThreadInfo(epicsThreadOSD *pthreadInfo,unsigned int level)
|
||||
{
|
||||
if(!pthreadInfo) {
|
||||
fprintf(epicsGetStdout()," NAME EPICS ID "
|
||||
"LWP ID OSIPRI OSSPRI STATE\n");
|
||||
} else {
|
||||
struct sched_param param;
|
||||
int policy;
|
||||
int priority = 0;
|
||||
|
||||
if(pthreadInfo->tid) {
|
||||
int status;
|
||||
status = pthread_getschedparam(pthreadInfo->tid,&policy,¶m);
|
||||
if(!status) priority = param.sched_priority;
|
||||
}
|
||||
fprintf(epicsGetStdout(),"%16.16s %18p %8lu %3d%8d %8.8s\n",
|
||||
pthreadInfo->name,(void *)
|
||||
pthreadInfo,(unsigned long)pthreadInfo->lwpId,
|
||||
pthreadInfo->osiPriority,priority,
|
||||
pthreadInfo->isSuspended?"SUSPEND":"OK");
|
||||
}
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
|
||||
epicsThreadInit();
|
||||
epicsThreadShow(0,level);
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsThreadShowAll");
|
||||
pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
|
||||
while(pthreadInfo) {
|
||||
showThreadInfo(pthreadInfo,level);
|
||||
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
|
||||
}
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadShowAll");
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsigned int level)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
int found = 0;
|
||||
|
||||
epicsThreadInit();
|
||||
if(!showThread) {
|
||||
showThreadInfo(0,level);
|
||||
return;
|
||||
}
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsThreadShowAll");
|
||||
pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
|
||||
while(pthreadInfo) {
|
||||
if (((epicsThreadId)pthreadInfo == showThread)
|
||||
|| ((epicsThreadId)pthreadInfo->tid == showThread)) {
|
||||
found = 1;
|
||||
showThreadInfo(pthreadInfo,level);
|
||||
}
|
||||
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
|
||||
}
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadShowAll");
|
||||
if (!found)
|
||||
printf("Thread %#lx (%lu) not found.\n", (unsigned long)showThread, (unsigned long)showThread);
|
||||
}
|
||||
|
||||
|
||||
epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void)
|
||||
{
|
||||
pthread_key_t *key;
|
||||
int status;
|
||||
|
||||
epicsThreadInit();
|
||||
key = callocMustSucceed(1,sizeof(pthread_key_t),"epicsThreadPrivateCreate");
|
||||
status = pthread_key_create(key,0);
|
||||
checkStatusQuit(status,"pthread_key_create","epicsThreadPrivateCreate");
|
||||
return((epicsThreadPrivateId)key);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id)
|
||||
{
|
||||
pthread_key_t *key = (pthread_key_t *)id;
|
||||
int status;
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
status = pthread_key_delete(*key);
|
||||
checkStatusQuit(status,"pthread_key_delete","epicsThreadPrivateDelete");
|
||||
free((void *)key);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadPrivateSet (epicsThreadPrivateId id, void *value)
|
||||
{
|
||||
pthread_key_t *key = (pthread_key_t *)id;
|
||||
int status;
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
if(errVerbose && !value)
|
||||
errlogPrintf("epicsThreadPrivateSet: setting value of 0\n");
|
||||
status = pthread_setspecific(*key,value);
|
||||
checkStatusQuit(status,"pthread_setspecific","epicsThreadPrivateSet");
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI *epicsThreadPrivateGet(epicsThreadPrivateId id)
|
||||
{
|
||||
pthread_key_t *key = (pthread_key_t *)id;
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
return pthread_getspecific(*key);
|
||||
}
|
||||
|
||||
epicsShareFunc double epicsShareAPI epicsThreadSleepQuantum ()
|
||||
{
|
||||
double hz;
|
||||
hz = sysconf ( _SC_CLK_TCK );
|
||||
return 1.0 / hz;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,22 @@ static long vxDevWriteProbe (unsigned wordSize, volatile void *ptr, const void *
|
||||
|
||||
static void *devA24Malloc(size_t size);
|
||||
static void devA24Free(void *pBlock);
|
||||
static long devInit(void) { return 0;}
|
||||
|
||||
|
||||
static int (*sysIntEnableFunc)(int) = NULL;
|
||||
static int (*sysIntDisableFunc)(int) = NULL;
|
||||
static int (*sysIntEnablePICFunc)(int) = NULL;
|
||||
static int (*sysIntDisablePICFunc)(int) = NULL;
|
||||
|
||||
static long devInit(void)
|
||||
{
|
||||
/* We don't know which functions are implemented in the BSP */
|
||||
sysIntEnableFunc = epicsFindSymbol ("sysIntEnable");
|
||||
sysIntDisableFunc = epicsFindSymbol ("sysIntDisable");
|
||||
sysIntDisablePICFunc = epicsFindSymbol ("sysIntDisablePIC");
|
||||
sysIntEnablePICFunc = epicsFindSymbol ("sysIntEnablePIC");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long vxDevConnectInterruptVME (
|
||||
unsigned vectorNumber,
|
||||
@@ -214,16 +229,8 @@ static long vxDevDisconnectInterruptVME (
|
||||
*/
|
||||
static long vxDevEnableInterruptLevelVME (unsigned level)
|
||||
{
|
||||
# if CPU_FAMILY != I80X86
|
||||
int s;
|
||||
s = sysIntEnable (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intEnFail;
|
||||
}
|
||||
return 0;
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
if (!sysIntEnableFunc) return S_dev_intEnFail;
|
||||
return sysIntEnableFunc (level) == OK ? 0 : S_dev_intEnFail;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -231,16 +238,8 @@ static long vxDevEnableInterruptLevelVME (unsigned level)
|
||||
*/
|
||||
long devEnableInterruptLevelISA (unsigned level)
|
||||
{
|
||||
# if CPU_FAMILY == I80X86
|
||||
int s;
|
||||
s = sysIntEnablePIC (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intEnFail;
|
||||
}
|
||||
return 0;
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
if (!sysIntEnablePICFunc) return S_dev_intEnFail;
|
||||
return sysIntEnablePICFunc (level) == OK ? 0 : S_dev_intEnFail;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -248,17 +247,8 @@ long devEnableInterruptLevelISA (unsigned level)
|
||||
*/
|
||||
long devDisableInterruptLevelISA (unsigned level)
|
||||
{
|
||||
# if CPU_FAMILY == I80X86
|
||||
int s;
|
||||
s = sysIntDisablePIC (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intEnFail;
|
||||
}
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
|
||||
return 0;
|
||||
if (!sysIntDisablePICFunc) return S_dev_intDissFail;
|
||||
return sysIntDisablePICFunc (level) == OK ? 0 : S_dev_intDissFail;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -266,16 +256,8 @@ long devDisableInterruptLevelISA (unsigned level)
|
||||
*/
|
||||
static long vxDevDisableInterruptLevelVME (unsigned level)
|
||||
{
|
||||
# if CPU_FAMILY != I80X86
|
||||
int s;
|
||||
s = sysIntDisable (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intDissFail;
|
||||
}
|
||||
return 0;
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
if (!sysIntDisableFunc) return S_dev_intDissFail;
|
||||
return sysIntDisableFunc (level) == OK ? 0 : S_dev_intDissFail;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -176,7 +176,7 @@ recordtype(ai) {
|
||||
pp(TRUE)
|
||||
interest(2)
|
||||
}
|
||||
field(ROFF,DBF_ULONG) {
|
||||
field(ROFF,DBF_LONG) {
|
||||
prompt("Raw Offset")
|
||||
pp(TRUE)
|
||||
interest(2)
|
||||
|
||||
@@ -82,7 +82,7 @@ recordtype(ao) {
|
||||
interest(1)
|
||||
size(16)
|
||||
}
|
||||
field(ROFF,DBF_ULONG) {
|
||||
field(ROFF,DBF_LONG) {
|
||||
prompt("Raw Offset")
|
||||
pp(TRUE)
|
||||
interest(2)
|
||||
|
||||
27
startup/win64.bat
Normal file
27
startup/win64.bat
Normal file
@@ -0,0 +1,27 @@
|
||||
@ECHO OFF
|
||||
REM *************************************************************************
|
||||
REM Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
REM National Laboratory.
|
||||
REM Copyright (c) 2002 The Regents of the University of California, as
|
||||
REM Operator of Los Alamos National Laboratory.
|
||||
REM EPICS BASE Versions 3.13.7
|
||||
REM and higher are distributed subject to a Software License Agreement found
|
||||
REM in file LICENSE that is included with this distribution.
|
||||
|
||||
set PATH=%PATH%;C:\cygwin\bin
|
||||
REM --------------- Visual c++ ------------------------
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" amd64
|
||||
|
||||
REM --------------- CUDA -----------------------------
|
||||
|
||||
|
||||
REM --------------- EPICS -----------------------------
|
||||
REM -- R3.14 requirements
|
||||
set EPICS_HOST_ARCH=windows-x64
|
||||
set PATH=%PATH%;C:\epics\base-3.14.12.4\bin\%EPICS_HOST_ARCH%
|
||||
REM ===================================================
|
||||
REM ====== OPTIONAL ENVIRONMENT VARIABLES FOLLOW ======
|
||||
|
||||
REM ---------------- EPICS tools ----------------------
|
||||
REM -- HOST_ARCH needed for Makefile.Host builds --
|
||||
set HOST_ARCH=WIN32
|
||||
Reference in New Issue
Block a user