Add thread hooks to epicsThread that are called when a thread starts or exits
- add Linux implementation that
+ sets the system command name to the EPICS thread name
+ retrieves the Linux LWP ID and prints it instead of the posix thread ID
in show commands
This commit is contained in:
@@ -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
|
||||
|
||||
58
src/libCom/osi/os/Linux/osdThread.h
Normal file
58
src/libCom/osi/os/Linux/osdThread.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
#ifndef osdThreadh
|
||||
#define osdThreadh
|
||||
|
||||
#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;
|
||||
|
||||
/* Hooks being called when a thread starts or exits */
|
||||
typedef void (*EPICS_THREAD_HOOK_ROUTINE)(epicsThreadOSD *pthreadInfo);
|
||||
epicsShareFunc void epicsThreadHooksInit();
|
||||
epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook);
|
||||
epicsShareFunc void epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook);
|
||||
epicsShareFunc void epicsThreadRunStartHooks(epicsThreadOSD *pthreadInfo);
|
||||
epicsShareFunc void epicsThreadRunExitHooks(epicsThreadOSD *pthreadInfo);
|
||||
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook;
|
||||
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultExitHook;
|
||||
|
||||
epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId(epicsThreadId id);
|
||||
|
||||
epicsShareFunc void epicsShowThreadInfo(epicsThreadOSD *pthreadInfo, unsigned int level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* osdThreadh */
|
||||
62
src/libCom/osi/os/Linux/osdThreadExtra.c
Normal file
62
src/libCom/osi/os/Linux/osdThreadExtra.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*************************************************************************\
|
||||
* 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 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"
|
||||
|
||||
void epicsShowThreadInfo(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 %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(epicsThreadOSD *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 epicsThreadDefaultStartHook = thread_hook;
|
||||
EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultExitHook;
|
||||
15
src/libCom/osi/os/default/osdThreadExtra.c
Normal file
15
src/libCom/osi/os/default/osdThreadExtra.c
Normal file
@@ -0,0 +1,15 @@
|
||||
/*************************************************************************\
|
||||
* 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: Ralph Lange Date: 26 Jun 2012 */
|
||||
|
||||
/* Null default thread hooks for all platforms that do not do anything special */
|
||||
|
||||
EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook;
|
||||
EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultExitHook;
|
||||
87
src/libCom/osi/os/default/osdThreadHooks.c
Normal file
87
src/libCom/osi/os/default/osdThreadHooks.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* 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"
|
||||
|
||||
#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;
|
||||
static ELLLIST exitHooks;
|
||||
static epicsMutexId hookLock;
|
||||
|
||||
static void addHook (ELLLIST *list, EPICS_THREAD_HOOK_ROUTINE func)
|
||||
{
|
||||
epicsThreadHook *pHook;
|
||||
|
||||
pHook = calloc(1, sizeof(epicsThreadHook));
|
||||
if (!pHook) checkStatusOnceReturn(errno,"calloc","epicsThreadAddStartHook");
|
||||
pHook->func = func;
|
||||
epicsMutexLock(hookLock);
|
||||
ellInsert(list, NULL, &pHook->node);
|
||||
epicsMutexUnlock(hookLock);
|
||||
}
|
||||
|
||||
static void runHooks (ELLLIST *list, epicsThreadOSD *pthreadInfo) {
|
||||
epicsThreadHook *pHook;
|
||||
|
||||
/* As we're only ever inserting hooks at the head of the list, forward traversing is safe */
|
||||
pHook = (epicsThreadHook *) ellFirst(list);
|
||||
while (pHook) {
|
||||
pHook->func(pthreadInfo);
|
||||
pHook = (epicsThreadHook *) ellNext(&pHook->node);
|
||||
}
|
||||
}
|
||||
|
||||
void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE func)
|
||||
{
|
||||
addHook(&startHooks, func);
|
||||
}
|
||||
|
||||
void epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE func)
|
||||
{
|
||||
addHook(&exitHooks, func);
|
||||
}
|
||||
|
||||
void epicsThreadHooksInit()
|
||||
{
|
||||
hookLock = epicsMutexMustCreate();
|
||||
ellInit(&startHooks);
|
||||
ellInit(&exitHooks);
|
||||
if (epicsThreadDefaultStartHook) epicsThreadAddStartHook(epicsThreadDefaultStartHook);
|
||||
if (epicsThreadDefaultExitHook) epicsThreadAddExitHook(epicsThreadDefaultExitHook);
|
||||
}
|
||||
|
||||
void epicsThreadRunStartHooks(epicsThreadOSD *pthreadInfo)
|
||||
{
|
||||
runHooks(&startHooks, pthreadInfo);
|
||||
}
|
||||
|
||||
void epicsThreadRunExitHooks(epicsThreadOSD *pthreadInfo)
|
||||
{
|
||||
runHooks(&exitHooks, pthreadInfo);
|
||||
}
|
||||
@@ -57,22 +57,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 +350,7 @@ static void once(void)
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadInit");
|
||||
status = atexit(epicsExitCallAtExits);
|
||||
checkStatusOnce(status,"atexit");
|
||||
epicsThreadHooksInit();
|
||||
epicsThreadOnceCalled = 1;
|
||||
}
|
||||
|
||||
@@ -375,7 +360,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,9 +373,11 @@ static void * start_routine(void *arg)
|
||||
pthreadInfo->isOnThreadList = 1;
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","start_routine");
|
||||
epicsThreadRunStartHooks(pthreadInfo);
|
||||
|
||||
(*pthreadInfo->createFunc)(pthreadInfo->createArg);
|
||||
|
||||
epicsThreadRunExitHooks(pthreadInfo);
|
||||
epicsExitCallAtThreadExits ();
|
||||
|
||||
free_threadInfo(pthreadInfo);
|
||||
@@ -747,29 +734,6 @@ epicsShareFunc void epicsShareAPI epicsThreadGetName(epicsThreadId pthreadInfo,
|
||||
name[size-1] = '\0';
|
||||
}
|
||||
|
||||
static void showThreadInfo(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");
|
||||
}
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
@@ -783,7 +747,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level)
|
||||
return;
|
||||
pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
|
||||
while(pthreadInfo) {
|
||||
showThreadInfo(pthreadInfo,level);
|
||||
epicsShowThreadInfo(pthreadInfo,level);
|
||||
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
|
||||
}
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
@@ -798,7 +762,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsi
|
||||
|
||||
epicsThreadInit();
|
||||
if(!showThread) {
|
||||
showThreadInfo(0,level);
|
||||
epicsShowThreadInfo(0,level);
|
||||
return;
|
||||
}
|
||||
status = mutexLock(&listLock);
|
||||
@@ -810,7 +774,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsi
|
||||
if (((epicsThreadId)pthreadInfo == showThread)
|
||||
|| ((epicsThreadId)pthreadInfo->tid == showThread)) {
|
||||
found = 1;
|
||||
showThreadInfo(pthreadInfo,level);
|
||||
epicsShowThreadInfo(pthreadInfo,level);
|
||||
}
|
||||
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
|
||||
}
|
||||
|
||||
@@ -13,12 +13,42 @@
|
||||
#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;
|
||||
|
||||
/* Hooks being called when a thread starts or exits */
|
||||
typedef void (*EPICS_THREAD_HOOK_ROUTINE)(epicsThreadOSD *pthreadInfo);
|
||||
epicsShareFunc void epicsThreadHooksInit();
|
||||
epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook);
|
||||
epicsShareFunc void epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook);
|
||||
epicsShareFunc void epicsThreadRunStartHooks(epicsThreadOSD *pthreadInfo);
|
||||
epicsShareFunc void epicsThreadRunExitHooks(epicsThreadOSD *pthreadInfo);
|
||||
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook;
|
||||
epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultExitHook;
|
||||
|
||||
epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId(epicsThreadId id);
|
||||
|
||||
epicsShareFunc void epicsShowThreadInfo(epicsThreadOSD *pthreadInfo, unsigned int level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
42
src/libCom/osi/os/posix/osdThreadExtra.c
Normal file
42
src/libCom/osi/os/posix/osdThreadExtra.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*************************************************************************\
|
||||
* 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"
|
||||
|
||||
void epicsShowThreadInfo(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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user