Merged Ralph's thread-hooks branch.

Minor modifications to fix the vxWorks epicsThreadInit() and
rename some functions.
This commit is contained in:
Andrew Johnson
2012-07-04 13:28:55 -05:00
16 changed files with 570 additions and 67 deletions

View File

@@ -15,6 +15,17 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.</p>
<h2 align="center">Changes between 3.14.x and 3.15.0.x</h2>
<!-- Insert new items immediately below here ... -->
<h3>New API to hook into thread creation</h3>
<p>A hook API has been added allowing user-supplied functions to be called
whenever a thread starts. The calls are made from the thread's context,
and can be used to control additional thread properties not handled inside
EPICS base, e.g. setting the scheduling policy or CPU affinity (on SMP
systems).</p>
<p>The API also supports a mapping operation, calling a user-supplied function
for every thread that is currently running.</p>
<h3>New scan rate units</h3>
<p>Scan rates defined in the menuScan.dbd file may now be specified in seconds,

View File

@@ -104,6 +104,8 @@ THREAD_CPPFLAGS_NO += -DDONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING
osdThread_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING))
Com_SRCS += osdThread.c
Com_SRCS += osdThreadExtra.c
Com_SRCS += osdThreadHooks.c
Com_SRCS += osdMutex.c
Com_SRCS += osdEvent.c
Com_SRCS += osdTime.cpp

View File

@@ -3,8 +3,8 @@
* 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
* Copyright (c) 2012 ITER Organization
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef epicsThreadh
@@ -101,6 +101,11 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level);
epicsShareFunc void epicsShareAPI epicsThreadShow(
epicsThreadId id,unsigned int level);
/* Hooks called when a thread starts, map function called once for every thread */
typedef void (*EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id);
epicsShareFunc void epicsThreadHookAdd(EPICS_THREAD_HOOK_ROUTINE hook);
epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func);
typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId;
epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void);
epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id);

View File

@@ -0,0 +1,45 @@
/*************************************************************************\
* 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 is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef INC_osdThread_H
#define INC_osdThread_H
#include <pthread.h>
#include "shareLib.h"
#include "ellLib.h"
#include "epicsEvent.h"
#ifdef __cplusplus
extern "C" {
#endif
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[1]; /* actually larger */
} epicsThreadOSD;
epicsShareFunc pthread_t epicsThreadGetPosixThreadId(epicsThreadId id);
#ifdef __cplusplus
}
#endif
#endif /* INC_osdThread_H */

View File

@@ -0,0 +1,69 @@
/*************************************************************************\
* 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.
* Copyright (c) 2012 ITER Organization
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 18JAN2000 */
/* This differs from the posix implementation of epicsThread by:
* - printing the Linux LWP ID instead of the POSIX thread ID in the show routines
* - installing a default thread start hook, that sets the Linux thread name to the
* EPICS thread name to make it visible on OS level, and discovers the LWP ID */
#include <unistd.h>
#include <signal.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/prctl.h>
#define epicsExportSharedSymbols
#include "epicsStdio.h"
#include "ellLib.h"
#include "epicsEvent.h"
#include "epicsThread.h"
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadHookDefault;
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadHookMain;
void epicsThreadShowInfo(epicsThreadId pthreadInfo, unsigned int level)
{
if (!pthreadInfo) {
fprintf(epicsGetStdout(), " NAME EPICS ID "
"LWP ID OSIPRI OSSPRI STATE\n");
} else {
struct sched_param param;
int priority = 0;
if (pthreadInfo->tid) {
int policy;
int status = pthread_getschedparam(pthreadInfo->tid, &policy,
&param);
if (!status)
priority = param.sched_priority;
}
fprintf(epicsGetStdout(),"%16.16s %12p %8lu %3d%8d %8.8s\n",
pthreadInfo->name,(void *)
pthreadInfo,(unsigned long)pthreadInfo->lwpId,
pthreadInfo->osiPriority,priority,
pthreadInfo->isSuspended ? "SUSPEND" : "OK");
}
}
static void thread_hook(epicsThreadId pthreadInfo)
{
/* Set the name of the thread's process. Limited to 16 characters. */
char comm[16];
snprintf(comm, sizeof(comm), "%s", pthreadInfo->name);
prctl(PR_SET_NAME, comm, 0l, 0l, 0l);
pthreadInfo->lwpId = syscall(SYS_gettid);
}
EPICS_THREAD_HOOK_ROUTINE epicsThreadHookDefault = thread_hook;
EPICS_THREAD_HOOK_ROUTINE epicsThreadHookMain = thread_hook;

