Merge lp:~johill-lanl/epics-base/epicsThreadOnce-atomics-based into lp:~epics-core/epics-base/3.15

Proposed by Jeff Hill
Status: Rejected
Rejected by: Andrew Johnson
Proposed branch: lp:~johill-lanl/epics-base/epicsThreadOnce-atomics-based
Merge into: lp:~epics-core/epics-base/3.15
Prerequisite: lp:~epics-core/epics-base/epicsR3.15-atomics
Diff against target: 435 lines (+132/-166) (has conflicts)
8 files modified
src/libCom/Makefile (+1/-0)
src/libCom/misc/ipAddrToAsciiAsynchronous.cpp (+1/-1)
src/libCom/osi/epicsThread.h (+1/-1)
src/libCom/osi/epicsThreadOnce.cpp (+129/-0)
src/libCom/osi/os/RTEMS/osdThread.c (+0/-32)
src/libCom/osi/os/WIN32/osdThread.c (+0/-35)
src/libCom/osi/os/posix/osdThread.c (+0/-44)
src/libCom/osi/os/vxWorks/osdThread.c (+0/-53)
Text conflict in src/libCom/Makefile
To merge this branch: bzr merge lp:~johill-lanl/epics-base/epicsThreadOnce-atomics-based
Reviewer Review Type Date Requested Status
Andrew Johnson Needs Fixing
Review via email: mp+73606@code.launchpad.net

This proposal supersedes a proposal from 2011-08-31.

Description of the change

o added new epicsAtomics based, and OS independent, implementation of epicsThreadOnce in epicsThreadOnce.cpp
o changed type of epicsThreadOnceId from epicsThreadId to void *
o fixed once flag isnt initialized with EPICSTHREAD_ONCE_INIT in ipAddrToAsciiAsynchronous.cpp
o removed OS dependent implementations of epicsThreadOnce from {posix, RTEMS, vxWorks, win32}

To post a comment you must log in.
12261. By Jeff Hill

fixed spelling in comment

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

Hi Jeff,

The epicsThreadOnce.cpp file has an essential function epicsThreadOnceOnly() which calls cantProceed(), epicsThreadSleep() and errlogPrintf() [the cantProceed() function also calls both of the other two]. Unfortunately both the errlog and generalTime facilities rely on epicsThreadOnce during initialization, thus this implementation could be subject to circular startup problems.

When I try to boot an IOC on vxWorks 6.8 with this code, it hangs silently while executing the C++ static constructors.

If I replace the errlogPrintf() call with std::printf(), after maybe a 10 second delay waiting for the vxWorks munch file to finish loading I get the message "epicsThreadOnce: waiting for another thread to finish calling the once function" which then repeats forever. Here's the stack of the thread loading the munch file:

0x00206b2c ld +0xb4 : usrModuleLoad ()
0x002069e0 usrModuleLoad+0x1c : loadModule ()
0x001da4c0 loadModule +0x24 : loadModuleAt ()
0x001da3d4 loadModuleAt +0xe0 : 0x001da02c ()
0x001da198 loadLibInit +0x21c: cplusLoadFixup ()
0x002141a4 cplusLoadFixup+0x8c : cplusCallCtors ()
0x00143594 cplusCallCtors+0x28 : _GLOBAL__I_iocshPpdbbase ()
0x010b2bc8 _GLOBAL__I_iocshPpdbbase+0x28 : 0x010b2ae8 ()
0x010b2b44 iocshRegister+0x210: iocshRegister ()
0x010b2978 iocshRegister+0x44 : 0x010b0d40 ()
0x010b0d70 gphInitPvt +0x16c: epicsThreadOnce ()
0x010bdfc4 epicsThreadOnce+0xfc : 0x010c59bc (0x8000003c)
0x010c5a44 epicsThreadSleep+0x8c : taskDelay ()

I suspect it may not be possible to fix this in a generic, portable fashion. The current implementations of epicsThreadOnce() are all OS-specific and understand the OS-specific startup requirements. However I'd be happy to test a revised version if you manage to get it working properly on vxWorks.

- Andrew

review: Needs Fixing

Unmerged revisions

12261. By Jeff Hill

fixed spelling in comment

12260. By Jeff Hill

