1/*++ 2 3Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR> 4This program and the accompanying materials 5are licensed and made available under the terms and conditions of the BSD License 6which accompanies this distribution. The full text of the license may be found at 7http://opensource.org/licenses/bsd-license.php 8 9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12Module Name: 13 14 MultiThread.c 15 16Abstract: 17 18 This module is used to add multi-thread build support to ProcessDsc utility 19 to improve the build performance. 20 21--*/ 22 23#include <windows.h> 24#include <stdio.h> 25#include <string.h> 26#include <stdlib.h> 27#include <direct.h> 28#include "Common.h" 29#include "MultiThread.h" 30 31BUILD_ITEM * 32AddBuildItem ( 33 BUILD_ITEM **BuildList, 34 INT8 *BaseName, 35 INT8 *Processor, 36 INT8 *Makefile 37 ) 38/*++ 39 40Routine Description: 41 42 Add a build item to a specified build list 43 44Arguments: 45 46 BuildList - build list where the new build item will be added 47 BaseName - base name of the new module 48 Processor - processor type of the new module 49 Makefile - makefile name of the new module 50 51Returns: 52 53 Pointer to the newly added build item 54 55--*/ 56{ 57 BUILD_ITEM *NewBuildItem; 58 59 // 60 // Create a new build item 61 // 62 NewBuildItem = malloc (sizeof (BUILD_ITEM)); 63 if (NewBuildItem == NULL) { 64 return NULL; 65 } 66 memset (NewBuildItem, 0, sizeof (BUILD_ITEM)); 67 NewBuildItem->BaseName = _strdup (BaseName); 68 NewBuildItem->Processor = _strdup (Processor); 69 NewBuildItem->Makefile = _strdup (Makefile); 70 71 // 72 // Add the build item to the head of the build list 73 // 74 NewBuildItem->Next = *BuildList; 75 *BuildList = NewBuildItem; 76 77 return NewBuildItem; 78} 79 80SOURCE_FILE_ITEM * 81AddSourceFile ( 82 BUILD_ITEM *BuildItem, 83 INT8 *FileName 84 ) 85/*++ 86 87Routine Description: 88 89 Add a source file for a build item 90 91Arguments: 92 93 BuildItem - build item to add the source file 94 FileName - source file name to be added 95 96Returns: 97 98 Pointer to the newly added source file item 99 100--*/ 101{ 102 SOURCE_FILE_ITEM *NewSourceFile; 103 104 // 105 // Create a new source file item 106 // 107 NewSourceFile = malloc (sizeof (SOURCE_FILE_ITEM)); 108 if (NewSourceFile == NULL) { 109 return NULL; 110 } 111 memset (NewSourceFile, 0, sizeof (SOURCE_FILE_ITEM)); 112 NewSourceFile->FileName = _strdup (FileName); 113 114 // 115 // Add the source file item to the head of the source file list 116 // 117 NewSourceFile->Next = BuildItem->SourceFileList; 118 BuildItem->SourceFileList = NewSourceFile; 119 120 return NewSourceFile; 121} 122 123DEPENDENCY_ITEM * 124AddDependency ( 125 BUILD_ITEM *BuildList, 126 BUILD_ITEM *BuildItem, 127 INT8 *BaseName, 128 INT8 AdjustIndex 129 ) 130/*++ 131 132Routine Description: 133 134 Add a build dependency for a build item in the specified build list 135 136Arguments: 137 138 BuildList - build list where to search the dependency 139 BuildItem - build item to add the dependency 140 BaseName - dependency module base name 141 AdjustIndex - Adjust BuildItem->Index when non-zero 142 143Returns: 144 145 Pointer to the newly added build dependency 146 147--*/ 148{ 149 BUILD_ITEM *TempBuildItem; 150 DEPENDENCY_ITEM *NewDependency; 151 152 // 153 // Search the dependency in the build list 154 // 155 TempBuildItem = BuildList; 156 while (TempBuildItem != NULL) { 157 if ((_stricmp (TempBuildItem->BaseName, BaseName) == 0) && 158 (_stricmp (TempBuildItem->Processor, BuildItem->Processor) == 0) && 159 (TempBuildItem != BuildItem)) { 160 break; 161 } 162 TempBuildItem = TempBuildItem->Next; 163 } 164 if (TempBuildItem == NULL) { 165 return NULL; 166 } 167 168 // 169 // This index is used to isolate two modules with same base name and processor. 170 // (ProcessDsc allows duplicate base name libraries.) 171 // 172 if (AdjustIndex) { 173 BuildItem->Index = TempBuildItem->Index + 1; 174 } 175 176 // 177 // Create a new build dependency item 178 // 179 NewDependency = malloc (sizeof (DEPENDENCY_ITEM)); 180 if (NewDependency == NULL) { 181 return NULL; 182 } 183 memset (NewDependency, 0, sizeof (DEPENDENCY_ITEM)); 184 NewDependency->Dependency = TempBuildItem; 185 186 // 187 // Add the build dependency item to the head of the dependency list 188 // 189 NewDependency->Next = BuildItem->DependencyList; 190 BuildItem->DependencyList = NewDependency; 191 192 return NewDependency; 193} 194 195void 196FreeBuildList ( 197 BUILD_ITEM *BuildList 198 ) 199/*++ 200 201Routine Description: 202 203 Free a build list 204 205Arguments: 206 207 BuildList - build list to be freed 208 209Returns: 210 211--*/ 212{ 213 BUILD_ITEM *TempBuildItem; 214 BUILD_ITEM *FreeBuildItem; 215 SOURCE_FILE_ITEM *TempSourceFile; 216 SOURCE_FILE_ITEM *FreeSourceFile; 217 DEPENDENCY_ITEM *TempDependency; 218 DEPENDENCY_ITEM *FreeDependency; 219 220 TempBuildItem = BuildList; 221 while (TempBuildItem != NULL) { 222 free (TempBuildItem->BaseName); 223 free (TempBuildItem->Processor); 224 free (TempBuildItem->Makefile); 225 226 // 227 // Free source file list 228 // 229 TempSourceFile = TempBuildItem->SourceFileList; 230 while (TempSourceFile != NULL) { 231 FreeSourceFile = TempSourceFile; 232 TempSourceFile = TempSourceFile->Next; 233 free (FreeSourceFile); 234 } 235 236 // 237 // Free dependency list 238 // 239 TempDependency = TempBuildItem->DependencyList; 240 while (TempDependency != NULL) { 241 FreeDependency = TempDependency; 242 TempDependency = TempDependency->Next; 243 free (FreeDependency); 244 } 245 246 FreeBuildItem = TempBuildItem; 247 TempBuildItem = TempBuildItem->Next; 248 free (FreeBuildItem); 249 } 250} 251 252COMPONENTS_ITEM * 253AddComponentsItem ( 254 COMPONENTS_ITEM **ComponentsList 255 ) 256/*++ 257 258Routine Description: 259 260 Add a new components item to a specified components list 261 262Arguments: 263 264 ComponentsList - components list where the new components item will be added 265 266Returns: 267 268 Pointer to the newly added components item 269 270--*/ 271{ 272 COMPONENTS_ITEM *NewComponents; 273 COMPONENTS_ITEM *TempComponents; 274 275 // 276 // Create a new components item 277 // 278 NewComponents = malloc (sizeof (COMPONENTS_ITEM)); 279 if (NewComponents == NULL) { 280 return NULL; 281 } 282 memset (NewComponents, 0, sizeof (COMPONENTS_ITEM)); 283 284 // 285 // Add the components item to the tail of the components list 286 // 287 TempComponents = *ComponentsList; 288 if (TempComponents == NULL) { 289 *ComponentsList = NewComponents; 290 } else { 291 while (TempComponents->Next != NULL) { 292 TempComponents = TempComponents->Next; 293 } 294 TempComponents->Next = NewComponents; 295 } 296 297 return NewComponents; 298} 299 300void 301FreeComponentsList ( 302 COMPONENTS_ITEM *ComponentsList 303 ) 304/*++ 305 306Routine Description: 307 308 Free a components list 309 310Arguments: 311 312 ComponentsList - components list to be freed 313 314Returns: 315 316--*/ 317{ 318 COMPONENTS_ITEM *TempComponents; 319 COMPONENTS_ITEM *FreeComponents; 320 321 TempComponents = ComponentsList; 322 while (TempComponents != NULL) { 323 FreeBuildList (TempComponents->BuildList); 324 FreeComponents = TempComponents; 325 TempComponents = TempComponents->Next; 326 free (FreeComponents); 327 } 328} 329 330// 331// Module globals for multi-thread build 332// 333static INT8 mError; // non-zero means error occurred 334static INT8 mDone; // non-zero means no more build items available for build 335static UINT32 mThreadNumber; // thread number 336static INT8 *mBuildDir; // build directory 337static INT8 mLogDir[MAX_PATH]; // build item log dir 338static CRITICAL_SECTION mCriticalSection; // critical section object 339static HANDLE mSemaphoreHandle; // semaphore for "ready for build" items in mWaitingList 340static HANDLE mEventHandle; // event signaled when one build item is finished 341static BUILD_ITEM *mPendingList; // build list for build items which are not ready for build 342static BUILD_ITEM *mWaitingList; // build list for build items which are ready for build 343static BUILD_ITEM *mBuildingList; // build list for build items which are buiding 344static BUILD_ITEM *mDoneList; // build list for build items which already finish the build 345 346// 347// Restore the BuildList (not care about the sequence of the build items) 348// 349static void 350RestoreBuildList ( 351 BUILD_ITEM **BuildList 352 ) 353{ 354 BUILD_ITEM *TempBuildItem; 355 356 if (mPendingList != NULL) { 357 // 358 // Add the mPendingList to the header of *BuildList 359 // 360 TempBuildItem = mPendingList; 361 while (TempBuildItem->Next != NULL) { 362 TempBuildItem = TempBuildItem->Next; 363 } 364 TempBuildItem->Next = *BuildList; 365 *BuildList = mPendingList; 366 } 367 368 if (mWaitingList != NULL) { 369 // 370 // Add the mWaitingList to the header of *BuildList 371 // 372 TempBuildItem = mWaitingList; 373 while (TempBuildItem->Next != NULL) { 374 TempBuildItem = TempBuildItem->Next; 375 } 376 TempBuildItem->Next = *BuildList; 377 *BuildList = mWaitingList; 378 } 379 380 if (mBuildingList != NULL) { 381 // 382 // Add the mBuildingList to the header of *BuildList 383 // 384 TempBuildItem = mBuildingList; 385 while (TempBuildItem->Next != NULL) { 386 TempBuildItem = TempBuildItem->Next; 387 } 388 TempBuildItem->Next = *BuildList; 389 *BuildList = mBuildingList; 390 } 391 392 if (mDoneList != NULL) { 393 // 394 // Add the mDoneList to the header of *BuildList 395 // 396 TempBuildItem = mDoneList; 397 while (TempBuildItem->Next != NULL) { 398 TempBuildItem = TempBuildItem->Next; 399 } 400 TempBuildItem->Next = *BuildList; 401 *BuildList = mDoneList; 402 } 403} 404 405// 406// Return non-zero when no source file build conflict 407// 408static INT8 409CheckSourceFile ( 410 SOURCE_FILE_ITEM *SourceFileList 411 ) 412{ 413 BUILD_ITEM *TempBuildItem; 414 SOURCE_FILE_ITEM *TempSourceFile; 415 416 while (SourceFileList != NULL) { 417 TempBuildItem = mBuildingList; 418 while (TempBuildItem != NULL) { 419 TempSourceFile = TempBuildItem->SourceFileList; 420 while (TempSourceFile != NULL) { 421 if (_stricmp (SourceFileList->FileName, TempSourceFile->FileName) == 0) { 422 return 0; 423 } 424 TempSourceFile = TempSourceFile->Next; 425 } 426 TempBuildItem = TempBuildItem->Next; 427 } 428 SourceFileList = SourceFileList->Next; 429 } 430 431 return 1; 432} 433 434// 435// Return non-zero when all the dependency build items has been built 436// 437static INT8 438CheckDependency ( 439 DEPENDENCY_ITEM *DependencyList 440 ) 441{ 442 while (DependencyList != NULL) { 443 if (!(DependencyList->Dependency->CompleteFlag)) { 444 return 0; 445 } 446 DependencyList = DependencyList->Next; 447 } 448 449 return 1; 450} 451 452// 453// Run the build task. The system() function call will cause stdout conflict 454// in multi-thread envroment, so implement this through CreateProcess(). 455// 456static INT8 457RunBuildTask ( 458 INT8 *WorkingDir, 459 INT8 *LogFile, 460 INT8 *BuildCmd 461 ) 462{ 463 HANDLE FileHandle; 464 SECURITY_ATTRIBUTES SecAttr; 465 PROCESS_INFORMATION ProcInfo; 466 STARTUPINFO StartInfo; 467 BOOL FuncRetn; 468 DWORD ExitCode; 469 470 // 471 // Init SecAttr 472 // 473 SecAttr.nLength = sizeof (SECURITY_ATTRIBUTES); 474 SecAttr.bInheritHandle = TRUE; 475 SecAttr.lpSecurityDescriptor = NULL; 476 477 // 478 // Create the log file 479 // 480 FileHandle = CreateFile ( 481 LogFile, // file to create 482 GENERIC_WRITE, // open for writing 483 0, // do not share 484 &SecAttr, // can be inherited by child processes 485 CREATE_ALWAYS, // overwrite existing 486 FILE_ATTRIBUTE_NORMAL, // normal file 487 NULL // no attr. template 488 ); 489 490 if (FileHandle == INVALID_HANDLE_VALUE) { 491 EnterCriticalSection (&mCriticalSection); 492 Error (NULL, 0, 0, NULL, "could not open file %s", LogFile); 493 LeaveCriticalSection (&mCriticalSection); 494 return 1; 495 } 496 497 // 498 // Init ProcInfo and StartInfo 499 // 500 ZeroMemory (&ProcInfo, sizeof (PROCESS_INFORMATION)); 501 ZeroMemory (&StartInfo, sizeof (STARTUPINFO)); 502 StartInfo.cb = sizeof (STARTUPINFO); 503 StartInfo.hStdError = FileHandle; 504 StartInfo.hStdOutput = FileHandle; 505 StartInfo.hStdInput = GetStdHandle (STD_INPUT_HANDLE); 506 StartInfo.dwFlags = STARTF_USESTDHANDLES; 507 508 // 509 // Create the child process 510 // 511 FuncRetn = CreateProcess ( 512 NULL, // no application name 513 BuildCmd, // command line 514 NULL, // process security attributes 515 NULL, // primary thread security attributes 516 TRUE, // handles are inherited 517 0, // creation flags 518 NULL, // use parent's environment 519 WorkingDir, // set current directory 520 &StartInfo, // STARTUPINFO pointer 521 &ProcInfo // receives PROCESS_INFORMATION 522 ); 523 524 if (FuncRetn == FALSE) { 525 EnterCriticalSection (&mCriticalSection); 526 Error (NULL, 0, 0, NULL, "could not create child process"); 527 LeaveCriticalSection (&mCriticalSection); 528 CloseHandle (FileHandle); 529 return 1; 530 } 531 532 // 533 // Wait until child process exits 534 // 535 WaitForSingleObject (ProcInfo.hProcess, INFINITE); 536 GetExitCodeProcess (ProcInfo.hProcess, &ExitCode); 537 CloseHandle (ProcInfo.hProcess); 538 CloseHandle (ProcInfo.hThread); 539 CloseHandle (FileHandle); 540 541 if (ExitCode != 0) { 542 return 1; 543 } else { 544 return 0; 545 } 546} 547 548// 549// Thread function 550// 551static DWORD WINAPI 552ThreadProc ( 553 LPVOID lpParam 554 ) 555{ 556 UINT32 ThreadId; 557 BUILD_ITEM *PreviousBuildItem; 558 BUILD_ITEM *CurrentBuildItem; 559 BUILD_ITEM *NextBuildItem; 560 INT8 WorkingDir[MAX_PATH]; 561 INT8 LogFile[MAX_PATH]; 562 INT8 BuildCmd[MAX_PATH]; 563 564 ThreadId = (UINT32)lpParam; 565 // 566 // Loop until error occurred or no more build items available for build 567 // 568 for (;;) { 569 WaitForSingleObject (mSemaphoreHandle, INFINITE); 570 if (mError || mDone) { 571 return 0; 572 } 573 574 // 575 // When code runs here, there must have one build item available for this 576 // thread. Loop until error occurred or get one build item for build. 577 // 578 for (;;) { 579 EnterCriticalSection (&mCriticalSection); 580 PreviousBuildItem = NULL; 581 CurrentBuildItem = mWaitingList; 582 while (CurrentBuildItem != NULL) { 583 NextBuildItem = CurrentBuildItem->Next; 584 // 585 // CheckSourceFile() is to avoid concurrently build the same source file 586 // which may cause the muti-thread build failure 587 // 588 if (CheckSourceFile (CurrentBuildItem->SourceFileList)) { 589 // 590 // Move the current build item from mWaitingList 591 // 592 if (PreviousBuildItem != NULL) { 593 PreviousBuildItem->Next = NextBuildItem; 594 } else { 595 mWaitingList = NextBuildItem; 596 } 597 // 598 // Add the current build item to the head of mBuildingList 599 // 600 CurrentBuildItem->Next = mBuildingList; 601 mBuildingList = CurrentBuildItem; 602 // 603 // If no more build items is pending or waiting for build, 604 // wake up every child thread for exit. 605 // 606 if ((mPendingList == NULL) && (mWaitingList == NULL)) { 607 mDone = 1; 608 // 609 // Make sure to wake up every child thread for exit 610 // 611 ReleaseSemaphore (mSemaphoreHandle, mThreadNumber, NULL); 612 } 613 break; 614 } 615 PreviousBuildItem = CurrentBuildItem; 616 CurrentBuildItem = NextBuildItem; 617 } 618 if (CurrentBuildItem != NULL) { 619 // 620 // Display build item info 621 // 622 printf ("\t[Thread_%d] nmake -nologo -f %s all\n", ThreadId, CurrentBuildItem->Makefile); 623 // 624 // Prepare build task 625 // 626 sprintf (WorkingDir, "%s\\%s", mBuildDir, CurrentBuildItem->Processor); 627 sprintf (LogFile, "%s\\%s_%s_%d.txt", mLogDir, CurrentBuildItem->BaseName, 628 CurrentBuildItem->Processor, CurrentBuildItem->Index); 629 sprintf (BuildCmd, "nmake -nologo -f %s all", CurrentBuildItem->Makefile); 630 LeaveCriticalSection (&mCriticalSection); 631 break; 632 } else { 633 LeaveCriticalSection (&mCriticalSection); 634 // 635 // All the build items in mWaitingList have source file conflict with 636 // mBuildingList. This rarely hapeens. Need wait for the build items in 637 // mBuildingList to be finished by other child threads. 638 // 639 Sleep (1000); 640 if (mError) { 641 return 0; 642 } 643 } 644 } 645 646 // 647 // Start to build the CurrentBuildItem 648 // 649 if (RunBuildTask (WorkingDir, LogFile, BuildCmd)) { 650 // 651 // Build failure 652 // 653 mError = 1; 654 // 655 // Make sure to wake up every child thread for exit 656 // 657 ReleaseSemaphore (mSemaphoreHandle, mThreadNumber, NULL); 658 SetEvent(mEventHandle); 659 660 return mError; 661 } else { 662 // 663 // Build success 664 // 665 CurrentBuildItem->CompleteFlag = 1; 666 667 EnterCriticalSection (&mCriticalSection); 668 // 669 // Move this build item from mBuildingList 670 // 671 if (mBuildingList == CurrentBuildItem) { 672 mBuildingList = mBuildingList->Next; 673 } else { 674 NextBuildItem = mBuildingList; 675 while (NextBuildItem->Next != CurrentBuildItem) { 676 NextBuildItem = NextBuildItem->Next; 677 } 678 NextBuildItem->Next = CurrentBuildItem->Next; 679 } 680 // 681 // Add this build item to mDoneList 682 // 683 CurrentBuildItem->Next = mDoneList; 684 mDoneList = CurrentBuildItem; 685 LeaveCriticalSection (&mCriticalSection); 686 687 SetEvent(mEventHandle); 688 } 689 } 690} 691 692INT8 693StartMultiThreadBuild ( 694 BUILD_ITEM **BuildList, 695 UINT32 ThreadNumber, 696 INT8 *BuildDir 697 ) 698/*++ 699 700Routine Description: 701 702 Start multi-thread build for a specified build list 703 704Arguments: 705 706 BuildList - build list for multi-thread build 707 ThreadNumber - thread number for multi-thread build 708 BuildDir - build dir 709 710Returns: 711 712 0 - Successfully finished the multi-thread build 713 other value - Build failure 714 715--*/ 716{ 717 UINT32 Index; 718 UINT32 Count; 719 BUILD_ITEM *PreviousBuildItem; 720 BUILD_ITEM *CurrentBuildItem; 721 BUILD_ITEM *NextBuildItem; 722 HANDLE *ThreadHandle; 723 INT8 Cmd[MAX_PATH]; 724 725 mError = 0; 726 mDone = 0; 727 mThreadNumber = ThreadNumber; 728 mBuildDir = BuildDir; 729 mPendingList = *BuildList; 730 *BuildList = NULL; 731 mWaitingList = NULL; 732 mBuildingList = NULL; 733 mDoneList = NULL; 734 735 // 736 // Do nothing when mPendingList is empty 737 // 738 if (mPendingList == NULL) { 739 return 0; 740 } 741 742 // 743 // Get build item count of mPendingList 744 // 745 Count = 0; 746 CurrentBuildItem = mPendingList; 747 while (CurrentBuildItem != NULL) { 748 Count++; 749 CurrentBuildItem = CurrentBuildItem->Next; 750 } 751 752 // 753 // The semaphore is also used to wake up child threads for exit, 754 // so need to make sure "maximum count" >= "thread number". 755 // 756 if (Count < ThreadNumber) { 757 Count = ThreadNumber; 758 } 759 760 // 761 // Init mSemaphoreHandle 762 // 763 mSemaphoreHandle = CreateSemaphore ( 764 NULL, // default security attributes 765 0, // initial count 766 Count, // maximum count 767 NULL // unnamed semaphore 768 ); 769 if (mSemaphoreHandle == NULL) { 770 Error (NULL, 0, 0, NULL, "failed to create semaphore"); 771 RestoreBuildList (BuildList); 772 return 1; 773 } 774 775 // 776 // Init mEventHandle 777 // 778 mEventHandle = CreateEvent( 779 NULL, // default security attributes 780 FALSE, // auto-reset event 781 TRUE, // initial state is signaled 782 NULL // object not named 783 ); 784 if (mEventHandle == NULL) { 785 Error (NULL, 0, 0, NULL, "failed to create event"); 786 CloseHandle (mSemaphoreHandle); 787 RestoreBuildList (BuildList); 788 return 1; 789 } 790 791 // 792 // Init mCriticalSection 793 // 794 InitializeCriticalSection (&mCriticalSection); 795 796 // 797 // Create build item log dir 798 // 799 sprintf (mLogDir, "%s\\Log", mBuildDir); 800 _mkdir (mLogDir); 801 802 // 803 // Create child threads for muti-thread build 804 // 805 ThreadHandle = malloc (ThreadNumber * sizeof (HANDLE)); 806 if (ThreadHandle == NULL) { 807 Error (NULL, 0, 0, NULL, "failed to allocate memory"); 808 CloseHandle (mSemaphoreHandle); 809 CloseHandle (mEventHandle); 810 RestoreBuildList (BuildList); 811 return 1; 812 } 813 for (Index = 0; Index < ThreadNumber; Index++) { 814 ThreadHandle[Index] = CreateThread ( 815 NULL, // default security attributes 816 0, // use default stack size 817 ThreadProc, // thread function 818 (LPVOID)Index, // argument to thread function: use Index as thread id 819 0, // use default creation flags 820 NULL // thread identifier not needed 821 ); 822 if (ThreadHandle[Index] == NULL) { 823 Error (NULL, 0, 0, NULL, "failed to create Thread_%d", Index); 824 mError = 1; 825 ThreadNumber = Index; 826 // 827 // Make sure to wake up every child thread for exit 828 // 829 ReleaseSemaphore (mSemaphoreHandle, ThreadNumber, NULL); 830 break; 831 } 832 } 833 834 // 835 // Loop until error occurred or no more build items pending for build 836 // 837 for (;;) { 838 WaitForSingleObject (mEventHandle, INFINITE); 839 if (mError) { 840 break; 841 } 842 Count = 0; 843 844 EnterCriticalSection (&mCriticalSection); 845 PreviousBuildItem = NULL; 846 CurrentBuildItem = mPendingList; 847 while (CurrentBuildItem != NULL) { 848 NextBuildItem = CurrentBuildItem->Next; 849 if (CheckDependency (CurrentBuildItem->DependencyList)) { 850 // 851 // Move the current build item from mPendingList 852 // 853 if (PreviousBuildItem != NULL) { 854 PreviousBuildItem->Next = NextBuildItem; 855 } else { 856 mPendingList = NextBuildItem; 857 } 858 // 859 // Add the current build item to the head of mWaitingList 860 // 861 CurrentBuildItem->Next = mWaitingList; 862 mWaitingList = CurrentBuildItem; 863 Count++; 864 } else { 865 PreviousBuildItem = CurrentBuildItem; 866 } 867 CurrentBuildItem = NextBuildItem; 868 } 869 LeaveCriticalSection (&mCriticalSection); 870 871 ReleaseSemaphore (mSemaphoreHandle, Count, NULL); 872 if (mPendingList == NULL) { 873 break; 874 } 875 } 876 877 // 878 // Wait until all threads have terminated 879 // 880 WaitForMultipleObjects (ThreadNumber, ThreadHandle, TRUE, INFINITE); 881 882 if (mError && (mBuildingList != NULL)) { 883 // 884 // Dump build failure log of the first build item which doesn't finish the build 885 // 886 printf ("\tnmake -nologo -f %s all\n", mBuildingList->Makefile); 887 sprintf (Cmd, "type %s\\%s_%s_%d.txt 2>NUL", mLogDir, mBuildingList->BaseName, 888 mBuildingList->Processor, mBuildingList->Index); 889 _flushall (); 890 if (system (Cmd)) { 891 Error (NULL, 0, 0, NULL, "failed to run \"%s\"", Cmd); 892 } 893 } 894 895 DeleteCriticalSection (&mCriticalSection); 896 for (Index = 0; Index < ThreadNumber; Index++) { 897 CloseHandle (ThreadHandle[Index]); 898 } 899 free (ThreadHandle); 900 CloseHandle (mSemaphoreHandle); 901 CloseHandle (mEventHandle); 902 RestoreBuildList (BuildList); 903 904 return mError; 905} 906