]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/MultiThread.c
b6a72eca784c6aad6a1ab40275373d5786c09d17
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Tools / Source / ProcessDsc / MultiThread.c
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 }