text: /*============================================================
  **
  ** Source: criticalsectionfunctions/test4/test4.c
  ** 
  ** Purpose: Test to see if threads blocked on a CRITICAL_SECTION object will 
  ** be released in an orderly manner.  This case looks at the following
  ** scenario.  If one thread owns a CRITICAL_SECTION object and two threads 
  ** block in EnterCriticalSection, trying to hold the already owned 
  ** CRITICAL_SECTION object, when the first thread releases the CRITICAL_SECTION
  ** object, will one and only one of the waiters get unblocked?
  **
  ** Dependencies: CreateThread
  **               InitializeCriticalSection
  **               EnterCriticalSection
  **               LeaveCriticalSection
  **               DeleteCriticalSection
  **               Sleep
  **               WaitForSingleObject
  ** 
  ** 
  **  Copyright (c) 2006 Microsoft Corporation.  All rights reserved.
  ** 
  **  The use and distribution terms for this software are contained in the file
  **  named license.txt, which can be found in the root of this distribution.
  **  By using this software in any fashion, you are agreeing to be bound by the
  **  terms of this license.
  ** 
  **  You must not remove this notice, or any other, from this software.
  ** 
  **
  **=========================================================*/
  
  #include <palsuite.h>
  
  #define NUM_BLOCKING_THREADS 2
                           
  BOOL bTestResult;
  CRITICAL_SECTION CriticalSection;
  HANDLE hThread[NUM_BLOCKING_THREADS];
  HANDLE hEvent;
  DWORD dwThreadId[NUM_BLOCKING_THREADS];
  volatile int flags[NUM_BLOCKING_THREADS] = {0,0};
  
  DWORD PALAPI ThreadTest1(LPVOID lpParam)
  {
  
      EnterCriticalSection ( &CriticalSection );
  
      flags[0] = 1;
      
      return 0;
  
  }
  
  DWORD PALAPI ThreadTest2(LPVOID lpParam)
  {
  
      EnterCriticalSection ( &CriticalSection );
  
      flags[1] = 1;
  
      return 0;
  
  }
  
  int __cdecl main(int argc, char **argv)
  {
  
      DWORD dwRet;
      DWORD dwRet1;
      bTestResult = FAIL;
      
      if ((PAL_Initialize(argc,argv)) != 0)
      {
          return(bTestResult);
      }
  
      /*
       * Create Critical Section Object
       */
      InitializeCriticalSection ( &CriticalSection );
  
      EnterCriticalSection ( &CriticalSection );
  
      hThread[0] = CreateThread(NULL,
                                0,
                                &ThreadTest1,
                                (LPVOID) 0,
                                CREATE_SUSPENDED,
                                &dwThreadId[0]);
      if (hThread[0] == NULL)
      {
          Trace("PALSUITE ERROR: CreateThread(%p, %d, %p, %p, %d, %p) call "
               "failed.\nGetLastError returned %d.\n", NULL, 0, &ThreadTest1,
               (LPVOID) 0, CREATE_SUSPENDED, &dwThreadId[0], GetLastError());
          LeaveCriticalSection(&CriticalSection);
          DeleteCriticalSection ( &CriticalSection );
          Fail("");
      }
      
      hThread[1] = CreateThread(NULL,
                                0,
                                &ThreadTest2,
                                (LPVOID) 0,
                                CREATE_SUSPENDED,
                                &dwThreadId[1]);
      if (hThread[1] == NULL)
      {
          Trace("PALSUITE ERROR: CreateThread(%p, %d, %p, %p, %d, %p) call "
               "failed.\nGetLastError returned %d.\n", NULL, 0, &ThreadTest2,
               (LPVOID) 0, CREATE_SUSPENDED, &dwThreadId[1], GetLastError());
          LeaveCriticalSection(&CriticalSection);
  
          dwRet = ResumeThread(hThread[0]);
          if (-1 == dwRet)
          {
              Trace("PALSUITE ERROR: ResumeThread(%p) call failed.\n"
                    "GetLastError returned '%d'.\n", hThread[0],
               GetLastError());
      }
  
          dwRet = WaitForSingleObject(hThread[0], 10000);
          if (WAIT_OBJECT_0 == dwRet)
          {
              Trace("PALSUITE ERROR: WaitForSingleObject(%p, %d) call "
                    "failed.  '%d' was returned instead of the expected '%d'.\n"
                    "GetLastError returned '%d'.\n", hThread[0], 10000, dwRet, 
                    WAIT_OBJECT_0, GetLastError());
          }
  
          if (0 == CloseHandle(hThread[0]))
          {
              Trace("PALSUITE NOTIFICATION: CloseHandle(%p) call failed.\n"
                    "GetLastError returned %d.  Not failing tests.\n", 
                    hThread[0], GetLastError());
          }
  
          DeleteCriticalSection(&CriticalSection);
          Fail("");
      }
  
      /* 
       * Set other thread priorities to be higher than ours & Sleep to ensure 
       * we give up the processor. 
       */
      dwRet = (DWORD) SetThreadPriority(hThread[0], 
                                        THREAD_PRIORITY_ABOVE_NORMAL);
      if (0 == dwRet)
      {
          Trace("PALSUITE ERROR: SetThreadPriority(%p, %d) call failed.\n"
                "GetLastError returned %d", hThread[0], 
                THREAD_PRIORITY_ABOVE_NORMAL, GetLastError());
      }
      
      dwRet = (DWORD) SetThreadPriority(hThread[1], 
                                        THREAD_PRIORITY_ABOVE_NORMAL);
      if (0 == dwRet)
      {
          Trace("PALSUITE ERROR: SetThreadPriority(%p, %d) call failed.\n"
                "GetLastError returned %d", hThread[1], 
                THREAD_PRIORITY_ABOVE_NORMAL, GetLastError());
      }
  
      dwRet = ResumeThread(hThread[0]);
      if (-1 == dwRet)
      {
          Trace("PALSUITE ERROR: ResumeThread(%p, %d) call failed.\n"
                "GetLastError returned %d", hThread[0], 
                GetLastError() );
      }
     
      dwRet = ResumeThread(hThread[1]); 
      if (-1 == dwRet)
      {
          Trace("PALSUITE ERROR: ResumeThread(%p, %d) call failed.\n"
                "GetLastError returned %d", hThread[0], 
                GetLastError());              
      }
  
      Sleep (0);
  
      LeaveCriticalSection (&CriticalSection);
      
      dwRet = WaitForSingleObject(hThread[0], 10000);
      dwRet1 = WaitForSingleObject(hThread[1], 10000);
  
      if ((WAIT_OBJECT_0 == dwRet) || 
          (WAIT_OBJECT_0 == dwRet1))
      {
          if ((1 == flags[0] && 0 == flags[1]) ||
              (0 == flags[0] && 1 == flags[1]))
          {
              bTestResult = PASS;
          }
          else 
          {
              bTestResult = FAIL;
              Trace ("PALSUITE ERROR: flags[%d] = {%d,%d}.  These values are"
                     "inconsistent.\nCriticalSection test failed.\n",
                     NUM_BLOCKING_THREADS, flags[0], flags[1]);
          }
  
          /* Fail the test if both threads returned WAIT_OBJECT_0 */
          if ((WAIT_OBJECT_0 == dwRet) && (WAIT_OBJECT_0 == dwRet1))
          {
              bTestResult = FAIL;
              Trace ("PALSUITE ERROR: WaitForSingleObject(%p, %d) and "
                     "WaitForSingleObject(%p, %d)\nboth returned dwRet = '%d'\n"
                     "One should have returned WAIT_TIMEOUT ('%d').\n", 
                     hThread[0], 10000, hThread[1], 10000, dwRet, WAIT_TIMEOUT);
          }        
      }
      else 
      {
          bTestResult = FAIL;
          Trace ("PALSUITE ERROR: WaitForSingleObject(%p, %d) and "
                 "WaitForSingleObject(%p, %d)\nReturned dwRet = '%d' and\n"
                 "dwRet1 = '%d' respectively.\n", hThread[0], 10000, hThread[1],
                 10000, dwRet, dwRet1);
      }    
  
      if (WAIT_OBJECT_0 == dwRet)
      {
          if (0 == CloseHandle(hThread[0]))
          {
              Trace("PALSUITE NOTIFICATION: CloseHandle(%p) call failed.\n"
                    "GetLastError returned %d.  Not failing tests.\n", 
                    hThread[0], GetLastError());
          }
      }
      if (WAIT_OBJECT_0 == dwRet1)
      {
          if (0 == CloseHandle(hThread[1]))
          {
              Trace("PALSUITE NOTIFICATION: CloseHandle(%p) call failed.\n"
                    "GetLastError returned %d.  Not failing tests.\n", 
                    hThread[1], GetLastError());
          }
      }
      DeleteCriticalSection(&CriticalSection);
      PAL_Terminate();
      return (bTestResult);
  }
  