View File

@@ -39,6 +39,9 @@
#include "osdInterrupt.h"
#include "epicsExit.h"
epicsShareFunc void epicsThreadHooksInit(epicsThreadId id);
epicsShareFunc void epicsThreadHooksRun(epicsThreadId id);
/*
* Per-task variables
*/
@@ -164,6 +167,7 @@ threadWrapper (rtems_task_argument arg)
{
struct taskVar *v = (struct taskVar *)arg;
epicsThreadHooksRun(v->id);
(*v->funptr)(v->parm);
epicsExitCallAtThreadExits ();
taskVarLock ();
@@ -235,6 +239,7 @@ epicsThreadInit (void)
taskVarMutex = epicsMutexMustCreate ();
rtems_task_ident (RTEMS_SELF, 0, &tid);
setThreadInfo (tid, "_main_", NULL, NULL);
epicsThreadHooksInit(tid);
initialized = 1;
epicsThreadCreate ("ImsgDaemon", 99,
epicsThreadGetStackSize (epicsThreadStackSmall),
@@ -639,20 +644,18 @@ showInternalTaskInfo (rtems_id tid)
#endif
}
static void
epicsThreadShowHeader (void)
{
fprintf(epicsGetStdout()," PRIORITY\n");
fprintf(epicsGetStdout()," ID EPICS RTEMS STATE WAIT NAME\n");
fprintf(epicsGetStdout(),"+--------+-----------+--------+--------+---------------------+\n");
}
static void
epicsThreadShowInfo (struct taskVar *v, unsigned int level)
{
if (!v) {
fprintf(epicsGetStdout()," PRIORITY\n");
fprintf(epicsGetStdout()," ID EPICS RTEMS STATE WAIT NAME\n");
fprintf(epicsGetStdout(),"+--------+-----------+--------+--------+---------------------+\n");
} else {
fprintf(epicsGetStdout(),"%9.8x", (int)v->id);
showInternalTaskInfo (v->id);
fprintf(epicsGetStdout()," %s\n", v->name);
}
}
void epicsThreadShow (epicsThreadId id, unsigned int level)
@@ -660,7 +663,7 @@ void epicsThreadShow (epicsThreadId id, unsigned int level)
struct taskVar *v;
if (!id) {
epicsThreadShowHeader ();
epicsThreadShowInfo (NULL, level);
return;
}
taskVarLock ();
@@ -674,6 +677,23 @@ void epicsThreadShow (epicsThreadId id, unsigned int level)
fprintf(epicsGetStdout(),"*** Thread %x does not exist.\n", (unsigned int)id);
}
void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func)
{
struct taskVar *v;
taskVarLock ();
/*
* Map tasks in the order of creation (backwards through list)
*/
for (v = taskVarHead ; v != NULL && v->forw != NULL ; v = v->forw)
continue;
while (v) {
func ((epicsThreadId)v->id);
v = v->back;
}
taskVarUnlock ();
}
void epicsThreadShowAll (unsigned int level)
{
struct taskVar *v;

View File

@@ -38,6 +38,9 @@
#include "ellLib.h"
#include "epicsExit.h"
epicsShareFunc void epicsThreadHooksInit(epicsThreadId id);
epicsShareFunc void epicsThreadHooksRun(epicsThreadId id);
void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName );
static void threadCleanupWIN32 ( void );
@@ -226,6 +229,7 @@ static win32ThreadGlobal * fetchWin32ThreadGlobal ( void )
pWin32ThreadGlobal = 0;
return 0;
}
epicsThreadHooksInit (NULL);
InterlockedExchange ( & initCompleted, 1 );
@@ -496,6 +500,7 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter )
success = TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, pParm );
if ( success ) {
epicsThreadHooksRun ( ( epicsThreadId ) pParm );
/* printf ( "starting thread %d\n", pParm->id ); */
( *pParm->funptr ) ( pParm->parm );
/* printf ( "terminating thread %d\n", pParm->id ); */
@@ -510,7 +515,6 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter )
}
epicsExitCallAtThreadExits ();
/*
* CAUTION: !!!! the thread id might continue to be used after this thread exits !!!!
*/
@@ -947,9 +951,9 @@ static const char * epics_GetThreadPriorityAsString ( HANDLE thr )
}
/*
* epicsThreadShowPrivate ()
* epicsThreadShowInfo ()
*/
static void epicsThreadShowPrivate ( epicsThreadId id, unsigned level )
static void epicsThreadShowInfo ( epicsThreadId id, unsigned level )
{
win32ThreadParam * pParm = ( win32ThreadParam * ) id;
@@ -974,6 +978,28 @@ static void epicsThreadShowPrivate ( epicsThreadId id, unsigned level )
fprintf (epicsGetStdout(),"\n" );
}
/*
* epicsThreadMap ()
*/
epicsShareFunc void epicsShareAPI epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func )
{
win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
win32ThreadParam * pParm;
if ( ! pGbl ) {
return;
}
EnterCriticalSection ( & pGbl->mutex );
for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {
func ( ( epicsThreadId ) pParm );
}
LeaveCriticalSection ( & pGbl->mutex );
}
/*
* epicsThreadShowAll ()
*/
@@ -987,11 +1013,11 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll ( unsigned level )
}
EnterCriticalSection ( & pGbl->mutex );
epicsThreadShowPrivate ( 0, level );
for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
epicsThreadShowInfo ( 0, level );
for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {
epicsThreadShowPrivate ( ( epicsThreadId ) pParm, level );
epicsThreadShowInfo ( ( epicsThreadId ) pParm, level );
}
LeaveCriticalSection ( & pGbl->mutex );
@@ -1002,8 +1028,8 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll ( unsigned level )
*/
epicsShareFunc void epicsShareAPI epicsThreadShow ( epicsThreadId id, unsigned level )
{
epicsThreadShowPrivate ( 0, level );
epicsThreadShowPrivate ( id, level );
epicsThreadShowInfo ( 0, level );
epicsThreadShowInfo ( id, level );
}
/*

View File

@@ -0,0 +1,19 @@
/*************************************************************************\
* Copyright (c) 2012 ITER Organization
*
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Ralph Lange Date: 26 Jun 2012 */
/* Null default thread hooks for all platforms that do not do anything special */
#define epicsExportSharedSymbols
#include "shareLib.h"
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadHookDefault;
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadHookMain;
EPICS_THREAD_HOOK_ROUTINE epicsThreadHookDefault;
EPICS_THREAD_HOOK_ROUTINE epicsThreadHookMain;

