This is Unofficial EPICS BASE Doxygen Site
osdThread.c
Go to the documentation of this file.
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 /*
11  * Author: Jeff Hill
12  */
13 
14 #include <string.h>
15 #include <stdlib.h>
16 #include <stddef.h>
17 #include <stdio.h>
18 
19 #define VC_EXTRALEAN
20 #define STRICT
21 #ifndef _WIN32_WINNT
22 # define _WIN32_WINNT 0x400 /* No support for W95 */
23 #endif
24 #include <windows.h>
25 #include <process.h> /* for _endthread() etc */
26 
27 #include "epicsStdio.h"
28 #include "libComAPI.h"
29 #include "epicsThread.h"
30 #include "cantProceed.h"
31 #include "epicsAssert.h"
32 #include "ellLib.h"
33 #include "epicsExit.h"
34 #include "epicsAtomic.h"
35 
36 LIBCOM_API void osdThreadHooksRun(epicsThreadId id);
37 
38 void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName );
39 
40 typedef struct win32ThreadGlobal {
41  CRITICAL_SECTION mutex;
45 
46 typedef struct epicsThreadOSD {
47  ELLNODE node;
48  int refcnt;
49  HANDLE handle;
51  void * parm;
52  char * pName;
53  DWORD id;
54  unsigned epicsPriority;
56  int joinable;
58 
59 typedef struct epicsThreadPrivateOSD {
60  DWORD key;
62 
63 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
64 # define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
65 #endif
66 
67 #define osdOrdinaryPriorityStateCount 5u
68 static const int osdOrdinaryPriorityList [osdOrdinaryPriorityStateCount] =
69 {
70  THREAD_PRIORITY_LOWEST, /* -2 on >= W2K ??? on W95 */
71  THREAD_PRIORITY_BELOW_NORMAL, /* -1 on >= W2K ??? on W95 */
72  THREAD_PRIORITY_NORMAL, /* 0 on >= W2K ??? on W95 */
73  THREAD_PRIORITY_ABOVE_NORMAL, /* 1 on >= W2K ??? on W95 */
74  THREAD_PRIORITY_HIGHEST /* 2 on >= W2K ??? on W95 */
75 };
76 
77 # define osdRealtimePriorityStateCount 14u
78 static const int osdRealtimePriorityList [osdRealtimePriorityStateCount] =
79 {
80  -7, /* allowed on >= W2k, but no #define supplied */
81  -6, /* allowed on >= W2k, but no #define supplied */
82  -5, /* allowed on >= W2k, but no #define supplied */
83  -4, /* allowed on >= W2k, but no #define supplied */
84  -3, /* allowed on >= W2k, but no #define supplied */
85  THREAD_PRIORITY_LOWEST, /* -2 on >= W2K ??? on W95 */
86  THREAD_PRIORITY_BELOW_NORMAL, /* -1 on >= W2K ??? on W95 */
87  THREAD_PRIORITY_NORMAL, /* 0 on >= W2K ??? on W95 */
88  THREAD_PRIORITY_ABOVE_NORMAL, /* 1 on >= W2K ??? on W95 */
89  THREAD_PRIORITY_HIGHEST, /* 2 on >= W2K ??? on W95 */
90  3, /* allowed on >= W2k, but no #define supplied */
91  4, /* allowed on >= W2k, but no #define supplied */
92  5, /* allowed on >= W2k, but no #define supplied */
93  6 /* allowed on >= W2k, but no #define supplied */
94 };
95 
96 #if defined(EPICS_BUILD_DLL)
97 BOOL WINAPI DllMain (
98  HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved )
99 {
100  static DWORD dllHandleIndex;
101  HMODULE dllHandle = 0;
102  BOOL success = TRUE;
103 
104  switch ( dwReason )
105  {
106  case DLL_PROCESS_ATTACH:
107  dllHandleIndex = TlsAlloc ();
108  if ( dllHandleIndex == TLS_OUT_OF_INDEXES ) {
109  success = FALSE;
110  }
111  break;
112 
113  case DLL_PROCESS_DETACH:
114  success = TlsFree ( dllHandleIndex );
115  break;
116 
117  case DLL_THREAD_ATTACH:
118  /*
119  * Dont allow user's explicitly calling FreeLibrary for Com.dll to yank
120  * the carpet out from under EPICS threads that are still using Com.dll
121  */
122 #if _WIN32_WINNT >= 0x0501
123  /*
124  * Only in WXP
125  * Thats a shame because this is probably much faster
126  */
127  success = GetModuleHandleEx (
128  GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
129  ( LPCTSTR ) DllMain, & dllHandle );
130 #else
131  {
132  char name[256];
133  DWORD nChar = GetModuleFileName (
134  hModule, name, sizeof ( name ) );
135  if ( nChar && nChar < sizeof ( name ) ) {
136  dllHandle = LoadLibrary ( name );
137  if ( ! dllHandle ) {
138  success = FALSE;
139  }
140  }
141  else {
142  success = FALSE;
143  }
144  }
145 #endif
146  if ( success ) {
147  success = TlsSetValue ( dllHandleIndex, dllHandle );
148  }
149  break;
150  case DLL_THREAD_DETACH:
151  /*
152  * Thread is exiting, release Com.dll. I am assuming that windows is
153  * smart enough to postpone the unload until this function returns.
154  */
155  dllHandle = TlsGetValue ( dllHandleIndex );
156  if ( dllHandle ) {
157  success = FreeLibrary ( dllHandle );
158  }
159  break;
160  }
161 
162  return success;
163 }
164 #endif
165 
166 /*
167  * fetchWin32ThreadGlobal ()
168  * Search for "Synchronization and Multiprocessor Issues" in ms doc
169  * to understand why this is necessary and why this works on smp systems.
170  */
171 static win32ThreadGlobal * fetchWin32ThreadGlobal ( void )
172 {
173  static win32ThreadGlobal * pWin32ThreadGlobal = 0;
174  static LONG initStarted = 0;
175  static LONG initCompleted = 0;
176  LONG started;
177  LONG done;
178 
179  done = InterlockedCompareExchange ( & initCompleted, 0, 0 );
180  if ( done ) {
181  return pWin32ThreadGlobal;
182  }
183 
184  started = InterlockedCompareExchange ( & initStarted, 0, 1 );
185  if ( started ) {
186  unsigned tries = 0u;
187  while ( ! InterlockedCompareExchange ( & initCompleted, 0, 0 ) ) {
188  /*
189  * I am not fond of busy loops, but since this will
190  * collide very infrequently and this is the lowest
191  * level init then perhaps this is ok
192  */
193  Sleep ( 1 );
194  if ( tries++ > 1000 ) {
195  return 0;
196  }
197  }
198  return pWin32ThreadGlobal;
199  }
200 
201  pWin32ThreadGlobal = ( win32ThreadGlobal * )
202  calloc ( 1, sizeof ( * pWin32ThreadGlobal ) );
203  if ( ! pWin32ThreadGlobal ) {
204  InterlockedExchange ( & initStarted, 0 );
205  return 0;
206  }
207 
208  InitializeCriticalSection ( & pWin32ThreadGlobal->mutex );
209  ellInit ( & pWin32ThreadGlobal->threadList );
210  pWin32ThreadGlobal->tlsIndexThreadLibraryEPICS = TlsAlloc();
211  if ( pWin32ThreadGlobal->tlsIndexThreadLibraryEPICS == 0xFFFFFFFF ) {
212  DeleteCriticalSection ( & pWin32ThreadGlobal->mutex );
213  free ( pWin32ThreadGlobal );
214  pWin32ThreadGlobal = 0;
215  return 0;
216  }
217 
218  InterlockedExchange ( & initCompleted, 1 );
219 
220  return pWin32ThreadGlobal;
221 }
222 
223 static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm )
224 {
225  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
226  if ( ! pGbl ) {
227  fprintf ( stderr, "epicsParmCleanupWIN32: unable to find ctx\n" );
228  return;
229  }
230 
231  if ( pParm ) {
232  int cnt = epicsAtomicDecrIntT(&pParm->refcnt);
233  if(cnt > 0) return;
234  assert(cnt==0);
235 
236  /* fprintf ( stderr, "thread %s is exiting\n", pParm->pName ); */
237  EnterCriticalSection ( & pGbl->mutex );
238  ellDelete ( & pGbl->threadList, & pParm->node );
239  LeaveCriticalSection ( & pGbl->mutex );
240 
241  CloseHandle ( pParm->handle );
242  free ( pParm );
243  }
244 }
245 
246 /*
247  * epicsThreadExitMain ()
248  */
249 LIBCOM_API void epicsStdCall epicsThreadExitMain ( void )
250 {
251  _endthread ();
252 }
253 
254 /*
255  * osdPriorityMagFromPriorityOSI ()
256  */
257 static unsigned osdPriorityMagFromPriorityOSI ( unsigned osiPriority, unsigned priorityStateCount )
258 {
259  unsigned magnitude;
260 
261  /* optimizer will remove this one if epicsThreadPriorityMin is zero */
262  /* and osiPriority is unsigned */
263  if ( osiPriority < epicsThreadPriorityMin ) {
264  osiPriority = epicsThreadPriorityMin;
265  }
266 
267  if ( osiPriority > epicsThreadPriorityMax ) {
268  osiPriority = epicsThreadPriorityMax;
269  }
270 
271  magnitude = osiPriority * priorityStateCount;
272  magnitude /= ( epicsThreadPriorityMax - epicsThreadPriorityMin ) + 1;
273 
274  return magnitude;
275 }
276 
277 LIBCOM_API
279 {}
280 
281 /*
282  * epicsThreadGetOsdPriorityValue ()
283  */
284 static int epicsThreadGetOsdPriorityValue ( unsigned osiPriority )
285 {
286  const DWORD priorityClass = GetPriorityClass ( GetCurrentProcess () );
287  const int * pStateList;
288  unsigned stateCount;
289  unsigned magnitude;
290 
291  if ( priorityClass == REALTIME_PRIORITY_CLASS ) {
292  stateCount = osdRealtimePriorityStateCount;
293  pStateList = osdRealtimePriorityList;
294  }
295  else {
296  stateCount = osdOrdinaryPriorityStateCount;
297  pStateList = osdOrdinaryPriorityList;
298  }
299 
300  magnitude = osdPriorityMagFromPriorityOSI ( osiPriority, stateCount );
301  return pStateList[magnitude];
302 }
303 
304 /*
305  * osiPriorityMagFromMagnitueOSD ()
306  */
307 static unsigned osiPriorityMagFromMagnitueOSD ( unsigned magnitude, unsigned osdPriorityStateCount )
308 {
309  unsigned osiPriority;
310 
311  osiPriority = magnitude * ( epicsThreadPriorityMax - epicsThreadPriorityMin );
312  osiPriority /= osdPriorityStateCount - 1u;
313  osiPriority += epicsThreadPriorityMin;
314 
315  return osiPriority;
316 }
317 
318 
319 /*
320  * epicsThreadGetOsiPriorityValue ()
321  */
322 static unsigned epicsThreadGetOsiPriorityValue ( int osdPriority )
323 {
324  const DWORD priorityClass = GetPriorityClass ( GetCurrentProcess () );
325  const int * pStateList;
326  unsigned stateCount;
327  unsigned magnitude;
328 
329  if ( priorityClass == REALTIME_PRIORITY_CLASS ) {
330  stateCount = osdRealtimePriorityStateCount;
331  pStateList = osdRealtimePriorityList;
332  }
333  else {
334  stateCount = osdOrdinaryPriorityStateCount;
335  pStateList = osdOrdinaryPriorityList;
336  }
337 
338  for ( magnitude = 0u; magnitude < stateCount; magnitude++ ) {
339  if ( osdPriority == pStateList[magnitude] ) {
340  break;
341  }
342  }
343 
344  if ( magnitude >= stateCount ) {
345  fprintf ( stderr,
346  "Unrecognized WIN32 thread priority level %d.\n",
347  osdPriority );
348  fprintf ( stderr,
349  "Mapping to EPICS thread priority level epicsThreadPriorityMin.\n" );
350  return epicsThreadPriorityMin;
351  }
352 
353  return osiPriorityMagFromMagnitueOSD ( magnitude, stateCount );
354 }
355 
356 /*
357  * epicsThreadLowestPriorityLevelAbove ()
358  */
360  ( unsigned int priority, unsigned * pPriorityJustAbove )
361 {
362  const DWORD priorityClass = GetPriorityClass ( GetCurrentProcess () );
364  unsigned stateCount;
365  unsigned magnitude;
366 
367  if ( priorityClass == REALTIME_PRIORITY_CLASS ) {
368  stateCount = osdRealtimePriorityStateCount;
369  }
370  else {
371  stateCount = osdOrdinaryPriorityStateCount;
372  }
373 
374  magnitude = osdPriorityMagFromPriorityOSI ( priority, stateCount );
375 
376  if ( magnitude < ( stateCount - 1 ) ) {
377  *pPriorityJustAbove = osiPriorityMagFromMagnitueOSD ( magnitude + 1u, stateCount );
379  }
380  else {
382  }
383  return status;
384 }
385 
386 /*
387  * epicsThreadHighestPriorityLevelBelow ()
388  */
390  ( unsigned int priority, unsigned * pPriorityJustBelow )
391 {
392  const DWORD priorityClass = GetPriorityClass ( GetCurrentProcess () );
394  unsigned stateCount;
395  unsigned magnitude;
396 
397  if ( priorityClass == REALTIME_PRIORITY_CLASS ) {
398  stateCount = osdRealtimePriorityStateCount;
399  }
400  else {
401  stateCount = osdOrdinaryPriorityStateCount;
402  }
403 
404  magnitude = osdPriorityMagFromPriorityOSI ( priority, stateCount );
405 
406  if ( magnitude > 0u ) {
407  *pPriorityJustBelow = osiPriorityMagFromMagnitueOSD ( magnitude - 1u, stateCount );
409  }
410  else {
412  }
413  return status;
414 }
415 
416 /*
417  * epicsThreadGetStackSize ()
418  */
419 LIBCOM_API unsigned int epicsStdCall
421 {
422  #define STACK_SIZE(f) (f * 0x10000 * sizeof(void *))
423  static const unsigned stackSizeTable[epicsThreadStackBig+1] = {
424  STACK_SIZE(1), STACK_SIZE(2), STACK_SIZE(4)
425  };
426 
427  if (stackSizeClass<epicsThreadStackSmall) {
428  fprintf ( stderr,
429  "epicsThreadGetStackSize illegal argument (too small)");
430  return stackSizeTable[epicsThreadStackBig];
431  }
432 
433  if (stackSizeClass>epicsThreadStackBig) {
434  fprintf ( stderr,
435  "epicsThreadGetStackSize illegal argument (too large)");
436  return stackSizeTable[epicsThreadStackBig];
437  }
438 
439  return stackSizeTable[stackSizeClass];
440 }
441 
442 /*
443  * epicsWin32ThreadEntry()
444  */
445 static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter )
446 {
447  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
448  win32ThreadParam * pParm = ( win32ThreadParam * ) lpParameter;
449  unsigned retStat = 0u;
450  BOOL success;
451 
452  if ( pGbl ) {
453  setThreadName ( pParm->id, pParm->pName );
454 
455  success = TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, pParm );
456  if ( success ) {
457  osdThreadHooksRun ( ( epicsThreadId ) pParm );
458  /* printf ( "starting thread %d\n", pParm->id ); */
459  ( *pParm->funptr ) ( pParm->parm );
460  /* printf ( "terminating thread %d\n", pParm->id ); */
461  retStat = 1;
462  }
463  else {
464  fprintf ( stderr, "epicsWin32ThreadEntry: unable to set private\n" );
465  }
466  }
467  else {
468  fprintf ( stderr, "epicsWin32ThreadEntry: unable to find ctx\n" );
469  }
470 
472  /*
473  * CAUTION: !!!! the thread id might continue to be used after this thread exits !!!!
474  */
475 
476  if ( pGbl ) {
477  TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, (void*)0xdeadbeef );
478  }
479 
480  epicsParmCleanupWIN32 ( pParm );
481 
482  return retStat; /* this indirectly closes the thread handle */
483 }
484 
485 static win32ThreadParam * epicsThreadParmCreate ( const char *pName )
486 {
487  win32ThreadParam *pParmWIN32;
488 
489  pParmWIN32 = calloc ( 1, sizeof ( *pParmWIN32 ) + strlen ( pName ) + 1 );
490  if ( pParmWIN32 ) {
491  pParmWIN32->pName = (char *) ( pParmWIN32 + 1 );
492  strcpy ( pParmWIN32->pName, pName );
493  pParmWIN32->isSuspended = 0;
494  epicsAtomicIncrIntT(&pParmWIN32->refcnt);
495  }
496  return pParmWIN32;
497 }
498 
499 static win32ThreadParam * epicsThreadImplicitCreate ( void )
500 {
501  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
502  DWORD id = GetCurrentThreadId ();
503  win32ThreadParam * pParm;
504  char name[64];
505  HANDLE handle;
506  BOOL success;
507 
508  if ( ! pGbl ) {
509  fprintf ( stderr, "epicsThreadImplicitCreate: unable to find ctx\n" );
510  return 0;
511  }
512 
513  success = DuplicateHandle ( GetCurrentProcess (), GetCurrentThread (),
514  GetCurrentProcess (), & handle, 0, FALSE, DUPLICATE_SAME_ACCESS );
515  if ( ! success ) {
516  return 0;
517  }
518  {
519  unsigned long idForFormat = id;
520  sprintf ( name, "win%lx", idForFormat );
521  }
522  pParm = epicsThreadParmCreate ( name );
523  if ( pParm ) {
524  int win32ThreadPriority;
525 
526  pParm->handle = handle;
527  pParm->id = id;
528  win32ThreadPriority = GetThreadPriority ( pParm->handle );
529  assert ( win32ThreadPriority != THREAD_PRIORITY_ERROR_RETURN );
530  pParm->epicsPriority = epicsThreadGetOsiPriorityValue ( win32ThreadPriority );
531  success = TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, pParm );
532  if ( ! success ) {
533  epicsParmCleanupWIN32 ( pParm );
534  pParm = 0;
535  }
536  else {
537  EnterCriticalSection ( & pGbl->mutex );
538  ellAdd ( & pGbl->threadList, & pParm->node );
539  LeaveCriticalSection ( & pGbl->mutex );
540  }
541  }
542  return pParm;
543 }
544 
545 /*
546  * epicsThreadCreate ()
547  */
549  const char * pName,
550  EPICSTHREADFUNC pFunc, void * pParm,
551  const epicsThreadOpts *opts )
552 {
553  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
554  win32ThreadParam * pParmWIN32;
555  unsigned int stackSize;
556  int osdPriority;
557  DWORD wstat;
558  BOOL bstat;
559 
560  if ( ! pGbl ) {
561  return NULL;
562  }
563 
564  if (!opts) {
565  static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT;
566  opts = &opts_default;
567  }
568  stackSize = opts->stackSize;
569  if (stackSize <= epicsThreadStackBig)
570  stackSize = epicsThreadGetStackSize(stackSize);
571 
572  pParmWIN32 = epicsThreadParmCreate ( pName );
573  if ( pParmWIN32 == 0 ) {
574  return ( epicsThreadId ) pParmWIN32;
575  }
576  pParmWIN32->funptr = pFunc;
577  pParmWIN32->parm = pParm;
578  pParmWIN32->epicsPriority = opts->priority;
579  if(opts->joinable) {
580  pParmWIN32->joinable = 1;
581  epicsAtomicIncrIntT(&pParmWIN32->refcnt);
582  }
583 
584  {
585  unsigned threadId;
586  pParmWIN32->handle = (HANDLE) _beginthreadex (
587  0, stackSize, epicsWin32ThreadEntry,
588  pParmWIN32,
589  CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION,
590  & threadId );
591  if ( pParmWIN32->handle == 0 ) {
592  free ( pParmWIN32 );
593  return NULL;
594  }
595  /* weird win32 interface threadId parameter inconsistency */
596  pParmWIN32->id = ( DWORD ) threadId ;
597  }
598 
599  osdPriority = epicsThreadGetOsdPriorityValue (opts->priority);
600  bstat = SetThreadPriority ( pParmWIN32->handle, osdPriority );
601  if (!bstat) {
602  CloseHandle ( pParmWIN32->handle );
603  free ( pParmWIN32 );
604  return NULL;
605  }
606 
607  EnterCriticalSection ( & pGbl->mutex );
608  ellAdd ( & pGbl->threadList, & pParmWIN32->node );
609  LeaveCriticalSection ( & pGbl->mutex );
610 
611  wstat = ResumeThread ( pParmWIN32->handle );
612  if (wstat==0xFFFFFFFF) {
613  EnterCriticalSection ( & pGbl->mutex );
614  ellDelete ( & pGbl->threadList, & pParmWIN32->node );
615  LeaveCriticalSection ( & pGbl->mutex );
616  CloseHandle ( pParmWIN32->handle );
617  free ( pParmWIN32 );
618  return NULL;
619  }
620 
621  return ( epicsThreadId ) pParmWIN32;
622 }
623 
625 {
626  win32ThreadParam * pParmWIN32 = id;
627 
628  if(!id) {
629  /* no-op */
630  } else if(epicsAtomicCmpAndSwapIntT(&id->joinable, 1, 0)!=1) {
631  if(epicsThreadGetIdSelf()==id) {
632  fprintf(stderr, "Warning: %s thread self-join of unjoinable\n", pParmWIN32->pName);
633 
634  } else {
635  /* try to error nicely, however in all likelyhood de-ref of
636  * 'id' has already caused SIGSEGV as we are racing thread exit,
637  * which free's 'id'.
638  */
639  cantProceed("Error: %s thread not joinable.\n", pParmWIN32->pName);
640  }
641 
642  } else if(epicsThreadGetIdSelf() != id) {
643  DWORD status = WaitForSingleObject(pParmWIN32->handle, INFINITE);
644  if(status != WAIT_OBJECT_0) {
645  /* TODO: signal error? */
646  }
647 
648  epicsParmCleanupWIN32(pParmWIN32);
649  } else {
650  /* join self silently does nothing */
651  epicsParmCleanupWIN32(pParmWIN32);
652  }
653 }
654 
655 /*
656  * epicsThreadSuspendSelf ()
657  */
658 LIBCOM_API void epicsStdCall epicsThreadSuspendSelf ()
659 {
660  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
661  win32ThreadParam * pParm;
662  DWORD stat;
663 
664  assert ( pGbl );
665 
666  pParm = ( win32ThreadParam * )
667  TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS );
668  if ( ! pParm ) {
669  pParm = epicsThreadImplicitCreate ();
670  }
671  if ( pParm ) {
672  EnterCriticalSection ( & pGbl->mutex );
673  pParm->isSuspended = 1;
674  LeaveCriticalSection ( & pGbl->mutex );
675  }
676  stat = SuspendThread ( GetCurrentThread () );
677  assert ( stat != 0xFFFFFFFF );
678 }
679 
680 /*
681  * epicsThreadResume ()
682  */
683 LIBCOM_API void epicsStdCall epicsThreadResume ( epicsThreadId id )
684 {
685  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
686  win32ThreadParam * pParm = ( win32ThreadParam * ) id;
687  DWORD stat;
688 
689  assert ( pGbl );
690 
691  EnterCriticalSection ( & pGbl->mutex );
692 
693  stat = ResumeThread ( pParm->handle );
694  pParm->isSuspended = 0;
695 
696  LeaveCriticalSection ( & pGbl->mutex );
697 
698  assert ( stat != 0xFFFFFFFF );
699 }
700 
701 /*
702  * epicsThreadGetPriority ()
703  */
704 LIBCOM_API unsigned epicsStdCall epicsThreadGetPriority (epicsThreadId id)
705 {
706  win32ThreadParam * pParm = ( win32ThreadParam * ) id;
707  return pParm->epicsPriority;
708 }
709 
710 /*
711  * epicsThreadGetPrioritySelf ()
712  */
713 LIBCOM_API unsigned epicsStdCall epicsThreadGetPrioritySelf ()
714 {
715  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
716  win32ThreadParam * pParm;
717 
718  assert ( pGbl );
719 
720  pParm = ( win32ThreadParam * )
721  TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS );
722  if ( ! pParm ) {
723  pParm = epicsThreadImplicitCreate ();
724  }
725  if ( pParm ) {
726  return pParm->epicsPriority;
727  }
728  else {
729  int win32ThreadPriority =
730  GetThreadPriority ( GetCurrentThread () );
731  assert ( win32ThreadPriority != THREAD_PRIORITY_ERROR_RETURN );
732  return epicsThreadGetOsiPriorityValue ( win32ThreadPriority );
733  }
734 }
735 
736 /*
737  * epicsThreadSetPriority ()
738  */
739 LIBCOM_API void epicsStdCall epicsThreadSetPriority ( epicsThreadId id, unsigned priority )
740 {
741  win32ThreadParam * pParm = ( win32ThreadParam * ) id;
742  BOOL stat = SetThreadPriority ( pParm->handle, epicsThreadGetOsdPriorityValue (priority) );
743  assert (stat);
744 }
745 
746 /*
747  * epicsThreadIsEqual ()
748  */
749 LIBCOM_API int epicsStdCall epicsThreadIsEqual ( epicsThreadId id1, epicsThreadId id2 )
750 {
751  win32ThreadParam * pParm1 = ( win32ThreadParam * ) id1;
752  win32ThreadParam * pParm2 = ( win32ThreadParam * ) id2;
753  return ( id1 == id2 && pParm1->id == pParm2->id );
754 }
755 
756 /*
757  * epicsThreadIsSuspended ()
758  */
759 LIBCOM_API int epicsStdCall epicsThreadIsSuspended ( epicsThreadId id )
760 {
761  win32ThreadParam *pParm = ( win32ThreadParam * ) id;
762  DWORD exitCode;
763  BOOL stat;
764 
765  stat = GetExitCodeThread ( pParm->handle, & exitCode );
766  if ( stat ) {
767  if ( exitCode != STILL_ACTIVE ) {
768  return 1;
769  }
770  else {
771  return pParm->isSuspended;
772  }
773  }
774  else {
775  return 1;
776  }
777 }
778 
779 /*
780  * epicsThreadSleep ()
781  */
782 LIBCOM_API void epicsStdCall epicsThreadSleep ( double seconds )
783 {
784  static const unsigned mSecPerSec = 1000;
785  DWORD milliSecDelay;
786 
787  if ( seconds > 0.0 ) {
788  seconds *= mSecPerSec;
789  seconds += 0.99999999; /* 8 9s here is optimal */
790  milliSecDelay = ( seconds >= INFINITE ) ?
791  INFINITE - 1 : ( DWORD ) seconds;
792  }
793  else { /* seconds <= 0 or NAN */
794  milliSecDelay = 0u;
795  }
796  Sleep ( milliSecDelay );
797 }
798 
799 /*
800  * epicsThreadSleepQuantum ()
801  */
802 double epicsStdCall epicsThreadSleepQuantum ()
803 {
804  /*
805  * Its worth noting here that the sleep quantum on windows can
806  * mysteriously get better. I eventually tracked this down to
807  * codes that call timeBeginPeriod(1). Calling timeBeginPeriod()
808  * specifying a better timer resolution also increases the interrupt
809  * load. This appears to be related to java applet activity.
810  * The function timeGetDevCaps can tell us the range of periods
811  * that can be specified to timeBeginPeriod, but alas there
812  * appears to be no way to find out what the value of the global
813  * minimum of all timeBeginPeriod calls for all processes is.
814  */
815  static const double secPerTick = 100e-9;
816  DWORD adjustment;
817  DWORD delay;
818  BOOL disabled;
819  BOOL success;
820 
821  success = GetSystemTimeAdjustment (
822  & adjustment, & delay, & disabled );
823  if ( success ) {
824  return delay * secPerTick;
825  }
826  else {
827  return 0.0;
828  }
829 }
830 
831 /*
832  * epicsThreadGetIdSelf ()
833  */
834 LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf (void)
835 {
836  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
837  win32ThreadParam * pParm;
838 
839  assert ( pGbl );
840 
841  pParm = ( win32ThreadParam * ) TlsGetValue (
843  if ( ! pParm ) {
844  pParm = epicsThreadImplicitCreate ();
845  assert ( pParm ); /* very dangerous to allow non-unique thread id into use */
846  }
847  return ( epicsThreadId ) pParm;
848 }
849 
850 LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetId ( const char * pName )
851 {
852  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
853  win32ThreadParam * pParm;
854 
855  if ( ! pGbl ) {
856  return 0;
857  }
858 
859  EnterCriticalSection ( & pGbl->mutex );
860 
861  for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
862  pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {
863  if ( pParm->pName ) {
864  if ( strcmp ( pParm->pName, pName ) == 0 ) {
865  break;
866  }
867  }
868  }
869 
870  LeaveCriticalSection ( & pGbl->mutex );
871 
872  /* !!!! warning - the thread parm could vanish at any time !!!! */
873 
874  return ( epicsThreadId ) pParm;
875 }
876 
877 
878 /*
879  * epicsThreadGetNameSelf ()
880  */
881 LIBCOM_API const char * epicsStdCall epicsThreadGetNameSelf (void)
882 {
883  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
884  win32ThreadParam * pParm;
885 
886  if ( ! pGbl ) {
887  return "thread library not initialized";
888  }
889 
890  pParm = ( win32ThreadParam * )
891  TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS );
892  if ( ! pParm ) {
893  pParm = epicsThreadImplicitCreate ();
894  }
895 
896  if ( pParm ) {
897  if ( pParm->pName ) {
898  return pParm->pName;
899  }
900  }
901  return "anonymous";
902 }
903 
904 /*
905  * epicsThreadGetName ()
906  */
907 LIBCOM_API void epicsStdCall epicsThreadGetName (
908  epicsThreadId id, char * pName, size_t size )
909 {
910  win32ThreadParam * pParm = ( win32ThreadParam * ) id;
911 
912  if ( size ) {
913  size_t sizeMinusOne = size-1;
914  strncpy ( pName, pParm->pName, sizeMinusOne );
915  pName [sizeMinusOne] = '\0';
916  }
917 }
918 
919 /*
920  * epics_GetThreadPriorityAsString ()
921  */
922 static const char * epics_GetThreadPriorityAsString ( HANDLE thr )
923 {
924  const char * pPriName = "?????";
925  switch ( GetThreadPriority ( thr ) ) {
926  case THREAD_PRIORITY_TIME_CRITICAL:
927  pPriName = "tm-crit";
928  break;
929  case THREAD_PRIORITY_HIGHEST:
930  pPriName = "high";
931  break;
932  case THREAD_PRIORITY_ABOVE_NORMAL:
933  pPriName = "normal+";
934  break;
935  case THREAD_PRIORITY_NORMAL:
936  pPriName = "normal";
937  break;
938  case THREAD_PRIORITY_BELOW_NORMAL:
939  pPriName = "normal-";
940  break;
941  case THREAD_PRIORITY_LOWEST:
942  pPriName = "low";
943  break;
944  case THREAD_PRIORITY_IDLE:
945  pPriName = "idle";
946  break;
947  }
948  return pPriName;
949 }
950 
951 /*
952  * epicsThreadShowInfo ()
953  */
954 static void epicsThreadShowInfo ( epicsThreadId id, unsigned level )
955 {
956  win32ThreadParam * pParm = ( win32ThreadParam * ) id;
957 
958  if ( pParm ) {
959  unsigned long idForFormat = pParm->id;
960  fprintf ( epicsGetStdout(), "%-15s %-8p %-8lx %-9u %-9s %-7s", pParm->pName,
961  (void *) pParm, idForFormat, pParm->epicsPriority,
962  epics_GetThreadPriorityAsString ( pParm->handle ),
963  epicsThreadIsSuspended ( id ) ? "suspend" : "ok" );
964  if ( level ) {
965  fprintf (epicsGetStdout(), " %-8p %-8p ",
966  (void *) pParm->handle, (void *) pParm->parm );
967  }
968  }
969  else {
970  fprintf (epicsGetStdout(),
971  "NAME EPICS-ID WIN32-ID EPICS-PRI WIN32-PRI STATE " );
972  if ( level ) {
973  fprintf (epicsGetStdout(), " HANDLE FUNCTION PARAMETER" );
974  }
975  }
976  fprintf (epicsGetStdout(),"\n" );
977 }
978 
979 /*
980  * epicsThreadMap ()
981  */
983 {
984  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
985  win32ThreadParam * pParm;
986 
987  if ( ! pGbl ) {
988  return;
989  }
990 
991  EnterCriticalSection ( & pGbl->mutex );
992 
993  for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
994  pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {
995  func ( ( epicsThreadId ) pParm );
996  }
997 
998  LeaveCriticalSection ( & pGbl->mutex );
999 }
1000 
1001 /*
1002  * epicsThreadShowAll ()
1003  */
1004 LIBCOM_API void epicsStdCall epicsThreadShowAll ( unsigned level )
1005 {
1006  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
1007  win32ThreadParam * pParm;
1008 
1009  if ( ! pGbl ) {
1010  return;
1011  }
1012 
1013  EnterCriticalSection ( & pGbl->mutex );
1014 
1015  epicsThreadShowInfo ( 0, level );
1016  for ( pParm = ( win32ThreadParam * ) ellFirst ( & pGbl->threadList );
1017  pParm; pParm = ( win32ThreadParam * ) ellNext ( & pParm->node ) ) {
1018  epicsThreadShowInfo ( ( epicsThreadId ) pParm, level );
1019  }
1020 
1021  LeaveCriticalSection ( & pGbl->mutex );
1022 }
1023 
1024 /*
1025  * epicsThreadShow ()
1026  */
1027 LIBCOM_API void epicsStdCall epicsThreadShow ( epicsThreadId id, unsigned level )
1028 {
1029  epicsThreadShowInfo ( 0, level );
1030  epicsThreadShowInfo ( id, level );
1031 }
1032 
1033 /*
1034  * epicsThreadOnce ()
1035  */
1036 LIBCOM_API void epicsStdCall epicsThreadOnce (
1037  epicsThreadOnceId *id, void (*func)(void *), void *arg )
1038 {
1039  static struct epicsThreadOSD threadOnceComplete;
1040  #define EPICS_THREAD_ONCE_DONE & threadOnceComplete
1041  win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal ();
1042 
1043  assert ( pGbl );
1044 
1045  EnterCriticalSection ( & pGbl->mutex );
1046 
1047  if ( *id != EPICS_THREAD_ONCE_DONE ) {
1048  if ( *id == EPICS_THREAD_ONCE_INIT ) { /* first call */
1049  *id = epicsThreadGetIdSelf(); /* mark active */
1050  LeaveCriticalSection ( & pGbl->mutex );
1051  func ( arg );
1052  EnterCriticalSection ( & pGbl->mutex );
1053  *id = EPICS_THREAD_ONCE_DONE; /* mark done */
1054  } else if ( *id == epicsThreadGetIdSelf() ) {
1055  LeaveCriticalSection ( & pGbl->mutex );
1056  cantProceed( "Recursive epicsThreadOnce() initialization\n" );
1057  } else
1058  while ( *id != EPICS_THREAD_ONCE_DONE ) {
1059  /* Another thread is in the above func(arg) call. */
1060  LeaveCriticalSection ( & pGbl->mutex );
1062  EnterCriticalSection ( & pGbl->mutex );
1063  }
1064  }
1065  LeaveCriticalSection ( & pGbl->mutex );
1066 }
1067 
1068 /*
1069  * epicsThreadPrivateCreate ()
1070  */
1072 {
1073  epicsThreadPrivateOSD *p = ( epicsThreadPrivateOSD * ) malloc ( sizeof ( *p ) );
1074  if ( p ) {
1075  p->key = TlsAlloc ();
1076  if ( p->key == 0xFFFFFFFF ) {
1077  free ( p );
1078  p = 0;
1079  }
1080  }
1081  return p;
1082 }
1083 
1084 /*
1085  * epicsThreadPrivateDelete ()
1086  */
1087 LIBCOM_API void epicsStdCall epicsThreadPrivateDelete ( epicsThreadPrivateId p )
1088 {
1089  BOOL stat = TlsFree ( p->key );
1090  assert ( stat );
1091  free ( p );
1092 }
1093 
1094 /*
1095  * epicsThreadPrivateSet ()
1096  */
1097 LIBCOM_API void epicsStdCall epicsThreadPrivateSet ( epicsThreadPrivateId pPvt, void *pVal )
1098 {
1099  BOOL stat = TlsSetValue ( pPvt->key, (void *) pVal );
1100  assert (stat);
1101 }
1102 
1103 /*
1104  * epicsThreadPrivateGet ()
1105  */
1106 LIBCOM_API void * epicsStdCall epicsThreadPrivateGet ( epicsThreadPrivateId pPvt )
1107 {
1108  return ( void * ) TlsGetValue ( pPvt->key );
1109 }
1110 
1111 /*
1112  * epicsThreadGetCPUs ()
1113  */
1114 LIBCOM_API int epicsThreadGetCPUs ( void )
1115 {
1116  SYSTEM_INFO sysinfo;
1117  GetSystemInfo(&sysinfo);
1118  if (sysinfo.dwNumberOfProcessors > 0)
1119  return sysinfo.dwNumberOfProcessors;
1120  return 1;
1121 }
1122 
1123 #ifdef TEST_CODES
1124 void testPriorityMapping ()
1125 {
1126  unsigned i;
1127 
1129  printf ("%u %d\n", i, epicsThreadGetOsdPriorityValue (i) );
1130  }
1131 
1132  for (i=0; i<osdPriorityStateCount; i++) {
1133  printf ("%d %u\n", osdPriorityList[i], epicsThreadGetOsiPriorityValue(osdPriorityList[i]));
1134  }
1135  return 0;
1136 }
1137 #endif
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass stackSizeClass)
Definition: osdThread.c:466
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadHighestPriorityLevelBelow(unsigned int priority, unsigned *pPriorityJustBelow)
Definition: osdThread.c:740
LIBCOM_API int epicsThreadGetCPUs(void)
Definition: osdThread.c:990
LIBCOM_API epicsThreadPrivateId epicsStdCall epicsThreadPrivateCreate(void)
Definition: osdThread.c:934
#define osdRealtimePriorityStateCount
Definition: osdThread.c:77
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
Definition: osdThread.c:790
HANDLE handle
Definition: osdThread.c:49
struct epicsThreadOSD win32ThreadParam
LIBCOM_API void epicsStdCall epicsThreadExitMain(void)
Definition: osdThread.c:683
int epicsThreadGetOsiPriorityValue(int ossPriority)
Definition: osdThread.c:85
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
epicsThreadBooleanStatus
Definition: epicsThread.h:93
#define FALSE
Definition: dbDefs.h:32
pvd::Status status
An EPICS-specific replacement for ANSI C&#39;s assert.
#define STACK_SIZE_PARAM_IS_A_RESERVATION
Definition: osdThread.c:64
LIBCOM_API void epicsExitCallAtThreadExits(void)
Internal routine that runs the registered thread exit routines.
Definition: epicsExit.c:121
int i
Definition: scan.c:967
EPICSTHREADFUNC funptr
Definition: osdThread.c:50
ELLNODE node
Definition: osdThread.h:24
LIBCOM_API void epicsThreadRealtimeLock(void)
Definition: osdThread.c:425
struct epicsThreadPrivateOSD epicsThreadPrivateOSD
LIBCOM_API double epicsStdCall epicsThreadSleepQuantum()
Query a value approximating the OS timer/scheduler resolution.
Definition: osdThread.c:981
void(* EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id)
Definition: epicsThread.h:302
#define printf
Definition: epicsStdio.h:41
char isSuspended
Definition: osdThread.c:55
#define NULL
Definition: catime.c:38
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT(int *pTarget, int oldVal, int newVal)
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadLowestPriorityLevelAbove(unsigned int priority, unsigned *pPriorityJustAbove)
Definition: osdThread.c:757
unsigned int joinable
Definition: epicsThread.h:158
ELLLIST threadList
Definition: osdThread.c:42
void setThreadName(DWORD dwThreadID, LPCSTR szThreadName)
#define EPICS_THREAD_ONCE_DONE
LIBCOM_API void epicsStdCall epicsThreadPrivateSet(epicsThreadPrivateId id, void *value)
Definition: osdThread.c:961
DWORD tlsIndexThreadLibraryEPICS
Definition: osdThread.c:43
LIBCOM_API void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level)
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg)
Definition: osdThread.c:487
A doubly-linked list library.
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
FILE *epicsStdCall epicsGetStdout(void)
Definition: epicsStdio.c:47
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
epicsThreadStackSizeClass
Definition: epicsThread.h:89
CRITICAL_SECTION mutex
Definition: osdThread.c:41
#define epicsThreadPriorityMax
Definition: epicsThread.h:71
LIBCOM_API void epicsStdCall * epicsThreadPrivateGet(epicsThreadPrivateId id)
Definition: osdThread.c:973
epicsThreadId epicsThreadCreateOpt(const char *name, EPICSTHREADFUNC funptr, void *parm, const epicsThreadOpts *opts)
Allocate and start a new OS thread.
Definition: osdThread.c:529
unsigned int stackSize
Definition: epicsThread.h:154
void * parm
Definition: osdThread.c:51
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPrioritySelf(void)
Definition: osdThread.c:707
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetId(const char *name)
Definition: osdThread.c:826
Extended replacement for the Posix exit and atexit routines.
LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
Definition: osdThread.c:664
LIBCOM_API void epicsStdCall epicsThreadShow(epicsThreadId showThread, unsigned int level)
Definition: osdThread.c:903
LIBCOM_API int epicsStdCall epicsThreadIsSuspended(epicsThreadId pthreadInfo)
Definition: osdThread.c:784
List node type.
Definition: ellLib.h:45
LIBCOM_API void epicsStdCall epicsThreadResume(epicsThreadOSD *pthreadInfo)
Definition: osdThread.c:676
LIBCOM_API void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func)
Definition: osdThread.c:864
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT(int *pTarget)
#define STACK_SIZE(f)
char * pName
Definition: osdThread.c:52
void done(int k)
Definition: antelope.c:77
#define TRUE
Definition: dbDefs.h:27
unsigned int priority
Definition: epicsThread.h:150
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
LIBCOM_API void epicsStdCall epicsThreadShowAll(unsigned int level)
Definition: osdThread.c:883
#define EPICS_THREAD_OPTS_INIT
Definition: epicsThread.h:167
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT(int *pTarget)
LIBCOM_API void cantProceed(const char *msg,...)
Definition: cantProceed.c:54
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPriority(epicsThreadId pthreadInfo)
Definition: osdThread.c:701
void epicsThreadMustJoin(epicsThreadId id)
Definition: osdThread.c:632
Routines for code that can&#39;t continue or return after an error.
unsigned epicsPriority
Definition: osdThread.c:54
#define stderr
Definition: epicsStdio.h:32
LIBCOM_API void osdThreadHooksRun(epicsThreadId id)
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
Definition: osdThread.c:810
const unsigned mSecPerSec
Definition: fdManager.cpp:34
LIBCOM_API void epicsStdCall epicsThreadSetPriority(epicsThreadId pthreadInfo, unsigned int priority)
Definition: osdThread.c:713
List header type.
Definition: ellLib.h:56
C++ and C descriptions for a thread.
epicsTimeStamp started
Definition: epicsUnitTest.c:52
LIBCOM_API void epicsStdCall epicsThreadPrivateDelete(epicsThreadPrivateId id)
Definition: osdThread.c:950
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
#define epicsThreadPriorityMin
Definition: epicsThread.h:72
#define osdOrdinaryPriorityStateCount
Definition: osdThread.c:67
void(* EPICSTHREADFUNC)(void *parm)
Definition: epicsThread.h:66
struct win32ThreadGlobal win32ThreadGlobal
LIBCOM_API const char epicsStdCall * epicsThreadGetNameSelf()
Definition: osdThread.c:846
LIBCOM_API int epicsStdCall epicsThreadIsEqual(epicsThreadId p1, epicsThreadId p2)
Definition: osdThread.c:776
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89
LIBCOM_API void epicsStdCall epicsThreadGetName(epicsThreadId pthreadInfo, char *name, size_t size)
Definition: osdThread.c:857