diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index 989784685..e22091712 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -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 diff --git a/src/libCom/osi/os/Linux/osdThread.h b/src/libCom/osi/os/Linux/osdThread.h new file mode 100644 index 000000000..52637b16f --- /dev/null +++ b/src/libCom/osi/os/Linux/osdThread.h @@ -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 + +#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 */ diff --git a/src/libCom/osi/os/Linux/osdThreadExtra.c b/src/libCom/osi/os/Linux/osdThreadExtra.c new file mode 100644 index 000000000..d6cd5a164 --- /dev/null +++ b/src/libCom/osi/os/Linux/osdThreadExtra.c @@ -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 +#include +#include +#include +#include + +#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; diff --git a/src/libCom/osi/os/default/osdThreadExtra.c b/src/libCom/osi/os/default/osdThreadExtra.c new file mode 100644 index 000000000..bc5571e4a --- /dev/null +++ b/src/libCom/osi/os/default/osdThreadExtra.c @@ -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; diff --git a/src/libCom/osi/os/default/osdThreadHooks.c b/src/libCom/osi/os/default/osdThreadHooks.c new file mode 100644 index 000000000..b553cc160 --- /dev/null +++ b/src/libCom/osi/os/default/osdThreadHooks.c @@ -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 +#include +#include +#include + +#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); +} diff --git a/src/libCom/osi/os/posix/osdThread.c b/src/libCom/osi/os/posix/osdThread.c index 3c8844f70..e3989e1bf 100644 --- a/src/libCom/osi/os/posix/osdThread.c +++ b/src/libCom/osi/os/posix/osdThread.c @@ -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); } diff --git a/src/libCom/osi/os/posix/osdThread.h b/src/libCom/osi/os/posix/osdThread.h index 99cfe319a..6ce223e6e 100644 --- a/src/libCom/osi/os/posix/osdThread.h +++ b/src/libCom/osi/os/posix/osdThread.h @@ -13,12 +13,42 @@ #include #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 } diff --git a/src/libCom/osi/os/posix/osdThreadExtra.c b/src/libCom/osi/os/posix/osdThreadExtra.c new file mode 100644 index 000000000..93a149307 --- /dev/null +++ b/src/libCom/osi/os/posix/osdThreadExtra.c @@ -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"); + } +} +