View File

@@ -0,0 +1,75 @@
/*************************************************************************\
* Copyright (c) 2012 ITER Organization
*
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Ralph Lange Date: 28 Jun 2012 */
/* Secure hooks for epicsThread */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define epicsExportSharedSymbols
#include "ellLib.h"
#include "epicsMutex.h"
#include "epicsThread.h"
epicsShareFunc void epicsThreadHooksRun(epicsThreadId id);
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadHookDefault;
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadHookMain;
#define checkStatusOnceReturn(status, message, method) \
if((status)) { \
fprintf(stderr,"%s error %s\n",(message),strerror((status))); \
fprintf(stderr," %s\n",(method)); \
return; }
typedef struct epicsThreadHook {
ELLNODE node;
EPICS_THREAD_HOOK_ROUTINE func;
} epicsThreadHook;
static ELLLIST startHooks = ELLLIST_INIT;
static epicsMutexId hookLock;
epicsShareFunc void epicsThreadHookAdd(EPICS_THREAD_HOOK_ROUTINE hook)
{
epicsThreadHook *pHook;
pHook = calloc(1, sizeof(epicsThreadHook));
if (!pHook)
checkStatusOnceReturn(errno, "calloc", "epicsThreadHookAdd");
pHook->func = hook;
epicsMutexLock(hookLock);
ellAdd(&startHooks, &pHook->node);
epicsMutexUnlock(hookLock);
}
epicsShareFunc void epicsThreadHooksInit(epicsThreadId id)
{
if (!hookLock) {
hookLock = epicsMutexMustCreate();
if (epicsThreadHookDefault)
epicsThreadHookAdd(epicsThreadHookDefault);
}
if (id && epicsThreadHookMain)
epicsThreadHookMain(id);
}
epicsShareFunc void epicsThreadHooksRun(epicsThreadId id)
{
epicsThreadHook *pHook;
epicsMutexLock(hookLock);
pHook = (epicsThreadHook *) ellFirst(&startHooks);
while (pHook) {
pHook->func(id);
pHook = (epicsThreadHook *) ellNext(&pHook->node);
}
epicsMutexUnlock(hookLock);
}

