]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/MultiThread.c
EdkCompatibilityPkg: Remove EdkCompatibilityPkg
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Tools / Source / ProcessDsc / MultiThread.c
diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/MultiThread.c b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/MultiThread.c
deleted file mode 100644 (file)
index b6a72ec..0000000
+++ /dev/null
@@ -1,905 +0,0 @@
-/*++\r
-\r
-Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials                          \r
-are licensed and made available under the terms and conditions of the BSD License         \r
-which accompanies this distribution.  The full text of the license may be found at        \r
-http://opensource.org/licenses/bsd-license.php                                            \r
-                                                                                          \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
-\r
-Module Name:\r
-\r
-  MultiThread.c\r
-\r
-Abstract:\r
-\r
-  This module is used to add multi-thread build support to ProcessDsc utility \r
-  to improve the build performance. \r
-\r
---*/\r
-\r
-#include <windows.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-#include <direct.h>\r
-#include "Common.h"\r
-#include "MultiThread.h"\r
-\r
-BUILD_ITEM *\r
-AddBuildItem (\r
-  BUILD_ITEM  **BuildList,\r
-  INT8        *BaseName,\r
-  INT8        *Processor,\r
-  INT8        *Makefile\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  \r
-  Add a build item to a specified build list\r
-\r
-Arguments:\r
-  \r
-  BuildList  - build list where the new build item will be added\r
-  BaseName   - base name of the new module\r
-  Processor  - processor type of the new module\r
-  Makefile   - makefile name of the new module\r
-\r
-Returns:\r
-\r
-  Pointer to the newly added build item\r
-\r
---*/\r
-{\r
-  BUILD_ITEM  *NewBuildItem;\r
-  \r
-  //\r
-  // Create a new build item\r
-  //\r
-  NewBuildItem = malloc (sizeof (BUILD_ITEM));\r
-  if (NewBuildItem == NULL) {\r
-    return NULL;\r
-  }\r
-  memset (NewBuildItem, 0, sizeof (BUILD_ITEM));\r
-  NewBuildItem->BaseName  = _strdup (BaseName);\r
-  NewBuildItem->Processor = _strdup (Processor);\r
-  NewBuildItem->Makefile = _strdup (Makefile);\r
-  \r
-  //\r
-  // Add the build item to the head of the build list\r
-  //\r
-  NewBuildItem->Next = *BuildList;\r
-  *BuildList = NewBuildItem;\r
-  \r
-  return NewBuildItem;\r
-}\r
-\r
-SOURCE_FILE_ITEM *\r
-AddSourceFile (\r
-  BUILD_ITEM  *BuildItem, \r
-  INT8        *FileName\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  \r
-  Add a source file for a build item\r
-\r
-Arguments:\r
-  \r
-  BuildItem - build item to add the source file\r
-  FileName  - source file name to be added\r
-\r
-Returns:\r
-\r
-  Pointer to the newly added source file item\r
-\r
---*/\r
-{\r
-  SOURCE_FILE_ITEM *NewSourceFile;\r
-  \r
-  //\r
-  // Create a new source file item\r
-  //\r
-  NewSourceFile = malloc (sizeof (SOURCE_FILE_ITEM));\r
-  if (NewSourceFile == NULL) {\r
-    return NULL;\r
-  }\r
-  memset (NewSourceFile, 0, sizeof (SOURCE_FILE_ITEM));\r
-  NewSourceFile->FileName  = _strdup (FileName);\r
-  \r
-  //\r
-  // Add the source file item to the head of the source file list\r
-  //\r
-  NewSourceFile->Next = BuildItem->SourceFileList;\r
-  BuildItem->SourceFileList = NewSourceFile;\r
-  \r
-  return NewSourceFile; \r
-}\r
-\r
-DEPENDENCY_ITEM *\r
-AddDependency (\r
-  BUILD_ITEM  *BuildList, \r
-  BUILD_ITEM  *BuildItem, \r
-  INT8        *BaseName,\r
-  INT8        AdjustIndex\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  \r
-  Add a build dependency for a build item in the specified build list\r
-\r
-Arguments:\r
-  \r
-  BuildList   - build list where to search the dependency\r
-  BuildItem   - build item to add the dependency\r
-  BaseName    - dependency module base name\r
-  AdjustIndex - Adjust BuildItem->Index when non-zero\r
-\r
-Returns:\r
-\r
-  Pointer to the newly added build dependency\r
-\r
---*/\r
-{\r
-  BUILD_ITEM       *TempBuildItem;\r
-  DEPENDENCY_ITEM  *NewDependency;\r
-  \r
-  //\r
-  // Search the dependency in the build list\r
-  //\r
-  TempBuildItem = BuildList;\r
-  while (TempBuildItem != NULL) {\r
-    if ((_stricmp (TempBuildItem->BaseName, BaseName) == 0) &&\r
-        (_stricmp (TempBuildItem->Processor, BuildItem->Processor) == 0) &&\r
-        (TempBuildItem != BuildItem)) {\r
-      break;\r
-    }\r
-    TempBuildItem = TempBuildItem->Next;\r
-  }\r
-  if (TempBuildItem == NULL) {\r
-    return NULL;\r
-  }\r
-  \r
-  //\r
-  // This index is used to isolate two modules with same base name and processor.\r
-  // (ProcessDsc allows duplicate base name libraries.)\r
-  //\r
-  if (AdjustIndex) {\r
-    BuildItem->Index = TempBuildItem->Index + 1;\r
-  }\r
-  \r
-  //\r
-  // Create a new build dependency item\r
-  //\r
-  NewDependency = malloc (sizeof (DEPENDENCY_ITEM));\r
-  if (NewDependency == NULL) {\r
-    return NULL;\r
-  }\r
-  memset (NewDependency, 0, sizeof (DEPENDENCY_ITEM));\r
-  NewDependency->Dependency  = TempBuildItem;\r
-  \r
-  //\r
-  // Add the build dependency item to the head of the dependency list\r
-  //\r
-  NewDependency->Next = BuildItem->DependencyList;\r
-  BuildItem->DependencyList = NewDependency;\r
-  \r
-  return NewDependency; \r
-}\r
-\r
-void\r
-FreeBuildList (\r
-  BUILD_ITEM  *BuildList\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  \r
-  Free a build list\r
-\r
-Arguments:\r
-  \r
-  BuildList  - build list to be freed\r
-\r
-Returns:\r
-\r
---*/\r
-{\r
-  BUILD_ITEM       *TempBuildItem;\r
-  BUILD_ITEM       *FreeBuildItem;\r
-  SOURCE_FILE_ITEM *TempSourceFile;\r
-  SOURCE_FILE_ITEM *FreeSourceFile;\r
-  DEPENDENCY_ITEM  *TempDependency;\r
-  DEPENDENCY_ITEM  *FreeDependency;\r
-  \r
-  TempBuildItem = BuildList;\r
-  while (TempBuildItem != NULL) {\r
-    free (TempBuildItem->BaseName);\r
-    free (TempBuildItem->Processor);\r
-    free (TempBuildItem->Makefile);\r
-\r
-    //\r
-    // Free source file list\r
-    //\r
-    TempSourceFile = TempBuildItem->SourceFileList;\r
-    while (TempSourceFile != NULL) {\r
-      FreeSourceFile = TempSourceFile;\r
-      TempSourceFile = TempSourceFile->Next;\r
-      free (FreeSourceFile);\r
-    }\r
-\r
-    //\r
-    // Free dependency list\r
-    //\r
-    TempDependency = TempBuildItem->DependencyList;\r
-    while (TempDependency != NULL) {\r
-      FreeDependency = TempDependency;\r
-      TempDependency = TempDependency->Next;\r
-      free (FreeDependency);\r
-    }\r
-\r
-    FreeBuildItem = TempBuildItem;\r
-    TempBuildItem = TempBuildItem->Next;\r
-    free (FreeBuildItem);\r
-  }\r
-}\r
-\r
-COMPONENTS_ITEM *\r
-AddComponentsItem (\r
-  COMPONENTS_ITEM  **ComponentsList\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  \r
-  Add a new components item to a specified components list\r
-\r
-Arguments:\r
-  \r
-  ComponentsList  - components list where the new components item will be added\r
-\r
-Returns:\r
-\r
-  Pointer to the newly added components item\r
-\r
---*/\r
-{\r
-  COMPONENTS_ITEM  *NewComponents;\r
-  COMPONENTS_ITEM  *TempComponents;\r
-  \r
-  //\r
-  // Create a new components item\r
-  //\r
-  NewComponents = malloc (sizeof (COMPONENTS_ITEM));\r
-  if (NewComponents == NULL) {\r
-    return NULL;\r
-  }\r
-  memset (NewComponents, 0, sizeof (COMPONENTS_ITEM));\r
-  \r
-  //\r
-  // Add the components item to the tail of the components list\r
-  //\r
-  TempComponents = *ComponentsList;\r
-  if (TempComponents == NULL) {\r
-    *ComponentsList = NewComponents;\r
-  } else {\r
-    while (TempComponents->Next != NULL) {\r
-      TempComponents = TempComponents->Next;\r
-    }\r
-    TempComponents->Next = NewComponents;\r
-  }\r
-  \r
-  return NewComponents;\r
-}\r
-\r
-void\r
-FreeComponentsList (\r
-  COMPONENTS_ITEM  *ComponentsList\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  \r
-  Free a components list\r
-\r
-Arguments:\r
-  \r
-  ComponentsList  - components list to be freed\r
-\r
-Returns:\r
-\r
---*/\r
-{\r
-  COMPONENTS_ITEM  *TempComponents;\r
-  COMPONENTS_ITEM  *FreeComponents;\r
-  \r
-  TempComponents = ComponentsList;\r
-  while (TempComponents != NULL) {\r
-    FreeBuildList (TempComponents->BuildList);\r
-    FreeComponents = TempComponents;\r
-    TempComponents = TempComponents->Next;\r
-    free (FreeComponents);\r
-  }\r
-}\r
-\r
-//\r
-// Module globals for multi-thread build\r
-//\r
-static INT8             mError;            // non-zero means error occurred\r
-static INT8             mDone;             // non-zero means no more build items available for build\r
-static UINT32           mThreadNumber;     // thread number\r
-static INT8             *mBuildDir;        // build directory\r
-static INT8             mLogDir[MAX_PATH]; // build item log dir\r
-static CRITICAL_SECTION mCriticalSection;  // critical section object\r
-static HANDLE           mSemaphoreHandle;  // semaphore for "ready for build" items in mWaitingList\r
-static HANDLE           mEventHandle;      // event signaled when one build item is finished\r
-static BUILD_ITEM       *mPendingList;     // build list for build items which are not ready for build\r
-static BUILD_ITEM       *mWaitingList;     // build list for build items which are ready for build\r
-static BUILD_ITEM       *mBuildingList;    // build list for build items which are buiding\r
-static BUILD_ITEM       *mDoneList;        // build list for build items which already finish the build\r
-\r
-//\r
-// Restore the BuildList (not care about the sequence of the build items)\r
-//\r
-static void\r
-RestoreBuildList (\r
-  BUILD_ITEM  **BuildList\r
-  )\r
-{\r
-  BUILD_ITEM  *TempBuildItem;\r
-  \r
-  if (mPendingList != NULL) {\r
-    //\r
-    // Add the mPendingList to the header of *BuildList\r
-    //\r
-    TempBuildItem = mPendingList;\r
-    while (TempBuildItem->Next != NULL) {\r
-      TempBuildItem = TempBuildItem->Next;\r
-    }\r
-    TempBuildItem->Next = *BuildList;\r
-    *BuildList = mPendingList;\r
-  }\r
-\r
-  if (mWaitingList != NULL) {\r
-    //\r
-    // Add the mWaitingList to the header of *BuildList\r
-    //\r
-    TempBuildItem = mWaitingList;\r
-    while (TempBuildItem->Next != NULL) {\r
-      TempBuildItem = TempBuildItem->Next;\r
-    }\r
-    TempBuildItem->Next = *BuildList;\r
-    *BuildList = mWaitingList;\r
-  }\r
-\r
-  if (mBuildingList != NULL) {\r
-    //\r
-    // Add the mBuildingList to the header of *BuildList\r
-    //\r
-    TempBuildItem = mBuildingList;\r
-    while (TempBuildItem->Next != NULL) {\r
-      TempBuildItem = TempBuildItem->Next;\r
-    }\r
-    TempBuildItem->Next = *BuildList;\r
-    *BuildList = mBuildingList;\r
-  }\r
-\r
-  if (mDoneList != NULL) {\r
-    //\r
-    // Add the mDoneList to the header of *BuildList\r
-    //\r
-    TempBuildItem = mDoneList;\r
-    while (TempBuildItem->Next != NULL) {\r
-      TempBuildItem = TempBuildItem->Next;\r
-    }\r
-    TempBuildItem->Next = *BuildList;\r
-    *BuildList = mDoneList;\r
-  }\r
-}\r
-\r
-//\r
-// Return non-zero when no source file build conflict\r
-//\r
-static INT8\r
-CheckSourceFile (\r
-  SOURCE_FILE_ITEM  *SourceFileList\r
-  )\r
-{\r
-  BUILD_ITEM        *TempBuildItem;\r
-  SOURCE_FILE_ITEM  *TempSourceFile;\r
-  \r
-  while (SourceFileList != NULL) {\r
-    TempBuildItem = mBuildingList;\r
-    while (TempBuildItem != NULL) {\r
-      TempSourceFile = TempBuildItem->SourceFileList;\r
-      while (TempSourceFile != NULL) {\r
-        if (_stricmp (SourceFileList->FileName, TempSourceFile->FileName) == 0) {\r
-          return 0;\r
-        }\r
-        TempSourceFile = TempSourceFile->Next;\r
-      }\r
-      TempBuildItem = TempBuildItem->Next;\r
-    }\r
-    SourceFileList = SourceFileList->Next;\r
-  }\r
-  \r
-  return 1;\r
-}\r
-\r
-//\r
-// Return non-zero when all the dependency build items has been built\r
-//\r
-static INT8\r
-CheckDependency (\r
-  DEPENDENCY_ITEM  *DependencyList\r
-  )\r
-{\r
-  while (DependencyList != NULL) {\r
-    if (!(DependencyList->Dependency->CompleteFlag)) {\r
-      return 0;\r
-    }\r
-    DependencyList = DependencyList->Next;\r
-  }\r
-  \r
-  return 1;\r
-}\r
-\r
-//\r
-// Run the build task. The system() function call  will cause stdout conflict \r
-// in multi-thread envroment, so implement this through CreateProcess().\r
-//\r
-static INT8\r
-RunBuildTask (\r
-  INT8  *WorkingDir, \r
-  INT8  *LogFile, \r
-  INT8  *BuildCmd\r
-  )\r
-{\r
-  HANDLE                FileHandle;\r
-  SECURITY_ATTRIBUTES   SecAttr;\r
-  PROCESS_INFORMATION   ProcInfo; \r
-  STARTUPINFO           StartInfo;\r
-  BOOL                  FuncRetn;\r
-  DWORD                 ExitCode;\r
-  \r
-  //\r
-  // Init SecAttr\r
-  //\r
-  SecAttr.nLength              = sizeof (SECURITY_ATTRIBUTES); \r
-  SecAttr.bInheritHandle       = TRUE; \r
-  SecAttr.lpSecurityDescriptor = NULL;\r
-  \r
-  //\r
-  // Create the log file\r
-  //\r
-  FileHandle = CreateFile (\r
-                 LogFile,                // file to create\r
-                 GENERIC_WRITE,          // open for writing\r
-                 0,                      // do not share\r
-                 &SecAttr,               // can be inherited by child processes\r
-                 CREATE_ALWAYS,          // overwrite existing\r
-                 FILE_ATTRIBUTE_NORMAL,  // normal file\r
-                 NULL                    // no attr. template\r
-                 );\r
-\r
-  if (FileHandle == INVALID_HANDLE_VALUE) { \r
-      EnterCriticalSection (&mCriticalSection);\r
-      Error (NULL, 0, 0, NULL, "could not open file %s", LogFile);\r
-      LeaveCriticalSection (&mCriticalSection);\r
-      return 1;\r
-  }\r
-  \r
-  //\r
-  // Init ProcInfo and StartInfo\r
-  //\r
-  ZeroMemory (&ProcInfo, sizeof (PROCESS_INFORMATION));\r
-  ZeroMemory (&StartInfo, sizeof (STARTUPINFO));\r
-  StartInfo.cb         = sizeof (STARTUPINFO); \r
-  StartInfo.hStdError  = FileHandle;\r
-  StartInfo.hStdOutput = FileHandle;\r
-  StartInfo.hStdInput  = GetStdHandle (STD_INPUT_HANDLE);\r
-  StartInfo.dwFlags    = STARTF_USESTDHANDLES;\r
-\r
-  //\r
-  // Create the child process\r
-  //\r
-  FuncRetn = CreateProcess (\r
-               NULL,          // no application name\r
-               BuildCmd,      // command line \r
-               NULL,          // process security attributes \r
-               NULL,          // primary thread security attributes \r
-               TRUE,          // handles are inherited \r
-               0,             // creation flags \r
-               NULL,          // use parent's environment \r
-               WorkingDir,    // set current directory \r
-               &StartInfo,    // STARTUPINFO pointer \r
-               &ProcInfo      // receives PROCESS_INFORMATION \r
-               );\r
-  \r
-  if (FuncRetn == FALSE) {\r
-    EnterCriticalSection (&mCriticalSection);\r
-    Error (NULL, 0, 0, NULL, "could not create child process");\r
-    LeaveCriticalSection (&mCriticalSection);\r
-    CloseHandle (FileHandle);\r
-    return 1;\r
-  } \r
-  \r
-  //\r
-  // Wait until child process exits\r
-  //\r
-  WaitForSingleObject (ProcInfo.hProcess, INFINITE);\r
-  GetExitCodeProcess (ProcInfo.hProcess, &ExitCode);\r
-  CloseHandle (ProcInfo.hProcess);\r
-  CloseHandle (ProcInfo.hThread);\r
-  CloseHandle (FileHandle);\r
-  \r
-  if (ExitCode != 0) {\r
-    return 1;\r
-  } else {\r
-    return 0;\r
-  }\r
-}\r
-\r
-//\r
-// Thread function\r
-//\r
-static DWORD WINAPI\r
-ThreadProc (\r
-  LPVOID lpParam\r
-  )\r
-{\r
-  UINT32      ThreadId;\r
-  BUILD_ITEM  *PreviousBuildItem;\r
-  BUILD_ITEM  *CurrentBuildItem;\r
-  BUILD_ITEM  *NextBuildItem;\r
-  INT8        WorkingDir[MAX_PATH];  \r
-  INT8        LogFile[MAX_PATH];\r
-  INT8        BuildCmd[MAX_PATH];\r
-  \r
-  ThreadId = (UINT32)lpParam;\r
-  //\r
-  // Loop until error occurred or no more build items available for build\r
-  //\r
-  for (;;) {\r
-    WaitForSingleObject (mSemaphoreHandle, INFINITE);\r
-    if (mError || mDone) {\r
-      return 0;\r
-    }\r
-    \r
-    //\r
-    // When code runs here, there must have one build item available for this \r
-    // thread. Loop until error occurred or get one build item for build.\r
-    //\r
-    for (;;) {\r
-      EnterCriticalSection (&mCriticalSection);\r
-      PreviousBuildItem = NULL;\r
-      CurrentBuildItem  = mWaitingList;\r
-      while (CurrentBuildItem != NULL) {\r
-        NextBuildItem = CurrentBuildItem->Next;\r
-        //\r
-        // CheckSourceFile() is to avoid concurrently build the same source file\r
-        // which may cause the muti-thread build failure\r
-        //\r
-        if (CheckSourceFile (CurrentBuildItem->SourceFileList)) {\r
-          //\r
-          // Move the current build item from mWaitingList\r
-          //\r
-          if (PreviousBuildItem != NULL) {\r
-            PreviousBuildItem->Next = NextBuildItem;\r
-          } else {\r
-            mWaitingList = NextBuildItem;\r
-          }\r
-          //\r
-          // Add the current build item to the head of mBuildingList\r
-          //\r
-          CurrentBuildItem->Next = mBuildingList;\r
-          mBuildingList = CurrentBuildItem;\r
-          //\r
-          // If no more build items is pending or waiting for build,\r
-          // wake up every child thread for exit.\r
-          //\r
-          if ((mPendingList == NULL) && (mWaitingList == NULL)) {\r
-            mDone = 1;\r
-            //\r
-            // Make sure to wake up every child thread for exit\r
-            //        \r
-            ReleaseSemaphore (mSemaphoreHandle, mThreadNumber, NULL);\r
-          }\r
-          break;\r
-        }\r
-        PreviousBuildItem = CurrentBuildItem;\r
-        CurrentBuildItem  = NextBuildItem;\r
-      }\r
-      if (CurrentBuildItem != NULL) {\r
-        //\r
-        // Display build item info\r
-        //\r
-        printf ("\t[Thread_%d] nmake -nologo -f %s all\n", ThreadId, CurrentBuildItem->Makefile);\r
-        //\r
-        // Prepare build task\r
-        //\r
-        sprintf (WorkingDir, "%s\\%s", mBuildDir, CurrentBuildItem->Processor);\r
-        sprintf (LogFile, "%s\\%s_%s_%d.txt", mLogDir, CurrentBuildItem->BaseName, \r
-                 CurrentBuildItem->Processor, CurrentBuildItem->Index);\r
-        sprintf (BuildCmd, "nmake -nologo -f %s all", CurrentBuildItem->Makefile);\r
-        LeaveCriticalSection (&mCriticalSection);\r
-        break;\r
-      } else {\r
-        LeaveCriticalSection (&mCriticalSection);\r
-        //\r
-        // All the build items in mWaitingList have source file conflict with \r
-        // mBuildingList. This rarely hapeens. Need wait for the build items in\r
-        // mBuildingList to be finished by other child threads.\r
-        //\r
-        Sleep (1000);\r
-        if (mError) {\r
-          return 0;\r
-        }\r
-      }\r
-    }\r
-    \r
-    //\r
-    // Start to build the CurrentBuildItem\r
-    //\r
-    if (RunBuildTask (WorkingDir, LogFile, BuildCmd)) {\r
-      //\r
-      // Build failure\r
-      //\r
-      mError = 1;\r
-      //\r
-      // Make sure to wake up every child thread for exit\r
-      //\r
-      ReleaseSemaphore (mSemaphoreHandle, mThreadNumber, NULL);\r
-      SetEvent(mEventHandle);\r
-\r
-      return mError;\r
-    } else {\r
-      //\r
-      // Build success\r
-      //\r
-      CurrentBuildItem->CompleteFlag = 1;\r
-      \r
-      EnterCriticalSection (&mCriticalSection);\r
-      //\r
-      // Move this build item from mBuildingList\r
-      //\r
-      if (mBuildingList == CurrentBuildItem) {\r
-        mBuildingList = mBuildingList->Next;\r
-      } else {\r
-        NextBuildItem = mBuildingList;\r
-        while (NextBuildItem->Next != CurrentBuildItem) {\r
-          NextBuildItem = NextBuildItem->Next;\r
-        }\r
-        NextBuildItem->Next = CurrentBuildItem->Next;\r
-      }\r
-      //\r
-      // Add this build item to mDoneList\r
-      //\r
-      CurrentBuildItem->Next = mDoneList;\r
-      mDoneList = CurrentBuildItem;\r
-      LeaveCriticalSection (&mCriticalSection);\r
-      \r
-      SetEvent(mEventHandle);\r
-    }\r
-  }\r
-}\r
-\r
-INT8\r
-StartMultiThreadBuild (\r
-  BUILD_ITEM  **BuildList,\r
-  UINT32      ThreadNumber,\r
-  INT8        *BuildDir\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  \r
-  Start multi-thread build for a specified build list\r
-\r
-Arguments:\r
-  \r
-  BuildList     - build list for multi-thread build\r
-  ThreadNumber  - thread number for multi-thread build\r
-  BuildDir      - build dir\r
-\r
-Returns:\r
-\r
-  0             - Successfully finished the multi-thread build\r
-  other value   - Build failure\r
-\r
---*/\r
-{\r
-  UINT32        Index;\r
-  UINT32        Count;\r
-  BUILD_ITEM    *PreviousBuildItem;\r
-  BUILD_ITEM    *CurrentBuildItem;\r
-  BUILD_ITEM    *NextBuildItem;\r
-  HANDLE        *ThreadHandle;\r
-  INT8          Cmd[MAX_PATH];\r
-  \r
-  mError        = 0;\r
-  mDone         = 0;\r
-  mThreadNumber = ThreadNumber;\r
-  mBuildDir     = BuildDir;\r
-  mPendingList  = *BuildList;\r
-  *BuildList    = NULL;\r
-  mWaitingList  = NULL;\r
-  mBuildingList = NULL;\r
-  mDoneList     = NULL;\r
-  \r
-  //\r
-  // Do nothing when mPendingList is empty\r
-  //\r
-  if (mPendingList == NULL) {\r
-    return 0;\r
-  }\r
-  \r
-  //\r
-  // Get build item count of mPendingList\r
-  //\r
-  Count = 0;\r
-  CurrentBuildItem = mPendingList;\r
-  while (CurrentBuildItem != NULL) {\r
-    Count++;\r
-    CurrentBuildItem = CurrentBuildItem->Next;\r
-  }\r
-  \r
-  //\r
-  // The semaphore is also used to wake up child threads for exit,\r
-  // so need to make sure "maximum count" >= "thread number".\r
-  //\r
-  if (Count < ThreadNumber) {\r
-    Count = ThreadNumber;\r
-  }\r
-  \r
-  //\r
-  // Init mSemaphoreHandle\r
-  //\r
-  mSemaphoreHandle = CreateSemaphore (\r
-                       NULL,       // default security attributes\r
-                       0,          // initial count\r
-                       Count,      // maximum count\r
-                       NULL        // unnamed semaphore\r
-                       );\r
-  if (mSemaphoreHandle == NULL) {\r
-    Error (NULL, 0, 0, NULL, "failed to create semaphore");\r
-    RestoreBuildList (BuildList);\r
-    return 1;\r
-  }  \r
-\r
-  //\r
-  // Init mEventHandle\r
-  //\r
-  mEventHandle = CreateEvent( \r
-                   NULL,     // default security attributes\r
-                   FALSE,    // auto-reset event\r
-                   TRUE,     // initial state is signaled\r
-                   NULL      // object not named\r
-                   ); \r
-  if (mEventHandle == NULL) { \r
-    Error (NULL, 0, 0, NULL, "failed to create event");\r
-    CloseHandle (mSemaphoreHandle);\r
-    RestoreBuildList (BuildList);\r
-    return 1;\r
-  }\r
-  \r
-  //\r
-  // Init mCriticalSection\r
-  //\r
-  InitializeCriticalSection (&mCriticalSection);\r
-  \r
-  //\r
-  // Create build item log dir\r
-  //\r
-  sprintf (mLogDir, "%s\\Log", mBuildDir);\r
-  _mkdir (mLogDir);\r
-  \r
-  //\r
-  // Create child threads for muti-thread build\r
-  //\r
-  ThreadHandle = malloc (ThreadNumber * sizeof (HANDLE));\r
-  if (ThreadHandle == NULL) {\r
-    Error (NULL, 0, 0, NULL, "failed to allocate memory");\r
-    CloseHandle (mSemaphoreHandle);\r
-    CloseHandle (mEventHandle);\r
-    RestoreBuildList (BuildList);\r
-    return 1;\r
-  }\r
-  for (Index = 0; Index < ThreadNumber; Index++) {\r
-    ThreadHandle[Index] = CreateThread (\r
-                            NULL,           // default security attributes\r
-                            0,              // use default stack size\r
-                            ThreadProc,     // thread function\r
-                            (LPVOID)Index,  // argument to thread function: use Index as thread id\r
-                            0,              // use default creation flags\r
-                            NULL            // thread identifier not needed\r
-                            );\r
-    if (ThreadHandle[Index] == NULL) {\r
-      Error (NULL, 0, 0, NULL, "failed to create Thread_%d", Index);\r
-      mError       = 1;\r
-      ThreadNumber = Index;\r
-      //\r
-      // Make sure to wake up every child thread for exit\r
-      //\r
-      ReleaseSemaphore (mSemaphoreHandle, ThreadNumber, NULL);\r
-      break;\r
-    }\r
-  }\r
-  \r
-  //\r
-  // Loop until error occurred or no more build items pending for build\r
-  //\r
-  for (;;) {\r
-    WaitForSingleObject (mEventHandle, INFINITE);\r
-    if (mError) {\r
-      break;\r
-    }\r
-    Count = 0;\r
-    \r
-    EnterCriticalSection (&mCriticalSection);\r
-    PreviousBuildItem = NULL;\r
-    CurrentBuildItem  = mPendingList;\r
-    while (CurrentBuildItem != NULL) {\r
-      NextBuildItem = CurrentBuildItem->Next;\r
-      if (CheckDependency (CurrentBuildItem->DependencyList)) {\r
-        //\r
-        // Move the current build item from mPendingList\r
-        //\r
-        if (PreviousBuildItem != NULL) {\r
-          PreviousBuildItem->Next = NextBuildItem;\r
-        } else {\r
-          mPendingList = NextBuildItem;\r
-        }\r
-        //\r
-        // Add the current build item to the head of mWaitingList\r
-        //\r
-        CurrentBuildItem->Next = mWaitingList;\r
-        mWaitingList = CurrentBuildItem;\r
-        Count++;\r
-      } else {\r
-        PreviousBuildItem = CurrentBuildItem;\r
-      }\r
-      CurrentBuildItem  = NextBuildItem;\r
-    }\r
-    LeaveCriticalSection (&mCriticalSection);\r
-    \r
-    ReleaseSemaphore (mSemaphoreHandle, Count, NULL);\r
-    if (mPendingList == NULL) {\r
-      break;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Wait until all threads have terminated\r
-  //\r
-  WaitForMultipleObjects (ThreadNumber, ThreadHandle, TRUE, INFINITE);\r
-  \r
-  if (mError && (mBuildingList != NULL)) {\r
-    //\r
-    // Dump build failure log of the first build item which doesn't finish the build\r
-    //\r
-    printf ("\tnmake -nologo -f %s all\n", mBuildingList->Makefile);\r
-    sprintf (Cmd, "type %s\\%s_%s_%d.txt 2>NUL", mLogDir, mBuildingList->BaseName,\r
-             mBuildingList->Processor, mBuildingList->Index);\r
-    _flushall ();\r
-    if (system (Cmd)) {\r
-      Error (NULL, 0, 0, NULL, "failed to run \"%s\"", Cmd);\r
-    }\r
-  }\r
-\r
-  DeleteCriticalSection (&mCriticalSection);\r
-  for (Index = 0; Index < ThreadNumber; Index++) {\r
-    CloseHandle (ThreadHandle[Index]);\r
-  }\r
-  free (ThreadHandle);\r
-  CloseHandle (mSemaphoreHandle);\r
-  CloseHandle (mEventHandle);\r
-  RestoreBuildList (BuildList);\r
-\r
-  return mError;\r
-}\r