Merged Ralph's thread-hooks branch.
Minor modifications to fix the vxWorks epicsThreadInit() and rename some functions.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
45
src/libCom/osi/os/Linux/osdThread.h
Normal file
45
src/libCom/osi/os/Linux/osdThread.h
Normal 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 */
|
||||
69
src/libCom/osi/os/Linux/osdThreadExtra.c
Normal file
69
src/libCom/osi/os/Linux/osdThreadExtra.c
Normal 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,
|
||||
¶m);
|
||||
|
||||
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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
19
src/libCom/osi/os/default/osdThreadExtra.c
Normal file
19
src/libCom/osi/os/default/osdThreadExtra.c
Normal 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;
|
||||
75
src/libCom/osi/os/default/osdThreadHooks.c
Normal file
75
src/libCom/osi/os/default/osdThreadHooks.c
Normal 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);
|
||||
}
|
||||
@@ -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,¶m);
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
48
src/libCom/osi/os/posix/osdThreadExtra.c
Normal file
48
src/libCom/osi/os/posix/osdThreadExtra.c
Normal 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,¶m);
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
127
src/libCom/test/epicsThreadHooksTest.c
Normal file
127
src/libCom/test/epicsThreadHooksTest.c
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user