Merge lp:~ralph-lange/epics-base/thread-hooks into lp:~epics-core/epics-base/3.15

Proposed by Ralph Lange
Status: Merged
Merged at revision: 12303
Proposed branch: lp:~ralph-lange/epics-base/thread-hooks
Merge into: lp:~epics-core/epics-base/3.15
Diff against target: 967 lines (+553/-66)
15 files modified
documentation/RELEASE_NOTES.html (+11/-0)
src/libCom/osi/Makefile (+2/-0)
src/libCom/osi/epicsThread.h (+8/-2)
src/libCom/osi/os/Linux/osdThread.h (+46/-0)
src/libCom/osi/os/Linux/osdThreadExtra.c (+66/-0)
src/libCom/osi/os/RTEMS/osdThread.c (+28/-9)
src/libCom/osi/os/WIN32/osdThread.c (+34/-9)
src/libCom/osi/os/default/osdThreadExtra.c (+19/-0)
src/libCom/osi/os/default/osdThreadHooks.c (+74/-0)
src/libCom/osi/os/posix/osdThread.c (+24/-40)
src/libCom/osi/os/posix/osdThread.h (+19/-1)
src/libCom/osi/os/posix/osdThreadExtra.c (+48/-0)
src/libCom/osi/os/vxWorks/osdThread.c (+47/-5)
src/libCom/test/Makefile (+5/-0)
src/libCom/test/epicsThreadHooksTest.c (+122/-0)
To merge this branch: bzr merge lp:~ralph-lange/epics-base/thread-hooks
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
Review via email: mp+112806@code.launchpad.net

Description of the change

Adds two interfaces for user hooks that are being called from epicsThread:

epicsThreadAddStartHook(func) and epicsThreadAddExitHook(func) each add a user function to an internal list of hooks that are being called from the thread context, immediately before or after each thread's main routine runs.
For Linux, the default start hook adds the thread's Linux LWP ID to the thread info block and sets the Linux name to match the epics thread name, and epicsShowThread() is overwritten to print this LWP ID instead of the POSIX thread ID.

epicsThreadMap(func) immediately calls the user supplied func for each currently existing thread.

Caveat: The WIN32 implementation needs the start/exit hooks calls added - I simply do not understand this implementation well enough to do that.
The vxWorks implementation of epicsThreadMap() only works for up to 2048 threads, and needs to be made dynamic.

To post a comment you must log in.
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

> /* As we're only ever inserting hooks at the head of the list, forward traversing is safe */
> pHook = (epicsThreadHook *) ellFirst(list);

It can be unlocked to traverse, but the mutex should be locked when fetching the head pointer.

Revision history for this message
Andrew Johnson (anj) wrote :

Should the AtThreadExits run before the ExitHooks? You have this in several places:
  + epicsThreadRunExitHooks(pthreadInfo);
    epicsExitCallAtThreadExits ();
My feeling is that task-specific clean-up should happen before the generic task clean-up, so things nest nicely.

