+++ /dev/null
-/*++\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