1 /*++ 2 3 Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 14 MultiThread.c 15 16 Abstract: 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 31 BUILD_ITEM * 32 AddBuildItem ( 33 BUILD_ITEM **BuildList, 34 INT8 *BaseName, 35 INT8 *Processor, 36 INT8 *Makefile 37 ) 38 /*++ 39 40 Routine Description: 41 42 Add a build item to a specified build list 43 44 Arguments: 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 51 Returns: 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 80 SOURCE_FILE_ITEM * 81 AddSourceFile ( 82 BUILD_ITEM *BuildItem, 83 INT8 *FileName 84 ) 85 /*++ 86 87 Routine Description: 88 89 Add a source file for a build item 90 91 Arguments: 92 93 BuildItem - build item to add the source file 94 FileName - source file name to be added 95 96 Returns: 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 123 DEPENDENCY_ITEM * 124 AddDependency ( 125 BUILD_ITEM *BuildList, 126 BUILD_ITEM *BuildItem, 127 INT8 *BaseName, 128 INT8 AdjustIndex 129 ) 130 /*++ 131 132 Routine Description: 133 134 Add a build dependency for a build item in the specified build list 135 136 Arguments: 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 143 Returns: 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 195 void 196 FreeBuildList ( 197 BUILD_ITEM *BuildList 198 ) 199 /*++ 200 201 Routine Description: 202 203 Free a build list 204 205 Arguments: 206 207 BuildList - build list to be freed 208 209 Returns: 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 252 COMPONENTS_ITEM * 253 AddComponentsItem ( 254 COMPONENTS_ITEM **ComponentsList 255 ) 256 /*++ 257 258 Routine Description: 259 260 Add a new components item to a specified components list 261 262 Arguments: 263 264 ComponentsList - components list where the new components item will be added 265 266 Returns: 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 300 void 301 FreeComponentsList ( 302 COMPONENTS_ITEM *ComponentsList 303 ) 304 /*++ 305 306 Routine Description: 307 308 Free a components list 309 310 Arguments: 311 312 ComponentsList - components list to be freed 313 314 Returns: 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 // 333 static INT8 mError; // non-zero means error occurred 334 static INT8 mDone; // non-zero means no more build items available for build 335 static UINT32 mThreadNumber; // thread number 336 static INT8 *mBuildDir; // build directory 337 static INT8 mLogDir[MAX_PATH]; // build item log dir 338 static CRITICAL_SECTION mCriticalSection; // critical section object 339 static HANDLE mSemaphoreHandle; // semaphore for "ready for build" items in mWaitingList 340 static HANDLE mEventHandle; // event signaled when one build item is finished 341 static BUILD_ITEM *mPendingList; // build list for build items which are not ready for build 342 static BUILD_ITEM *mWaitingList; // build list for build items which are ready for build 343 static BUILD_ITEM *mBuildingList; // build list for build items which are buiding 344 static 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 // 349 static void 350 RestoreBuildList ( 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 // 408 static INT8 409 CheckSourceFile ( 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 // 437 static INT8 438 CheckDependency ( 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 // 456 static INT8 457 RunBuildTask ( 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 // 551 static DWORD WINAPI 552 ThreadProc ( 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 692 INT8 693 StartMultiThreadBuild ( 694 BUILD_ITEM **BuildList, 695 UINT32 ThreadNumber, 696 INT8 *BuildDir 697 ) 698 /*++ 699 700 Routine Description: 701 702 Start multi-thread build for a specified build list 703 704 Arguments: 705 706 BuildList - build list for multi-thread build 707 ThreadNumber - thread number for multi-thread build 708 BuildDir - build dir 709 710 Returns: 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