I think the Win32 calls to the epicsThreadRun*Hooks() routines belong in the epicsWin32ThreadEntry() routine, and epicsThreadHooksInit() should be called towards the bottom of fetchWin32ThreadGlobal() after the atexit() call but before initCompleted gets set (there doesn't look to be anything in the mutex creation code that would cause problems there).

Then with some tests in libCom/test/epicsThreadTest.cpp and comments in the Release Notes I think this should be good to go. Eventually I'll want the API documenting in the AppDevGuide too, but not for this release.

Thanks,

- Andrew

Revision history for this message
Ralph Lange (ralph-lange) wrote :

> > /* As we're only ever inserting hooks at the head of the list, forward
> traversing is safe */
> > pHook = (epicsThreadHook *) ellFirst(list);
>
> It can be unlocked to traverse, but the mutex should be locked when fetching
> the head pointer.

That's because the pointer modifying operations (in elllib.c) are not atomic?
Other than that, I would assume the map function could either get or miss the element currently being inserted or added, and both would be ok.

12306. By Ralph Lange

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

12307. By Ralph Lange

libCom/osi: Make vxWorks implementation of epicsThreadMap() safe and dynamic

12308. By Ralph Lange

libCom/test: Add test for epicsThreadHooks

12309. By Ralph Lange

documentation: Add epicsThreadHooks info to RELEASE NOTES

Revision history for this message
Ralph Lange (ralph-lange) wrote :

I think I pretty much worked down the list.

Revision history for this message
Andrew Johnson (anj) wrote :

Hi Ralph,

Thanks.

Sorry, a couple more issues, then I think I'm done:

The name 'epicsShowThreadInfo' implies this routine is part of the epicsShow subsystem. The original name 'showThreadInfo' was static and thus only used internally to the posix implementation, but if you're making it visible I think it needs to match the other epicsThread... names. Maybe name it epicsThreadShowPrivate(), which matches the Win32 implementation (although there the routine is static).

If you don't intend that routine to be called by user code the declaration for it doesn't have to appear in any header files either, it could just appear in the posix/osdThread.c file where it's used. I would also prefer that it take an epicsThreadId argument instead of the epicsThreadOSD* pointer; that should remain for internal use only (epicsThread.h has a typedef making the two identical).

- Andrew

Revision history for this message
Andrew Johnson (anj) wrote :

Sorry, a few more, although they're minor.

Please don't mark new API routines with epicsShareAPI; I'm trying to phase that out since almost nobody needs to use Pascal calling conventions on Windows any more. It's really only needed for routines that may be called by Visual Basic (if there are any users of that left), so it may still be necessary on CA API routines but not really on most others.

This may be more of a discussion point. Here's my output from epicsThreadShowAll:

epics> epicsThreadShowAll
            NAME EPICS ID LWP ID OSIPRI OSSPRI STATE
          _main_ 0x10b1060 0 0 0 OK
          errlog 0x113c830 20849 10 0 OK
          taskwd 0x113cc80 20850 10 0 OK
      timerQueue 0x113d5e0 20851 70 0 OK
           cbLow 0x113d8c0 20852 59 0 OK
        cbMedium 0x113db90 20853 64 0 OK
          cbHigh 0x113de60 20854 71 0 OK
        dbCaLink 0x113e300 20855 50 0 OK
        scanOnce 0x113ea10 20856 70 0 OK
         scan-10 0x114d670 20857 60 0 OK
          scan-5 0x114d8b0 20858 61 0 OK
          scan-2 0x114daf0 20859 62 0 OK
          scan-1 0x114dd30 20860 63 0 OK
        scan-0.5 0x114df70 20861 64 0 OK
        scan-0.2 0x114e1b0 20862 65 0 OK
        scan-0.1 0x114e3f0 20863 66 0 OK
         CAS-TCP 0x114ebc0 20864 18 0 OK
      CAS-beacon 0x7f043c000990 20865 17 0 OK
         CAS-UDP 0x7f0440000970 20866 16 0 OK

The _main_ thread is not started using epicsThreadCreate() and thus never runs the thread_hook, so we don't know its LWP ID. It would be nice if we could see it here. The _main_ thread gets its epicsThreadOSD structure created and added to pthreadList inside the once() routine in od/posix/osdThread.c before epicsThreadHooksInit() is run. The Init() routine cannot call any other epicsThread... routines such as epicsThreadGetIdSelf() because once() hasn't finished yet. Maybe epicsThreadHooksInit() could take main's epicsThreadId as an argument and (if non-zero) call the StartHook for it?

I think we can safely forget about calling _main_'s ExitHook, which brings up the interesting question of whether ExitHook is actually needed -- any StartHook can register an epicsAtThreadExit() routine if it needs to do clean-up. If we were to remove the ExitHooks we would never have problems with an ExitHook being called for a thread for which where there was no corresponding StartHook. It also means that the ExitHook routines would be run in the reverse order of the StartHook routines, whereas at the moment the order is the same.

- Andrew

Revision history for this message
Ralph Lange (ralph-lange) wrote :

Hi Andrew,

> The name 'epicsShowThreadInfo' implies this routine is part of the epicsShow
> subsystem. The original name 'showThreadInfo' was static and thus only used
> internally to the posix implementation, but if you're making it visible I
> think it needs to match the other epicsThread... names. Maybe name it
> epicsThreadShowPrivate(), which matches the Win32 implementation (although
> there the routine is static).

Will do.
On a closely related issue, I am quite unhappy with the confusing names of the public API functions

epicsThreadPrivateCreate
epicsThreadPrivateDelete
epicsThreadPrivateSet
epicsThreadPrivateGet

that are - unlike the other funtions that contain "Private" - *not* private, but public functions.
Also, they implement what is more commonly called "thread local storage".
Do you think it would be worthwhile renaming them to *Local* and deprecate the existing names, adding macros to continue supporting them?!

> If you don't intend that routine to be called by user code the declaration for
> it doesn't have to appear in any header files either, it could just appear in
> the posix/osdThread.c file where it's used.

True. Will do.

> I would also prefer that it take
> an epicsThreadId argument instead of the epicsThreadOSD* pointer; that should
> remain for internal use only (epicsThread.h has a typedef making the two
> identical).

If (after the mentioned change) the function is private, not in any header file, and any implementation would have to cast the argument to an epicsThreadOSD* pointer anyway, I don't see the point in using the opaque type.

~Ralph

12310. By Ralph Lange

libCom/osi: Streamline epicsThreadShowInfo functions between implementations
- epicsThreadShowInfo: private function to print headers or task line,
  not in header file, using internal pointer type

Revision history for this message
Ralph Lange (ralph-lange) wrote :

> Please don't mark new API routines with epicsShareAPI; I'm trying to phase
> that out [...]

Will do.

> This may be more of a discussion point. Here's my output from
> epicsThreadShowAll:
>
> epics> epicsThreadShowAll
> NAME EPICS ID LWP ID OSIPRI OSSPRI STATE
> _main_ 0x10b1060 0 0 0 OK
> errlog 0x113c830 20849 10 0 OK
> [...]
>
> The _main_ thread is not started using epicsThreadCreate() and thus never runs
> the thread_hook, so we don't know its LWP ID. It would be nice if we could
> see it here.

I had considered this, then decided against, as the POSIX implementation shows the POSIX thread id as 0, and I wanted to stay minimally invasive.
If you think this is a good idea (I do), I will add that.

> I think we can safely forget about calling _main_'s ExitHook, which brings up
> the interesting question of whether ExitHook is actually needed -- any
> StartHook can register an epicsAtThreadExit() routine if it needs to do clean-
> up. If we were to remove the ExitHooks we would never have problems with an
> ExitHook being called for a thread for which where there was no corresponding
> StartHook.

Good! That was my initial approach, and I added the ExitHook routines only out of a gut feeling that I wold have to justify if I didn't.
The argument about an exit hook being called where the start hook wasn't added at thread creation time is an excellent one.

> It also means that the ExitHook routines would be run in the
> reverse order of the StartHook routines, whereas at the moment the order is
> the same.

Not true. They are run in correct (reverse) order, which is covered by the test. Never mind.

~Ralph

12311. By Ralph Lange

libCom/osi: Don't decorate epicsThreadHook functions with epicsShareAPI

12312. By Ralph Lange

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

12313. By Ralph Lange

libCom/osi: Add default start hook for _main_ thread

Revision history for this message
Ralph Lange (ralph-lange) wrote :

> [...] The _main_ thread gets its epicsThreadOSD structure created and
> added to pthreadList inside the once() routine in od/posix/osdThread.c before
> epicsThreadHooksInit() is run. The Init() routine cannot call any other
> epicsThread... routines such as epicsThreadGetIdSelf() because once() hasn't
> finished yet.

I don't like all thread start hooks to inherit this limitation, so I implemented this using a second default hook, that is exclusively used for _main_.

So - if I did not miss anything - the list seems to be worked through, again.

~Ralph

12314. By Ralph Lange

documentation: Updated RELEASE_NOTES

Revision history for this message
Andrew Johnson (anj) wrote :

Hi Ralph,

I made some minor changes while merging this, the most important being to properly fix the vxWorks epicsThreadInit() code so it is only run once. I also renamed a few things so the hooking API is now called epicsThreadHookAdd(), and I added the test routine to epicsRunLibComTests().

I'll do a test run on vxWorks when I'm back at work tomorrow.

Thanks,

- Andrew

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'documentation/RELEASE_NOTES.html'
--- documentation/RELEASE_NOTES.html 2012-06-27 21:43:15 +0000
+++ documentation/RELEASE_NOTES.html 2012-07-03 14:42:25 +0000
@@ -15,6 +15,17 @@
15<h2 align="center">Changes between 3.14.x and 3.15.0.x</h2>15<h2 align="center">Changes between 3.14.x and 3.15.0.x</h2>
16<!-- Insert new items immediately below here ... -->16<!-- Insert new items immediately below here ... -->
1717
18<h3>New API to hook into thread creation</h3>
19
20<p>A hook API has been added allowing user-supplied functions to be called
21whenever a thread starts. The calls are made from the thread's context,
22and can be used to control additional thread properties not handled inside
23EPICS base, e.g. setting the scheduling policy or CPU affinity (on SMP
24systems).</p>
25
26<p>The API also supports a mapping operation, calling a user-supplied function
27for every thread that is currently running.</p>
28
18<h3>New scan rate units</h3>29<h3>New scan rate units</h3>
1930
20<p>Scan rates defined in the menuScan.dbd file may now be specified in seconds,31<p>Scan rates defined in the menuScan.dbd file may now be specified in seconds,
2132
=== modified file 'src/libCom/osi/Makefile'
--- src/libCom/osi/Makefile 2012-05-03 17:19:34 +0000
+++ src/libCom/osi/Makefile 2012-07-03 14:42:25 +0000
@@ -104,6 +104,8 @@
104osdThread_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING))104osdThread_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING))
105105
106Com_SRCS += osdThread.c106Com_SRCS += osdThread.c
107Com_SRCS += osdThreadExtra.c
108Com_SRCS += osdThreadHooks.c
107Com_SRCS += osdMutex.c109Com_SRCS += osdMutex.c
108Com_SRCS += osdEvent.c110Com_SRCS += osdEvent.c
109Com_SRCS += osdTime.cpp111Com_SRCS += osdTime.cpp
110112
=== modified file 'src/libCom/osi/epicsThread.h'
--- src/libCom/osi/epicsThread.h 2010-04-26 20:38:11 +0000
+++ src/libCom/osi/epicsThread.h 2012-07-03 14:42:25 +0000
@@ -3,8 +3,8 @@
3* National Laboratory.3* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as4* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.5* Operator of Los Alamos National Laboratory.
6* EPICS BASE Versions 3.13.76* Copyright (c) 2012 ITER Organization
7* and higher are distributed subject to a Software License Agreement found7* EPICS BASE is distributed subject to a Software License Agreement found
8* in file LICENSE that is included with this distribution. 8* in file LICENSE that is included with this distribution.
9\*************************************************************************/9\*************************************************************************/
10#ifndef epicsThreadh10#ifndef epicsThreadh
@@ -101,6 +101,12 @@
101epicsShareFunc void epicsShareAPI epicsThreadShow(101epicsShareFunc void epicsShareAPI epicsThreadShow(
102 epicsThreadId id,unsigned int level);102 epicsThreadId id,unsigned int level);
103103
104/* Hooks called when a thread starts, map function called once for every thread */
105typedef void (*EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id);
106epicsShareFunc void epicsThreadHooksInit(epicsThreadId id);
107epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook);
108epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func);
109
104typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId;110typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId;
105epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void);111epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void);
106epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id);112epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id);
107113
=== added file 'src/libCom/osi/os/Linux/osdThread.h'
--- src/libCom/osi/os/Linux/osdThread.h 1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/Linux/osdThread.h 2012-07-03 14:42:25 +0000
@@ -0,0 +1,46 @@
1/*************************************************************************\
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.
6* EPICS BASE Versions 3.13.7
7* and higher are distributed subject to a Software License Agreement found
8* in file LICENSE that is included with this distribution.
9\*************************************************************************/
10#ifndef osdThreadh
11#define osdThreadh
12
13#include <pthread.h>
14
15#include "shareLib.h"
16#include "ellLib.h"
17#include "epicsEvent.h"
18
19#ifdef __cplusplus
20extern "C" {
21#endif
22
23typedef struct epicsThreadOSD {
24 ELLNODE node;
25 pthread_t tid;
26 pid_t lwpId;
27 pthread_attr_t attr;
28 struct sched_param schedParam;
29 EPICSTHREADFUNC createFunc;
30 void *createArg;
31 epicsEventId suspendEvent;
32 int isSuspended;
33 int isEpicsThread;
34 int isFifoScheduled;
35 int isOnThreadList;
36 unsigned int osiPriority;
37 char name[1]; /* actually larger */
38} epicsThreadOSD;
39
40epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId(epicsThreadId id);
41
42#ifdef __cplusplus
43}
44#endif
45
46#endif /* osdThreadh */
047
=== added file 'src/libCom/osi/os/Linux/osdThreadExtra.c'
--- src/libCom/osi/os/Linux/osdThreadExtra.c 1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/Linux/osdThreadExtra.c 2012-07-03 14:42:25 +0000
@@ -0,0 +1,66 @@
1/*************************************************************************\
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.
6* Copyright (c) 2012 ITER Organization
7* EPICS BASE is distributed subject to a Software License Agreement found
8* in file LICENSE that is included with this distribution.
9\*************************************************************************/
10
11/* Author: Marty Kraimer Date: 18JAN2000 */
12
13/* This differs from the posix implementation of epicsThread by:
14 * - printing the Linux LWP ID instead of the POSIX thread ID in the show routines
15 * - installing a default thread start hook, that sets the Linux thread name to the
16 * EPICS thread name to make it visible on OS level, and discovers the LWP ID */
17
18#include <unistd.h>
19#include <signal.h>
20#include <sys/syscall.h>
21#include <sys/types.h>
22#include <sys/prctl.h>
23
24#define epicsExportSharedSymbols
25#include "epicsStdio.h"
26#include "ellLib.h"
27#include "epicsEvent.h"
28#include "epicsThread.h"
29
30epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook;
31epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook;
32
33void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level)
34{
35 if(!pthreadInfo) {
36 fprintf(epicsGetStdout()," NAME EPICS ID "
37 "LWP ID OSIPRI OSSPRI STATE\n");
38 } else {
39 struct sched_param param;
40 int policy;
41 int priority = 0;
42
43 if(pthreadInfo->tid) {
44 int status;
45 status = pthread_getschedparam(pthreadInfo->tid,&policy,&param);
46 if(!status) priority = param.sched_priority;
47 }
48 fprintf(epicsGetStdout(),"%16.16s %12p %8lu %3d%8d %8.8s\n",
49 pthreadInfo->name,(void *)
50 pthreadInfo,(unsigned long)pthreadInfo->lwpId,
51 pthreadInfo->osiPriority,priority,
52 pthreadInfo->isSuspended?"SUSPEND":"OK");
53 }
54}
55
56static void thread_hook(epicsThreadOSD *pthreadInfo)
57{
58 /* Set the name of the thread's process. Limited to 16 characters. */
59 char comm[16];
60 snprintf(comm, sizeof(comm), "%s", pthreadInfo->name);
61 prctl(PR_SET_NAME, comm, 0l, 0l, 0l);
62 pthreadInfo->lwpId = syscall(SYS_gettid);
63}
64
65EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook = thread_hook;
66EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook = thread_hook;
067
=== modified file 'src/libCom/osi/os/RTEMS/osdThread.c'
--- src/libCom/osi/os/RTEMS/osdThread.c 2010-10-05 19:27:37 +0000
+++ src/libCom/osi/os/RTEMS/osdThread.c 2012-07-03 14:42:25 +0000
@@ -39,6 +39,8 @@
39#include "osdInterrupt.h"39#include "osdInterrupt.h"
40#include "epicsExit.h"40#include "epicsExit.h"
4141
42epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id);
43
42/*44/*
43 * Per-task variables45 * Per-task variables
44 */46 */
@@ -164,6 +166,7 @@
164{166{
165 struct taskVar *v = (struct taskVar *)arg;167 struct taskVar *v = (struct taskVar *)arg;
166168
169 epicsThreadRunStartHooks(v->id);
167 (*v->funptr)(v->parm);170 (*v->funptr)(v->parm);
168 epicsExitCallAtThreadExits ();171 epicsExitCallAtThreadExits ();
169 taskVarLock ();172 taskVarLock ();
@@ -235,6 +238,7 @@
235 taskVarMutex = epicsMutexMustCreate ();238 taskVarMutex = epicsMutexMustCreate ();
236 rtems_task_ident (RTEMS_SELF, 0, &tid);239 rtems_task_ident (RTEMS_SELF, 0, &tid);
237 setThreadInfo (tid, "_main_", NULL, NULL);240 setThreadInfo (tid, "_main_", NULL, NULL);
241 epicsThreadHooksInit(tid);
238 initialized = 1;242 initialized = 1;
239 epicsThreadCreate ("ImsgDaemon", 99,243 epicsThreadCreate ("ImsgDaemon", 99,
240 epicsThreadGetStackSize (epicsThreadStackSmall),244 epicsThreadGetStackSize (epicsThreadStackSmall),
@@ -640,19 +644,17 @@
640}644}
641645
642static void646static void
643epicsThreadShowHeader (void)
644{
645 fprintf(epicsGetStdout()," PRIORITY\n");
646 fprintf(epicsGetStdout()," ID EPICS RTEMS STATE WAIT NAME\n");
647 fprintf(epicsGetStdout(),"+--------+-----------+--------+--------+---------------------+\n");
648}
649
650static void
651epicsThreadShowInfo (struct taskVar *v, unsigned int level)647epicsThreadShowInfo (struct taskVar *v, unsigned int level)
652{648{
649 if (!v) {
650 fprintf(epicsGetStdout()," PRIORITY\n");
651 fprintf(epicsGetStdout()," ID EPICS RTEMS STATE WAIT NAME\n");
652 fprintf(epicsGetStdout(),"+--------+-----------+--------+--------+---------------------+\n");
653 } else {
653 fprintf(epicsGetStdout(),"%9.8x", (int)v->id);654 fprintf(epicsGetStdout(),"%9.8x", (int)v->id);
654 showInternalTaskInfo (v->id);655 showInternalTaskInfo (v->id);
655 fprintf(epicsGetStdout()," %s\n", v->name);656 fprintf(epicsGetStdout()," %s\n", v->name);
657 }
656}658}
657659
658void epicsThreadShow (epicsThreadId id, unsigned int level)660void epicsThreadShow (epicsThreadId id, unsigned int level)
@@ -660,7 +662,7 @@
660 struct taskVar *v;662 struct taskVar *v;
661663
662 if (!id) {664 if (!id) {
663 epicsThreadShowHeader ();665 epicsThreadShowInfo (NULL, level);
664 return;666 return;
665 }667 }
666 taskVarLock ();668 taskVarLock ();
@@ -674,6 +676,23 @@
674 fprintf(epicsGetStdout(),"*** Thread %x does not exist.\n", (unsigned int)id);676 fprintf(epicsGetStdout(),"*** Thread %x does not exist.\n", (unsigned int)id);
675}677}
676678
679void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func)
680{
681 struct taskVar *v;
682
683 taskVarLock ();
684 /*
685 * Map tasks in the order of creation (backwards through list)
686 */
687 for (v = taskVarHead ; v != NULL && v->forw != NULL ; v = v->forw)
688 continue;
689 while (v) {
690 func ((epicsThreadId)v->id);
691 v = v->back;
692 }
693 taskVarUnlock ();
694}
695
677void epicsThreadShowAll (unsigned int level)696void epicsThreadShowAll (unsigned int level)
678{697{
679 struct taskVar *v;698 struct taskVar *v;
680699
=== modified file 'src/libCom/osi/os/WIN32/osdThread.c'
--- src/libCom/osi/os/WIN32/osdThread.c 2012-02-03 00:14:01 +0000
+++ src/libCom/osi/os/WIN32/osdThread.c 2012-07-03 14:42:25 +0000
@@ -38,6 +38,8 @@
38#include "ellLib.h"38#include "ellLib.h"
39#include "epicsExit.h"39#include "epicsExit.h"
4040
41epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id);
42
41void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName );43void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName );
42static void threadCleanupWIN32 ( void );44static void threadCleanupWIN32 ( void );
4345
@@ -226,6 +228,7 @@
226 pWin32ThreadGlobal = 0;228 pWin32ThreadGlobal = 0;
227 return 0;229 return 0;
228 }230 }
231 epicsThreadHooksInit (NULL);
229232
230 InterlockedExchange ( & initCompleted, 1 );233 InterlockedExchange ( & initCompleted, 1 );
231234
@@ -496,6 +499,7 @@
496499
497 success = TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, pParm );500 success = TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, pParm );
498 if ( success ) {501 if ( success ) {
502 epicsThreadRunStartHooks ( ( epicsThreadId ) pParm );
499 /* printf ( "starting thread %d\n", pParm->id ); */503 /* printf ( "starting thread %d\n", pParm->id ); */
500 ( *pParm->funptr ) ( pParm->parm );504 ( *pParm->funptr ) ( pParm->parm );
501 /* printf ( "terminating thread %d\n", pParm->id ); */505 /* printf ( "terminating thread %d\n", pParm->id ); */
@@ -510,7 +514,6 @@
510 }514 }
511515
512 epicsExitCallAtThreadExits ();516 epicsExitCallAtThreadExits ();
513
514 /*517 /*
515 * CAUTION: !!!! the thread id might continue to be used after this thread exits !!!!518 * CAUTION: !!!! the thread id might continue to be used after this thread exits !!!!
516 */519 */
@@ -947,9 +950,9 @@
947}950}
948951
949/*952/*
950 * epicsThreadShowPrivate ()953 * epicsThreadShowInfo ()
951 */954 */
952static void epicsThreadShowPrivate ( epicsThreadId id, unsigned level )955static void epicsThreadShowInfo ( epicsThreadId id, unsigned level )
953{956{
954 win32ThreadParam * pParm = ( win32ThreadParam * ) id;957 win32ThreadParam * pParm = ( win32ThreadParam * ) id;
955958
@@ -975,6 +978,28 @@
975}978}
976979
977/*980/*
981 * epicsThreadMap ()
982 */
983epicsShareFunc void epicsShareAPI epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func )
984{
985 win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
986 win32ThreadParam * pParm;
987
988 if ( ! pGbl ) {
989 return;
990 }
991
992 EnterCriticalSection ( & pGbl->mutex );
993
994 for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
995 pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {
996 func ( ( epicsThreadId ) pParm );
997 }
998
999 LeaveCriticalSection ( & pGbl->mutex );
1000}
1001
1002/*
978 * epicsThreadShowAll ()1003 * epicsThreadShowAll ()
979 */1004 */
980epicsShareFunc void epicsShareAPI epicsThreadShowAll ( unsigned level )1005epicsShareFunc void epicsShareAPI epicsThreadShowAll ( unsigned level )
@@ -987,11 +1012,11 @@
987 }1012 }
9881013
989 EnterCriticalSection ( & pGbl->mutex );1014 EnterCriticalSection ( & pGbl->mutex );
990 1015
991 epicsThreadShowPrivate ( 0, level );1016 epicsThreadShowInfo ( 0, level );
992 for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList ); 1017 for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
993 pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {1018 pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {
994 epicsThreadShowPrivate ( ( epicsThreadId ) pParm, level );1019 epicsThreadShowInfo ( ( epicsThreadId ) pParm, level );
995 }1020 }
9961021
997 LeaveCriticalSection ( & pGbl->mutex );1022 LeaveCriticalSection ( & pGbl->mutex );
@@ -1002,8 +1027,8 @@
1002 */1027 */
1003epicsShareFunc void epicsShareAPI epicsThreadShow ( epicsThreadId id, unsigned level )1028epicsShareFunc void epicsShareAPI epicsThreadShow ( epicsThreadId id, unsigned level )
1004{1029{
1005 epicsThreadShowPrivate ( 0, level );1030 epicsThreadShowInfo ( 0, level );
1006 epicsThreadShowPrivate ( id, level );1031 epicsThreadShowInfo ( id, level );
1007}1032}
10081033
1009/*1034/*
10101035
=== added file 'src/libCom/osi/os/default/osdThreadExtra.c'
--- src/libCom/osi/os/default/osdThreadExtra.c 1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/default/osdThreadExtra.c 2012-07-03 14:42:25 +0000
@@ -0,0 +1,19 @@
1/*************************************************************************\
2* Copyright (c) 2012 ITER Organization
3*
4* EPICS BASE is distributed subject to a Software License Agreement found
5* in file LICENSE that is included with this distribution.
6\*************************************************************************/
7
8/* Author: Ralph Lange Date: 26 Jun 2012 */
9
10/* Null default thread hooks for all platforms that do not do anything special */
11
12#define epicsExportSharedSymbols
13#include "shareLib.h"
14
15epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook;
16epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook;
17
18EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook;
19EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook;
020
=== added file 'src/libCom/osi/os/default/osdThreadHooks.c'
--- src/libCom/osi/os/default/osdThreadHooks.c 1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/default/osdThreadHooks.c 2012-07-03 14:42:25 +0000
@@ -0,0 +1,74 @@
1/*************************************************************************\
2* Copyright (c) 2012 ITER Organization
3*
4* EPICS BASE is distributed subject to a Software License Agreement found
5* in file LICENSE that is included with this distribution.
6\*************************************************************************/
7
8/* Author: Ralph Lange Date: 28 Jun 2012 */
9
10/* Secure hooks for epicsThread */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <errno.h>
15#include <string.h>
16
17#define epicsExportSharedSymbols
18#include "ellLib.h"
19#include "epicsMutex.h"
20#include "epicsThread.h"
21
22epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id);
23epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook;
24epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook;
25
26#define checkStatusOnceReturn(status, message, method) \
27if((status)) { \
28 fprintf(stderr,"%s error %s\n",(message),strerror((status))); \
29 fprintf(stderr," %s\n",(method)); \
30 return; }
31
32typedef struct epicsThreadHook {
33 ELLNODE node;
34 EPICS_THREAD_HOOK_ROUTINE func;
35} epicsThreadHook;
36
37static ELLLIST startHooks = ELLLIST_INIT;
38
39/* Locking could probably be avoided, if elllist implementation was using atomic ops */
40static epicsMutexId hookLock;
41
42epicsShareFunc void epicsThreadAddStartHook(EPICS_THREAD_HOOK_ROUTINE hook)
43{
44 epicsThreadHook *pHook;
45
46 pHook = calloc(1, sizeof(epicsThreadHook));
47 if (!pHook) checkStatusOnceReturn(errno,"calloc","epicsThreadAddStartHook");
48 pHook->func = hook;
49 epicsMutexLock(hookLock);
50 ellAdd(&startHooks, &pHook->node);
51 epicsMutexUnlock(hookLock);
52}
53
54epicsShareFunc void epicsThreadHooksInit(epicsThreadId id)
55{
56 if (!hookLock) {
57 hookLock = epicsMutexMustCreate();
58 if (epicsThreadDefaultStartHook) epicsThreadAddStartHook(epicsThreadDefaultStartHook);
59 }
60 if (id && epicsThreadMainStartHook) epicsThreadMainStartHook(id);
61}
62
63epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id)
64{
65 epicsThreadHook *pHook;
66
67 epicsMutexLock(hookLock);
68 pHook = (epicsThreadHook *) ellFirst(&startHooks);
69 while (pHook) {
70 pHook->func(id);
71 pHook = (epicsThreadHook *) ellNext(&pHook->node);
72 }
73 epicsMutexUnlock(hookLock);
74}
075
=== modified file 'src/libCom/osi/os/posix/osdThread.c'
--- src/libCom/osi/os/posix/osdThread.c 2012-06-19 19:28:26 +0000
+++ src/libCom/osi/os/posix/osdThread.c 2012-07-03 14:42:25 +0000
@@ -3,6 +3,7 @@
3* National Laboratory.3* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as4* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.5* Operator of Los Alamos National Laboratory.
6* Copyright (c) 2012 ITER Organization
6* EPICS BASE is distributed subject to a Software License Agreement found7* EPICS BASE is distributed subject to a Software License Agreement found
7* in file LICENSE that is included with this distribution. 8* in file LICENSE that is included with this distribution.
8\*************************************************************************/9\*************************************************************************/
@@ -34,6 +35,9 @@
34#include "epicsAssert.h"35#include "epicsAssert.h"
35#include "epicsExit.h"36#include "epicsExit.h"
3637
38epicsShareFunc void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level);
39epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id);
40
37static int mutexLock(pthread_mutex_t *id)41static int mutexLock(pthread_mutex_t *id)
38{42{
39 int status;43 int status;
@@ -57,22 +61,6 @@
57 int schedPolicy;61 int schedPolicy;
58} commonAttr;62} commonAttr;
5963
60typedef struct epicsThreadOSD {
61 ELLNODE node;
62 pthread_t tid;
63 pthread_attr_t attr;
64 struct sched_param schedParam;
65 EPICSTHREADFUNC createFunc;
66 void *createArg;
67 epicsEventId suspendEvent;
68 int isSuspended;
69 int isEpicsThread;
70 int isFifoScheduled;
71 int isOnThreadList;
72 unsigned int osiPriority;
73 char name[1]; /* actually larger */
74} epicsThreadOSD;
75
76#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING64#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
77typedef struct {65typedef struct {
78 int min_pri, max_pri;66 int min_pri, max_pri;
@@ -366,6 +354,7 @@
366 checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadInit");354 checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadInit");
367 status = atexit(epicsExitCallAtExits);355 status = atexit(epicsExitCallAtExits);
368 checkStatusOnce(status,"atexit");356 checkStatusOnce(status,"atexit");
357 epicsThreadHooksInit(pthreadInfo);
369 epicsThreadOnceCalled = 1;358 epicsThreadOnceCalled = 1;
370}359}
371360
372361
@@ -375,7 +364,7 @@
375 int status;364 int status;
376 int oldtype;365 int oldtype;
377 sigset_t blockAllSig;366 sigset_t blockAllSig;
378 367
379 sigfillset(&blockAllSig);368 sigfillset(&blockAllSig);
380 pthread_sigmask(SIG_SETMASK,&blockAllSig,NULL);369 pthread_sigmask(SIG_SETMASK,&blockAllSig,NULL);
381 status = pthread_setspecific(getpthreadInfo,arg);370 status = pthread_setspecific(getpthreadInfo,arg);
@@ -388,11 +377,11 @@
388 pthreadInfo->isOnThreadList = 1;377 pthreadInfo->isOnThreadList = 1;
389 status = pthread_mutex_unlock(&listLock);378 status = pthread_mutex_unlock(&listLock);
390 checkStatusQuit(status,"pthread_mutex_unlock","start_routine");379 checkStatusQuit(status,"pthread_mutex_unlock","start_routine");
380 epicsThreadRunStartHooks(pthreadInfo);
391381
392 (*pthreadInfo->createFunc)(pthreadInfo->createArg);382 (*pthreadInfo->createFunc)(pthreadInfo->createArg);
393383
394 epicsExitCallAtThreadExits ();384 epicsExitCallAtThreadExits ();
395
396 free_threadInfo(pthreadInfo);385 free_threadInfo(pthreadInfo);
397 return(0);386 return(0);
398}387}
@@ -747,27 +736,23 @@
747 name[size-1] = '\0';736 name[size-1] = '\0';
748}737}
749738
750739
751static void showThreadInfo(epicsThreadOSD *pthreadInfo,unsigned int level)740epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func)
752{741{
753 if(!pthreadInfo) {742 epicsThreadOSD *pthreadInfo;
754 fprintf(epicsGetStdout()," NAME EPICS ID "743 int status;
755 "PTHREAD ID OSIPRI OSSPRI STATE\n");
756 } else {
757 struct sched_param param;
758 int policy;
759 int priority = 0;
760744
761 if(pthreadInfo->tid) {745 epicsThreadInit();
762 int status;746 status = mutexLock(&listLock);
763 status = pthread_getschedparam(pthreadInfo->tid,&policy,&param);747 checkStatus(status, "pthread_mutex_lock epicsThreadMap");
764 if(!status) priority = param.sched_priority;748 if (status)
765 }749 return;
766 fprintf(epicsGetStdout(),"%16.16s %12p %12lu %3d%8d %8.8s\n",750 pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
767 pthreadInfo->name,(void *)751 while (pthreadInfo) {
768 pthreadInfo,(unsigned long)pthreadInfo->tid,752 func(pthreadInfo);
769 pthreadInfo->osiPriority,priority,753 pthreadInfo = (epicsThreadOSD *)ellNext(&pthreadInfo->node);
770 pthreadInfo->isSuspended?"SUSPEND":"OK");
771 }754 }
755 status = pthread_mutex_unlock(&listLock);
756 checkStatus(status, "pthread_mutex_unlock epicsThreadMap");
772}757}
773758
774epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level)759epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level)
@@ -783,7 +768,7 @@
783 return;768 return;
784 pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);769 pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
785 while(pthreadInfo) {770 while(pthreadInfo) {
786 showThreadInfo(pthreadInfo,level);771 epicsThreadShowInfo(pthreadInfo,level);
787 pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);772 pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
788 }773 }
789 status = pthread_mutex_unlock(&listLock);774 status = pthread_mutex_unlock(&listLock);
@@ -798,7 +783,7 @@
798783
799 epicsThreadInit();784 epicsThreadInit();
800 if(!showThread) {785 if(!showThread) {
801 showThreadInfo(0,level);786 epicsThreadShowInfo(0,level);
802 return;787 return;
803 }788 }
804 status = mutexLock(&listLock);789 status = mutexLock(&listLock);
@@ -810,7 +795,7 @@
810 if (((epicsThreadId)pthreadInfo == showThread)795 if (((epicsThreadId)pthreadInfo == showThread)
811 || ((epicsThreadId)pthreadInfo->tid == showThread)) {796 || ((epicsThreadId)pthreadInfo->tid == showThread)) {
812 found = 1;797 found = 1;
813 showThreadInfo(pthreadInfo,level);798 epicsThreadShowInfo(pthreadInfo,level);
814 }799 }
815 pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);800 pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
816 }801 }
@@ -820,7 +805,6 @@
820 if (!found)805 if (!found)
821 printf("Thread %#lx (%lu) not found.\n", (unsigned long)showThread, (unsigned long)showThread);806 printf("Thread %#lx (%lu) not found.\n", (unsigned long)showThread, (unsigned long)showThread);
822}807}
823
824808
825809
826epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void)810epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void)
827{811{
828812
=== modified file 'src/libCom/osi/os/posix/osdThread.h'
--- src/libCom/osi/os/posix/osdThread.h 2008-08-06 16:54:25 +0000
+++ src/libCom/osi/os/posix/osdThread.h 2012-07-03 14:42:25 +0000
@@ -13,12 +13,30 @@
13#include <pthread.h>13#include <pthread.h>
1414
15#include "shareLib.h"15#include "shareLib.h"
16#include "ellLib.h"
17#include "epicsEvent.h"
1618
17#ifdef __cplusplus19#ifdef __cplusplus
18extern "C" {20extern "C" {
19#endif21#endif
2022
21epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId ( epicsThreadId id );23typedef struct epicsThreadOSD {
24 ELLNODE node;
25 pthread_t tid;
26 pthread_attr_t attr;
27 struct sched_param schedParam;
28 EPICSTHREADFUNC createFunc;
29 void *createArg;
30 epicsEventId suspendEvent;
31 int isSuspended;
32 int isEpicsThread;
33 int isFifoScheduled;
34 int isOnThreadList;
35 unsigned int osiPriority;
36 char name[1]; /* actually larger */
37} epicsThreadOSD;
38
39epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId(epicsThreadId id);
2240
23#ifdef __cplusplus41#ifdef __cplusplus
24}42}
2543
=== added file 'src/libCom/osi/os/posix/osdThreadExtra.c'
--- src/libCom/osi/os/posix/osdThreadExtra.c 1970-01-01 00:00:00 +0000
+++ src/libCom/osi/os/posix/osdThreadExtra.c 2012-07-03 14:42:25 +0000
@@ -0,0 +1,48 @@
1/*************************************************************************\
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.
6* EPICS BASE is distributed subject to a Software License Agreement found
7* in file LICENSE that is included with this distribution.
8\*************************************************************************/
9
10/* Author: Marty Kraimer Date: 18JAN2000 */
11
12/* This is part of the posix implementation of epicsThread */
13
14#define epicsExportSharedSymbols
15#include "epicsStdio.h"
16#include "ellLib.h"
17#include "epicsEvent.h"
18#include "epicsThread.h"
19
20epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook;
21epicsShareExtern EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook;
22
23EPICS_THREAD_HOOK_ROUTINE epicsThreadDefaultStartHook;
24EPICS_THREAD_HOOK_ROUTINE epicsThreadMainStartHook;
25
26void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level)
27{
28 if(!pthreadInfo) {
29 fprintf(epicsGetStdout()," NAME EPICS ID "
30 "PTHREAD ID OSIPRI OSSPRI STATE\n");
31 } else {
32 struct sched_param param;
33 int policy;
34 int priority = 0;
35
36 if(pthreadInfo->tid) {
37 int status;
38 status = pthread_getschedparam(pthreadInfo->tid,&policy,&param);
39 if(!status) priority = param.sched_priority;
40 }
41 fprintf(epicsGetStdout(),"%16.16s %12p %12lu %3d%8d %8.8s\n",
42 pthreadInfo->name,(void *)
43 pthreadInfo,(unsigned long)pthreadInfo->tid,
44 pthreadInfo->osiPriority,priority,
45 pthreadInfo->isSuspended?"SUSPEND":"OK");
46 }
47}
48
049
=== modified file 'src/libCom/osi/os/vxWorks/osdThread.c'
--- src/libCom/osi/os/vxWorks/osdThread.c 2010-08-11 15:45:17 +0000
+++ src/libCom/osi/os/vxWorks/osdThread.c 2012-07-03 14:42:25 +0000
@@ -3,6 +3,7 @@
3* National Laboratory.3* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as4* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.5* Operator of Los Alamos National Laboratory.
6* Copyright (c) 2012 ITER Organization
6* EPICS BASE is distributed subject to a Software License Agreement found7* EPICS BASE is distributed subject to a Software License Agreement found
7* in file LICENSE that is included with this distribution. 8* in file LICENSE that is included with this distribution.
8\*************************************************************************/9\*************************************************************************/
@@ -32,6 +33,8 @@
32#include "vxLib.h"33#include "vxLib.h"
33#include "epicsExit.h"34#include "epicsExit.h"
3435
36epicsShareFunc void epicsThreadRunStartHooks(epicsThreadId id);
37
35#if CPU_FAMILY == MC680X038#if CPU_FAMILY == MC680X0
36#define ARCH_STACK_FACTOR 139#define ARCH_STACK_FACTOR 1
37#elif CPU_FAMILY == SPARC40#elif CPU_FAMILY == SPARC
@@ -42,6 +45,12 @@
42static const unsigned stackSizeTable[epicsThreadStackBig+1] = 45static const unsigned stackSizeTable[epicsThreadStackBig+1] =
43 {4000*ARCH_STACK_FACTOR, 6000*ARCH_STACK_FACTOR, 11000*ARCH_STACK_FACTOR};46 {4000*ARCH_STACK_FACTOR, 6000*ARCH_STACK_FACTOR, 11000*ARCH_STACK_FACTOR};
4447
48/* Table and lock for epicsThreadMap() */
49#define ID_LIST_CHUNK 512
50static int *taskIdList = 0;
51int taskIdListSize = 0;
52static SEM_ID epicsThreadListMutex = 0;
53
45/*The following forces atReboot to be loaded*/54/*The following forces atReboot to be loaded*/
46extern int atRebootExtern;55extern int atRebootExtern;
47static struct pext {56static struct pext {
@@ -83,16 +92,25 @@
83 }92 }
84}93}
8594
95static void mutexInit(SEM_ID lock)
96{
97 if (lock == 0) {
98 lock = semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);
99 assert(lock);
100 }
101}
102
86static void epicsThreadInit(void)103static void epicsThreadInit(void)
87{104{
88 static int lock = 0;105 static int lock = 0;
89106
90 while(!vxTas(&lock)) taskDelay(1);107 while(!vxTas(&lock)) taskDelay(1);
91 if(epicsThreadOnceMutex==0) {108 epicsThreadHooksInit(NULL);
92 epicsThreadOnceMutex = semMCreate(109 mutexInit(epicsThreadOnceMutex);
93 SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);110 mutexInit(epicsThreadListMutex);
94 assert(epicsThreadOnceMutex);111 taskIdList = calloc(ID_LIST_CHUNK, sizeof(int));
95 }112 assert(taskIdList);
113 taskIdListSize = ID_LIST_CHUNK;
96 lock = 0;114 lock = 0;
97}115}
98116
@@ -157,6 +175,7 @@
157 taskVarAdd(tid,(int *)(char *)&papTSD);175 taskVarAdd(tid,(int *)(char *)&papTSD);
158 /*Make sure that papTSD is still 0 after that call to taskVarAdd*/176 /*Make sure that papTSD is still 0 after that call to taskVarAdd*/
159 papTSD = 0;177 papTSD = 0;
178 epicsThreadRunStartHooks((epicsThreadId)tid);
160 (*func)(parm);179 (*func)(parm);
161 epicsExitCallAtThreadExits ();180 epicsExitCallAtThreadExits ();
162 free(papTSD);181 free(papTSD);
@@ -312,6 +331,29 @@
312 name[size-1] = '\0';331 name[size-1] = '\0';
313}332}
314333
334epicsShareFunc void epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func )
335{
336 int noTasks = 0;
337 int i;
338 int result;
339
340 result = semTake(epicsThreadListMutex, WAIT_FOREVER);
341 assert(result == OK);
342 while (noTasks == 0) {
343 noTasks = taskIdListGet(taskIdList, taskIdListSize);
344 if (noTasks == taskIdListSize) {
345 taskIdList = realloc(taskIdList, (taskIdListSize+ID_LIST_CHUNK)*sizeof(int));
346 assert(taskIdList);
347 taskIdListSize += ID_LIST_CHUNK;
348 noTasks = 0;
349 }
350 }
351 for (i = 0; i < noTasks; i++) {
352 func ((epicsThreadId)taskIdList[i]);
353 }
354 semGive(epicsThreadListMutex);
355}
356
315void epicsThreadShowAll(unsigned int level)357void epicsThreadShowAll(unsigned int level)
316{358{
317 taskShow(0,2);359 taskShow(0,2);
318360
=== modified file 'src/libCom/test/Makefile'
--- src/libCom/test/Makefile 2012-06-22 19:06:52 +0000
+++ src/libCom/test/Makefile 2012-07-03 14:42:25 +0000
@@ -89,6 +89,11 @@
89testHarness_SRCS += epicsThreadPrivateTest.cpp89testHarness_SRCS += epicsThreadPrivateTest.cpp
90TESTS += epicsThreadPrivateTest90TESTS += epicsThreadPrivateTest
9191
92TESTPROD_HOST += epicsThreadHooksTest
93epicsThreadHooksTest_SRCS += epicsThreadHooksTest.c
94testHarness_SRCS += epicsThreadHooksTest.c
95TESTS += epicsThreadHooksTest
96
92TESTPROD_HOST += epicsExitTest97TESTPROD_HOST += epicsExitTest
93epicsExitTest_SRCS += epicsExitTest.c98epicsExitTest_SRCS += epicsExitTest.c
94testHarness_SRCS += epicsExitTest.c99testHarness_SRCS += epicsExitTest.c
95100
=== added file 'src/libCom/test/epicsThreadHooksTest.c'
--- src/libCom/test/epicsThreadHooksTest.c 1970-01-01 00:00:00 +0000
+++ src/libCom/test/epicsThreadHooksTest.c 2012-07-03 14:42:25 +0000
@@ -0,0 +1,122 @@
1/*************************************************************************\
2* Copyright (c) 2012 ITER Organization
3*
4* EPICS BASE is distributed subject to a Software License Agreement found
5* in file LICENSE that is included with this distribution.
6\*************************************************************************/
7
8/* epicsThreadHooksTest.c */
9
10#include <stdio.h>
11#include <stdint.h>
12
13#include "epicsThread.h"
14#include "epicsExit.h"
15#include "epicsEvent.h"
16#include "errlog.h"
17#include "epicsUnitTest.h"
18#include "testMain.h"
19
20#define THREAD_NO 6
21#define HOOKS_NO 4
22
23epicsThreadPrivateId threadNo;
24static int order[THREAD_NO][HOOKS_NO];
25static int cnt[THREAD_NO];
26static int mine[THREAD_NO];
27static int called[THREAD_NO];
28static epicsThreadId tid[THREAD_NO];
29epicsEventId shutdown[THREAD_NO];
30
31static int newThreadIndex(epicsThreadId id)
32{
33 int i = 0;
34 while (tid[i] != 0 && i < THREAD_NO) i++;
35 tid[i] = id;
36 return i;
37}
38
39static int findThreadIndex(epicsThreadId id)
40{
41 int i = 0;
42 while (tid[i] != id && i < THREAD_NO) i++;
43 return i;
44}
45
46static void atExitHook1 (void *arg)
47{
48 int no = findThreadIndex(epicsThreadGetIdSelf());
49 order[no][3] = cnt[no]++;
50}
51
52static void atExitHook2 (void *arg)
53{
54 int no = findThreadIndex(epicsThreadGetIdSelf());
55 order[no][2] = cnt[no]++;
56}
57
58static void startHook1 (epicsThreadId id)
59{
60 int no = newThreadIndex(id);
61 order[no][0] = cnt[no]++;
62 epicsAtThreadExit(atExitHook1, NULL);
63}
64
65static void startHook2 (epicsThreadId id)
66{
67 int no = findThreadIndex(id);
68 order[no][1] = cnt[no]++;
69 epicsAtThreadExit(atExitHook2, NULL);
70}
71
72static void my_thread (void *arg)
73{
74 int no = findThreadIndex(epicsThreadGetIdSelf());
75 mine[no] = 1;
76 epicsEventMustWait((epicsEventId) arg);
77}
78
79static void mapper (epicsThreadId id)
80{
81 called[findThreadIndex(id)]++;
82}
83
84MAIN(epicsThreadHooksTest)
85{
86 int i;
87 int ok;
88
89 testPlan(THREAD_NO);
90 epicsThreadAddStartHook(startHook1);
91 epicsThreadAddStartHook(startHook2);
92
93 for (i = 0; i < THREAD_NO-1; i++) {
94 shutdown[i] = epicsEventCreate(epicsEventEmpty);
95 char name[10];
96 sprintf(name, "t%d", (int) i);
97 epicsThreadCreate(name, epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), my_thread, shutdown[i]);
98 }
99
100 epicsThreadMap(mapper);
101
102 ok = 1;
103 for (i = 0; i < THREAD_NO-1; i++) {
104 if (mine[i] && called[i] != 1) ok = 0;
105 }
106 testOk(ok, "All tasks covered once by epicsThreadMap");
107
108 for (i = 0; i < THREAD_NO-1; i++) {
109 epicsEventSignal(shutdown[i]);
110 }
111
112 epicsThreadSleep(1.0);
113
114 for (i = 0; i < THREAD_NO; i++) {
115 int j;
116 for (j = 0; j < HOOKS_NO; j++) {
117 if (mine[i] && order[i][j]!=j) ok = 0;
118 }
119 if (mine[i]) testOk(ok, "All hooks for task %d called in correct order", (int)i);
120 }
121 return testDone();
122}

Subscribers

People subscribed via source and target branches