View File

@@ -3,6 +3,7 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* Copyright (c) 2012 ITER Organization
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
@@ -34,6 +35,10 @@
#include "epicsAssert.h"
#include "epicsExit.h"
epicsShareFunc void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level);
epicsShareFunc void epicsThreadHooksInit(epicsThreadId id);
epicsShareFunc void epicsThreadHooksRun(epicsThreadId id);
static int mutexLock(pthread_mutex_t *id)
{
int status;
@@ -57,22 +62,6 @@ typedef struct commonAttr{
int schedPolicy;
} commonAttr;
typedef struct epicsThreadOSD {
ELLNODE node;
pthread_t tid;
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[1]; /* actually larger */
} epicsThreadOSD;
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
typedef struct {
int min_pri, max_pri;
@@ -366,6 +355,7 @@ static void once(void)
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadInit");
status = atexit(epicsExitCallAtExits);
checkStatusOnce(status,"atexit");
epicsThreadHooksInit(pthreadInfo);
epicsThreadOnceCalled = 1;
}
@@ -375,7 +365,7 @@ static void * start_routine(void *arg)
int status;
int oldtype;
sigset_t blockAllSig;
sigfillset(&blockAllSig);
pthread_sigmask(SIG_SETMASK,&blockAllSig,NULL);
status = pthread_setspecific(getpthreadInfo,arg);
@@ -388,11 +378,11 @@ static void * start_routine(void *arg)
pthreadInfo->isOnThreadList = 1;
status = pthread_mutex_unlock(&listLock);
checkStatusQuit(status,"pthread_mutex_unlock","start_routine");
epicsThreadHooksRun(pthreadInfo);
(*pthreadInfo->createFunc)(pthreadInfo->createArg);
epicsExitCallAtThreadExits ();
free_threadInfo(pthreadInfo);
return(0);
}
@@ -704,7 +694,7 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetIdSelf(void) {
return(pthreadInfo);
}
epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId ( epicsThreadId threadId )
epicsShareFunc pthread_t epicsThreadGetPosixThreadId ( epicsThreadId threadId )
{
return threadId->tid;
}
@@ -747,27 +737,23 @@ epicsShareFunc void epicsShareAPI epicsThreadGetName(epicsThreadId pthreadInfo,
name[size-1] = '\0';
}
static void showThreadInfo(epicsThreadOSD *pthreadInfo,unsigned int level)
epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func)
{
if(!pthreadInfo) {
fprintf(epicsGetStdout()," NAME EPICS ID "
"PTHREAD ID OSIPRI OSSPRI STATE\n");
} else {
struct sched_param param;
int policy;
int priority = 0;
epicsThreadOSD *pthreadInfo;
int status;
if(pthreadInfo->tid) {
int status;
status = pthread_getschedparam(pthreadInfo->tid,&policy,&param);
if(!status) priority = param.sched_priority;
}
fprintf(epicsGetStdout(),"%16.16s %12p %12lu %3d%8d %8.8s\n",
pthreadInfo->name,(void *)
pthreadInfo,(unsigned long)pthreadInfo->tid,
pthreadInfo->osiPriority,priority,
pthreadInfo->isSuspended?"SUSPEND":"OK");
epicsThreadInit();
status = mutexLock(&listLock);
checkStatus(status, "pthread_mutex_lock epicsThreadMap");
if (status)
return;
pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
while (pthreadInfo) {
func(pthreadInfo);
pthreadInfo = (epicsThreadOSD *)ellNext(&pthreadInfo->node);
}
status = pthread_mutex_unlock(&listLock);
checkStatus(status, "pthread_mutex_unlock epicsThreadMap");
}
epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level)
@@ -783,7 +769,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level)
return;
pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
while(pthreadInfo) {
showThreadInfo(pthreadInfo,level);
epicsThreadShowInfo(pthreadInfo,level);
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
}
status = pthread_mutex_unlock(&listLock);
@@ -798,7 +784,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsi
epicsThreadInit();
if(!showThread) {
showThreadInfo(0,level);
epicsThreadShowInfo(0,level);
return;
}
status = mutexLock(&listLock);
@@ -810,7 +796,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsi
if (((epicsThreadId)pthreadInfo == showThread)
|| ((epicsThreadId)pthreadInfo->tid == showThread)) {
found = 1;
showThreadInfo(pthreadInfo,level);
epicsThreadShowInfo(pthreadInfo,level);
}
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
}
@@ -820,7 +806,6 @@ epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsi
if (!found)
printf("Thread %#lx (%lu) not found.\n", (unsigned long)showThread, (unsigned long)showThread);
}
epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void)
{

View File

@@ -13,12 +13,30 @@
#include <pthread.h>
#include "shareLib.h"
#include "ellLib.h"
#include "epicsEvent.h"
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId ( epicsThreadId id );
typedef struct epicsThreadOSD {
ELLNODE node;
pthread_t tid;
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[1]; /* actually larger */
} epicsThreadOSD;
epicsShareFunc pthread_t epicsThreadGetPosixThreadId(epicsThreadId id);
#ifdef __cplusplus
}

