22 # define _WIN32_WINNT 0x400 28 #include "libComAPI.h" 63 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION 64 # define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 67 #define osdOrdinaryPriorityStateCount 5u 70 THREAD_PRIORITY_LOWEST,
71 THREAD_PRIORITY_BELOW_NORMAL,
72 THREAD_PRIORITY_NORMAL,
73 THREAD_PRIORITY_ABOVE_NORMAL,
74 THREAD_PRIORITY_HIGHEST
77 # define osdRealtimePriorityStateCount 14u 85 THREAD_PRIORITY_LOWEST,
86 THREAD_PRIORITY_BELOW_NORMAL,
87 THREAD_PRIORITY_NORMAL,
88 THREAD_PRIORITY_ABOVE_NORMAL,
89 THREAD_PRIORITY_HIGHEST,
96 #if defined(EPICS_BUILD_DLL) 98 HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved )
100 static DWORD dllHandleIndex;
101 HMODULE dllHandle = 0;
106 case DLL_PROCESS_ATTACH:
107 dllHandleIndex = TlsAlloc ();
108 if ( dllHandleIndex == TLS_OUT_OF_INDEXES ) {
113 case DLL_PROCESS_DETACH:
114 success = TlsFree ( dllHandleIndex );
117 case DLL_THREAD_ATTACH:
122 #if _WIN32_WINNT >= 0x0501 127 success = GetModuleHandleEx (
128 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
129 ( LPCTSTR ) DllMain, & dllHandle );
133 DWORD nChar = GetModuleFileName (
134 hModule, name,
sizeof ( name ) );
135 if ( nChar && nChar <
sizeof ( name ) ) {
136 dllHandle = LoadLibrary ( name );
147 success = TlsSetValue ( dllHandleIndex, dllHandle );
150 case DLL_THREAD_DETACH:
155 dllHandle = TlsGetValue ( dllHandleIndex );
157 success = FreeLibrary ( dllHandle );
174 static LONG initStarted = 0;
175 static LONG initCompleted = 0;
179 done = InterlockedCompareExchange ( & initCompleted, 0, 0 );
181 return pWin32ThreadGlobal;
184 started = InterlockedCompareExchange ( & initStarted, 0, 1 );
187 while ( ! InterlockedCompareExchange ( & initCompleted, 0, 0 ) ) {
194 if ( tries++ > 1000 ) {
198 return pWin32ThreadGlobal;
202 calloc ( 1,
sizeof ( * pWin32ThreadGlobal ) );
203 if ( ! pWin32ThreadGlobal ) {
204 InterlockedExchange ( & initStarted, 0 );
208 InitializeCriticalSection ( & pWin32ThreadGlobal->
mutex );
212 DeleteCriticalSection ( & pWin32ThreadGlobal->
mutex );
213 free ( pWin32ThreadGlobal );
214 pWin32ThreadGlobal = 0;
218 InterlockedExchange ( & initCompleted, 1 );
220 return pWin32ThreadGlobal;
227 fprintf (
stderr,
"epicsParmCleanupWIN32: unable to find ctx\n" );
237 EnterCriticalSection ( & pGbl->
mutex );
239 LeaveCriticalSection ( & pGbl->
mutex );
241 CloseHandle ( pParm->
handle );
257 static unsigned osdPriorityMagFromPriorityOSI (
unsigned osiPriority,
unsigned priorityStateCount )
271 magnitude = osiPriority * priorityStateCount;
284 static int epicsThreadGetOsdPriorityValue (
unsigned osiPriority )
286 const DWORD priorityClass = GetPriorityClass ( GetCurrentProcess () );
287 const int * pStateList;
291 if ( priorityClass == REALTIME_PRIORITY_CLASS ) {
293 pStateList = osdRealtimePriorityList;
297 pStateList = osdOrdinaryPriorityList;
300 magnitude = osdPriorityMagFromPriorityOSI ( osiPriority, stateCount );
301 return pStateList[magnitude];
307 static unsigned osiPriorityMagFromMagnitueOSD (
unsigned magnitude,
unsigned osdPriorityStateCount )
309 unsigned osiPriority;
312 osiPriority /= osdPriorityStateCount - 1u;
324 const DWORD priorityClass = GetPriorityClass ( GetCurrentProcess () );
325 const int * pStateList;
329 if ( priorityClass == REALTIME_PRIORITY_CLASS ) {
331 pStateList = osdRealtimePriorityList;
335 pStateList = osdOrdinaryPriorityList;
338 for ( magnitude = 0u; magnitude < stateCount; magnitude++ ) {
339 if ( osdPriority == pStateList[magnitude] ) {
344 if ( magnitude >= stateCount ) {
346 "Unrecognized WIN32 thread priority level %d.\n",
349 "Mapping to EPICS thread priority level epicsThreadPriorityMin.\n" );
353 return osiPriorityMagFromMagnitueOSD ( magnitude, stateCount );
360 (
unsigned int priority,
unsigned * pPriorityJustAbove )
362 const DWORD priorityClass = GetPriorityClass ( GetCurrentProcess () );
367 if ( priorityClass == REALTIME_PRIORITY_CLASS ) {
374 magnitude = osdPriorityMagFromPriorityOSI ( priority, stateCount );
376 if ( magnitude < ( stateCount - 1 ) ) {
377 *pPriorityJustAbove = osiPriorityMagFromMagnitueOSD ( magnitude + 1u, stateCount );
390 (
unsigned int priority,
unsigned * pPriorityJustBelow )
392 const DWORD priorityClass = GetPriorityClass ( GetCurrentProcess () );
397 if ( priorityClass == REALTIME_PRIORITY_CLASS ) {
404 magnitude = osdPriorityMagFromPriorityOSI ( priority, stateCount );
406 if ( magnitude > 0u ) {
407 *pPriorityJustBelow = osiPriorityMagFromMagnitueOSD ( magnitude - 1u, stateCount );
419 LIBCOM_API
unsigned int epicsStdCall
422 #define STACK_SIZE(f) (f * 0x10000 * sizeof(void *)) 429 "epicsThreadGetStackSize illegal argument (too small)");
435 "epicsThreadGetStackSize illegal argument (too large)");
439 return stackSizeTable[stackSizeClass];
445 static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter )
449 unsigned retStat = 0u;
464 fprintf (
stderr,
"epicsWin32ThreadEntry: unable to set private\n" );
468 fprintf (
stderr,
"epicsWin32ThreadEntry: unable to find ctx\n" );
480 epicsParmCleanupWIN32 ( pParm );
489 pParmWIN32 = calloc ( 1,
sizeof ( *pParmWIN32 ) + strlen ( pName ) + 1 );
491 pParmWIN32->
pName = (
char *) ( pParmWIN32 + 1 );
492 strcpy ( pParmWIN32->
pName, pName );
502 DWORD
id = GetCurrentThreadId ();
509 fprintf (
stderr,
"epicsThreadImplicitCreate: unable to find ctx\n" );
513 success = DuplicateHandle ( GetCurrentProcess (), GetCurrentThread (),
514 GetCurrentProcess (), & handle, 0,
FALSE, DUPLICATE_SAME_ACCESS );
519 unsigned long idForFormat = id;
520 sprintf ( name,
"win%lx", idForFormat );
522 pParm = epicsThreadParmCreate ( name );
524 int win32ThreadPriority;
528 win32ThreadPriority = GetThreadPriority ( pParm->
handle );
529 assert ( win32ThreadPriority != THREAD_PRIORITY_ERROR_RETURN );
533 epicsParmCleanupWIN32 ( pParm );
537 EnterCriticalSection ( & pGbl->
mutex );
539 LeaveCriticalSection ( & pGbl->
mutex );
555 unsigned int stackSize;
566 opts = &opts_default;
572 pParmWIN32 = epicsThreadParmCreate ( pName );
573 if ( pParmWIN32 == 0 ) {
576 pParmWIN32->
funptr = pFunc;
577 pParmWIN32->
parm = pParm;
586 pParmWIN32->
handle = (HANDLE) _beginthreadex (
587 0, stackSize, epicsWin32ThreadEntry,
591 if ( pParmWIN32->
handle == 0 ) {
596 pParmWIN32->
id = ( DWORD ) threadId ;
599 osdPriority = epicsThreadGetOsdPriorityValue (opts->
priority);
600 bstat = SetThreadPriority ( pParmWIN32->
handle, osdPriority );
602 CloseHandle ( pParmWIN32->
handle );
607 EnterCriticalSection ( & pGbl->
mutex );
609 LeaveCriticalSection ( & pGbl->
mutex );
611 wstat = ResumeThread ( pParmWIN32->
handle );
612 if (wstat==0xFFFFFFFF) {
613 EnterCriticalSection ( & pGbl->
mutex );
615 LeaveCriticalSection ( & pGbl->
mutex );
616 CloseHandle ( pParmWIN32->
handle );
632 fprintf(
stderr,
"Warning: %s thread self-join of unjoinable\n", pParmWIN32->
pName);
643 DWORD
status = WaitForSingleObject(pParmWIN32->
handle, INFINITE);
644 if(status != WAIT_OBJECT_0) {
648 epicsParmCleanupWIN32(pParmWIN32);
651 epicsParmCleanupWIN32(pParmWIN32);
669 pParm = epicsThreadImplicitCreate ();
672 EnterCriticalSection ( & pGbl->
mutex );
674 LeaveCriticalSection ( & pGbl->
mutex );
676 stat = SuspendThread ( GetCurrentThread () );
677 assert ( stat != 0xFFFFFFFF );
691 EnterCriticalSection ( & pGbl->
mutex );
693 stat = ResumeThread ( pParm->
handle );
696 LeaveCriticalSection ( & pGbl->
mutex );
698 assert ( stat != 0xFFFFFFFF );
723 pParm = epicsThreadImplicitCreate ();
729 int win32ThreadPriority =
730 GetThreadPriority ( GetCurrentThread () );
731 assert ( win32ThreadPriority != THREAD_PRIORITY_ERROR_RETURN );
742 BOOL stat = SetThreadPriority ( pParm->
handle, epicsThreadGetOsdPriorityValue (priority) );
753 return ( id1 == id2 && pParm1->
id == pParm2->
id );
765 stat = GetExitCodeThread ( pParm->
handle, & exitCode );
767 if ( exitCode != STILL_ACTIVE ) {
787 if ( seconds > 0.0 ) {
789 seconds += 0.99999999;
790 milliSecDelay = ( seconds >= INFINITE ) ?
791 INFINITE - 1 : ( DWORD ) seconds;
796 Sleep ( milliSecDelay );
815 static const double secPerTick = 100e-9;
821 success = GetSystemTimeAdjustment (
822 & adjustment, & delay, & disabled );
824 return delay * secPerTick;
844 pParm = epicsThreadImplicitCreate ();
859 EnterCriticalSection ( & pGbl->
mutex );
863 if ( pParm->
pName ) {
864 if ( strcmp ( pParm->
pName, pName ) == 0 ) {
870 LeaveCriticalSection ( & pGbl->
mutex );
887 return "thread library not initialized";
893 pParm = epicsThreadImplicitCreate ();
897 if ( pParm->
pName ) {
913 size_t sizeMinusOne = size-1;
914 strncpy ( pName, pParm->
pName, sizeMinusOne );
915 pName [sizeMinusOne] =
'\0';
922 static const char * epics_GetThreadPriorityAsString ( HANDLE thr )
924 const char * pPriName =
"?????";
925 switch ( GetThreadPriority ( thr ) ) {
926 case THREAD_PRIORITY_TIME_CRITICAL:
927 pPriName =
"tm-crit";
929 case THREAD_PRIORITY_HIGHEST:
932 case THREAD_PRIORITY_ABOVE_NORMAL:
933 pPriName =
"normal+";
935 case THREAD_PRIORITY_NORMAL:
938 case THREAD_PRIORITY_BELOW_NORMAL:
939 pPriName =
"normal-";
941 case THREAD_PRIORITY_LOWEST:
944 case THREAD_PRIORITY_IDLE:
959 unsigned long idForFormat = pParm->
id;
962 epics_GetThreadPriorityAsString ( pParm->
handle ),
966 (
void *) pParm->
handle, (
void *) pParm->
parm );
971 "NAME EPICS-ID WIN32-ID EPICS-PRI WIN32-PRI STATE " );
991 EnterCriticalSection ( & pGbl->
mutex );
998 LeaveCriticalSection ( & pGbl->
mutex );
1013 EnterCriticalSection ( & pGbl->
mutex );
1021 LeaveCriticalSection ( & pGbl->
mutex );
1040 #define EPICS_THREAD_ONCE_DONE & threadOnceComplete 1045 EnterCriticalSection ( & pGbl->mutex );
1050 LeaveCriticalSection ( & pGbl->mutex );
1052 EnterCriticalSection ( & pGbl->mutex );
1055 LeaveCriticalSection ( & pGbl->mutex );
1056 cantProceed(
"Recursive epicsThreadOnce() initialization\n" );
1060 LeaveCriticalSection ( & pGbl->mutex );
1062 EnterCriticalSection ( & pGbl->mutex );
1065 LeaveCriticalSection ( & pGbl->mutex );
1075 p->
key = TlsAlloc ();
1076 if ( p->
key == 0xFFFFFFFF ) {
1089 BOOL stat = TlsFree ( p->
key );
1099 BOOL stat = TlsSetValue ( pPvt->
key, (
void *) pVal );
1108 return (
void * ) TlsGetValue ( pPvt->
key );
1116 SYSTEM_INFO sysinfo;
1117 GetSystemInfo(&sysinfo);
1118 if (sysinfo.dwNumberOfProcessors > 0)
1119 return sysinfo.dwNumberOfProcessors;
1124 void testPriorityMapping ()
1129 printf (
"%u %d\n", i, epicsThreadGetOsdPriorityValue (i) );
1132 for (i=0; i<osdPriorityStateCount; i++) {
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass stackSizeClass)
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadHighestPriorityLevelBelow(unsigned int priority, unsigned *pPriorityJustBelow)
LIBCOM_API int epicsThreadGetCPUs(void)
LIBCOM_API epicsThreadPrivateId epicsStdCall epicsThreadPrivateCreate(void)
#define osdRealtimePriorityStateCount
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
struct epicsThreadOSD win32ThreadParam
LIBCOM_API void epicsStdCall epicsThreadExitMain(void)
int epicsThreadGetOsiPriorityValue(int ossPriority)
#define assert(exp)
Declare that a condition should be true.
An EPICS-specific replacement for ANSI C's assert.
#define STACK_SIZE_PARAM_IS_A_RESERVATION
LIBCOM_API void epicsExitCallAtThreadExits(void)
Internal routine that runs the registered thread exit routines.
LIBCOM_API void epicsThreadRealtimeLock(void)
struct epicsThreadPrivateOSD epicsThreadPrivateOSD
LIBCOM_API double epicsStdCall epicsThreadSleepQuantum()
Query a value approximating the OS timer/scheduler resolution.
void(* EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id)
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT(int *pTarget, int oldVal, int newVal)
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadLowestPriorityLevelAbove(unsigned int priority, unsigned *pPriorityJustAbove)
void setThreadName(DWORD dwThreadID, LPCSTR szThreadName)
#define EPICS_THREAD_ONCE_DONE
LIBCOM_API void epicsStdCall epicsThreadPrivateSet(epicsThreadPrivateId id, void *value)
DWORD tlsIndexThreadLibraryEPICS
LIBCOM_API void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level)
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg)
A doubly-linked list library.
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
#define ellNext(PNODE)
Find the next node in list.
FILE *epicsStdCall epicsGetStdout(void)
#define EPICS_THREAD_ONCE_INIT
epicsThreadStackSizeClass
#define epicsThreadPriorityMax
LIBCOM_API void epicsStdCall * epicsThreadPrivateGet(epicsThreadPrivateId id)
epicsThreadId epicsThreadCreateOpt(const char *name, EPICSTHREADFUNC funptr, void *parm, const epicsThreadOpts *opts)
Allocate and start a new OS thread.
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPrioritySelf(void)
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetId(const char *name)
Extended replacement for the Posix exit and atexit routines.
LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
LIBCOM_API void epicsStdCall epicsThreadShow(epicsThreadId showThread, unsigned int level)
LIBCOM_API int epicsStdCall epicsThreadIsSuspended(epicsThreadId pthreadInfo)
LIBCOM_API void epicsStdCall epicsThreadResume(epicsThreadOSD *pthreadInfo)
LIBCOM_API void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func)
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT(int *pTarget)
#define ellInit(PLIST)
Initialize a list type.
LIBCOM_API void epicsStdCall epicsThreadShowAll(unsigned int level)
#define EPICS_THREAD_OPTS_INIT
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT(int *pTarget)
LIBCOM_API void cantProceed(const char *msg,...)
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPriority(epicsThreadId pthreadInfo)
void epicsThreadMustJoin(epicsThreadId id)
Routines for code that can't continue or return after an error.
LIBCOM_API void osdThreadHooksRun(epicsThreadId id)
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
const unsigned mSecPerSec
LIBCOM_API void epicsStdCall epicsThreadSetPriority(epicsThreadId pthreadInfo, unsigned int priority)
C++ and C descriptions for a thread.
LIBCOM_API void epicsStdCall epicsThreadPrivateDelete(epicsThreadPrivateId id)
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
#define epicsThreadPriorityMin
#define osdOrdinaryPriorityStateCount
void(* EPICSTHREADFUNC)(void *parm)
struct win32ThreadGlobal win32ThreadGlobal
LIBCOM_API const char epicsStdCall * epicsThreadGetNameSelf()
LIBCOM_API int epicsStdCall epicsThreadIsEqual(epicsThreadId p1, epicsThreadId p2)
#define ellFirst(PLIST)
Find the first node in list.
LIBCOM_API void epicsStdCall epicsThreadGetName(epicsThreadId pthreadInfo, char *name, size_t size)