(file) Return to injector.cpp CVS log (file) (dir) Up to [OMI] / omi / nits / injector

  1 krisbash 1.1 #include <nits/base/Globals.h>
  2              
  3              #ifdef _MSC_VER
  4                  #include <psapi.h>
  5              #else
  6                  #include <stdio.h>
  7              #endif
  8              #include <pal/palcommon.h>
  9              #include <pal/process.h>
 10              #include <pal/strings.h>
 11              #include <iostream>
 12              #include <fstream>
 13              
 14              
 15              using namespace std;
 16              #if defined(_MSC_VER)
 17              # pragma warning(disable : 4702)
 18              #endif
 19              
 20              struct SharedSegmentHeader
 21              {
 22 krisbash 1.1     union
 23                  {
 24                      ptrdiff_t status;
 25                      double doubleAlignment;
 26                  };
 27              };
 28              
 29              PAL_Char *Copy(_In_opt_z_ const PAL_Char * str)
 30              {
 31                  if (str == NULL)
 32                  {
 33                      return NULL;
 34                  }
 35              
 36                  int length = (int)Tcslen(str);
 37                  PAL_Char *copy = new PAL_Char[length + 1];
 38              
 39                  if(!copy)
 40                  {
 41                      return NULL;
 42                  }
 43 krisbash 1.1     
 44                  Tcslcpy(copy, str, length + 1);
 45              
 46                  return copy;
 47              }
 48              
 49              PSTR ConvertStringToA(_In_opt_z_ const wchar_t *buf)
 50              {
 51                  if(buf == NULL)
 52                      return NULL;
 53              
 54              #ifdef _MSC_VER
 55                  int size = WideCharToMultiByte(CP_THREAD_ACP, 0, buf, -1, NULL, NULL, NULL, NULL);
 56              #else
 57                  int size = wcstombs(NULL, buf, 0);
 58              #endif
 59                  if (size == 0)
 60                  {
 61                      return NULL;
 62                  }
 63              
 64 krisbash 1.1 #ifdef _MSC_VER
 65                  PSTR ansibuf = new char[size];
 66                  size = WideCharToMultiByte(CP_THREAD_ACP, 0, buf, -1, ansibuf, size, NULL, NULL);
 67              #else
 68                  PSTR ansibuf = new char[size + 1];
 69                  size = wcstombs(ansibuf, buf, size + 1);
 70              #endif
 71                  if (size == 0)
 72                  {
 73                      delete [] ansibuf;
 74                      return NULL;
 75                  }
 76              #ifndef _MSC_VER
 77                  else
 78                  {
 79                      ansibuf[size] = '\0';
 80                  }
 81              #endif
 82              
 83                  return ansibuf;
 84              }
 85 krisbash 1.1 
 86              PWSTR ConvertStringToW(_In_opt_z_ const char *buf)
 87              {
 88                  if(buf == NULL)
 89                      return NULL;
 90              
 91              #ifdef _MSC_VER
 92                  int size = MultiByteToWideChar(CP_THREAD_ACP, 0, buf, -1, NULL, NULL);
 93              #else
 94                  int size = mbstowcs(0, buf, 0);
 95              #endif
 96                  if (size == 0)
 97                  {
 98                      return NULL;
 99                  }
100              
101              
102              
103              #ifdef _MSC_VER
104                  PWSTR widebuf = new wchar_t[size];
105                  size = MultiByteToWideChar(CP_THREAD_ACP, 0,
106 krisbash 1.1             buf, -1, widebuf, size);
107              #else
108                  PWSTR widebuf = new wchar_t[size + 1];
109                  size = mbstowcs(widebuf, buf, size);
110              #endif
111                  if (size == 0)
112                  {
113                      delete [] widebuf;
114                      return NULL;
115                  }
116              #ifndef _MSC_VER
117                  else
118                  {
119                      widebuf[size] = L'\0';
120                  }
121              #endif
122              
123                  return widebuf;
124              }
125              
126              char *ConvertPalCharToStringA(_In_opt_z_ const PAL_Char *buf)
127 krisbash 1.1 {
128              #ifdef CONFIG_ENABLE_WCHAR
129                  return ConvertStringToA(buf);
130              #else
131                  return Copy(buf);
132              #endif
133              
134              }
135              
136              PAL_Char *ConvertStringAToPalChar(_In_opt_z_ const char *buf)
137              {
138                  if(buf == NULL)
139                      return NULL;
140              
141              #ifdef CONFIG_ENABLE_WCHAR
142                  return ConvertStringToW(buf);
143              #else
144                  return Copy(buf);
145              #endif
146              }
147              
148 krisbash 1.1 namespace TestSystem {
149              
150              Fault::Fault() : m_lock(0)
151              {
152                  Reset(CallSite_NONE, 0, false);
153              
154                  m_mainThread = Thread_ID();;
155                  m_minimumAttemptDifferentThread = 0;
156              }
157              
158              void Fault::Reset(int site, int iteration, bool breakOnFault)
159              {
160                  m_site = site;
161                  m_iteration = iteration;
162                  m_attempt = 0;
163              
164                  m_break = breakOnFault;
165                  m_faulted = false;
166                  m_filtered = false;
167                  m_hit = CallSite_NONE;
168                  m_line = 0;
169 krisbash 1.1     m_file[0] = '\0';
170              
171                  m_faultedAttempt = 0;
172                  m_firstAttemptDifferentThread = 0;
173              }
174              
175              Globals::Globals()
176                  : m_version(SharedMemoryVersion),
177                    m_runLock(0),
178                    m_attachLock(0),
179                    m_pipeLock(FALSE),
180                    m_pipeChars(0)
181              {
182                  m_pipe[0] = '\0';
183                  m_debugger[0] = '\0';
184                  m_binaryFilter[0] = '\0';
185                  m_binaryTarget[0] = '\0';
186              
187                  for (int i = 0; i < InjectorListSize; i++)
188                      m_injectors[i].process = 0;
189              
190 krisbash 1.1     Reset();
191              
192                  for (int i = 0; i < ResultCount; i++)
193                  {
194                      m_statistics[i] = 0;
195                  }
196              }
197              
198              Globals::~Globals()
199              {
200              }
201              
202              void Globals::Reset()
203              {
204                  m_result = Skipped;
205              
206                  m_stopReportingIgnoredErrors = false;
207              
208                  m_config.traces = NitsTraceAllTests;
209                  m_config.mode = NitsTestCompoundFault;
210                  m_config.breakFault = false;
211 krisbash 1.1     m_config.breakAssert = false;
212                  m_config.skipFlakyTests = false;
213              
214                  m_simAuto.Reset(CallSite_NONE, 0, false);
215                  m_simManual.Reset(CallSite_NONE, 0, false);
216              
217                  m_faultError = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
218                  m_faultEvent[0] = L'\0';
219                  m_debugger[0] = L'\0';
220                  m_binaryFilter[0] = '\0';
221                  m_binaryTarget[0] = '\0';
222              }
223              
224              } //namespace TestSystem
225              
226              static void PatchBinary(
227                  _In_z_ PAL_Char *binary)
228              {
229                  Shlib *library = NULL;
230                  Shlib *framework;
231                  NitsFT *target;
232 krisbash 1.1     NitsFT *source;
233                  ptrdiff_t *targetNitsPresence = NULL;
234              
235                  //printf("\nPatching binary %s\n", binary);
236                  
237                  library = Shlib_Open_Injected(binary, NitsReservedCallSite());
238              
239                  if (library == NULL)
240                  {
241                      return;
242                  }
243              
244                  target = (NitsFT *)Shlib_Sym(library, "NITS_STUB");
245                  if (target == NULL)
246                  {
247                      Shlib_Close(library);
248                      return;
249                  }
250              
251                  targetNitsPresence = (ptrdiff_t *)Shlib_Sym(library, "NITS_PRESENCE_STUB");
252                  if (targetNitsPresence == NULL)
253 krisbash 1.1     {
254                      Shlib_Close(library);
255                      return;
256                  }
257              
258              #ifdef _MSC_VER
259                  framework = Shlib_Open_Injected(PAL_T("nitsdll.dll"), NitsReservedCallSite());
260              #else
261                  framework = Shlib_Open_Injected(PAL_T("libnits.so"), NitsReservedCallSite());
262              #endif
263                  if (framework == NULL)
264                  {
265                      return;
266                  }
267              
268                  source = (NitsFT *)Shlib_Sym(framework, "NITS_IMPL");
269                  if (source == NULL)
270                  {
271                      Shlib_Close(library);
272                      return;
273                  }
274 krisbash 1.1 
275              #ifdef _MSC_VER
276                  // changing the protection on the page to execute read write so that 
277                  // injector can patch the NITS stub table with the NITS API table values
278                  DWORD oldProtection = 0;
279                  if(VirtualProtect(target, sizeof(NitsFT), PAGE_EXECUTE_READWRITE, &oldProtection) == 0)
280                  {
281                      Shlib_Close(library);
282                      return;
283                  }
284              #endif
285              
286                  memcpy(target, source, sizeof(NitsFT));
287              
288                  Atomic_Swap(targetNitsPresence, NitsActive);
289              
290                  Shlib_Close(library);
291              }
292              
293              static unsigned DoesBinaryMatch(
294                  _In_ PAL_Char *list,
295 krisbash 1.1     _In_z_ PAL_Char *name)
296              {
297                  for (;;)
298                  {
299              #ifdef _MSC_VER
300              #pragma prefast(push)
301              #pragma prefast (disable: 26006)
302              #endif
303                      if (*list == '\0')
304                          return FALSE;
305                      
306                      // This is to enable specifying a substring of the 
307                      // target string; it is useful when all your target dll have some common substring
308                      if(*list == PAL_T('*'))
309                      {
310                          list++;
311                          if(Tcsstr(name, list))
312                              return TRUE;
313                      }
314                      else if (Tcscasecmp(list, name) == 0)
315                          return TRUE;
316 krisbash 1.1 
317              #ifdef _MSC_VER
318              #pragma prefast(pop)
319              #endif
320                      list += Tcslen(list) + 1;
321                  }
322              }
323              
324              #ifdef _MSC_VER
325              typedef HMODULE LoadedModule;
326              #else
327              typedef struct _LoadedModule
328              {
329                  PAL_Char *modulePath;
330                  PAL_Char *moduleBaseName;
331              } LoadedModule;
332              #endif
333              
334              BOOL EnumProcessModulesHelper(
335                      _Out_writes_bytes_(cb) LoadedModule *lphModule,
336                      _In_ DWORD cb,
337 krisbash 1.1         _Out_ LPDWORD lpcbNeeded)
338              {
339              #ifdef _MSC_VER
340                  return EnumProcessModules(GetCurrentProcess(), lphModule, cb, lpcbNeeded);
341              #else
342                  char buf[MAX_PATH] = "/proc/";
343                  DWORD count = 0;
344                  DWORD maxCount = cb / sizeof(LoadedModule);
345              
346                  ostringstream s;
347                  string convertedString;
348                  s << Process_ID();
349                  convertedString = s.str();
350                  Strlcpy(buf + 6, convertedString.c_str(), MAX_PATH - 6);
351                  Strlcpy(buf + Strlen(buf), "/maps", 6);
352                  
353                  ifstream file(buf);
354              
355                  if (!file.good())
356                  {
357                      Tprintf(PAL_T("ERROR: maps file could not be loaded for current process"));
358 krisbash 1.1         return FALSE;
359                  }
360                  while (file.good() && (count < maxCount))
361                  {
362                      char *startOfPath = NULL;
363                      PAL_Char *nextFwdSlash = NULL;
364                      PAL_Char *currentBaseName = NULL;
365                      lphModule[count].modulePath = NULL;
366                      lphModule[count].moduleBaseName = NULL;
367                      file >> buf;
368                      startOfPath = strchr(buf, '/');
369                      if(startOfPath)
370                      {
371                          lphModule[count].modulePath = ConvertStringAToPalChar(startOfPath);
372                          if(lphModule[count].modulePath == NULL)
373                          {
374                              Tprintf(PAL_T("ERROR: could not allocate memory while enumerating modules"));
375                              return FALSE;
376                          }
377              
378                          currentBaseName = lphModule[count].modulePath;
379 krisbash 1.1             nextFwdSlash = Tcschr(currentBaseName, PAL_T('/'));
380                          while(nextFwdSlash && nextFwdSlash[1] != PAL_T('\0'))
381                          {
382                              currentBaseName = nextFwdSlash + 1;
383                              nextFwdSlash = Tcschr(currentBaseName, PAL_T('/'));
384                          }
385                          lphModule[count].moduleBaseName = currentBaseName;
386              
387                          count++;
388                      }
389                  }
390              
391                  *lpcbNeeded = count * sizeof(LoadedModule);
392                  return TRUE;
393              #endif
394              }
395              
396              DWORD GetModuleBaseNameHelper(
397                      _In_opt_ LoadedModule hModule,
398                      _Out_writes_z_(nSize) PAL_Char *lpBaseName,
399                      _In_ DWORD nSize)
400 krisbash 1.1 {
401              #ifdef _MSC_VER
402                  return GetModuleBaseName(GetCurrentProcess(), hModule, lpBaseName, nSize);
403              #else
404                  if(hModule.moduleBaseName == NULL)
405                      return 0;
406              
407                  return Tcslcpy(lpBaseName, hModule.moduleBaseName, nSize);
408              #endif
409              }
410              
411              void ProcessPatches(TestSystem::Globals *globals)
412              {
413                  if (globals->m_runLock == 0)
414                      return;
415              
416                  unsigned isMatch = 0;
417                  /* Sweep through the list of loaded modules. */
418                  LoadedModule modules[200];
419                  DWORD size = 0;
420                  unsigned count = 0;
421 krisbash 1.1     unsigned i;
422                  PAL_Char name[MAX_PATH];
423              
424                  if (EnumProcessModulesHelper(modules, sizeof(modules), &size) == FALSE)
425                  {
426                      return;
427                  }
428              
429                  count = size / sizeof(LoadedModule);
430              
431                  if (globals->m_binaryFilter[0] == '\0')
432                  {
433                      /* There is no filter. Match target binaries in any process. */
434                      isMatch = 1;
435                  }
436                  else for (i = 0; i < count; i++)
437                  {
438                      if(GetModuleBaseNameHelper(modules[i], name, MAX_PATH) == 0)
439                          continue;
440                      
441                      if (DoesBinaryMatch(globals->m_binaryFilter, name))
442 krisbash 1.1         {
443                          /* Found one of the filter modules. */
444                          isMatch = 1;
445                          break;
446                      }
447                  }
448              
449                  if (isMatch == 0)
450                      goto Cleanup;
451              
452                  for (i = 0; i < count; i++)
453                  {
454                      if(GetModuleBaseNameHelper(modules[i], name, MAX_PATH) == 0)
455                          continue;
456                      
457                      if (DoesBinaryMatch(globals->m_binaryTarget, name))
458                      {
459                          /* Found a target module. Trap this! */
460                          PatchBinary(name);
461                      }
462                  }
463 krisbash 1.1     
464              Cleanup:
465              #ifndef _MSC_VER
466                  if(count != 0)
467                  {
468                      for(i = 0; i < count; i++)
469                      {
470                          if(modules[i].modulePath != NULL)
471                          {
472                              delete [] (modules[i].modulePath);
473                          }
474                      }
475                  }
476              #endif
477                  return;
478              }
479              
480              static TestSystem::Globals g_tempGlobals;
481              
482              static volatile ptrdiff_t g_signalSemaphoreDeleted = 0;
483              static NamedSem g_signalSemaphore;
484 krisbash 1.1 static PAL_Boolean g_signalSemaphoreInitialized = PAL_FALSE;
485              static NamedSem g_waitSemaphore;
486              static PAL_Boolean g_waitSemaphoreInitialized = PAL_FALSE;
487              static NamedSem g_lockSemaphore;
488              static PAL_Boolean g_lockSemaphoreInitialized = PAL_FALSE;
489              static TestSystem::Globals *g_globals = NULL;
490              static TestSystem::InjectorTarget *g_injectorTarget = NULL;
491              static Shmem g_mapping;
492              volatile ptrdiff_t *g_status = NULL;
493              static volatile ptrdiff_t s_injectorStopping;
494              
495              PAL_Boolean TryMarkingSignalSemaphoreForDeletion()
496              {
497                  return (Atomic_CompareAndSwap(&g_signalSemaphoreDeleted, 0, 1) == 0);
498              }
499              
500              void MarkSignalSemaphoreAlive()
501              {
502                  Atomic_Swap(&g_signalSemaphoreDeleted, 0);
503              }
504              
505 krisbash 1.1 unsigned long InjectorSetup()
506              {
507                  void *start;
508                  size_t bytes = sizeof(TestSystem::Globals) + sizeof(SharedSegmentHeader);
509                  PAL_Char nameSignal[128] = PAL_T(CONFIG_SEMNAMELOCALPREFIX) PAL_T("NitsInjectorIn_");
510                  PAL_Char nameWait[128] = PAL_T(CONFIG_SEMNAMELOCALPREFIX) PAL_T("NitsInjectorOut_");
511                  PAL_Char conversionBuf[64] = PAL_T("");    
512                  const PAL_Char *convertedStr = NULL;
513                  size_t convertedSize = 0;
514                  // the lock semaphore is kept non-windows only since the issue with the injector is not observed on windows
515                  PAL_Char nameLock[128] = PAL_T(CONFIG_SEMNAMELOCALPREFIX) PAL_T("NitsInjectorLock_");    
516              
517                  const PAL_Char globalMappingName[] = PAL_T(CONFIG_SHMNAMEGLOBALPREFIX) PAL_T("NitsGlobalData");
518              
519                  s_injectorStopping = 0;
520              
521                  MarkSignalSemaphoreAlive();
522                  
523                  if(Shmem_Open(&g_mapping, globalMappingName, SHMEM_ACCESS_READWRITE, SHMEM_USER_ACCESS_ALLOW_ALL, bytes) != NO_ERROR)
524                  {
525              #ifdef _MSC_VER
526 krisbash 1.1         return GetLastError();
527              #else
528                      return ERROR_OUTOFMEMORY;
529              #endif
530                  }
531                  
532                  start = Shmem_Map(&g_mapping, SHMEM_ACCESS_READWRITE, 0, bytes);
533                  if (start == NULL)
534                  {
535              #ifdef _MSC_VER
536                      return GetLastError();
537              #else
538                      return ERROR_OUTOFMEMORY;
539              #endif
540                  }
541              
542                  /* The shared memory is mapped. Make sure the contents are initialized. */
543                  g_status = (ptrdiff_t *)start;
544                  g_globals = (TestSystem::Globals *)((char*)g_status + sizeof(SharedSegmentHeader));
545                  if (Atomic_CompareAndSwap(g_status, TestSystem::Unloaded, TestSystem::Loading) == TestSystem::Unloaded)
546                  {
547 krisbash 1.1         memcpy(g_globals, &g_tempGlobals, sizeof(TestSystem::Globals));
548                      *g_status = TestSystem::Loaded;
549                  }
550              
551                  while (*g_status != TestSystem::Loaded)
552                  {
553                      Sleep_Milliseconds(10);
554                  }
555              
556                  /* The shared memory space is now initialized. */
557                  /* Set up the semaphores used to trigger patching. */
558              
559                  if (g_globals->m_version != TestSystem::SharedMemoryVersion)
560                  {
561                      g_globals = NULL;
562                      return 0;
563                  }
564              
565                  TcsFromUInt64(conversionBuf, Process_ID(), &convertedStr, &convertedSize);
566                  Tcscat(nameSignal, 128, convertedStr);
567                  Tcscat(nameWait, 128, convertedStr);
568 krisbash 1.1     
569                  /* The semaphre signalled by the product to us. */
570                  g_signalSemaphoreInitialized = (0 == NamedSem_Open_Injected(&g_signalSemaphore, SEM_USER_ACCESS_ALLOW_ALL, 0, nameSignal, NAMEDSEM_FLAG_CREATE, NitsReservedCallSite()));
571              
572                  /* The product waits on this semaphre to continue execution. */
573                  g_waitSemaphoreInitialized = (0 == NamedSem_Open_Injected(&g_waitSemaphore, SEM_USER_ACCESS_ALLOW_ALL, 0, nameWait, NAMEDSEM_FLAG_CREATE, NitsReservedCallSite()));
574              
575                  Tcscat(nameLock, 128, convertedStr);
576              
577                  /* The product or unittest framework use this as a locking mechanism to access the wait and signal semaphore */
578                  g_lockSemaphoreInitialized = (0 == NamedSem_Open_Injected(&g_lockSemaphore, SEM_USER_ACCESS_ALLOW_ALL, 1, nameLock, NAMEDSEM_FLAG_CREATE, NitsReservedCallSite()));
579              
580                  /* Register the handles with the harness. */
581                  for (int i = 0; i < TestSystem::InjectorListSize; i++)
582                  {
583                      TestSystem::InjectorTarget *target = g_globals->m_injectors + i;
584              
585                      if (target->process != 0)
586                          continue;
587              
588                      if (Atomic_CompareAndSwap(&target->process, 0, Process_ID()) != 0)
589 krisbash 1.1             continue;
590              #ifdef _MSC_VER
591                      target->signalSemaphore = g_signalSemaphore.handle;
592                      target->waitSemaphore = g_waitSemaphore.handle;
593                      target->lockSemaphore = g_lockSemaphore.handle;
594              #endif
595                      g_injectorTarget = target;
596                      break;
597                  }
598              
599                  return 0;
600              }
601              
602              void CloseSemaphoreIfRequired(PAL_Boolean *initialized, NamedSem *semaphore)
603              {
604                  if(*initialized)
605                  {
606                      NamedSem_Close(semaphore);
607                      NamedSem_Destroy(semaphore);
608                      *initialized = PAL_FALSE;
609                  }
610 krisbash 1.1 }
611              
612              void Unload()
613              {
614                  if(g_injectorTarget != NULL)
615                  {
616                      /* Unregister with the harness. */
617                      Atomic_CompareAndSwap(&(g_injectorTarget->process), Process_ID(), 0);
618                  }
619              
620                  if(g_status)
621                  {
622                      g_injectorTarget = NULL;
623                      Shmem_Unmap(&g_mapping, const_cast<ptrdiff_t *>(g_status), sizeof(TestSystem::Globals) + sizeof(SharedSegmentHeader));
624                      Shmem_Close(&g_mapping);
625                  }
626              
627                  CloseSemaphoreIfRequired(&g_waitSemaphoreInitialized, &g_waitSemaphore);
628                  CloseSemaphoreIfRequired(&g_lockSemaphoreInitialized, &g_lockSemaphore);
629                  // either we or the NitsStopInjectorFunc will close signal semaphore
630                  // the function is to see who wins the race
631 krisbash 1.1     if(TryMarkingSignalSemaphoreForDeletion())
632                  {
633                      CloseSemaphoreIfRequired(&g_signalSemaphoreInitialized, &g_signalSemaphore);        
634                  }
635                  //printf("\nUnloading injector\n");
636              }
637              
638              
639              NITS_EXTERN_C PAL_Uint32 THREAD_API InjectorProc(_In_ void * param)
640              {
641                  PAL_UNUSED(param);
642              
643                  if (g_globals == NULL || g_injectorTarget == NULL)
644                  {
645                      //printf("\nUnloading injector since globals is null\n");
646                      Unload();
647                      return 0;
648                  }
649              
650                  for(;;)
651                  {
652 krisbash 1.1         int waitResult = NamedSem_TimedWait(&g_signalSemaphore, 10000);
653              
654                      if (g_globals->m_unload ||
655                          g_globals->m_version != TestSystem::SharedMemoryVersion ||
656                          g_injectorTarget->process != (long)Process_ID() ||
657                          s_injectorStopping)
658                      {
659                          NamedSem_Post(&g_waitSemaphore, 1);
660                          Unload();
661                          //printf("\nUnloading injector since globals told it to\n");
662                          return 0;
663                      }
664              
665                      // if the wait timed out, no need to patch; just go back to wait
666                      if(waitResult != 0)
667                      {
668                          continue;
669                      }
670              
671                      ProcessPatches(g_globals);
672              
673 krisbash 1.1         NamedSem_Post(&g_waitSemaphore, 1);
674                  }
675              }
676              
677              PAL_BEGIN_EXTERNC
678              
679              static volatile ptrdiff_t s_injectorRefs = 0;
680              static Thread s_injectorThread;
681              
682              #define INJECTOR_STOPPED  0
683              #define INJECTOR_STARTING 1
684              #define INJECTOR_STOPPING 2
685              #define INJECTOR_RUNNING  3
686              
687              NITS_DLLEXPORT int NITS_CALL NitsStartInjector(void)
688              {
689                  int result;
690                  ptrdiff_t oldRefs;
691                  ptrdiff_t newRefs;
692                  ptrdiff_t swapRefs;
693              
694 krisbash 1.1     for (;;)
695                  {
696                      oldRefs = PAL_PREFETCH(&s_injectorRefs);
697              
698                      if (oldRefs >= INJECTOR_RUNNING)
699                          newRefs = oldRefs + 1;
700                      else if (oldRefs == INJECTOR_STOPPED)
701                          newRefs = INJECTOR_STARTING;
702                      else
703                      {
704                          // this is a rare code path which occurs if two product binaries at the same time try to load the injector
705                          // and in that case one of them wins the race to set the s_injectorRefs to INJECTOR_STARTING
706                          // this is very quick transient state till the other thread sets the refs to INJECTOR_RUNNING which is few statements below in this function
707                          // not doing this leads to this thread not leaving the cpu for anyone else and slows down the process and the machine
708                          Sleep_Milliseconds(10);
709                          continue;
710                      }
711              
712                      swapRefs = Atomic_CompareAndSwap(&s_injectorRefs, oldRefs, newRefs);
713                      if (swapRefs == oldRefs)
714                          break;        
715 krisbash 1.1     }
716              
717                  if (newRefs != INJECTOR_STARTING)
718                      return 0;
719              
720                  result = InjectorSetup();
721                  if (result)
722                      goto Fail;
723              
724                  result = Thread_CreateJoinable_Injected(&s_injectorThread, InjectorProc, NULL, NULL, NitsReservedCallSite());
725                  if (result)
726                      goto Fail;
727              
728                  s_injectorRefs = INJECTOR_RUNNING;
729                  return 0;
730              
731              Fail:
732                  s_injectorRefs = INJECTOR_STOPPED;
733                  return result;
734              }
735              
736 krisbash 1.1 NITS_DLLEXPORT void NITS_CALL NitsStopInjector(void)
737              {
738                  ptrdiff_t oldRefs;
739                  ptrdiff_t newRefs;
740                  ptrdiff_t swapRefs;
741              
742                  for (;;)
743                  {
744                      oldRefs = PAL_PREFETCH(&s_injectorRefs);
745              
746                      if (oldRefs > INJECTOR_RUNNING)
747                          newRefs = oldRefs - 1;
748                      else if (oldRefs == INJECTOR_RUNNING)
749                          newRefs = INJECTOR_STOPPING;
750                      else if (oldRefs == INJECTOR_STOPPED)
751                          abort();
752                      else        
753                          continue;        
754              
755                      swapRefs = Atomic_CompareAndSwap(&s_injectorRefs, oldRefs, newRefs);
756                      if (swapRefs == oldRefs)
757 krisbash 1.1             break;
758                  }
759              
760                  if (newRefs != INJECTOR_STOPPING)
761                      return;
762              
763                  s_injectorStopping = 1;
764              
765                  // if injector has already called Unload and ended InjectorProc
766                  // in that case we dont need to post signalsemaphore
767                  // in other case we will post it since that will make the thread end quicker
768                  PAL_Boolean markedForDeletion = TryMarkingSignalSemaphoreForDeletion();
769                  if(markedForDeletion)
770                  {
771                      NamedSem_Post(&g_signalSemaphore, 1);
772                  }
773              
774                  PAL_Uint32 result = 0;
775              
776                  Thread_Join(&s_injectorThread, &result);
777              
778 krisbash 1.1     Thread_Destroy(&s_injectorThread);
779                  
780                  if(markedForDeletion)
781                  {
782                      CloseSemaphoreIfRequired(&g_signalSemaphoreInitialized, &g_signalSemaphore);        
783                  }
784              
785                  s_injectorRefs = INJECTOR_STOPPED;
786              }
787              
788              PAL_END_EXTERNC
789              

ViewCVS 0.9.2