View File

@@ -0,0 +1,48 @@
/*************************************************************************\
* 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 is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 18JAN2000 */
/* This is part of the posix implementation of epicsThread */
#define epicsExportSharedSymbols
#include "epicsStdio.h"
#include "ellLib.h"
#include "epicsEvent.h"
#include "epicsThread.h"
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadHookDefault;
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadHookMain;
EPICS_THREAD_HOOK_ROUTINE epicsThreadHookDefault;
EPICS_THREAD_HOOK_ROUTINE epicsThreadHookMain;
void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level)
{
if(!pthreadInfo) {
fprintf(epicsGetStdout()," NAME EPICS ID "
"PTHREAD 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,&param);
if(!status) priority = param.sched_priority;
}
fprintf(epicsGetStdout(),"%16.16s %12p %12lu %3d%8d %8.8s\n",
pthreadInfo->name,(void *)
pthreadInfo,(unsigned long)pthreadInfo->tid,
pthreadInfo->osiPriority,priority,
pthreadInfo->isSuspended?"SUSPEND":"OK");
}
}

View File

@@ -3,6 +3,7 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* Copyright (c) 2012 ITER Organization
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
@@ -32,6 +33,9 @@
#include "vxLib.h"
#include "epicsExit.h"
epicsShareFunc void epicsThreadHooksInit(epicsThreadId id);
epicsShareFunc void epicsThreadHooksRun(epicsThreadId id);
#if CPU_FAMILY == MC680X0
#define ARCH_STACK_FACTOR 1
#elif CPU_FAMILY == SPARC
@@ -42,6 +46,12 @@
static const unsigned stackSizeTable[epicsThreadStackBig+1] =
{4000*ARCH_STACK_FACTOR, 6000*ARCH_STACK_FACTOR, 11000*ARCH_STACK_FACTOR};
/* Table and lock for epicsThreadMap() */
#define ID_LIST_CHUNK 512
static int *taskIdList = 0;
int taskIdListSize = 0;
static SEM_ID epicsThreadListMutex = 0;
/*The following forces atReboot to be loaded*/
extern int atRebootExtern;
static struct pext {
@@ -86,12 +96,23 @@ static int getOssPriorityValue(unsigned int osiPriority)
static void epicsThreadInit(void)
{
static int lock = 0;
static int done = 0;
while(!vxTas(&lock)) taskDelay(1);
if(epicsThreadOnceMutex==0) {
epicsThreadOnceMutex = semMCreate(
SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);
assert(epicsThreadOnceMutex);
if (done) return;
while(!vxTas(&lock))
taskDelay(1);
if (!done) {
epicsThreadHooksInit(NULL);
epicsThreadOnceMutex = semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);
assert(epicsThreadOnceMutex);
epicsThreadListMutex semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);
assert(epicsThreadListMutex);
taskIdList = calloc(ID_LIST_CHUNK, sizeof(int));
assert(taskIdList);
taskIdListSize = ID_LIST_CHUNK;
done = 1;
}
lock = 0;
}
@@ -157,6 +178,7 @@ static void createFunction(EPICSTHREADFUNC func, void *parm)
taskVarAdd(tid,(int *)(char *)&papTSD);
/*Make sure that papTSD is still 0 after that call to taskVarAdd*/
papTSD = 0;
epicsThreadHooksRun((epicsThreadId)tid);
(*func)(parm);
epicsExitCallAtThreadExits ();
free(papTSD);
@@ -312,6 +334,29 @@ void epicsThreadGetName (epicsThreadId id, char *name, size_t size)
name[size-1] = '\0';
}
epicsShareFunc void epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func )
{
int noTasks = 0;
int i;
int result;
result = semTake(epicsThreadListMutex, WAIT_FOREVER);
assert(result == OK);
while (noTasks == 0) {
noTasks = taskIdListGet(taskIdList, taskIdListSize);
if (noTasks == taskIdListSize) {
taskIdList = realloc(taskIdList, (taskIdListSize+ID_LIST_CHUNK)*sizeof(int));
assert(taskIdList);
taskIdListSize += ID_LIST_CHUNK;
noTasks = 0;
}
}
for (i = 0; i < noTasks; i++) {
func ((epicsThreadId)taskIdList[i]);
}
semGive(epicsThreadListMutex);
}
void epicsThreadShowAll(unsigned int level)
{
taskShow(0,2);

View File

@@ -89,6 +89,11 @@ epicsThreadPrivateTest_SRCS += epicsThreadPrivateTest.cpp
testHarness_SRCS += epicsThreadPrivateTest.cpp
TESTS += epicsThreadPrivateTest
TESTPROD_HOST += epicsThreadHooksTest
epicsThreadHooksTest_SRCS += epicsThreadHooksTest.c
testHarness_SRCS += epicsThreadHooksTest.c
TESTS += epicsThreadHooksTest
TESTPROD_HOST += epicsExitTest
epicsExitTest_SRCS += epicsExitTest.c
testHarness_SRCS += epicsExitTest.c

View File

@@ -33,6 +33,7 @@ int epicsStringTest(void);
int epicsThreadOnceTest(void);
int epicsThreadPriorityTest(void);
int epicsThreadPrivateTest(void);
int epicsThreadHooksTest(void);
int epicsTimeTest(void);
int epicsTypesTest(void);
int macLibTest(void);
@@ -87,6 +88,8 @@ void epicsRunLibComTests(void)
runTest(epicsThreadPrivateTest);
runTest(epicsThreadHooksTest);
runTest(epicsTimeTest);
runTest(epicsTypesTest);

View File

@@ -0,0 +1,127 @@
/*************************************************************************\
* Copyright (c) 2012 ITER Organization
*
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* epicsThreadHooksTest.c */
#include <stdio.h>
#include <stdint.h>
#include "epicsThread.h"
#include "epicsExit.h"
#include "epicsEvent.h"
#include "errlog.h"
#include "epicsUnitTest.h"
#include "testMain.h"
#define THREAD_NO 6
#define HOOKS_NO 4
epicsThreadPrivateId threadNo;
static int order[THREAD_NO][HOOKS_NO];
static int cnt[THREAD_NO];
static int mine[THREAD_NO];
static int called[THREAD_NO];
static epicsThreadId tid[THREAD_NO];
epicsEventId shutdown[THREAD_NO];
static int newThreadIndex(epicsThreadId id)
{
int i = 0;
while (tid[i] != 0 && i < THREAD_NO) i++;
tid[i] = id;
return i;
}
static int findThreadIndex(epicsThreadId id)
{
int i = 0;
while (tid[i] != id && i < THREAD_NO) i++;
return i;
}
static void atExitHook1 (void *arg)
{
int no = findThreadIndex(epicsThreadGetIdSelf());
order[no][3] = cnt[no]++;
}
static void atExitHook2 (void *arg)
{
int no = findThreadIndex(epicsThreadGetIdSelf());
order[no][2] = cnt[no]++;
}
static void startHook1 (epicsThreadId id)
{
int no = newThreadIndex(id);
order[no][0] = cnt[no]++;
epicsAtThreadExit(atExitHook1, NULL);
}
static void startHook2 (epicsThreadId id)
{
int no = findThreadIndex(id);
order[no][1] = cnt[no]++;
epicsAtThreadExit(atExitHook2, NULL);
}
static void my_thread (void *arg)
{
int no = findThreadIndex(epicsThreadGetIdSelf());
mine[no] = 1;
epicsEventMustWait((epicsEventId) arg);
}
static void mapper (epicsThreadId id)
{
called[findThreadIndex(id)]++;
}
MAIN(epicsThreadHooksTest)
{
int i;
int ok;
testPlan(THREAD_NO);
epicsThreadHookAdd(startHook1);
epicsThreadHookAdd(startHook2);
for (i = 0; i < THREAD_NO-1; i++) {
char name[10];
shutdown[i] = epicsEventCreate(epicsEventEmpty);
sprintf(name, "t%d", (int) i);
epicsThreadCreate(name, epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
my_thread, shutdown[i]);
}
epicsThreadMap(mapper);
ok = 1;
for (i = 0; i < THREAD_NO-1; i++) {
if (mine[i] && called[i] != 1) ok = 0;
}
testOk(ok, "All tasks covered once by epicsThreadMap");
for (i = 0; i < THREAD_NO-1; i++) {
epicsEventSignal(shutdown[i]);
}
epicsThreadSleep(1.0);
for (i = 0; i < THREAD_NO; i++) {
int j;
for (j = 0; j < HOOKS_NO; j++) {
if (mine[i] && order[i][j]!=j) ok = 0;
}
if (mine[i])
testOk(ok, "All hooks for task %d called in correct order", (int)i);
}
return testDone();
}