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:
Ralph Lange
2012-06-28 18:12:26 +02:00
parent 4eb31d7edc
commit 222ea314b0
8 changed files with 304 additions and 44 deletions

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

@@ -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 */

View 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,&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(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;

View 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;

View 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);
}

View File

@@ -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,&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");
}
}
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);
}

View File

@@ -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
}

View 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,&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");
}
}