o moved epicsThreadOnce impl details to anonymous namespace
o fixed recursion sanity test is too agressive
o added some comments

12259. By Jeff Hill

o added new epicsAtomics based, and OS independent, implementation of epicsThreadOnce in epicsThreadOnce.cpp
o changed type of epicsThreadOnceId from epicsThreadId to void *
o fixed once flag isnt initialized with EPICSTHREAD_ONCE_INIT in ipAddrToAsciiAsynchronous.cpp
o removed OS dependent implementations of epicsThreadOnce from {posix, RTEMS, vxWorks, win32}

12258. By Jeff Hill <email address hidden>

fixed names on redefinition protection macros for vxWorks

12257. By Jeff Hill

fixed epics atomic read memory barrier name - old versions of vxWorks

12256. By Jeff Hill

fixed word missing from vxWorks specific read and write memory barrier functions

12255. By Jeff Hill <email address hidden>

fixed vxWorks name for epicsAtomicTest

12254. By Jeff Hill <email address hidden>

fixed wrong return type old vxWorks epicsAtomicUnlock

12253. By Jeff Hill

fixed test count

12252. By Jeff Hill

fixed vxWorks jumbled ifdef

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/libCom/Makefile'
--- src/libCom/Makefile 2011-08-31 22:40:22 +0000
+++ src/libCom/Makefile 2011-08-31 22:40:22 +0000
@@ -256,6 +256,7 @@
256SRCS += osdEnv.c256SRCS += osdEnv.c
257SRCS += epicsReadline.c257SRCS += epicsReadline.c
258SRCS += epicsTempFile.cpp258SRCS += epicsTempFile.cpp
259SRCS += epicsThreadOnce.cpp
259SRCS += epicsStdio.c260SRCS += epicsStdio.c
260SRCS += osdStdio.c261SRCS += osdStdio.c
261262
262263
=== modified file 'src/libCom/misc/ipAddrToAsciiAsynchronous.cpp'
--- src/libCom/misc/ipAddrToAsciiAsynchronous.cpp 2008-10-21 20:26:48 +0000
+++ src/libCom/misc/ipAddrToAsciiAsynchronous.cpp 2011-08-31 22:40:22 +0000
@@ -127,7 +127,7 @@
127ipAddrToAsciiEnginePrivate * ipAddrToAsciiEnginePrivate :: pEngine = 0;127ipAddrToAsciiEnginePrivate * ipAddrToAsciiEnginePrivate :: pEngine = 0;
128unsigned ipAddrToAsciiEnginePrivate :: numberOfReferences = 0u;128unsigned ipAddrToAsciiEnginePrivate :: numberOfReferences = 0u;
129bool ipAddrToAsciiEnginePrivate :: shutdownRequest = false;129bool ipAddrToAsciiEnginePrivate :: shutdownRequest = false;
130static epicsThreadOnceId ipAddrToAsciiEngineGlobalMutexOnceFlag = 0;130static epicsThreadOnceId ipAddrToAsciiEngineGlobalMutexOnceFlag = EPICS_THREAD_ONCE_INIT;
131131
132// the users are not required to supply a show routine132// the users are not required to supply a show routine
133// for there transaction callback class133// for there transaction callback class
134134
=== modified file 'src/libCom/osi/epicsThread.h'
--- src/libCom/osi/epicsThread.h 2010-04-26 20:38:11 +0000
+++ src/libCom/osi/epicsThread.h 2011-08-31 22:40:22 +0000
@@ -51,7 +51,7 @@
51/* (epicsThreadId)0 is guaranteed to be an invalid thread id */51/* (epicsThreadId)0 is guaranteed to be an invalid thread id */
52typedef struct epicsThreadOSD *epicsThreadId;52typedef struct epicsThreadOSD *epicsThreadId;
5353
54typedef epicsThreadId epicsThreadOnceId;54typedef void * epicsThreadOnceId;
55#define EPICS_THREAD_ONCE_INIT 055#define EPICS_THREAD_ONCE_INIT 0
5656
57epicsShareFunc void epicsShareAPI epicsThreadOnce(57epicsShareFunc void epicsShareAPI epicsThreadOnce(
5858
=== added file 'src/libCom/osi/epicsThreadOnce.cpp'
--- src/libCom/osi/epicsThreadOnce.cpp 1970-01-01 00:00:00 +0000
+++ src/libCom/osi/epicsThreadOnce.cpp 2011-08-31 22:40:22 +0000
@@ -0,0 +1,129 @@
1
2/*************************************************************************\
3* Copyright (c) 2011 LANS LLC, as Operator of
4* Los Alamos National Laboratory.
5* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
6* National Laboratory.
7* Copyright (c) 2002 The Regents of the University of California, as
8* Operator of Los Alamos National Laboratory.
9* EPICS BASE is distributed subject to a Software License Agreement found
10* in file LICENSE that is included with this distribution.
11\*************************************************************************/
12
13/*
14 * Author Jeffrey O. Hill johill@lanl.gov
15 * Original Authors (before converting to operating system independent code):
16 * Jeff Hill, Andrew Johnson, Marty Kraimer, Eric Norum
17 */
18
19#include <cstdlib>
20
21#define epicsExportSharedSymbols
22#include "errlog.h"
23#include "cantProceed.h"
24#include "epicsThread.h"
25#include "epicsAtomic.h"
26#include "epicsAssert.h"
27
28namespace {
29
30struct ThreadID {
31public:
32 ThreadID ();
33 ThreadID ( epicsThreadId id );
34 bool operator == ( const ThreadID & ) const;
35private:
36 epicsThreadId m_threadId;
37 ThreadID ( const ThreadID & ); // disabled
38 ThreadID & operator = ( const ThreadID & ); // disabled
39};
40
41inline ThreadID :: ThreadID ( epicsThreadId id ) :
42 m_threadId ( id )
43{
44}
45
46inline ThreadID :: ThreadID () : m_threadId ( 0 )
47{
48}
49
50inline bool ThreadID :: operator == ( const ThreadID & ctrl ) const
51{
52 return ctrl.m_threadId == m_threadId;
53}
54
55static ThreadID done;
56
57} // end of namespace anonymous
58
59using namespace epics;
60using namespace atomic;
61
62/*
63 * epicsThreadOnceOnly ()
64 */
65static void epicsShareAPI epicsThreadOnceOnly ( epicsThreadOnceId * pId,
66 void ( * pFunc )( void * ),
67 void * pArg )
68{
69 static const epicsThreadOnceId idStartup = EPICS_THREAD_ONCE_INIT;
70 ThreadID self ( epicsThreadGetIdSelf () );
71 epicsThreadOnceId pCurrent = compareAndSwap ( *pId, idStartup, & self );
72 if ( pCurrent != & done ) {
73 if ( pCurrent == idStartup ) {
74 ( *pFunc ) ( pArg );
75 set ( *pId, & done );
76 }
77 else {
78 {
79 ThreadID & initID =
80 * reinterpret_cast < ThreadID * > ( pCurrent );
81 if ( initID == self ) {
82 cantProceed( "epicsThreadOnce() once was called "
83 "recursively from the user's once fuction\n" );
84 }
85 }
86 static const std :: size_t spinDownInit = 1000u;
87 static const std :: size_t spinCount = 10u;
88 STATIC_ASSERT ( spinDownInit > spinCount );
89 static const std :: size_t spinThresh = spinDownInit - spinCount;
90 std :: size_t spinDown = spinDownInit;
91 do {
92 if ( spinDown <= spinThresh ) {
93 epicsThreadSleep ( epicsThreadSleepQuantum () );
94 }
95 if ( spinDown > 0u ) {
96 spinDown--;
97 }
98 else {
99 errlogPrintf ( "epicsThreadOnce: waiting for another "
100 "thread to finish calling the once function\n" );
101 spinDown = spinThresh;
102 }
103 pCurrent = get ( *pId );
104 } while ( pCurrent != & done );
105 }
106 }
107}
108
109//
110// we implement this as a separate function so that it is easy to see
111// that the performance impact of the primary (most commonly used) path
112// and that options for inlining this function are available (based on
113// source code organization)
114//
115// performance might be slightly better if this were implemented as an inline
116// function, but that would pull epicsAtomic.h into epicsThread.h, and on
117// windows this includes (the lean and mean version of) windows.h, so perhaps
118// its best to make this an out-of-line function as that type of instantiation
119// will probably have only a small negative impact on performance
120//
121extern "C" void epicsShareAPI epicsThreadOnce ( epicsThreadOnceId * pId,
122 void ( * pFunc )( void * ),
123 void * pArg )
124{
125 const epicsThreadOnceId pCurrent = get ( *pId );
126 if ( pCurrent != & done ) {
127 epicsThreadOnceOnly ( pId, pFunc, pArg );
128 }
129}
0130
=== 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 2011-08-31 22:40:22 +0000
@@ -60,7 +60,6 @@
60 * Support for `once-only' execution60 * Support for `once-only' execution
61 */61 */
62static int initialized = 0;62static int initialized = 0;
63static epicsMutexId onceMutex;
6463
65/*64/*
66 * Just map osi 0 to 99 into RTEMS 199 to 10065 * Just map osi 0 to 99 into RTEMS 199 to 100
@@ -231,7 +230,6 @@
231 rtems_task_priority old;230 rtems_task_priority old;
232231
233 rtems_task_set_priority (RTEMS_SELF, epicsThreadGetOssPriorityValue(99), &old);232 rtems_task_set_priority (RTEMS_SELF, epicsThreadGetOssPriorityValue(99), &old);
234 onceMutex = epicsMutexMustCreate();
235 taskVarMutex = epicsMutexMustCreate ();233 taskVarMutex = epicsMutexMustCreate ();
236 rtems_task_ident (RTEMS_SELF, 0, &tid);234 rtems_task_ident (RTEMS_SELF, 0, &tid);
237 setThreadInfo (tid, "_main_", NULL, NULL);235 setThreadInfo (tid, "_main_", NULL, NULL);
@@ -471,36 +469,6 @@
471}469}
472470
473/*471/*
474 * Ensure func() is run only once.
475 */
476void epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg)
477{
478 #define EPICS_THREAD_ONCE_DONE (epicsThreadId) 1
479
480 if (!initialized) epicsThreadInit();
481 epicsMutexMustLock(onceMutex);
482 if (*id != EPICS_THREAD_ONCE_DONE) {
483 if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
484 *id = epicsThreadGetIdSelf(); /* mark active */
485 epicsMutexUnlock(onceMutex);
486 func(arg);
487 epicsMutexMustLock(onceMutex);
488 *id = EPICS_THREAD_ONCE_DONE; /* mark done */
489 } else if (*id == epicsThreadGetIdSelf()) {
490 epicsMutexUnlock(onceMutex);
491 cantProceed("Recursive epicsThreadOnce() initialization\n");
492 } else
493 while (*id != EPICS_THREAD_ONCE_DONE) {
494 /* Another thread is in the above func(arg) call. */
495 epicsMutexUnlock(onceMutex);
496 epicsThreadSleep(epicsThreadSleepQuantum());
497 epicsMutexMustLock(onceMutex);
498 }
499 }
500 epicsMutexUnlock(onceMutex);
501}
502
503/*
504 * Thread private storage implementation based on the vxWorks472 * Thread private storage implementation based on the vxWorks
505 * implementation by Andrew Johnson APS/ASD.473 * implementation by Andrew Johnson APS/ASD.
506 */474 */
507475
=== modified file 'src/libCom/osi/os/WIN32/osdThread.c'
--- src/libCom/osi/os/WIN32/osdThread.c 2011-02-11 22:33:58 +0000
+++ src/libCom/osi/os/WIN32/osdThread.c 2011-08-31 22:40:22 +0000
@@ -1008,41 +1008,6 @@
1008}1008}
10091009
1010/*1010/*
1011 * epicsThreadOnce ()
1012 */
1013epicsShareFunc void epicsShareAPI epicsThreadOnce (
1014 epicsThreadOnceId *id, void (*func)(void *), void *arg )
1015{
1016 static struct epicsThreadOSD threadOnceComplete;
1017 #define EPICS_THREAD_ONCE_DONE & threadOnceComplete
1018 win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
1019
1020 assert ( pGbl );
1021
1022 EnterCriticalSection ( & pGbl->mutex );
1023
1024 if ( *id != EPICS_THREAD_ONCE_DONE ) {
1025 if ( *id == EPICS_THREAD_ONCE_INIT ) { /* first call */
1026 *id = epicsThreadGetIdSelf(); /* mark active */
1027 LeaveCriticalSection ( & pGbl->mutex );
1028 func ( arg );
1029 EnterCriticalSection ( & pGbl->mutex );
1030 *id = EPICS_THREAD_ONCE_DONE; /* mark done */
1031 } else if ( *id == epicsThreadGetIdSelf() ) {
1032 LeaveCriticalSection ( & pGbl->mutex );
1033 cantProceed( "Recursive epicsThreadOnce() initialization\n" );
1034 } else
1035 while ( *id != EPICS_THREAD_ONCE_DONE ) {
1036 /* Another thread is in the above func(arg) call. */
1037 LeaveCriticalSection ( & pGbl->mutex );
1038 epicsThreadSleep ( epicsThreadSleepQuantum() );
1039 EnterCriticalSection ( & pGbl->mutex );
1040 }
1041 }
1042 LeaveCriticalSection ( & pGbl->mutex );
1043}
1044
1045/*
1046 * epicsThreadPrivateCreate ()1011 * epicsThreadPrivateCreate ()
1047 */1012 */
1048epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate ()1013epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate ()
10491014
=== modified file 'src/libCom/osi/os/posix/osdThread.c'
--- src/libCom/osi/os/posix/osdThread.c 2010-05-14 22:26:54 +0000
+++ src/libCom/osi/os/posix/osdThread.c 2011-08-31 22:40:22 +0000
@@ -76,7 +76,6 @@
76} epicsThreadOSD;76} epicsThreadOSD;
7777
78static pthread_key_t getpthreadInfo;78static pthread_key_t getpthreadInfo;
79static pthread_mutex_t onceLock;
80static pthread_mutex_t listLock;79static pthread_mutex_t listLock;
81static ELLLIST pthreadList = ELLLIST_INIT;80static ELLLIST pthreadList = ELLLIST_INIT;
82static commonAttr *pcommonAttr = 0;81static commonAttr *pcommonAttr = 0;
@@ -207,8 +206,6 @@
207 int status;206 int status;
208207
209 pthread_key_create(&getpthreadInfo,0);208 pthread_key_create(&getpthreadInfo,0);
210 status = pthread_mutex_init(&onceLock,0);
211 checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
212 status = pthread_mutex_init(&listLock,0);209 status = pthread_mutex_init(&listLock,0);
213 checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");210 checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
214 pcommonAttr = calloc(1,sizeof(commonAttr));211 pcommonAttr = calloc(1,sizeof(commonAttr));
@@ -321,47 +318,6 @@
321#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/318#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
322}319}
323320
324321
325epicsShareFunc void epicsShareAPI epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
326{
327 static struct epicsThreadOSD threadOnceComplete;
328 #define EPICS_THREAD_ONCE_DONE &threadOnceComplete
329 int status;
330
331 epicsThreadInit();
332 status = mutexLock(&onceLock);
333 if(status) {
334 fprintf(stderr,"epicsThreadOnce: pthread_mutex_lock returned %s.\n",
335 strerror(status));
336 exit(-1);
337 }
338
339 if (*id != EPICS_THREAD_ONCE_DONE) {
340 if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
341 *id = epicsThreadGetIdSelf(); /* mark active */
342 status = pthread_mutex_unlock(&onceLock);
343 checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
344 func(arg);
345 status = mutexLock(&onceLock);
346 checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
347 *id = EPICS_THREAD_ONCE_DONE; /* mark done */
348 } else if (*id == epicsThreadGetIdSelf()) {
349 status = pthread_mutex_unlock(&onceLock);
350 checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
351 cantProceed("Recursive epicsThreadOnce() initialization\n");
352 } else
353 while (*id != EPICS_THREAD_ONCE_DONE) {
354 /* Another thread is in the above func(arg) call. */
355 status = pthread_mutex_unlock(&onceLock);
356 checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
357 epicsThreadSleep(epicsThreadSleepQuantum());
358 status = mutexLock(&onceLock);
359 checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
360 }
361 }
362 status = pthread_mutex_unlock(&onceLock);
363 checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadOnce");
364}
365
366epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate(const char *name,322epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate(const char *name,
367 unsigned int priority, unsigned int stackSize,323 unsigned int priority, unsigned int stackSize,
368 EPICSTHREADFUNC funptr,void *parm)324 EPICSTHREADFUNC funptr,void *parm)
369325
=== 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 2011-08-31 22:40:22 +0000
@@ -53,7 +53,6 @@
53static void **papTSD = 0;53static void **papTSD = 0;
54static int nepicsThreadPrivate = 0;54static int nepicsThreadPrivate = 0;
5555
56static SEM_ID epicsThreadOnceMutex = 0;
5756
5857
59/* Just map osi 0 to 99 into vx 100 to 199 */58/* Just map osi 0 to 99 into vx 100 to 199 */
60/* remember that for vxWorks lower number means higher priority */59/* remember that for vxWorks lower number means higher priority */
@@ -83,19 +82,6 @@
83 }82 }
84}83}
8584
86static void epicsThreadInit(void)
87{
88 static int lock = 0;
89
90 while(!vxTas(&lock)) taskDelay(1);
91 if(epicsThreadOnceMutex==0) {
92 epicsThreadOnceMutex = semMCreate(
93 SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);
94 assert(epicsThreadOnceMutex);
95 }
96 lock = 0;
97}
98
99unsigned int epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) 85unsigned int epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
100{86{
10187
@@ -112,43 +98,6 @@
112 return stackSizeTable[stackSizeClass];98 return stackSizeTable[stackSizeClass];
113}99}
114100
115struct epicsThreadOSD {};
116 /* Strictly speaking this should be a WIND_TCB, but we only need it to
117 * be able to create an epicsThreadId that is guaranteed never to be
118 * the same as any current TID, and since TIDs are pointers this works.
119 */
120
121void epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
122{
123 static struct epicsThreadOSD threadOnceComplete;
124 #define EPICS_THREAD_ONCE_DONE &threadOnceComplete
125 int result;
126
127 epicsThreadInit();
128 result = semTake(epicsThreadOnceMutex, WAIT_FOREVER);
129 assert(result == OK);
130 if (*id != EPICS_THREAD_ONCE_DONE) {
131 if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
132 *id = epicsThreadGetIdSelf(); /* mark active */
133 semGive(epicsThreadOnceMutex);
134 func(arg);
135 result = semTake(epicsThreadOnceMutex, WAIT_FOREVER);
136 assert(result == OK);
137 *id = EPICS_THREAD_ONCE_DONE; /* mark done */
138 } else if (*id == epicsThreadGetIdSelf()) {
139 semGive(epicsThreadOnceMutex);
140 cantProceed("Recursive epicsThreadOnce() initialization\n");
141 } else
142 while (*id != EPICS_THREAD_ONCE_DONE) {
143 /* Another thread is in the above func(arg) call. */
144 semGive(epicsThreadOnceMutex);
145 epicsThreadSleep(epicsThreadSleepQuantum());
146 result = semTake(epicsThreadOnceMutex, WAIT_FOREVER);
147 assert(result == OK);
148 }
149 }
150 semGive(epicsThreadOnceMutex);
151}
152101
153102
154static void createFunction(EPICSTHREADFUNC func, void *parm)103static void createFunction(EPICSTHREADFUNC func, void *parm)
155{104{
@@ -173,7 +122,6 @@
173 EPICSTHREADFUNC funptr,void *parm)122 EPICSTHREADFUNC funptr,void *parm)
174{123{
175 int tid;124 int tid;
176 if(epicsThreadOnceMutex==0) epicsThreadInit();
177 if(stackSize<100) {125 if(stackSize<100) {
178 errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n",name,stackSize);126 errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n",name,stackSize);
179 return(0);127 return(0);
@@ -343,7 +291,6 @@
343 static int lock = 0;291 static int lock = 0;
344 epicsThreadPrivateId id;292 epicsThreadPrivateId id;
345293
346 epicsThreadInit();
347 /*lock is necessary because ++nepicsThreadPrivate may not be indivisible*/294 /*lock is necessary because ++nepicsThreadPrivate may not be indivisible*/
348 while(!vxTas(&lock)) taskDelay(1);295 while(!vxTas(&lock)) taskDelay(1);
349 id = (epicsThreadPrivateId)++nepicsThreadPrivate;296 id = (epicsThreadPrivateId)++nepicsThreadPrivate;

Subscribers

People subscribed via source and target branches