EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/MultiThread.c

Go to the documentation of this file.
00001 /*++
00002 
00003 Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR>
00004 This program and the accompanying materials                          
00005 are licensed and made available under the terms and conditions of the BSD License         
00006 which accompanies this distribution.  The full text of the license may be found at        
00007 http://opensource.org/licenses/bsd-license.php                                            
00008                                                                                           
00009 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
00010 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
00011 
00012 Module Name:
00013 
00014   MultiThread.c
00015 
00016 Abstract:
00017 
00018   This module is used to add multi-thread build support to ProcessDsc utility 
00019   to improve the build performance. 
00020 
00021 --*/
00022 
00023 #include <windows.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026 #include <stdlib.h>
00027 #include <direct.h>
00028 #include "Common.h"
00029 #include "MultiThread.h"
00030 
00031 BUILD_ITEM *
00032 AddBuildItem (
00033   BUILD_ITEM  **BuildList,
00034   INT8        *BaseName,
00035   INT8        *Processor,
00036   INT8        *Makefile
00037   )
00038 /*++
00039 
00040 Routine Description:
00041   
00042   Add a build item to a specified build list
00043 
00044 Arguments:
00045   
00046   BuildList  - build list where the new build item will be added
00047   BaseName   - base name of the new module
00048   Processor  - processor type of the new module
00049   Makefile   - makefile name of the new module
00050 
00051 Returns:
00052 
00053   Pointer to the newly added build item
00054 
00055 --*/
00056 {
00057   BUILD_ITEM  *NewBuildItem;
00058   
00059   //
00060   // Create a new build item
00061   //
00062   NewBuildItem = malloc (sizeof (BUILD_ITEM));
00063   if (NewBuildItem == NULL) {
00064     return NULL;
00065   }
00066   memset (NewBuildItem, 0, sizeof (BUILD_ITEM));
00067   NewBuildItem->BaseName  = _strdup (BaseName);
00068   NewBuildItem->Processor = _strdup (Processor);
00069   NewBuildItem->Makefile = _strdup (Makefile);
00070   
00071   //
00072   // Add the build item to the head of the build list
00073   //
00074   NewBuildItem->Next = *BuildList;
00075   *BuildList = NewBuildItem;
00076   
00077   return NewBuildItem;
00078 }
00079 
00080 SOURCE_FILE_ITEM *
00081 AddSourceFile (
00082   BUILD_ITEM  *BuildItem, 
00083   INT8        *FileName
00084   )
00085 /*++
00086 
00087 Routine Description:
00088   
00089   Add a source file for a build item
00090 
00091 Arguments:
00092   
00093   BuildItem - build item to add the source file
00094   FileName  - source file name to be added
00095 
00096 Returns:
00097 
00098   Pointer to the newly added source file item
00099 
00100 --*/
00101 {
00102   SOURCE_FILE_ITEM *NewSourceFile;
00103   
00104   //
00105   // Create a new source file item
00106   //
00107   NewSourceFile = malloc (sizeof (SOURCE_FILE_ITEM));
00108   if (NewSourceFile == NULL) {
00109     return NULL;
00110   }
00111   memset (NewSourceFile, 0, sizeof (SOURCE_FILE_ITEM));
00112   NewSourceFile->FileName  = _strdup (FileName);
00113   
00114   //
00115   // Add the source file item to the head of the source file list
00116   //
00117   NewSourceFile->Next = BuildItem->SourceFileList;
00118   BuildItem->SourceFileList = NewSourceFile;
00119   
00120   return NewSourceFile; 
00121 }
00122 
00123 DEPENDENCY_ITEM *
00124 AddDependency (
00125   BUILD_ITEM  *BuildList, 
00126   BUILD_ITEM  *BuildItem, 
00127   INT8        *BaseName,
00128   INT8        AdjustIndex
00129   )
00130 /*++
00131 
00132 Routine Description:
00133   
00134   Add a build dependency for a build item in the specified build list
00135 
00136 Arguments:
00137   
00138   BuildList   - build list where to search the dependency
00139   BuildItem   - build item to add the dependency
00140   BaseName    - dependency module base name
00141   AdjustIndex - Adjust BuildItem->Index when non-zero
00142 
00143 Returns:
00144 
00145   Pointer to the newly added build dependency
00146 
00147 --*/
00148 {
00149   BUILD_ITEM       *TempBuildItem;
00150   DEPENDENCY_ITEM  *NewDependency;
00151   
00152   //
00153   // Search the dependency in the build list
00154   //
00155   TempBuildItem = BuildList;
00156   while (TempBuildItem != NULL) {
00157     if ((_stricmp (TempBuildItem->BaseName, BaseName) == 0) &&
00158         (_stricmp (TempBuildItem->Processor, BuildItem->Processor) == 0) &&
00159         (TempBuildItem != BuildItem)) {
00160       break;
00161     }
00162     TempBuildItem = TempBuildItem->Next;
00163   }
00164   if (TempBuildItem == NULL) {
00165     return NULL;
00166   }
00167   
00168   //
00169   // This index is used to isolate two modules with same base name and processor.
00170   // (ProcessDsc allows duplicate base name libraries.)
00171   //
00172   if (AdjustIndex) {
00173     BuildItem->Index = TempBuildItem->Index + 1;
00174   }
00175   
00176   //
00177   // Create a new build dependency item
00178   //
00179   NewDependency = malloc (sizeof (DEPENDENCY_ITEM));
00180   if (NewDependency == NULL) {
00181     return NULL;
00182   }
00183   memset (NewDependency, 0, sizeof (DEPENDENCY_ITEM));
00184   NewDependency->Dependency  = TempBuildItem;
00185   
00186   //
00187   // Add the build dependency item to the head of the dependency list
00188   //
00189   NewDependency->Next = BuildItem->DependencyList;
00190   BuildItem->DependencyList = NewDependency;
00191   
00192   return NewDependency; 
00193 }
00194 
00195 void
00196 FreeBuildList (
00197   BUILD_ITEM  *BuildList
00198   )
00199 /*++
00200 
00201 Routine Description:
00202   
00203   Free a build list
00204 
00205 Arguments:
00206   
00207   BuildList  - build list to be freed
00208 
00209 Returns:
00210 
00211 --*/
00212 {
00213   BUILD_ITEM       *TempBuildItem;
00214   BUILD_ITEM       *FreeBuildItem;
00215   SOURCE_FILE_ITEM *TempSourceFile;
00216   SOURCE_FILE_ITEM *FreeSourceFile;
00217   DEPENDENCY_ITEM  *TempDependency;
00218   DEPENDENCY_ITEM  *FreeDependency;
00219   
00220   TempBuildItem = BuildList;
00221   while (TempBuildItem != NULL) {
00222     free (TempBuildItem->BaseName);
00223     free (TempBuildItem->Processor);
00224     free (TempBuildItem->Makefile);
00225 
00226     //
00227     // Free source file list
00228     //
00229     TempSourceFile = TempBuildItem->SourceFileList;
00230     while (TempSourceFile != NULL) {
00231       FreeSourceFile = TempSourceFile;
00232       TempSourceFile = TempSourceFile->Next;
00233       free (FreeSourceFile);
00234     }
00235 
00236     //
00237     // Free dependency list
00238     //
00239     TempDependency = TempBuildItem->DependencyList;
00240     while (TempDependency != NULL) {
00241       FreeDependency = TempDependency;
00242       TempDependency = TempDependency->Next;
00243       free (FreeDependency);
00244     }
00245 
00246     FreeBuildItem = TempBuildItem;
00247     TempBuildItem = TempBuildItem->Next;
00248     free (FreeBuildItem);
00249   }
00250 }
00251 
00252 COMPONENTS_ITEM *
00253 AddComponentsItem (
00254   COMPONENTS_ITEM  **ComponentsList
00255   )
00256 /*++
00257 
00258 Routine Description:
00259   
00260   Add a new components item to a specified components list
00261 
00262 Arguments:
00263   
00264   ComponentsList  - components list where the new components item will be added
00265 
00266 Returns:
00267 
00268   Pointer to the newly added components item
00269 
00270 --*/
00271 {
00272   COMPONENTS_ITEM  *NewComponents;
00273   COMPONENTS_ITEM  *TempComponents;
00274   
00275   //
00276   // Create a new components item
00277   //
00278   NewComponents = malloc (sizeof (COMPONENTS_ITEM));
00279   if (NewComponents == NULL) {
00280     return NULL;
00281   }
00282   memset (NewComponents, 0, sizeof (COMPONENTS_ITEM));
00283   
00284   //
00285   // Add the components item to the tail of the components list
00286   //
00287   TempComponents = *ComponentsList;
00288   if (TempComponents == NULL) {
00289     *ComponentsList = NewComponents;
00290   } else {
00291     while (TempComponents->Next != NULL) {
00292       TempComponents = TempComponents->Next;
00293     }
00294     TempComponents->Next = NewComponents;
00295   }
00296   
00297   return NewComponents;
00298 }
00299 
00300 void
00301 FreeComponentsList (
00302   COMPONENTS_ITEM  *ComponentsList
00303   )
00304 /*++
00305 
00306 Routine Description:
00307   
00308   Free a components list
00309 
00310 Arguments:
00311   
00312   ComponentsList  - components list to be freed
00313 
00314 Returns:
00315 
00316 --*/
00317 {
00318   COMPONENTS_ITEM  *TempComponents;
00319   COMPONENTS_ITEM  *FreeComponents;
00320   
00321   TempComponents = ComponentsList;
00322   while (TempComponents != NULL) {
00323     FreeBuildList (TempComponents->BuildList);
00324     FreeComponents = TempComponents;
00325     TempComponents = TempComponents->Next;
00326     free (FreeComponents);
00327   }
00328 }
00329 
00330 //
00331 // Module globals for multi-thread build
00332 //
00333 static INT8             mError;            // non-zero means error occurred
00334 static INT8             mDone;             // non-zero means no more build items available for build
00335 static UINT32           mThreadNumber;     // thread number
00336 static INT8             *mBuildDir;        // build directory
00337 static INT8             mLogDir[MAX_PATH]; // build item log dir
00338 static CRITICAL_SECTION mCriticalSection;  // critical section object
00339 static HANDLE           mSemaphoreHandle;  // semaphore for "ready for build" items in mWaitingList
00340 static HANDLE           mEventHandle;      // event signaled when one build item is finished
00341 static BUILD_ITEM       *mPendingList;     // build list for build items which are not ready for build
00342 static BUILD_ITEM       *mWaitingList;     // build list for build items which are ready for build
00343 static BUILD_ITEM       *mBuildingList;    // build list for build items which are buiding
00344 static BUILD_ITEM       *mDoneList;        // build list for build items which already finish the build
00345 
00346 //
00347 // Restore the BuildList (not care about the sequence of the build items)
00348 //
00349 static void
00350 RestoreBuildList (
00351   BUILD_ITEM  **BuildList
00352   )
00353 {
00354   BUILD_ITEM  *TempBuildItem;
00355   
00356   if (mPendingList != NULL) {
00357     //
00358     // Add the mPendingList to the header of *BuildList
00359     //
00360     TempBuildItem = mPendingList;
00361     while (TempBuildItem->Next != NULL) {
00362       TempBuildItem = TempBuildItem->Next;
00363     }
00364     TempBuildItem->Next = *BuildList;
00365     *BuildList = mPendingList;
00366   }
00367 
00368   if (mWaitingList != NULL) {
00369     //
00370     // Add the mWaitingList to the header of *BuildList
00371     //
00372     TempBuildItem = mWaitingList;
00373     while (TempBuildItem->Next != NULL) {
00374       TempBuildItem = TempBuildItem->Next;
00375     }
00376     TempBuildItem->Next = *BuildList;
00377     *BuildList = mWaitingList;
00378   }
00379 
00380   if (mBuildingList != NULL) {
00381     //
00382     // Add the mBuildingList to the header of *BuildList
00383     //
00384     TempBuildItem = mBuildingList;
00385     while (TempBuildItem->Next != NULL) {
00386       TempBuildItem = TempBuildItem->Next;
00387     }
00388     TempBuildItem->Next = *BuildList;
00389     *BuildList = mBuildingList;
00390   }
00391 
00392   if (mDoneList != NULL) {
00393     //
00394     // Add the mDoneList to the header of *BuildList
00395     //
00396     TempBuildItem = mDoneList;
00397     while (TempBuildItem->Next != NULL) {
00398       TempBuildItem = TempBuildItem->Next;
00399     }
00400     TempBuildItem->Next = *BuildList;
00401     *BuildList = mDoneList;
00402   }
00403 }
00404 
00405 //
00406 // Return non-zero when no source file build conflict
00407 //
00408 static INT8
00409 CheckSourceFile (
00410   SOURCE_FILE_ITEM  *SourceFileList
00411   )
00412 {
00413   BUILD_ITEM        *TempBuildItem;
00414   SOURCE_FILE_ITEM  *TempSourceFile;
00415   
00416   while (SourceFileList != NULL) {
00417     TempBuildItem = mBuildingList;
00418     while (TempBuildItem != NULL) {
00419       TempSourceFile = TempBuildItem->SourceFileList;
00420       while (TempSourceFile != NULL) {
00421         if (_stricmp (SourceFileList->FileName, TempSourceFile->FileName) == 0) {
00422           return 0;
00423         }
00424         TempSourceFile = TempSourceFile->Next;
00425       }
00426       TempBuildItem = TempBuildItem->Next;
00427     }
00428     SourceFileList = SourceFileList->Next;
00429   }
00430   
00431   return 1;
00432 }
00433 
00434 //
00435 // Return non-zero when all the dependency build items has been built
00436 //
00437 static INT8
00438 CheckDependency (
00439   DEPENDENCY_ITEM  *DependencyList
00440   )
00441 {
00442   while (DependencyList != NULL) {
00443     if (!(DependencyList->Dependency->CompleteFlag)) {
00444       return 0;
00445     }
00446     DependencyList = DependencyList->Next;
00447   }
00448   
00449   return 1;
00450 }
00451 
00452 //
00453 // Run the build task. The system() function call  will cause stdout conflict 
00454 // in multi-thread envroment, so implement this through CreateProcess().
00455 //
00456 static INT8
00457 RunBuildTask (
00458   INT8  *WorkingDir, 
00459   INT8  *LogFile, 
00460   INT8  *BuildCmd
00461   )
00462 {
00463   HANDLE                FileHandle;
00464   SECURITY_ATTRIBUTES   SecAttr;
00465   PROCESS_INFORMATION   ProcInfo; 
00466   STARTUPINFO           StartInfo;
00467   BOOL                  FuncRetn;
00468   DWORD                 ExitCode;
00469   
00470   //
00471   // Init SecAttr
00472   //
00473   SecAttr.nLength              = sizeof (SECURITY_ATTRIBUTES); 
00474   SecAttr.bInheritHandle       = TRUE; 
00475   SecAttr.lpSecurityDescriptor = NULL;
00476   
00477   //
00478   // Create the log file
00479   //
00480   FileHandle = CreateFile (
00481                  LogFile,                // file to create
00482                  GENERIC_WRITE,          // open for writing
00483                  0,                      // do not share
00484                  &SecAttr,               // can be inherited by child processes
00485                  CREATE_ALWAYS,          // overwrite existing
00486                  FILE_ATTRIBUTE_NORMAL,  // normal file
00487                  NULL                    // no attr. template
00488                  );
00489 
00490   if (FileHandle == INVALID_HANDLE_VALUE) { 
00491       EnterCriticalSection (&mCriticalSection);
00492       Error (NULL, 0, 0, NULL, "could not open file %s", LogFile);
00493       LeaveCriticalSection (&mCriticalSection);
00494       return 1;
00495   }
00496   
00497   //
00498   // Init ProcInfo and StartInfo
00499   //
00500   ZeroMemory (&ProcInfo, sizeof (PROCESS_INFORMATION));
00501   ZeroMemory (&StartInfo, sizeof (STARTUPINFO));
00502   StartInfo.cb         = sizeof (STARTUPINFO); 
00503   StartInfo.hStdError  = FileHandle;
00504   StartInfo.hStdOutput = FileHandle;
00505   StartInfo.hStdInput  = GetStdHandle (STD_INPUT_HANDLE);
00506   StartInfo.dwFlags    = STARTF_USESTDHANDLES;
00507 
00508   //
00509   // Create the child process
00510   //
00511   FuncRetn = CreateProcess (
00512                NULL,          // no application name
00513                BuildCmd,      // command line 
00514                NULL,          // process security attributes 
00515                NULL,          // primary thread security attributes 
00516                TRUE,          // handles are inherited 
00517                0,             // creation flags 
00518                NULL,          // use parent's environment 
00519                WorkingDir,    // set current directory 
00520                &StartInfo,    // STARTUPINFO pointer 
00521                &ProcInfo      // receives PROCESS_INFORMATION 
00522                );
00523   
00524   if (FuncRetn == FALSE) {
00525     EnterCriticalSection (&mCriticalSection);
00526     Error (NULL, 0, 0, NULL, "could not create child process");
00527     LeaveCriticalSection (&mCriticalSection);
00528     CloseHandle (FileHandle);
00529     return 1;
00530   } 
00531   
00532   //
00533   // Wait until child process exits
00534   //
00535   WaitForSingleObject (ProcInfo.hProcess, INFINITE);
00536   GetExitCodeProcess (ProcInfo.hProcess, &ExitCode);
00537   CloseHandle (ProcInfo.hProcess);
00538   CloseHandle (ProcInfo.hThread);
00539   CloseHandle (FileHandle);
00540   
00541   if (ExitCode != 0) {
00542     return 1;
00543   } else {
00544     return 0;
00545   }
00546 }
00547 
00548 //
00549 // Thread function
00550 //
00551 static DWORD WINAPI
00552 ThreadProc (
00553   LPVOID lpParam
00554   )
00555 {
00556   UINT32      ThreadId;
00557   BUILD_ITEM  *PreviousBuildItem;
00558   BUILD_ITEM  *CurrentBuildItem;
00559   BUILD_ITEM  *NextBuildItem;
00560   INT8        WorkingDir[MAX_PATH];  
00561   INT8        LogFile[MAX_PATH];
00562   INT8        BuildCmd[MAX_PATH];
00563   
00564   ThreadId = (UINT32)lpParam;
00565   //
00566   // Loop until error occurred or no more build items available for build
00567   //
00568   for (;;) {
00569     WaitForSingleObject (mSemaphoreHandle, INFINITE);
00570     if (mError || mDone) {
00571       return 0;
00572     }
00573     
00574     //
00575     // When code runs here, there must have one build item available for this 
00576     // thread. Loop until error occurred or get one build item for build.
00577     //
00578     for (;;) {
00579       EnterCriticalSection (&mCriticalSection);
00580       PreviousBuildItem = NULL;
00581       CurrentBuildItem  = mWaitingList;
00582       while (CurrentBuildItem != NULL) {
00583         NextBuildItem = CurrentBuildItem->Next;
00584         //
00585         // CheckSourceFile() is to avoid concurrently build the same source file
00586         // which may cause the muti-thread build failure
00587         //
00588         if (CheckSourceFile (CurrentBuildItem->SourceFileList)) {
00589           //
00590           // Move the current build item from mWaitingList
00591           //
00592           if (PreviousBuildItem != NULL) {
00593             PreviousBuildItem->Next = NextBuildItem;
00594           } else {
00595             mWaitingList = NextBuildItem;
00596           }
00597           //
00598           // Add the current build item to the head of mBuildingList
00599           //
00600           CurrentBuildItem->Next = mBuildingList;
00601           mBuildingList = CurrentBuildItem;
00602           //
00603           // If no more build items is pending or waiting for build,
00604           // wake up every child thread for exit.
00605           //
00606           if ((mPendingList == NULL) && (mWaitingList == NULL)) {
00607             mDone = 1;
00608             //
00609             // Make sure to wake up every child thread for exit
00610             //        
00611             ReleaseSemaphore (mSemaphoreHandle, mThreadNumber, NULL);
00612           }
00613           break;
00614         }
00615         PreviousBuildItem = CurrentBuildItem;
00616         CurrentBuildItem  = NextBuildItem;
00617       }
00618       if (CurrentBuildItem != NULL) {
00619         //
00620         // Display build item info
00621         //
00622         printf ("\t[Thread_%d] nmake -nologo -f %s all\n", ThreadId, CurrentBuildItem->Makefile);
00623         //
00624         // Prepare build task
00625         //
00626         sprintf (WorkingDir, "%s\\%s", mBuildDir, CurrentBuildItem->Processor);
00627         sprintf (LogFile, "%s\\%s_%s_%d.txt", mLogDir, CurrentBuildItem->BaseName, 
00628                  CurrentBuildItem->Processor, CurrentBuildItem->Index);
00629         sprintf (BuildCmd, "nmake -nologo -f %s all", CurrentBuildItem->Makefile);
00630         LeaveCriticalSection (&mCriticalSection);
00631         break;
00632       } else {
00633         LeaveCriticalSection (&mCriticalSection);
00634         //
00635         // All the build items in mWaitingList have source file conflict with 
00636         // mBuildingList. This rarely hapeens. Need wait for the build items in
00637         // mBuildingList to be finished by other child threads.
00638         //
00639         Sleep (1000);
00640         if (mError) {
00641           return 0;
00642         }
00643       }
00644     }
00645     
00646     //
00647     // Start to build the CurrentBuildItem
00648     //
00649     if (RunBuildTask (WorkingDir, LogFile, BuildCmd)) {
00650       //
00651       // Build failure
00652       //
00653       mError = 1;
00654       //
00655       // Make sure to wake up every child thread for exit
00656       //
00657       ReleaseSemaphore (mSemaphoreHandle, mThreadNumber, NULL);
00658       SetEvent(mEventHandle);
00659 
00660       return mError;
00661     } else {
00662       //
00663       // Build success
00664       //
00665       CurrentBuildItem->CompleteFlag = 1;
00666       
00667       EnterCriticalSection (&mCriticalSection);
00668       //
00669       // Move this build item from mBuildingList
00670       //
00671       if (mBuildingList == CurrentBuildItem) {
00672         mBuildingList = mBuildingList->Next;
00673       } else {
00674         NextBuildItem = mBuildingList;
00675         while (NextBuildItem->Next != CurrentBuildItem) {
00676           NextBuildItem = NextBuildItem->Next;
00677         }
00678         NextBuildItem->Next = CurrentBuildItem->Next;
00679       }
00680       //
00681       // Add this build item to mDoneList
00682       //
00683       CurrentBuildItem->Next = mDoneList;
00684       mDoneList = CurrentBuildItem;
00685       LeaveCriticalSection (&mCriticalSection);
00686       
00687       SetEvent(mEventHandle);
00688     }
00689   }
00690 }
00691 
00692 INT8
00693 StartMultiThreadBuild (
00694   BUILD_ITEM  **BuildList,
00695   UINT32      ThreadNumber,
00696   INT8        *BuildDir
00697   )
00698 /*++
00699 
00700 Routine Description:
00701   
00702   Start multi-thread build for a specified build list
00703 
00704 Arguments:
00705   
00706   BuildList     - build list for multi-thread build
00707   ThreadNumber  - thread number for multi-thread build
00708   BuildDir      - build dir
00709 
00710 Returns:
00711 
00712   0             - Successfully finished the multi-thread build
00713   other value   - Build failure
00714 
00715 --*/
00716 {
00717   UINT32        Index;
00718   UINT32        Count;
00719   BUILD_ITEM    *PreviousBuildItem;
00720   BUILD_ITEM    *CurrentBuildItem;
00721   BUILD_ITEM    *NextBuildItem;
00722   HANDLE        *ThreadHandle;
00723   INT8          Cmd[MAX_PATH];
00724   
00725   mError        = 0;
00726   mDone         = 0;
00727   mThreadNumber = ThreadNumber;
00728   mBuildDir     = BuildDir;
00729   mPendingList  = *BuildList;
00730   *BuildList    = NULL;
00731   mWaitingList  = NULL;
00732   mBuildingList = NULL;
00733   mDoneList     = NULL;
00734   
00735   //
00736   // Do nothing when mPendingList is empty
00737   //
00738   if (mPendingList == NULL) {
00739     return 0;
00740   }
00741   
00742   //
00743   // Get build item count of mPendingList
00744   //
00745   Count = 0;
00746   CurrentBuildItem = mPendingList;
00747   while (CurrentBuildItem != NULL) {
00748     Count++;
00749     CurrentBuildItem = CurrentBuildItem->Next;
00750   }
00751   
00752   //
00753   // The semaphore is also used to wake up child threads for exit,
00754   // so need to make sure "maximum count" >= "thread number".
00755   //
00756   if (Count < ThreadNumber) {
00757     Count = ThreadNumber;
00758   }
00759   
00760   //
00761   // Init mSemaphoreHandle
00762   //
00763   mSemaphoreHandle = CreateSemaphore (
00764                        NULL,       // default security attributes
00765                        0,          // initial count
00766                        Count,      // maximum count
00767                        NULL        // unnamed semaphore
00768                        );
00769   if (mSemaphoreHandle == NULL) {
00770     Error (NULL, 0, 0, NULL, "failed to create semaphore");
00771     RestoreBuildList (BuildList);
00772     return 1;
00773   }  
00774 
00775   //
00776   // Init mEventHandle
00777   //
00778   mEventHandle = CreateEvent( 
00779                    NULL,     // default security attributes
00780                    FALSE,    // auto-reset event
00781                    TRUE,     // initial state is signaled
00782                    NULL      // object not named
00783                    ); 
00784   if (mEventHandle == NULL) { 
00785     Error (NULL, 0, 0, NULL, "failed to create event");
00786     CloseHandle (mSemaphoreHandle);
00787     RestoreBuildList (BuildList);
00788     return 1;
00789   }
00790   
00791   //
00792   // Init mCriticalSection
00793   //
00794   InitializeCriticalSection (&mCriticalSection);
00795   
00796   //
00797   // Create build item log dir
00798   //
00799   sprintf (mLogDir, "%s\\Log", mBuildDir);
00800   _mkdir (mLogDir);
00801   
00802   //
00803   // Create child threads for muti-thread build
00804   //
00805   ThreadHandle = malloc (ThreadNumber * sizeof (HANDLE));
00806   if (ThreadHandle == NULL) {
00807     Error (NULL, 0, 0, NULL, "failed to allocate memory");
00808     CloseHandle (mSemaphoreHandle);
00809     CloseHandle (mEventHandle);
00810     RestoreBuildList (BuildList);
00811     return 1;
00812   }
00813   for (Index = 0; Index < ThreadNumber; Index++) {
00814     ThreadHandle[Index] = CreateThread (
00815                             NULL,           // default security attributes
00816                             0,              // use default stack size
00817                             ThreadProc,     // thread function
00818                             (LPVOID)Index,  // argument to thread function: use Index as thread id
00819                             0,              // use default creation flags
00820                             NULL            // thread identifier not needed
00821                             );
00822     if (ThreadHandle[Index] == NULL) {
00823       Error (NULL, 0, 0, NULL, "failed to create Thread_%d", Index);
00824       mError       = 1;
00825       ThreadNumber = Index;
00826       //
00827       // Make sure to wake up every child thread for exit
00828       //
00829       ReleaseSemaphore (mSemaphoreHandle, ThreadNumber, NULL);
00830       break;
00831     }
00832   }
00833   
00834   //
00835   // Loop until error occurred or no more build items pending for build
00836   //
00837   for (;;) {
00838     WaitForSingleObject (mEventHandle, INFINITE);
00839     if (mError) {
00840       break;
00841     }
00842     Count = 0;
00843     
00844     EnterCriticalSection (&mCriticalSection);
00845     PreviousBuildItem = NULL;
00846     CurrentBuildItem  = mPendingList;
00847     while (CurrentBuildItem != NULL) {
00848       NextBuildItem = CurrentBuildItem->Next;
00849       if (CheckDependency (CurrentBuildItem->DependencyList)) {
00850         //
00851         // Move the current build item from mPendingList
00852         //
00853         if (PreviousBuildItem != NULL) {
00854           PreviousBuildItem->Next = NextBuildItem;
00855         } else {
00856           mPendingList = NextBuildItem;
00857         }
00858         //
00859         // Add the current build item to the head of mWaitingList
00860         //
00861         CurrentBuildItem->Next = mWaitingList;
00862         mWaitingList = CurrentBuildItem;
00863         Count++;
00864       } else {
00865         PreviousBuildItem = CurrentBuildItem;
00866       }
00867       CurrentBuildItem  = NextBuildItem;
00868     }
00869     LeaveCriticalSection (&mCriticalSection);
00870     
00871     ReleaseSemaphore (mSemaphoreHandle, Count, NULL);
00872     if (mPendingList == NULL) {
00873       break;
00874     }
00875   }
00876 
00877   //
00878   // Wait until all threads have terminated
00879   //
00880   WaitForMultipleObjects (ThreadNumber, ThreadHandle, TRUE, INFINITE);
00881   
00882   if (mError && (mBuildingList != NULL)) {
00883     //
00884     // Dump build failure log of the first build item which doesn't finish the build
00885     //
00886     printf ("\tnmake -nologo -f %s all\n", mBuildingList->Makefile);
00887     sprintf (Cmd, "type %s\\%s_%s_%d.txt 2>NUL", mLogDir, mBuildingList->BaseName,
00888              mBuildingList->Processor, mBuildingList->Index);
00889     _flushall ();
00890     if (system (Cmd)) {
00891       Error (NULL, 0, 0, NULL, "failed to run \"%s\"", Cmd);
00892     }
00893   }
00894 
00895   DeleteCriticalSection (&mCriticalSection);
00896   for (Index = 0; Index < ThreadNumber; Index++) {
00897     CloseHandle (ThreadHandle[Index]);
00898   }
00899   free (ThreadHandle);
00900   CloseHandle (mSemaphoreHandle);
00901   CloseHandle (mEventHandle);
00902   RestoreBuildList (BuildList);
00903 
00904   return mError;
00905 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines