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