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