From 222ea314b0af8a8053b3b25d900cb883ad42ba55 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 28 Jun 2012 18:12:26 +0200 Subject: [PATCH 01/15] 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 --- src/libCom/osi/Makefile | 2 + src/libCom/osi/os/Linux/osdThread.h | 58 +++++++++++++++ src/libCom/osi/os/Linux/osdThreadExtra.c | 62 +++++++++++++++ src/libCom/osi/os/default/osdThreadExtra.c | 15 ++++ src/libCom/osi/os/default/osdThreadHooks.c | 87 ++++++++++++++++++++++ src/libCom/osi/os/posix/osdThread.c | 50 ++----------- src/libCom/osi/os/posix/osdThread.h | 32 +++++++- src/libCom/osi/os/posix/osdThreadExtra.c | 42 +++++++++++ 8 files changed, 304 insertions(+), 44 deletions(-) create mode 100644 src/libCom/osi/os/Linux/osdThread.h create mode 100644 src/libCom/osi/os/Linux/osdThreadExtra.c create mode 100644 src/libCom/osi/os/default/osdThreadExtra.c create mode 100644 src/libCom/osi/os/default/osdThreadHooks.c create mode 100644 src/libCom/osi/os/posix/osdThreadExtra.c 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"); + } +} + From 803777329c0a28bbd8182dbb4a5943db6ab0553a Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Fri, 29 Jun 2012 11:15:47 +0200 Subject: [PATCH 02/15] Cleanup of epicsThread hooks - move declarations to epicsThread.h, use epicsThreadId type - use static elllist initializer for static lists --- src/libCom/osi/epicsThread.h | 10 ++++++++++ src/libCom/osi/os/Linux/osdThread.h | 10 ---------- src/libCom/osi/os/default/osdThreadHooks.c | 20 +++++++++----------- src/libCom/osi/os/posix/osdThread.h | 10 ---------- 4 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/libCom/osi/epicsThread.h b/src/libCom/osi/epicsThread.h index fa0a6bd70..6e6c30970 100644 --- a/src/libCom/osi/epicsThread.h +++ b/src/libCom/osi/epicsThread.h @@ -101,6 +101,16 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level); epicsShareFunc void epicsShareAPI epicsThreadShow( epicsThreadId id,unsigned int level); +/* Hooks being called when a thread starts or exits */ +typedef void (*EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id); +epicsShareFunc void epicsShareAPI epicsThreadHooksInit(void); +epicsShareFunc void epicsShareAPI epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook); +epicsShareFunc void epicsShareAPI epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook); +epicsShareFunc void epicsShareAPI epicsThreadRunStartHooks(epicsThreadId id); +epicsShareFunc void epicsShareAPI epicsThreadRunExitHooks(epicsThreadId id); +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultExitHook; + typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId; epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void); epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id); diff --git a/src/libCom/osi/os/Linux/osdThread.h b/src/libCom/osi/os/Linux/osdThread.h index 52637b16f..ebdd47659 100644 --- a/src/libCom/osi/os/Linux/osdThread.h +++ b/src/libCom/osi/os/Linux/osdThread.h @@ -37,16 +37,6 @@ typedef struct epicsThreadOSD { 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); diff --git a/src/libCom/osi/os/default/osdThreadHooks.c b/src/libCom/osi/os/default/osdThreadHooks.c index b553cc160..52f42b5ad 100644 --- a/src/libCom/osi/os/default/osdThreadHooks.c +++ b/src/libCom/osi/os/default/osdThreadHooks.c @@ -30,8 +30,8 @@ typedef struct epicsThreadHook { EPICS_THREAD_HOOK_ROUTINE func; } epicsThreadHook; -static ELLLIST startHooks; -static ELLLIST exitHooks; +static ELLLIST startHooks = ELLLIST_INIT; +static ELLLIST exitHooks = ELLLIST_INIT; static epicsMutexId hookLock; static void addHook (ELLLIST *list, EPICS_THREAD_HOOK_ROUTINE func) @@ -46,13 +46,13 @@ static void addHook (ELLLIST *list, EPICS_THREAD_HOOK_ROUTINE func) epicsMutexUnlock(hookLock); } -static void runHooks (ELLLIST *list, epicsThreadOSD *pthreadInfo) { +static void runHooks (ELLLIST *list, epicsThreadId id) { 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->func(id); pHook = (epicsThreadHook *) ellNext(&pHook->node); } } @@ -67,21 +67,19 @@ void epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE func) addHook(&exitHooks, func); } -void epicsThreadHooksInit() +void epicsThreadHooksInit(void) { hookLock = epicsMutexMustCreate(); - ellInit(&startHooks); - ellInit(&exitHooks); if (epicsThreadDefaultStartHook) epicsThreadAddStartHook(epicsThreadDefaultStartHook); if (epicsThreadDefaultExitHook) epicsThreadAddExitHook(epicsThreadDefaultExitHook); } -void epicsThreadRunStartHooks(epicsThreadOSD *pthreadInfo) +void epicsThreadRunStartHooks(epicsThreadId id) { - runHooks(&startHooks, pthreadInfo); + runHooks(&startHooks, id); } -void epicsThreadRunExitHooks(epicsThreadOSD *pthreadInfo) +void epicsThreadRunExitHooks(epicsThreadId id) { - runHooks(&exitHooks, pthreadInfo); + runHooks(&exitHooks, id); } diff --git a/src/libCom/osi/os/posix/osdThread.h b/src/libCom/osi/os/posix/osdThread.h index 6ce223e6e..0885f9410 100644 --- a/src/libCom/osi/os/posix/osdThread.h +++ b/src/libCom/osi/os/posix/osdThread.h @@ -36,16 +36,6 @@ typedef struct epicsThreadOSD { 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); From 7e9f0484332737f180dde9c755167470ca76c52a Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Fri, 29 Jun 2012 11:22:48 +0200 Subject: [PATCH 03/15] Add decorations to epicsThreadHooks.c --- src/libCom/osi/os/default/osdThreadHooks.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libCom/osi/os/default/osdThreadHooks.c b/src/libCom/osi/os/default/osdThreadHooks.c index 52f42b5ad..8fddfa1e1 100644 --- a/src/libCom/osi/os/default/osdThreadHooks.c +++ b/src/libCom/osi/os/default/osdThreadHooks.c @@ -57,29 +57,29 @@ static void runHooks (ELLLIST *list, epicsThreadId id) { } } -void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE func) +epicsShareFunc void epicsShareAPI epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook) { - addHook(&startHooks, func); + addHook(&startHooks, hook); } -void epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE func) +epicsShareFunc void epicsShareAPI epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook) { - addHook(&exitHooks, func); + addHook(&exitHooks, hook); } -void epicsThreadHooksInit(void) +epicsShareFunc void epicsShareAPI epicsThreadHooksInit(void) { hookLock = epicsMutexMustCreate(); if (epicsThreadDefaultStartHook) epicsThreadAddStartHook(epicsThreadDefaultStartHook); if (epicsThreadDefaultExitHook) epicsThreadAddExitHook(epicsThreadDefaultExitHook); } -void epicsThreadRunStartHooks(epicsThreadId id) +epicsShareFunc void epicsShareAPI epicsThreadRunStartHooks(epicsThreadId id) { runHooks(&startHooks, id); } -void epicsThreadRunExitHooks(epicsThreadId id) +epicsShareFunc void epicsShareAPI epicsThreadRunExitHooks(epicsThreadId id) { runHooks(&exitHooks, id); } From 1f5376b30b237a0824727a3d66b6577b87965548 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Fri, 29 Jun 2012 14:49:24 +0200 Subject: [PATCH 04/15] libCom/osi: Add RTEMS and vxWorks implementation for epicsThreadHooks --- src/libCom/osi/os/RTEMS/osdThread.c | 3 +++ src/libCom/osi/os/default/osdThreadHooks.c | 8 +++++--- src/libCom/osi/os/vxWorks/osdThread.c | 3 +++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c index 7fa541bfd..e6bb63f50 100644 --- a/src/libCom/osi/os/RTEMS/osdThread.c +++ b/src/libCom/osi/os/RTEMS/osdThread.c @@ -164,7 +164,9 @@ threadWrapper (rtems_task_argument arg) { struct taskVar *v = (struct taskVar *)arg; + epicsThreadRunStartHooks(pthreadInfo); (*v->funptr)(v->parm); + epicsThreadRunExitHooks(pthreadInfo); epicsExitCallAtThreadExits (); taskVarLock (); if (v->back) @@ -235,6 +237,7 @@ epicsThreadInit (void) taskVarMutex = epicsMutexMustCreate (); rtems_task_ident (RTEMS_SELF, 0, &tid); setThreadInfo (tid, "_main_", NULL, NULL); + epicsThreadHooksInit(); initialized = 1; epicsThreadCreate ("ImsgDaemon", 99, epicsThreadGetStackSize (epicsThreadStackSmall), diff --git a/src/libCom/osi/os/default/osdThreadHooks.c b/src/libCom/osi/os/default/osdThreadHooks.c index 8fddfa1e1..76e83d3ce 100644 --- a/src/libCom/osi/os/default/osdThreadHooks.c +++ b/src/libCom/osi/os/default/osdThreadHooks.c @@ -69,9 +69,11 @@ epicsShareFunc void epicsShareAPI epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTI epicsShareFunc void epicsShareAPI epicsThreadHooksInit(void) { - hookLock = epicsMutexMustCreate(); - if (epicsThreadDefaultStartHook) epicsThreadAddStartHook(epicsThreadDefaultStartHook); - if (epicsThreadDefaultExitHook) epicsThreadAddExitHook(epicsThreadDefaultExitHook); + if (!hookLock) { + hookLock = epicsMutexMustCreate(); + if (epicsThreadDefaultStartHook) epicsThreadAddStartHook(epicsThreadDefaultStartHook); + if (epicsThreadDefaultExitHook) epicsThreadAddExitHook(epicsThreadDefaultExitHook); + } } epicsShareFunc void epicsShareAPI epicsThreadRunStartHooks(epicsThreadId id) diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c index 09d451fab..a69ddae3a 100644 --- a/src/libCom/osi/os/vxWorks/osdThread.c +++ b/src/libCom/osi/os/vxWorks/osdThread.c @@ -88,6 +88,7 @@ static void epicsThreadInit(void) static int lock = 0; while(!vxTas(&lock)) taskDelay(1); + epicsThreadHooksInit(); if(epicsThreadOnceMutex==0) { epicsThreadOnceMutex = semMCreate( SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY); @@ -157,7 +158,9 @@ 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; + epicsThreadRunStartHooks(pthreadInfo); (*func)(parm); + epicsThreadRunExitHooks(pthreadInfo); epicsExitCallAtThreadExits (); free(papTSD); taskVarDelete(tid,(int *)(char *)&papTSD); From 8c323b2197fa1126fb1f77f9526b326e2a0c50c5 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Fri, 29 Jun 2012 17:54:38 +0200 Subject: [PATCH 05/15] libCom/osi: Add epicsThreadMap (calls user function for each thread) --- src/libCom/osi/epicsThread.h | 3 +++ src/libCom/osi/os/RTEMS/osdThread.c | 17 ++++++++++++++ src/libCom/osi/os/WIN32/osdThread.c | 33 +++++++++++++++++++++++++-- src/libCom/osi/os/posix/osdThread.c | 20 +++++++++++++++- src/libCom/osi/os/vxWorks/osdThread.c | 21 +++++++++++++++++ 5 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/libCom/osi/epicsThread.h b/src/libCom/osi/epicsThread.h index 6e6c30970..41547e87b 100644 --- a/src/libCom/osi/epicsThread.h +++ b/src/libCom/osi/epicsThread.h @@ -111,6 +111,9 @@ epicsShareFunc void epicsShareAPI epicsThreadRunExitHooks(epicsThreadId id); epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultExitHook; +/* Map func to all threads */ +epicsShareFunc void epicsShareAPI epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func); + typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId; epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void); epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id); diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c index e6bb63f50..07842b3a3 100644 --- a/src/libCom/osi/os/RTEMS/osdThread.c +++ b/src/libCom/osi/os/RTEMS/osdThread.c @@ -677,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 (v, arg); + v = v->back; + } + taskVarUnlock (); +} + void epicsThreadShowAll (unsigned int level) { struct taskVar *v; diff --git a/src/libCom/osi/os/WIN32/osdThread.c b/src/libCom/osi/os/WIN32/osdThread.c index 86f7b7df7..a588e6237 100644 --- a/src/libCom/osi/os/WIN32/osdThread.c +++ b/src/libCom/osi/os/WIN32/osdThread.c @@ -16,6 +16,13 @@ * */ +/* FIXME: + * The Windows implementation for thread hooks is still missing. + * epicsThreadHooksInit(); as part of the initialization + * epicsThreadRunStartHooks(pthreadInfo); from thread context before the user func runs + * epicsThreadRunExitHooks(pthreadInfo); from thread context after the user func exits + */ + #include #include #include @@ -974,6 +981,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,9 +1016,9 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll ( unsigned level ) } EnterCriticalSection ( & pGbl->mutex ); - + epicsThreadShowPrivate ( 0, level ); - for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList ); + for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList ); pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) { epicsThreadShowPrivate ( ( epicsThreadId ) pParm, level ); } diff --git a/src/libCom/osi/os/posix/osdThread.c b/src/libCom/osi/os/posix/osdThread.c index e3989e1bf..55e2c95d7 100644 --- a/src/libCom/osi/os/posix/osdThread.c +++ b/src/libCom/osi/os/posix/osdThread.c @@ -734,6 +734,25 @@ epicsShareFunc void epicsShareAPI epicsThreadGetName(epicsThreadId pthreadInfo, name[size-1] = '\0'; } +epicsShareFunc void epicsShareAPI epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func) +{ + epicsThreadOSD *pthreadInfo; + int status; + + 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) { epicsThreadOSD *pthreadInfo; @@ -784,7 +803,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) { diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c index a69ddae3a..bfaef04df 100644 --- a/src/libCom/osi/os/vxWorks/osdThread.c +++ b/src/libCom/osi/os/vxWorks/osdThread.c @@ -42,6 +42,10 @@ static const unsigned stackSizeTable[epicsThreadStackBig+1] = {4000*ARCH_STACK_FACTOR, 6000*ARCH_STACK_FACTOR, 11000*ARCH_STACK_FACTOR}; +/* FIXME: this is the beta implementation of epicsThreadMap for vxWorks. See below. */ +#define ID_LIST_SIZE 2048 +static int taskIdList[ID_LIST_SIZE]; + /*The following forces atReboot to be loaded*/ extern int atRebootExtern; static struct pext { @@ -315,6 +319,23 @@ void epicsThreadGetName (epicsThreadId id, char *name, size_t size) name[size-1] = '\0'; } +epicsShareFunc void epicsShareAPI epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func ) +{ +/* FIXME: add better vxWorks implementation that uses a dynamic taskIdList */ +/* Andrew says: + * use the vxWorks routine taskIdListGet(); + * that seems better, although there's no API to tell you how many tasks exist + * (I guess you could keep a count yourself if you register + * taskCreateHook and taskDeleteHook routines). */ + int noTasks; + int i; + + noTasks = taskIdListGet(taskIdList, ID_LIST_SIZE); + for (i = 0; i < noTasks; i++) { + func (i); + } +} + void epicsThreadShowAll(unsigned int level) { taskShow(0,2); From d6648d4473a828809b079c0368c9f2da101e2909 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Fri, 29 Jun 2012 18:12:07 +0200 Subject: [PATCH 06/15] libCom/osi: Add some copyrights for ITER --- src/libCom/osi/epicsThread.h | 4 ++-- src/libCom/osi/os/Linux/osdThreadExtra.c | 1 + src/libCom/osi/os/default/osdThreadExtra.c | 6 ++---- src/libCom/osi/os/default/osdThreadHooks.c | 4 ++-- src/libCom/osi/os/posix/osdThread.c | 1 + src/libCom/osi/os/vxWorks/osdThread.c | 1 + 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libCom/osi/epicsThread.h b/src/libCom/osi/epicsThread.h index 41547e87b..ab08e3d87 100644 --- a/src/libCom/osi/epicsThread.h +++ b/src/libCom/osi/epicsThread.h @@ -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 diff --git a/src/libCom/osi/os/Linux/osdThreadExtra.c b/src/libCom/osi/os/Linux/osdThreadExtra.c index d6cd5a164..fc1d2d1df 100644 --- a/src/libCom/osi/os/Linux/osdThreadExtra.c +++ b/src/libCom/osi/os/Linux/osdThreadExtra.c @@ -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. \*************************************************************************/ diff --git a/src/libCom/osi/os/default/osdThreadExtra.c b/src/libCom/osi/os/default/osdThreadExtra.c index bc5571e4a..31b3abac7 100644 --- a/src/libCom/osi/os/default/osdThreadExtra.c +++ b/src/libCom/osi/os/default/osdThreadExtra.c @@ -1,8 +1,6 @@ /*************************************************************************\ -* 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. \*************************************************************************/ diff --git a/src/libCom/osi/os/default/osdThreadHooks.c b/src/libCom/osi/os/default/osdThreadHooks.c index 76e83d3ce..c2cadeabf 100644 --- a/src/libCom/osi/os/default/osdThreadHooks.c +++ b/src/libCom/osi/os/default/osdThreadHooks.c @@ -1,6 +1,6 @@ /*************************************************************************\ -* Copyright (c) 2012 Helmholtz-Zentrum Berlin -* fuer Materialien und Energie GmbH. +* 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. \*************************************************************************/ diff --git a/src/libCom/osi/os/posix/osdThread.c b/src/libCom/osi/os/posix/osdThread.c index 55e2c95d7..1d88cfba8 100644 --- a/src/libCom/osi/os/posix/osdThread.c +++ b/src/libCom/osi/os/posix/osdThread.c @@ -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. \*************************************************************************/ diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c index bfaef04df..7c996b0e6 100644 --- a/src/libCom/osi/os/vxWorks/osdThread.c +++ b/src/libCom/osi/os/vxWorks/osdThread.c @@ -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. \*************************************************************************/ From cfd8c0abde997990c7d66274f3a2f543bc2668df Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Mon, 2 Jul 2012 11:31:01 +0200 Subject: [PATCH 07/15] libCom/osi: Fix nesting for epicsThreadHooks, add WIN32 implementation, lock traversal - call (generic) exit hook after calling the (specific) epicsExitCallAtThreadExits() - for start hooks added as 1-2-3, run exit hooks in opposite order: 3-2-1 - add calls to hooks module to WIN32 osdThread.c - add lock/unlock to hook list traversal --- src/libCom/osi/os/RTEMS/osdThread.c | 2 +- src/libCom/osi/os/WIN32/osdThread.c | 11 ++++------- src/libCom/osi/os/default/osdThreadHooks.c | 16 +++++++++++----- src/libCom/osi/os/posix/osdThread.c | 2 +- src/libCom/osi/os/vxWorks/osdThread.c | 2 +- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c index 07842b3a3..d6a94ad4a 100644 --- a/src/libCom/osi/os/RTEMS/osdThread.c +++ b/src/libCom/osi/os/RTEMS/osdThread.c @@ -166,8 +166,8 @@ threadWrapper (rtems_task_argument arg) epicsThreadRunStartHooks(pthreadInfo); (*v->funptr)(v->parm); - epicsThreadRunExitHooks(pthreadInfo); epicsExitCallAtThreadExits (); + epicsThreadRunExitHooks(pthreadInfo); taskVarLock (); if (v->back) v->back->forw = v->forw; diff --git a/src/libCom/osi/os/WIN32/osdThread.c b/src/libCom/osi/os/WIN32/osdThread.c index a588e6237..c66d9e606 100644 --- a/src/libCom/osi/os/WIN32/osdThread.c +++ b/src/libCom/osi/os/WIN32/osdThread.c @@ -16,13 +16,6 @@ * */ -/* FIXME: - * The Windows implementation for thread hooks is still missing. - * epicsThreadHooksInit(); as part of the initialization - * epicsThreadRunStartHooks(pthreadInfo); from thread context before the user func runs - * epicsThreadRunExitHooks(pthreadInfo); from thread context after the user func exits - */ - #include #include #include @@ -233,6 +226,7 @@ static win32ThreadGlobal * fetchWin32ThreadGlobal ( void ) pWin32ThreadGlobal = 0; return 0; } + epicsThreadHooksInit(); InterlockedExchange ( & initCompleted, 1 ); @@ -503,6 +497,7 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter ) success = TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, pParm ); if ( success ) { + epicsThreadRunStartHooks(pParm); /* printf ( "starting thread %d\n", pParm->id ); */ ( *pParm->funptr ) ( pParm->parm ); /* printf ( "terminating thread %d\n", pParm->id ); */ @@ -518,6 +513,8 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter ) epicsExitCallAtThreadExits (); + epicsThreadRunExitHooks(pParm); + /* * CAUTION: !!!! the thread id might continue to be used after this thread exits !!!! */ diff --git a/src/libCom/osi/os/default/osdThreadHooks.c b/src/libCom/osi/os/default/osdThreadHooks.c index c2cadeabf..9dc99e95e 100644 --- a/src/libCom/osi/os/default/osdThreadHooks.c +++ b/src/libCom/osi/os/default/osdThreadHooks.c @@ -32,9 +32,11 @@ typedef struct epicsThreadHook { static ELLLIST startHooks = ELLLIST_INIT; static ELLLIST exitHooks = ELLLIST_INIT; + +/* Locking could probably be avoided, if elllist implementation was using atomic ops */ static epicsMutexId hookLock; -static void addHook (ELLLIST *list, EPICS_THREAD_HOOK_ROUTINE func) +static void addHook (ELLLIST *list, EPICS_THREAD_HOOK_ROUTINE func, int atHead) { epicsThreadHook *pHook; @@ -42,29 +44,33 @@ static void addHook (ELLLIST *list, EPICS_THREAD_HOOK_ROUTINE func) if (!pHook) checkStatusOnceReturn(errno,"calloc","epicsThreadAddStartHook"); pHook->func = func; epicsMutexLock(hookLock); - ellInsert(list, NULL, &pHook->node); + if (atHead) + ellInsert(list, NULL, &pHook->node); + else + ellAdd(list, &pHook->node); epicsMutexUnlock(hookLock); } static void runHooks (ELLLIST *list, epicsThreadId id) { epicsThreadHook *pHook; - /* As we're only ever inserting hooks at the head of the list, forward traversing is safe */ + epicsMutexLock(hookLock); pHook = (epicsThreadHook *) ellFirst(list); while (pHook) { pHook->func(id); pHook = (epicsThreadHook *) ellNext(&pHook->node); } + epicsMutexUnlock(hookLock); } epicsShareFunc void epicsShareAPI epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook) { - addHook(&startHooks, hook); + addHook(&startHooks, hook, 0); } epicsShareFunc void epicsShareAPI epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook) { - addHook(&exitHooks, hook); + addHook(&exitHooks, hook, 1); } epicsShareFunc void epicsShareAPI epicsThreadHooksInit(void) diff --git a/src/libCom/osi/os/posix/osdThread.c b/src/libCom/osi/os/posix/osdThread.c index 1d88cfba8..8734106f4 100644 --- a/src/libCom/osi/os/posix/osdThread.c +++ b/src/libCom/osi/os/posix/osdThread.c @@ -378,8 +378,8 @@ static void * start_routine(void *arg) (*pthreadInfo->createFunc)(pthreadInfo->createArg); - epicsThreadRunExitHooks(pthreadInfo); epicsExitCallAtThreadExits (); + epicsThreadRunExitHooks(pthreadInfo); free_threadInfo(pthreadInfo); return(0); diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c index 7c996b0e6..f782f389c 100644 --- a/src/libCom/osi/os/vxWorks/osdThread.c +++ b/src/libCom/osi/os/vxWorks/osdThread.c @@ -165,8 +165,8 @@ static void createFunction(EPICSTHREADFUNC func, void *parm) papTSD = 0; epicsThreadRunStartHooks(pthreadInfo); (*func)(parm); - epicsThreadRunExitHooks(pthreadInfo); epicsExitCallAtThreadExits (); + epicsThreadRunExitHooks(pthreadInfo); free(papTSD); taskVarDelete(tid,(int *)(char *)&papTSD); } From 37e490d1b2b509d7996a33df1b47e20328f713b4 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Mon, 2 Jul 2012 14:21:39 +0200 Subject: [PATCH 08/15] libCom/osi: Make vxWorks implementation of epicsThreadMap() safe and dynamic --- src/libCom/osi/os/vxWorks/osdThread.c | 49 ++++++++++++++++++--------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c index f782f389c..9e0e7b70e 100644 --- a/src/libCom/osi/os/vxWorks/osdThread.c +++ b/src/libCom/osi/os/vxWorks/osdThread.c @@ -43,9 +43,11 @@ static const unsigned stackSizeTable[epicsThreadStackBig+1] = {4000*ARCH_STACK_FACTOR, 6000*ARCH_STACK_FACTOR, 11000*ARCH_STACK_FACTOR}; -/* FIXME: this is the beta implementation of epicsThreadMap for vxWorks. See below. */ -#define ID_LIST_SIZE 2048 -static int taskIdList[ID_LIST_SIZE]; +/* 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; @@ -88,17 +90,25 @@ static int getOssPriorityValue(unsigned int osiPriority) } } +static void mutexInit(SEM_ID lock) +{ + if (lock == 0) { + lock = semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY); + assert(lock); + } +} + static void epicsThreadInit(void) { static int lock = 0; while(!vxTas(&lock)) taskDelay(1); epicsThreadHooksInit(); - if(epicsThreadOnceMutex==0) { - epicsThreadOnceMutex = semMCreate( - SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY); - assert(epicsThreadOnceMutex); - } + mutexInit(epicsThreadOnceMutex); + mutexInit(epicsThreadListMutex); + taskIdList = calloc(ID_LIST_CHUNK, sizeof(int)); + assert(taskIdList); + taskIdListSize = ID_LIST_CHUNK; lock = 0; } @@ -322,19 +332,26 @@ void epicsThreadGetName (epicsThreadId id, char *name, size_t size) epicsShareFunc void epicsShareAPI epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func ) { -/* FIXME: add better vxWorks implementation that uses a dynamic taskIdList */ -/* Andrew says: - * use the vxWorks routine taskIdListGet(); - * that seems better, although there's no API to tell you how many tasks exist - * (I guess you could keep a count yourself if you register - * taskCreateHook and taskDeleteHook routines). */ - int noTasks; + int noTasks = 0; int i; + int result; - noTasks = taskIdListGet(taskIdList, ID_LIST_SIZE); + result = semTake(epicsThreadListMutex, WAIT_FOREVER); + assert(result == OK); + noTasks = taskIdListGet(taskIdList, taskIdListSize); + 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 (i); } + semGive(epicsThreadListMutex); } void epicsThreadShowAll(unsigned int level) From da91893ec24676c478946043a20c5cceb74b40f2 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Mon, 2 Jul 2012 18:18:54 +0200 Subject: [PATCH 09/15] libCom/test: Add test for epicsThreadHooks --- src/libCom/test/Makefile | 5 ++ src/libCom/test/epicsThreadHooksTest.c | 115 +++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 src/libCom/test/epicsThreadHooksTest.c diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index f38b01dbf..659b3fcd0 100644 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -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 diff --git a/src/libCom/test/epicsThreadHooksTest.c b/src/libCom/test/epicsThreadHooksTest.c new file mode 100644 index 000000000..cb13758b3 --- /dev/null +++ b/src/libCom/test/epicsThreadHooksTest.c @@ -0,0 +1,115 @@ +/*************************************************************************\ +* 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 +#include + +#include "epicsThread.h" +#include "epicsExit.h" +#include "errlog.h" +#include "epicsUnitTest.h" +#include "testMain.h" + +#define THREAD_NO 6 +#define HOOKS_NO 6 + +epicsThreadPrivateId threadNo; +static int order[THREAD_NO][HOOKS_NO]; +static int cnt[THREAD_NO]; +static int mine[THREAD_NO]; +static epicsThreadId tid[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 startHook1 (epicsThreadId id) +{ + int no = newThreadIndex(id); + order[no][0] = cnt[no]++; +} + +static void startHook2 (epicsThreadId id) +{ + int no = findThreadIndex(id); + order[no][1] = cnt[no]++; +} + +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 exitHook1 (epicsThreadId id) +{ + int no = findThreadIndex(id); + order[no][5] = cnt[no]++; +} + +static void exitHook2 (epicsThreadId id) +{ + int no = findThreadIndex(id); + order[no][4] = cnt[no]++; +} + +static void my_thread (void *arg) +{ + int no = findThreadIndex(epicsThreadGetIdSelf()); + mine[no] = 1; + epicsAtThreadExit(atExitHook1, NULL); + epicsAtThreadExit(atExitHook2, NULL); + epicsThreadSleep(0.1); +} + +MAIN(epicsThreadHooksTest) +{ + int i; + + testPlan(THREAD_NO-1); + epicsThreadAddStartHook(startHook1); + epicsThreadAddExitHook(exitHook1); + epicsThreadAddStartHook(startHook2); + epicsThreadAddExitHook(exitHook2); + + for (i = 0; i < THREAD_NO-1; i++) { + char name[10]; + sprintf(name, "t%d", (int) i); + epicsThreadCreate(name, epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), my_thread, NULL); + } + + epicsThreadSleep(1.0); + + for (i = 0; i < THREAD_NO; i++) { + int ok = 1; + int j; + for (j = 0; j < HOOKS_NO; j++) { + if (mine[i] && order[i][j]!=j) ok = 0; + } + if (mine[i]) testOk(ok, "All %d hooks for task %d called in correct order", HOOKS_NO, (int)i); + } + return testDone(); +} From 7c27c7c56d544b17b7a0ec29591e41b4efa6a463 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Mon, 2 Jul 2012 18:31:08 +0200 Subject: [PATCH 10/15] documentation: Add epicsThreadHooks info to RELEASE NOTES --- documentation/RELEASE_NOTES.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 139072f5d..9b78e72e0 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -15,6 +15,17 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.

Changes between 3.14.x and 3.15.0.x

+

New API to hook into thread creation and deletion

+ +

A hook API has been added allowing user-supplied functions to be called +whenever a thread starts or exits. 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).

+ +

The API also supports a mapping operation, calling a user-supplied function +for every thread that is currently running.

+

New scan rate units

Scan rates defined in the menuScan.dbd file may now be specified in seconds, From 0e6a01d56a1379c193f9c2dd918d2ddea02756cd Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 3 Jul 2012 11:16:09 +0200 Subject: [PATCH 11/15] libCom/osi: Streamline epicsThreadShowInfo functions between implementations - epicsThreadShowInfo: private function to print headers or task line, not in header file, using internal pointer type --- src/libCom/osi/os/Linux/osdThread.h | 2 -- src/libCom/osi/os/Linux/osdThreadExtra.c | 2 +- src/libCom/osi/os/RTEMS/osdThread.c | 16 +++++++--------- src/libCom/osi/os/WIN32/osdThread.c | 12 ++++++------ src/libCom/osi/os/posix/osdThread.c | 8 +++++--- src/libCom/osi/os/posix/osdThread.h | 2 -- src/libCom/osi/os/posix/osdThreadExtra.c | 2 +- 7 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/libCom/osi/os/Linux/osdThread.h b/src/libCom/osi/os/Linux/osdThread.h index ebdd47659..eb0a60ede 100644 --- a/src/libCom/osi/os/Linux/osdThread.h +++ b/src/libCom/osi/os/Linux/osdThread.h @@ -39,8 +39,6 @@ typedef struct epicsThreadOSD { epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId(epicsThreadId id); -epicsShareFunc void epicsShowThreadInfo(epicsThreadOSD *pthreadInfo, unsigned int level); - #ifdef __cplusplus } #endif diff --git a/src/libCom/osi/os/Linux/osdThreadExtra.c b/src/libCom/osi/os/Linux/osdThreadExtra.c index fc1d2d1df..aa830c6ee 100644 --- a/src/libCom/osi/os/Linux/osdThreadExtra.c +++ b/src/libCom/osi/os/Linux/osdThreadExtra.c @@ -27,7 +27,7 @@ #include "epicsEvent.h" #include "epicsThread.h" -void epicsShowThreadInfo(epicsThreadOSD *pthreadInfo, unsigned int level) +void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level) { if(!pthreadInfo) { fprintf(epicsGetStdout()," NAME EPICS ID " diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c index d6a94ad4a..13e2469f9 100644 --- a/src/libCom/osi/os/RTEMS/osdThread.c +++ b/src/libCom/osi/os/RTEMS/osdThread.c @@ -642,20 +642,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) @@ -663,7 +661,7 @@ void epicsThreadShow (epicsThreadId id, unsigned int level) struct taskVar *v; if (!id) { - epicsThreadShowHeader (); + epicsThreadShowInfo (NULL, level); return; } taskVarLock (); diff --git a/src/libCom/osi/os/WIN32/osdThread.c b/src/libCom/osi/os/WIN32/osdThread.c index c66d9e606..1acef7e52 100644 --- a/src/libCom/osi/os/WIN32/osdThread.c +++ b/src/libCom/osi/os/WIN32/osdThread.c @@ -951,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; @@ -1014,10 +1014,10 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll ( unsigned level ) EnterCriticalSection ( & pGbl->mutex ); - epicsThreadShowPrivate ( 0, level ); + 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 ); @@ -1028,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 ); } /* diff --git a/src/libCom/osi/os/posix/osdThread.c b/src/libCom/osi/os/posix/osdThread.c index 8734106f4..d1a0a2644 100644 --- a/src/libCom/osi/os/posix/osdThread.c +++ b/src/libCom/osi/os/posix/osdThread.c @@ -35,6 +35,8 @@ #include "epicsAssert.h" #include "epicsExit.h" +epicsShareFunc void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level); + static int mutexLock(pthread_mutex_t *id) { int status; @@ -767,7 +769,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level) return; pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList); while(pthreadInfo) { - epicsShowThreadInfo(pthreadInfo,level); + epicsThreadShowInfo(pthreadInfo,level); pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node); } status = pthread_mutex_unlock(&listLock); @@ -782,7 +784,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsi epicsThreadInit(); if(!showThread) { - epicsShowThreadInfo(0,level); + epicsThreadShowInfo(0,level); return; } status = mutexLock(&listLock); @@ -794,7 +796,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsi if (((epicsThreadId)pthreadInfo == showThread) || ((epicsThreadId)pthreadInfo->tid == showThread)) { found = 1; - epicsShowThreadInfo(pthreadInfo,level); + epicsThreadShowInfo(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 0885f9410..ee6f6cd4d 100644 --- a/src/libCom/osi/os/posix/osdThread.h +++ b/src/libCom/osi/os/posix/osdThread.h @@ -38,8 +38,6 @@ typedef struct epicsThreadOSD { epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId(epicsThreadId id); -epicsShareFunc void epicsShowThreadInfo(epicsThreadOSD *pthreadInfo, unsigned int level); - #ifdef __cplusplus } #endif diff --git a/src/libCom/osi/os/posix/osdThreadExtra.c b/src/libCom/osi/os/posix/osdThreadExtra.c index 93a149307..9df3485af 100644 --- a/src/libCom/osi/os/posix/osdThreadExtra.c +++ b/src/libCom/osi/os/posix/osdThreadExtra.c @@ -17,7 +17,7 @@ #include "epicsEvent.h" #include "epicsThread.h" -void epicsShowThreadInfo(epicsThreadOSD *pthreadInfo, unsigned int level) +void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level) { if(!pthreadInfo) { fprintf(epicsGetStdout()," NAME EPICS ID " From e834832cda3f06d26e764d6eba00fc88d7033278 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 3 Jul 2012 13:20:01 +0200 Subject: [PATCH 12/15] libCom/osi: Don't decorate epicsThreadHook functions with epicsShareAPI --- src/libCom/osi/epicsThread.h | 12 ++++++------ src/libCom/osi/os/default/osdThreadHooks.c | 10 +++++----- src/libCom/osi/os/posix/osdThread.c | 2 +- src/libCom/osi/os/vxWorks/osdThread.c | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libCom/osi/epicsThread.h b/src/libCom/osi/epicsThread.h index ab08e3d87..56710be20 100644 --- a/src/libCom/osi/epicsThread.h +++ b/src/libCom/osi/epicsThread.h @@ -103,16 +103,16 @@ epicsShareFunc void epicsShareAPI epicsThreadShow( /* Hooks being called when a thread starts or exits */ typedef void (*EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id); -epicsShareFunc void epicsShareAPI epicsThreadHooksInit(void); -epicsShareFunc void epicsShareAPI epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook); -epicsShareFunc void epicsShareAPI epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook); -epicsShareFunc void epicsShareAPI epicsThreadRunStartHooks(epicsThreadId id); -epicsShareFunc void epicsShareAPI epicsThreadRunExitHooks(epicsThreadId id); +epicsShareFunc void epicsThreadHooksInit(void); +epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook); +epicsShareFunc void epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook); +epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id); +epicsShareFunc void epicsThreadRunExitHooks(epicsThreadId id); epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultExitHook; /* Map func to all threads */ -epicsShareFunc void epicsShareAPI epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func); +epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func); typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId; epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void); diff --git a/src/libCom/osi/os/default/osdThreadHooks.c b/src/libCom/osi/os/default/osdThreadHooks.c index 9dc99e95e..c3a6a3fa8 100644 --- a/src/libCom/osi/os/default/osdThreadHooks.c +++ b/src/libCom/osi/os/default/osdThreadHooks.c @@ -63,17 +63,17 @@ static void runHooks (ELLLIST *list, epicsThreadId id) { epicsMutexUnlock(hookLock); } -epicsShareFunc void epicsShareAPI epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook) +epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook) { addHook(&startHooks, hook, 0); } -epicsShareFunc void epicsShareAPI epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook) +epicsShareFunc void epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook) { addHook(&exitHooks, hook, 1); } -epicsShareFunc void epicsShareAPI epicsThreadHooksInit(void) +epicsShareFunc void epicsThreadHooksInit(void) { if (!hookLock) { hookLock = epicsMutexMustCreate(); @@ -82,12 +82,12 @@ epicsShareFunc void epicsShareAPI epicsThreadHooksInit(void) } } -epicsShareFunc void epicsShareAPI epicsThreadRunStartHooks(epicsThreadId id) +epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id) { runHooks(&startHooks, id); } -epicsShareFunc void epicsShareAPI epicsThreadRunExitHooks(epicsThreadId id) +epicsShareFunc void epicsThreadRunExitHooks(epicsThreadId id) { runHooks(&exitHooks, id); } diff --git a/src/libCom/osi/os/posix/osdThread.c b/src/libCom/osi/os/posix/osdThread.c index d1a0a2644..5653e5937 100644 --- a/src/libCom/osi/os/posix/osdThread.c +++ b/src/libCom/osi/os/posix/osdThread.c @@ -737,7 +737,7 @@ epicsShareFunc void epicsShareAPI epicsThreadGetName(epicsThreadId pthreadInfo, name[size-1] = '\0'; } -epicsShareFunc void epicsShareAPI epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func) +epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func) { epicsThreadOSD *pthreadInfo; int status; diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c index 9e0e7b70e..61f2145f1 100644 --- a/src/libCom/osi/os/vxWorks/osdThread.c +++ b/src/libCom/osi/os/vxWorks/osdThread.c @@ -330,7 +330,7 @@ void epicsThreadGetName (epicsThreadId id, char *name, size_t size) name[size-1] = '\0'; } -epicsShareFunc void epicsShareAPI epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func ) +epicsShareFunc void epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func ) { int noTasks = 0; int i; From 7b47cad8e49a82402750183297eb50e8a1be8304 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 3 Jul 2012 14:38:12 +0200 Subject: [PATCH 13/15] libCom/osi: Clean up epicsThreadHooks API - remove exit hooks completely - remove non-public functions fom header files - add test for epicsThreadMap - fix bugs in RTEMS and vxWorks implementation of epicsThreadMap --- src/libCom/osi/epicsThread.h | 9 +--- src/libCom/osi/os/Linux/osdThreadExtra.c | 3 +- src/libCom/osi/os/RTEMS/osdThread.c | 7 +-- src/libCom/osi/os/WIN32/osdThread.c | 9 ++-- src/libCom/osi/os/default/osdThreadExtra.c | 6 ++- src/libCom/osi/os/default/osdThreadHooks.c | 49 +++++------------ src/libCom/osi/os/posix/osdThread.c | 3 +- src/libCom/osi/os/vxWorks/osdThread.c | 8 +-- src/libCom/test/epicsThreadHooksTest.c | 61 ++++++++++++---------- 9 files changed, 69 insertions(+), 86 deletions(-) diff --git a/src/libCom/osi/epicsThread.h b/src/libCom/osi/epicsThread.h index 56710be20..a94bd9c3b 100644 --- a/src/libCom/osi/epicsThread.h +++ b/src/libCom/osi/epicsThread.h @@ -101,17 +101,10 @@ epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level); epicsShareFunc void epicsShareAPI epicsThreadShow( epicsThreadId id,unsigned int level); -/* Hooks being called when a thread starts or exits */ +/* Hooks called when a thread starts, map function called once for every thread */ typedef void (*EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id); epicsShareFunc void epicsThreadHooksInit(void); epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook); -epicsShareFunc void epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook); -epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id); -epicsShareFunc void epicsThreadRunExitHooks(epicsThreadId id); -epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; -epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultExitHook; - -/* Map func to all threads */ epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func); typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId; diff --git a/src/libCom/osi/os/Linux/osdThreadExtra.c b/src/libCom/osi/os/Linux/osdThreadExtra.c index aa830c6ee..61a0ef2bd 100644 --- a/src/libCom/osi/os/Linux/osdThreadExtra.c +++ b/src/libCom/osi/os/Linux/osdThreadExtra.c @@ -27,6 +27,8 @@ #include "epicsEvent.h" #include "epicsThread.h" +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; + void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level) { if(!pthreadInfo) { @@ -60,4 +62,3 @@ static void thread_hook(epicsThreadOSD *pthreadInfo) } EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook = thread_hook; -EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultExitHook; diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c index 13e2469f9..70a014539 100644 --- a/src/libCom/osi/os/RTEMS/osdThread.c +++ b/src/libCom/osi/os/RTEMS/osdThread.c @@ -39,6 +39,8 @@ #include "osdInterrupt.h" #include "epicsExit.h" +epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id); + /* * Per-task variables */ @@ -164,10 +166,9 @@ threadWrapper (rtems_task_argument arg) { struct taskVar *v = (struct taskVar *)arg; - epicsThreadRunStartHooks(pthreadInfo); + epicsThreadRunStartHooks(v->id); (*v->funptr)(v->parm); epicsExitCallAtThreadExits (); - epicsThreadRunExitHooks(pthreadInfo); taskVarLock (); if (v->back) v->back->forw = v->forw; @@ -686,7 +687,7 @@ void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func) for (v = taskVarHead ; v != NULL && v->forw != NULL ; v = v->forw) continue; while (v) { - func (v, arg); + func ((epicsThreadId)v->id); v = v->back; } taskVarUnlock (); diff --git a/src/libCom/osi/os/WIN32/osdThread.c b/src/libCom/osi/os/WIN32/osdThread.c index 1acef7e52..e9c573731 100644 --- a/src/libCom/osi/os/WIN32/osdThread.c +++ b/src/libCom/osi/os/WIN32/osdThread.c @@ -38,6 +38,8 @@ #include "ellLib.h" #include "epicsExit.h" +epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id); + void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName ); static void threadCleanupWIN32 ( void ); @@ -226,7 +228,7 @@ static win32ThreadGlobal * fetchWin32ThreadGlobal ( void ) pWin32ThreadGlobal = 0; return 0; } - epicsThreadHooksInit(); + epicsThreadHooksInit (); InterlockedExchange ( & initCompleted, 1 ); @@ -497,7 +499,7 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter ) success = TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, pParm ); if ( success ) { - epicsThreadRunStartHooks(pParm); + epicsThreadRunStartHooks ( ( epicsThreadId ) pParm ); /* printf ( "starting thread %d\n", pParm->id ); */ ( *pParm->funptr ) ( pParm->parm ); /* printf ( "terminating thread %d\n", pParm->id ); */ @@ -512,9 +514,6 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter ) } epicsExitCallAtThreadExits (); - - epicsThreadRunExitHooks(pParm); - /* * CAUTION: !!!! the thread id might continue to be used after this thread exits !!!! */ diff --git a/src/libCom/osi/os/default/osdThreadExtra.c b/src/libCom/osi/os/default/osdThreadExtra.c index 31b3abac7..311db013d 100644 --- a/src/libCom/osi/os/default/osdThreadExtra.c +++ b/src/libCom/osi/os/default/osdThreadExtra.c @@ -9,5 +9,9 @@ /* Null default thread hooks for all platforms that do not do anything special */ +#define epicsExportSharedSymbols +#include "shareLib.h" + +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; + 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 index c3a6a3fa8..86f0113dd 100644 --- a/src/libCom/osi/os/default/osdThreadHooks.c +++ b/src/libCom/osi/os/default/osdThreadHooks.c @@ -19,6 +19,9 @@ #include "epicsMutex.h" #include "epicsThread.h" +epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id); +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; + #define checkStatusOnceReturn(status, message, method) \ if((status)) { \ fprintf(stderr,"%s error %s\n",(message),strerror((status))); \ @@ -31,63 +34,39 @@ typedef struct epicsThreadHook { } epicsThreadHook; static ELLLIST startHooks = ELLLIST_INIT; -static ELLLIST exitHooks = ELLLIST_INIT; /* Locking could probably be avoided, if elllist implementation was using atomic ops */ static epicsMutexId hookLock; -static void addHook (ELLLIST *list, EPICS_THREAD_HOOK_ROUTINE func, int atHead) +epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook) { epicsThreadHook *pHook; pHook = calloc(1, sizeof(epicsThreadHook)); if (!pHook) checkStatusOnceReturn(errno,"calloc","epicsThreadAddStartHook"); - pHook->func = func; + pHook->func = hook; epicsMutexLock(hookLock); - if (atHead) - ellInsert(list, NULL, &pHook->node); - else - ellAdd(list, &pHook->node); + ellAdd(&startHooks, &pHook->node); epicsMutexUnlock(hookLock); } -static void runHooks (ELLLIST *list, epicsThreadId id) { - epicsThreadHook *pHook; - - epicsMutexLock(hookLock); - pHook = (epicsThreadHook *) ellFirst(list); - while (pHook) { - pHook->func(id); - pHook = (epicsThreadHook *) ellNext(&pHook->node); - } - epicsMutexUnlock(hookLock); -} - -epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook) -{ - addHook(&startHooks, hook, 0); -} - -epicsShareFunc void epicsThreadAddExitHook(EPICS_THREAD_HOOK_ROUTINE hook) -{ - addHook(&exitHooks, hook, 1); -} - epicsShareFunc void epicsThreadHooksInit(void) { if (!hookLock) { hookLock = epicsMutexMustCreate(); if (epicsThreadDefaultStartHook) epicsThreadAddStartHook(epicsThreadDefaultStartHook); - if (epicsThreadDefaultExitHook) epicsThreadAddExitHook(epicsThreadDefaultExitHook); } } epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id) { - runHooks(&startHooks, id); -} + epicsThreadHook *pHook; -epicsShareFunc void epicsThreadRunExitHooks(epicsThreadId id) -{ - runHooks(&exitHooks, id); + epicsMutexLock(hookLock); + pHook = (epicsThreadHook *) ellFirst(&startHooks); + while (pHook) { + pHook->func(id); + pHook = (epicsThreadHook *) ellNext(&pHook->node); + } + epicsMutexUnlock(hookLock); } diff --git a/src/libCom/osi/os/posix/osdThread.c b/src/libCom/osi/os/posix/osdThread.c index 5653e5937..6eac4f8b8 100644 --- a/src/libCom/osi/os/posix/osdThread.c +++ b/src/libCom/osi/os/posix/osdThread.c @@ -36,6 +36,7 @@ #include "epicsExit.h" epicsShareFunc void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level); +epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id); static int mutexLock(pthread_mutex_t *id) { @@ -381,8 +382,6 @@ static void * start_routine(void *arg) (*pthreadInfo->createFunc)(pthreadInfo->createArg); epicsExitCallAtThreadExits (); - epicsThreadRunExitHooks(pthreadInfo); - free_threadInfo(pthreadInfo); return(0); } diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c index 61f2145f1..7953c03ef 100644 --- a/src/libCom/osi/os/vxWorks/osdThread.c +++ b/src/libCom/osi/os/vxWorks/osdThread.c @@ -33,6 +33,8 @@ #include "vxLib.h" #include "epicsExit.h" +epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id); + #if CPU_FAMILY == MC680X0 #define ARCH_STACK_FACTOR 1 #elif CPU_FAMILY == SPARC @@ -173,10 +175,9 @@ 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; - epicsThreadRunStartHooks(pthreadInfo); + epicsThreadRunStartHooks((epicsThreadId)tid); (*func)(parm); epicsExitCallAtThreadExits (); - epicsThreadRunExitHooks(pthreadInfo); free(papTSD); taskVarDelete(tid,(int *)(char *)&papTSD); } @@ -338,7 +339,6 @@ epicsShareFunc void epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func ) result = semTake(epicsThreadListMutex, WAIT_FOREVER); assert(result == OK); - noTasks = taskIdListGet(taskIdList, taskIdListSize); while (noTasks == 0) { noTasks = taskIdListGet(taskIdList, taskIdListSize); if (noTasks == taskIdListSize) { @@ -349,7 +349,7 @@ epicsShareFunc void epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func ) } } for (i = 0; i < noTasks; i++) { - func (i); + func ((epicsThreadId)taskIdList[i]); } semGive(epicsThreadListMutex); } diff --git a/src/libCom/test/epicsThreadHooksTest.c b/src/libCom/test/epicsThreadHooksTest.c index cb13758b3..ea5722ef7 100644 --- a/src/libCom/test/epicsThreadHooksTest.c +++ b/src/libCom/test/epicsThreadHooksTest.c @@ -12,18 +12,21 @@ #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 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) { @@ -40,18 +43,6 @@ static int findThreadIndex(epicsThreadId id) return i; } -static void startHook1 (epicsThreadId id) -{ - int no = newThreadIndex(id); - order[no][0] = cnt[no]++; -} - -static void startHook2 (epicsThreadId id) -{ - int no = findThreadIndex(id); - order[no][1] = cnt[no]++; -} - static void atExitHook1 (void *arg) { int no = findThreadIndex(epicsThreadGetIdSelf()); @@ -64,52 +55,68 @@ static void atExitHook2 (void *arg) order[no][2] = cnt[no]++; } -static void exitHook1 (epicsThreadId id) +static void startHook1 (epicsThreadId id) { - int no = findThreadIndex(id); - order[no][5] = cnt[no]++; + int no = newThreadIndex(id); + order[no][0] = cnt[no]++; + epicsAtThreadExit(atExitHook1, NULL); } -static void exitHook2 (epicsThreadId id) +static void startHook2 (epicsThreadId id) { int no = findThreadIndex(id); - order[no][4] = cnt[no]++; + order[no][1] = cnt[no]++; + epicsAtThreadExit(atExitHook2, NULL); } static void my_thread (void *arg) { int no = findThreadIndex(epicsThreadGetIdSelf()); mine[no] = 1; - epicsAtThreadExit(atExitHook1, NULL); - epicsAtThreadExit(atExitHook2, NULL); - epicsThreadSleep(0.1); + epicsEventMustWait((epicsEventId) arg); +} + +static void mapper (epicsThreadId id) +{ + called[findThreadIndex(id)]++; } MAIN(epicsThreadHooksTest) { int i; + int ok; - testPlan(THREAD_NO-1); + testPlan(THREAD_NO); epicsThreadAddStartHook(startHook1); - epicsThreadAddExitHook(exitHook1); epicsThreadAddStartHook(startHook2); - epicsThreadAddExitHook(exitHook2); for (i = 0; i < THREAD_NO-1; i++) { + shutdown[i] = epicsEventCreate(epicsEventEmpty); char name[10]; sprintf(name, "t%d", (int) i); - epicsThreadCreate(name, epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), my_thread, NULL); + 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 ok = 1; int j; for (j = 0; j < HOOKS_NO; j++) { if (mine[i] && order[i][j]!=j) ok = 0; } - if (mine[i]) testOk(ok, "All %d hooks for task %d called in correct order", HOOKS_NO, (int)i); + if (mine[i]) testOk(ok, "All hooks for task %d called in correct order", (int)i); } return testDone(); } From 137283ec0b70f175ac9c7b7ff37202974296e96f Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 3 Jul 2012 15:27:50 +0200 Subject: [PATCH 14/15] libCom/osi: Add default start hook for _main_ thread --- src/libCom/osi/epicsThread.h | 2 +- src/libCom/osi/os/Linux/osdThreadExtra.c | 2 ++ src/libCom/osi/os/RTEMS/osdThread.c | 2 +- src/libCom/osi/os/WIN32/osdThread.c | 2 +- src/libCom/osi/os/default/osdThreadExtra.c | 2 ++ src/libCom/osi/os/default/osdThreadHooks.c | 4 +++- src/libCom/osi/os/posix/osdThread.c | 2 +- src/libCom/osi/os/posix/osdThreadExtra.c | 6 ++++++ src/libCom/osi/os/vxWorks/osdThread.c | 2 +- 9 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/libCom/osi/epicsThread.h b/src/libCom/osi/epicsThread.h index a94bd9c3b..23457a0af 100644 --- a/src/libCom/osi/epicsThread.h +++ b/src/libCom/osi/epicsThread.h @@ -103,7 +103,7 @@ epicsShareFunc void epicsShareAPI epicsThreadShow( /* Hooks called when a thread starts, map function called once for every thread */ typedef void (*EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id); -epicsShareFunc void epicsThreadHooksInit(void); +epicsShareFunc void epicsThreadHooksInit(epicsThreadId id); epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook); epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func); diff --git a/src/libCom/osi/os/Linux/osdThreadExtra.c b/src/libCom/osi/os/Linux/osdThreadExtra.c index 61a0ef2bd..13a3b5df7 100644 --- a/src/libCom/osi/os/Linux/osdThreadExtra.c +++ b/src/libCom/osi/os/Linux/osdThreadExtra.c @@ -28,6 +28,7 @@ #include "epicsThread.h" epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook; void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level) { @@ -62,3 +63,4 @@ static void thread_hook(epicsThreadOSD *pthreadInfo) } EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook = thread_hook; +EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook = thread_hook; diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c index 70a014539..f3871bc43 100644 --- a/src/libCom/osi/os/RTEMS/osdThread.c +++ b/src/libCom/osi/os/RTEMS/osdThread.c @@ -238,7 +238,7 @@ epicsThreadInit (void) taskVarMutex = epicsMutexMustCreate (); rtems_task_ident (RTEMS_SELF, 0, &tid); setThreadInfo (tid, "_main_", NULL, NULL); - epicsThreadHooksInit(); + epicsThreadHooksInit(tid); initialized = 1; epicsThreadCreate ("ImsgDaemon", 99, epicsThreadGetStackSize (epicsThreadStackSmall), diff --git a/src/libCom/osi/os/WIN32/osdThread.c b/src/libCom/osi/os/WIN32/osdThread.c index e9c573731..30c72a10f 100644 --- a/src/libCom/osi/os/WIN32/osdThread.c +++ b/src/libCom/osi/os/WIN32/osdThread.c @@ -228,7 +228,7 @@ static win32ThreadGlobal * fetchWin32ThreadGlobal ( void ) pWin32ThreadGlobal = 0; return 0; } - epicsThreadHooksInit (); + epicsThreadHooksInit (NULL); InterlockedExchange ( & initCompleted, 1 ); diff --git a/src/libCom/osi/os/default/osdThreadExtra.c b/src/libCom/osi/os/default/osdThreadExtra.c index 311db013d..a63ab910f 100644 --- a/src/libCom/osi/os/default/osdThreadExtra.c +++ b/src/libCom/osi/os/default/osdThreadExtra.c @@ -13,5 +13,7 @@ #include "shareLib.h" epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook; EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; +EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook; diff --git a/src/libCom/osi/os/default/osdThreadHooks.c b/src/libCom/osi/os/default/osdThreadHooks.c index 86f0113dd..3fb1e159d 100644 --- a/src/libCom/osi/os/default/osdThreadHooks.c +++ b/src/libCom/osi/os/default/osdThreadHooks.c @@ -21,6 +21,7 @@ epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id); epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook; #define checkStatusOnceReturn(status, message, method) \ if((status)) { \ @@ -50,12 +51,13 @@ epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook) epicsMutexUnlock(hookLock); } -epicsShareFunc void epicsThreadHooksInit(void) +epicsShareFunc void epicsThreadHooksInit(epicsThreadId id) { if (!hookLock) { hookLock = epicsMutexMustCreate(); if (epicsThreadDefaultStartHook) epicsThreadAddStartHook(epicsThreadDefaultStartHook); } + if (id && epicsThreadMainStartHook) epicsThreadMainStartHook(id); } epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id) diff --git a/src/libCom/osi/os/posix/osdThread.c b/src/libCom/osi/os/posix/osdThread.c index 6eac4f8b8..f0926d230 100644 --- a/src/libCom/osi/os/posix/osdThread.c +++ b/src/libCom/osi/os/posix/osdThread.c @@ -354,7 +354,7 @@ static void once(void) checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadInit"); status = atexit(epicsExitCallAtExits); checkStatusOnce(status,"atexit"); - epicsThreadHooksInit(); + epicsThreadHooksInit(pthreadInfo); epicsThreadOnceCalled = 1; } diff --git a/src/libCom/osi/os/posix/osdThreadExtra.c b/src/libCom/osi/os/posix/osdThreadExtra.c index 9df3485af..8d4338e31 100644 --- a/src/libCom/osi/os/posix/osdThreadExtra.c +++ b/src/libCom/osi/os/posix/osdThreadExtra.c @@ -17,6 +17,12 @@ #include "epicsEvent.h" #include "epicsThread.h" +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; +epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook; + +EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook; +EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook; + void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level) { if(!pthreadInfo) { diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c index 7953c03ef..9a9eea5d2 100644 --- a/src/libCom/osi/os/vxWorks/osdThread.c +++ b/src/libCom/osi/os/vxWorks/osdThread.c @@ -105,7 +105,7 @@ static void epicsThreadInit(void) static int lock = 0; while(!vxTas(&lock)) taskDelay(1); - epicsThreadHooksInit(); + epicsThreadHooksInit(NULL); mutexInit(epicsThreadOnceMutex); mutexInit(epicsThreadListMutex); taskIdList = calloc(ID_LIST_CHUNK, sizeof(int)); From 39ed8f3d024808c5782e60fed94308d1aef6c4ce Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 3 Jul 2012 16:39:57 +0200 Subject: [PATCH 15/15] documentation: Updated RELEASE_NOTES --- documentation/RELEASE_NOTES.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 9b78e72e0..8c8705af0 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -15,12 +15,12 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.

Changes between 3.14.x and 3.15.0.x

-

New API to hook into thread creation and deletion

+

New API to hook into thread creation

A hook API has been added allowing user-supplied functions to be called -whenever a thread starts or exits. 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 +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).

The API also supports a mapping operation, calling a user-supplied function