VirtualBox

source: kBuild/trunk/src/kmk/incdep.c@ 2283

最後變更 在這個檔案從2283是 2283,由 bird 提交於 16 年 前

incdep.c: If we find LD_PRELOAD on linux, assume the worst and disable threading (try fixing the hppa debian build break generically).

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 49.2 KB
 
1#ifdef CONFIG_WITH_INCLUDEDEP
2/* $Id: incdep.c 2283 2009-02-24 04:54:00Z bird $ */
3/** @file
4 * incdep - Simple dependency files.
5 */
6
7/*
8 * Copyright (c) 2007-2009 knut st. osmundsen <[email protected]>
9 *
10 * This file is part of kBuild.
11 *
12 * kBuild is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * kBuild is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
24 *
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#ifdef __OS2__
31# define INCL_BASE
32# define INCL_ERRORS
33#endif
34
35#include "make.h"
36
37#if !defined(WINDOWS32) && !defined(__OS2__)
38# define HAVE_PTHREAD
39#endif
40
41#include <assert.h>
42
43#include <glob.h>
44
45#include "dep.h"
46#include "filedef.h"
47#include "job.h"
48#include "commands.h"
49#include "variable.h"
50#include "rule.h"
51#include "debug.h"
52#include "strcache2.h"
53
54#ifdef HAVE_FCNTL_H
55# include <fcntl.h>
56#else
57# include <sys/file.h>
58#endif
59
60#ifdef WINDOWS32
61# include <io.h>
62# include <process.h>
63# include <Windows.h>
64# define PARSE_IN_WORKER
65#endif
66
67#ifdef __OS2__
68# include <os2.h>
69# include <sys/fmutex.h>
70#endif
71
72#ifdef HAVE_PTHREAD
73# include <pthread.h>
74#endif
75
76#ifdef __APPLE__
77# include <malloc/malloc.h>
78# define PARSE_IN_WORKER
79#endif
80
81#if defined(__gnu_linux__) || defined(__linux__)
82# define PARSE_IN_WORKER
83#endif
84
85
86/*******************************************************************************
87* Structures and Typedefs *
88*******************************************************************************/
89struct incdep_variable_in_set
90{
91 struct incdep_variable_in_set *next;
92 /* the parameters */
93 struct strcache2_entry *name_entry; /* dep strcache - WRONG */
94 const char *value; /* xmalloc'ed */
95 unsigned int value_length;
96 int duplicate_value; /* 0 */
97 enum variable_origin origin;
98 int recursive;
99 struct variable_set *set;
100 const struct floc *flocp; /* NILF */
101};
102
103struct incdep_variable_def
104{
105 struct incdep_variable_def *next;
106 /* the parameters */
107 const struct floc *flocp; /* NILF */
108 struct strcache2_entry *name_entry; /* dep strcache - WRONG */
109 char *value; /* xmalloc'ed, free it */
110 unsigned int value_length;
111 enum variable_origin origin;
112 enum variable_flavor flavor;
113 int target_var;
114};
115
116struct incdep_recorded_files
117{
118 struct incdep_recorded_files *next;
119
120 /* the parameters */
121 struct strcache2_entry *filename_entry; /* dep strcache; converted to a nameseq record. */
122 const char *pattern; /* NULL */
123 const char *pattern_percent; /* NULL */
124 struct dep *deps; /* All the names are dep strcache entries. */
125 unsigned int cmds_started; /* 0 */
126 char *commands; /* NULL */
127 unsigned int commands_idx; /* 0 */
128 int two_colon; /* 0 */
129 const struct floc *flocp; /* NILF */
130};
131
132
133/* per dep file structure. */
134struct incdep
135{
136 struct incdep *next;
137 char *file_base;
138 char *file_end;
139
140 int worker_tid;
141#ifdef PARSE_IN_WORKER
142 unsigned int err_line_no;
143 const char *err_msg;
144
145 struct incdep_variable_in_set *recorded_variables_in_set_head;
146 struct incdep_variable_in_set *recorded_variables_in_set_tail;
147
148 struct incdep_variable_def *recorded_variable_defs_head;
149 struct incdep_variable_def *recorded_variable_defs_tail;
150
151 struct incdep_recorded_files *recorded_files_head;
152 struct incdep_recorded_files *recorded_files_tail;
153#endif
154
155 char name[1];
156};
157
158
159/*******************************************************************************
160* Global Variables *
161*******************************************************************************/
162
163/* mutex protecting the globals and an associated condition/event. */
164#ifdef HAVE_PTHREAD
165static pthread_mutex_t incdep_mtx;
166static pthread_cond_t incdep_cond_todo;
167static pthread_cond_t incdep_cond_done;
168
169#elif defined (WINDOWS32)
170static CRITICAL_SECTION incdep_mtx;
171static HANDLE incdep_hev_todo;
172static HANDLE incdep_hev_done;
173static int volatile incdep_hev_todo_waiters;
174static int volatile incdep_hev_done_waiters;
175
176#elif defined (__OS2__)
177static _fmutex incdep_mtx;
178static HEV incdep_hev_todo;
179static HEV incdep_hev_done;
180static int volatile incdep_hev_todo_waiters;
181static int volatile incdep_hev_done_waiters;
182#endif
183
184/* flag indicating whether the threads, lock and event/condvars has
185 been initialized or not. */
186static int incdep_initialized;
187
188/* the list of files that needs reading. */
189static struct incdep * volatile incdep_head_todo;
190static struct incdep * volatile incdep_tail_todo;
191
192/* the number of files that are currently being read. */
193static int volatile incdep_num_reading;
194
195/* the list of files that have been read. */
196static struct incdep * volatile incdep_head_done;
197static struct incdep * volatile incdep_tail_done;
198
199
200/* The handles to the worker threads. */
201#ifdef HAVE_PTHREAD
202# define INCDEP_MAX_THREADS 1
203static pthread_t incdep_threads[INCDEP_MAX_THREADS];
204
205#elif defined (WINDOWS32)
206# define INCDEP_MAX_THREADS 2
207static HANDLE incdep_threads[INCDEP_MAX_THREADS];
208
209#elif defined (__OS2__)
210# define INCDEP_MAX_THREADS 2
211static TID incdep_threads[INCDEP_MAX_THREADS];
212#endif
213
214static struct alloccache incdep_rec_caches[INCDEP_MAX_THREADS];
215static struct alloccache incdep_dep_caches[INCDEP_MAX_THREADS];
216static struct strcache2 incdep_dep_strcaches[INCDEP_MAX_THREADS];
217static struct strcache2 incdep_var_strcaches[INCDEP_MAX_THREADS];
218static unsigned incdep_num_threads;
219
220/* flag indicating whether the worker threads should terminate or not. */
221static int volatile incdep_terminate;
222
223#ifdef __APPLE__
224/* malloc zone for the incdep threads. */
225static malloc_zone_t *incdep_zone;
226#endif
227
228
229/*******************************************************************************
230* Internal Functions *
231*******************************************************************************/
232static void incdep_flush_it (struct floc *);
233static void eval_include_dep_file (struct incdep *, struct floc *);
234
235
236/* xmalloc wrapper.
237 For working around multithreaded performance problems found on Darwin,
238 Linux (glibc), and possibly other systems. */
239static void *
240incdep_xmalloc (struct incdep *cur, size_t size)
241{
242 void *ptr;
243
244#ifdef __APPLE__
245 if (cur && cur->worker_tid != -1)
246 {
247 ptr = malloc_zone_malloc (incdep_zone, size);
248 if (!ptr)
249 fatal (NILF, _("virtual memory exhausted"));
250 }
251 else
252 ptr = xmalloc (size);
253#else
254 ptr = xmalloc (size);
255#endif
256
257 (void)cur;
258 return ptr;
259}
260
261#if 0
262/* memset(malloc(sz),'\0',sz) wrapper. */
263static void *
264incdep_xcalloc (struct incdep *cur, size_t size)
265{
266 void *ptr;
267
268#ifdef __APPLE__
269 if (cur && cur->worker_tid != -1)
270 ptr = malloc_zone_calloc (incdep_zone, size, 1);
271 else
272 ptr = calloc (size, 1);
273#else
274 ptr = calloc (size, 1);
275#endif
276 if (!ptr)
277 fatal (NILF, _("virtual memory exhausted"));
278
279 (void)cur;
280 return ptr;
281}
282#endif /* unused */
283
284/* free wrapper */
285static void
286incdep_xfree (struct incdep *cur, void *ptr)
287{
288 /* free() *must* work for the allocation hacks above because
289 of free_dep_chain. */
290 free (ptr);
291 (void)cur;
292}
293
294/* alloc a dep structure. These are allocated in bunches to save time. */
295struct dep *
296incdep_alloc_dep (struct incdep *cur)
297{
298 struct alloccache *cache;
299 if (cur->worker_tid != -1)
300 cache = &incdep_dep_caches[cur->worker_tid];
301 else
302 cache = &dep_cache;
303 return alloccache_calloc (cache);
304}
305
306/* allocate a record. */
307static void *
308incdep_alloc_rec (struct incdep *cur)
309{
310 return alloccache_alloc (&incdep_rec_caches[cur->worker_tid]);
311}
312
313/* free a record. */
314static void
315incdep_free_rec (struct incdep *cur, void *rec)
316{
317 /*alloccache_free (&incdep_rec_caches[cur->worker_tid], rec); - doesn't work of course. */
318}
319
320
321/* grow a cache. */
322static void *
323incdep_cache_allocator (void *thrd, unsigned int size)
324{
325 (void)thrd;
326#ifdef __APPLE__
327 return malloc_zone_malloc (incdep_zone, size);
328#else
329 return xmalloc (size);
330#endif
331}
332
333/* term a cache. */
334static void
335incdep_cache_deallocator (void *thrd, void *ptr, unsigned int size)
336{
337 (void)thrd;
338 (void)size;
339 free (ptr);
340}
341
342/* acquires the lock */
343void
344incdep_lock(void)
345{
346#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS)
347 pthread_mutex_lock (&incdep_mtx);
348#elif defined (WINDOWS32)
349 EnterCriticalSection (&incdep_mtx);
350#elif defined (__OS2__)
351 _fmutex_request (&incdep_mtx, 0);
352#endif
353}
354
355/* releases the lock */
356void
357incdep_unlock(void)
358{
359#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS)
360 pthread_mutex_unlock (&incdep_mtx);
361#elif defined(WINDOWS32)
362 LeaveCriticalSection (&incdep_mtx);
363#elif defined(__OS2__)
364 _fmutex_release (&incdep_mtx);
365#endif
366}
367
368/* signals the main thread that there is stuff todo. caller owns the lock. */
369static void
370incdep_signal_done (void)
371{
372#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS)
373 pthread_cond_broadcast (&incdep_cond_done);
374#elif defined (WINDOWS32)
375 if (incdep_hev_done_waiters)
376 SetEvent (incdep_hev_done);
377#elif defined (__OS2__)
378 if (incdep_hev_done_waiters)
379 DosPostEventSem (incdep_hev_done);
380#endif
381}
382
383/* waits for a reader to finish reading. caller owns the lock. */
384static void
385incdep_wait_done (void)
386{
387#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS)
388 pthread_cond_wait (&incdep_cond_done, &incdep_mtx);
389
390#elif defined (WINDOWS32)
391 ResetEvent (incdep_hev_done);
392 incdep_hev_done_waiters++;
393 incdep_unlock ();
394 WaitForSingleObject (incdep_hev_done, INFINITE);
395 incdep_lock ();
396 incdep_hev_done_waiters--;
397
398#elif defined (__OS2__)
399 ULONG ulIgnore;
400 DosResetEventSem (incdep_hev_done, &ulIgnore);
401 incdep_hev_done_waiters++;
402 incdep_unlock ();
403 DosWaitEventSem (incdep_hev_done, SEM_INDEFINITE_WAIT);
404 incdep_lock ();
405 incdep_hev_done_waiters--;
406#endif
407}
408
409/* signals the worker threads. caller owns the lock. */
410static void
411incdep_signal_todo (void)
412{
413#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS)
414 pthread_cond_broadcast (&incdep_cond_todo);
415#elif defined(WINDOWS32)
416 if (incdep_hev_todo_waiters)
417 SetEvent (incdep_hev_todo);
418#elif defined(__OS2__)
419 if (incdep_hev_todo_waiters)
420 DosPostEventSem (incdep_hev_todo);
421#endif
422}
423
424/* waits for stuff to arrive in the todo list. caller owns the lock. */
425static void
426incdep_wait_todo (void)
427{
428#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS)
429 pthread_cond_wait (&incdep_cond_todo, &incdep_mtx);
430
431#elif defined (WINDOWS32)
432 ResetEvent (incdep_hev_todo);
433 incdep_hev_todo_waiters++;
434 incdep_unlock ();
435 WaitForSingleObject (incdep_hev_todo, INFINITE);
436 incdep_lock ();
437 incdep_hev_todo_waiters--;
438
439#elif defined (__OS2__)
440 ULONG ulIgnore;
441 DosResetEventSem (incdep_hev_todo, &ulIgnore);
442 incdep_hev_todo_waiters++;
443 incdep_unlock ();
444 DosWaitEventSem (incdep_hev_todo, SEM_INDEFINITE_WAIT);
445 incdep_lock ();
446 incdep_hev_todo_waiters--;
447#endif
448}
449
450/* Reads a dep file into memory. */
451static int
452incdep_read_file (struct incdep *cur, struct floc *f)
453{
454 int fd;
455 struct stat st;
456
457 errno = 0;
458#ifdef O_BINARY
459 fd = open (cur->name, O_RDONLY | O_BINARY, 0);
460#else
461 fd = open (cur->name, O_RDONLY, 0);
462#endif
463 if (fd < 0)
464 {
465 /* ignore non-existing dependency files. */
466 int err = errno;
467 if (err == ENOENT || stat (cur->name, &st) != 0)
468 return 1;
469 error (f, "%s: %s", cur->name, strerror (err));
470 return -1;
471 }
472 if (!fstat (fd, &st))
473 {
474 cur->file_base = incdep_xmalloc (cur, st.st_size + 1);
475 if (read (fd, cur->file_base, st.st_size) == st.st_size)
476 {
477 close (fd);
478 cur->file_end = cur->file_base + st.st_size;
479 cur->file_base[st.st_size] = '\0';
480 return 0;
481 }
482
483 /* bail out */
484
485 error (f, "%s: read: %s", cur->name, strerror (errno));
486 incdep_xfree (cur, cur->file_base);
487 }
488 else
489 error (f, "%s: fstat: %s", cur->name, strerror (errno));
490
491 close (fd);
492 cur->file_base = cur->file_end = NULL;
493 return -1;
494}
495
496/* Free the incdep structure. */
497static void
498incdep_freeit (struct incdep *cur)
499{
500#ifdef PARSE_IN_WORKER
501 assert (!cur->recorded_variables_in_set_head);
502 assert (!cur->recorded_variable_defs_head);
503 assert (!cur->recorded_files_head);
504#endif
505
506 incdep_xfree (cur, cur->file_base);
507 cur->next = NULL;
508 free (cur);
509}
510
511/* A worker thread. */
512void
513incdep_worker (int thrd)
514{
515 incdep_lock ();
516
517 while (!incdep_terminate)
518 {
519 /* get job from the todo list. */
520
521 struct incdep *cur = incdep_head_todo;
522 if (!cur)
523 {
524 incdep_wait_todo ();
525 continue;
526 }
527 if (cur->next)
528 incdep_head_todo = cur->next;
529 else
530 incdep_head_todo = incdep_tail_todo = NULL;
531 incdep_num_reading++;
532
533 /* read the file. */
534
535 incdep_unlock ();
536 cur->worker_tid = thrd;
537
538 incdep_read_file (cur, NILF);
539#ifdef PARSE_IN_WORKER
540 eval_include_dep_file (cur, NILF);
541#endif
542
543 cur->worker_tid = -1;
544 incdep_lock ();
545
546 /* insert finished job into the done list. */
547
548 incdep_num_reading--;
549 cur->next = NULL;
550 if (incdep_tail_done)
551 incdep_tail_done->next = cur;
552 else
553 incdep_head_done = cur;
554 incdep_tail_done = cur;
555
556 incdep_signal_done ();
557 }
558
559 incdep_unlock ();
560}
561
562/* Thread library specific thread functions wrapping incdep_wroker. */
563#ifdef HAVE_PTHREAD
564static void *
565incdep_worker_pthread (void *thrd)
566{
567 incdep_worker ((size_t)thrd);
568 return NULL;
569}
570
571#elif defined (WINDOWS32)
572static unsigned __stdcall
573incdep_worker_windows (void *thrd)
574{
575 incdep_worker ((size_t)thrd);
576 return 0;
577}
578
579#elif defined (__OS2__)
580static void
581incdep_worker_os2 (void *thrd)
582{
583 incdep_worker ((size_t)thrd);
584}
585#endif
586
587/* Checks if threads are enabled or not.
588
589 This is a special hack so that is possible to disable the threads when in a
590 debian fakeroot environment. Thus, in addition to the KMK_THREADS_DISABLED
591 and KMK_THREADS_ENABLED environment variable check we also check for signs
592 of fakeroot. */
593static int
594incdep_are_threads_enabled (void)
595{
596#if defined (CONFIG_WITHOUT_THREADS)
597 return 0;
598#endif
599
600 /* Generic overrides. */
601 if (getenv ("KMK_THREADS_DISABLED"))
602 {
603 message (1, "Threads disabled (environment)");
604 return 0;
605 }
606 if (getenv ("KMK_THREADS_ENABLED"))
607 return 1;
608
609#if defined (__gnu_linux__) || defined (__linux__)
610 /* Try detect fakeroot. */
611 if (getenv ("FAKEROOTKEY")
612 || getenv ("FAKEROOTUID")
613 || getenv ("FAKEROOTGID")
614 || getenv ("FAKEROOTEUID")
615 || getenv ("FAKEROOTEGID")
616 || getenv ("FAKEROOTSUID")
617 || getenv ("FAKEROOTSGID")
618 || getenv ("FAKEROOTFUID")
619 || getenv ("FAKEROOTFGID")
620 || getenv ("FAKEROOTDONTTRYCHOWN")
621 || getenv ("FAKEROOT_FD_BASE")
622 || getenv ("FAKEROOT_DB_SEARCH_PATHS"))
623 {
624 message (1, "Threads disabled (fakeroot)");
625 return 0;
626 }
627
628 /* LD_PRELOAD could indicate undetected debian fakeroot or some
629 other ingenius library which cannot deal correctly with threads. */
630 if (getenv ("LD_PRELOAD"))
631 {
632 message (1, "Threads disabled (LD_PRELOAD)");
633 return 0;
634 }
635
636#elif defined(__APPLE__) \
637 || defined(__sun__) || defined(__SunOS__) || defined(__sun) || defined(__SunOS) \
638 || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
639 /* No broken preload libraries known to be in common use on these platforms... */
640
641#elif defined(_MSC_VER) || defined(_WIN32) || defined(__OS2__)
642 /* No preload mess to care about. */
643
644#else
645# error "Add your self to the appropriate case above and send a patch to bird."
646#endif
647 return 1;
648}
649
650/* Creates the the worker threads. */
651static void
652incdep_init (struct floc *f)
653{
654 unsigned i;
655#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS)
656 int rc;
657 pthread_attr_t attr;
658
659#elif defined (WINDOWS32)
660 unsigned tid;
661 uintptr_t hThread;
662
663#elif defined (__OS2__)
664 int rc;
665 int tid;
666#endif
667 (void)f;
668
669 /* heap hacks */
670
671#ifdef __APPLE__
672 incdep_zone = malloc_create_zone (0, 0);
673 if (!incdep_zone)
674 incdep_zone = malloc_default_zone ();
675#endif
676
677
678 /* create the mutex and two condition variables / event objects. */
679
680#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS)
681 rc = pthread_mutex_init (&incdep_mtx, NULL);
682 if (rc)
683 fatal (f, _("pthread_mutex_init failed: err=%d"), rc);
684 rc = pthread_cond_init (&incdep_cond_todo, NULL);
685 if (rc)
686 fatal (f, _("pthread_cond_init failed: err=%d"), rc);
687 rc = pthread_cond_init (&incdep_cond_done, NULL);
688 if (rc)
689 fatal (f, _("pthread_cond_init failed: err=%d"), rc);
690
691#elif defined (WINDOWS32)
692 InitializeCriticalSection (&incdep_mtx);
693 incdep_hev_todo = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL);
694 if (!incdep_hev_todo)
695 fatal (f, _("CreateEvent failed: err=%d"), GetLastError());
696 incdep_hev_done = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL);
697 if (!incdep_hev_done)
698 fatal (f, _("CreateEvent failed: err=%d"), GetLastError());
699 incdep_hev_todo_waiters = 0;
700 incdep_hev_done_waiters = 0;
701
702#elif defined (__OS2__)
703 _fmutex_create (&incdep_mtx, 0);
704 rc = DosCreateEventSem (NULL, &incdep_hev_todo, 0, FALSE);
705 if (rc)
706 fatal (f, _("DosCreateEventSem failed: rc=%d"), rc);
707 rc = DosCreateEventSem (NULL, &incdep_hev_done, 0, FALSE);
708 if (rc)
709 fatal (f, _("DosCreateEventSem failed: rc=%d"), rc);
710 incdep_hev_todo_waiters = 0;
711 incdep_hev_done_waiters = 0;
712#endif
713
714 /* create the worker threads and associated per thread data. */
715
716 incdep_terminate = 0;
717 if (incdep_are_threads_enabled())
718 {
719 incdep_num_threads = sizeof (incdep_threads) / sizeof (incdep_threads[0]);
720 if (incdep_num_threads + 1 > job_slots)
721 incdep_num_threads = job_slots <= 1 ? 1 : job_slots - 1;
722 for (i = 0; i < incdep_num_threads; i++)
723 {
724 /* init caches */
725 unsigned rec_size = sizeof (struct incdep_variable_in_set);
726 if (rec_size < sizeof (struct incdep_variable_def))
727 rec_size = sizeof (struct incdep_variable_def);
728 if (rec_size < sizeof (struct incdep_recorded_files))
729 rec_size = sizeof (struct incdep_recorded_files);
730 alloccache_init (&incdep_rec_caches[i], rec_size, "incdep rec",
731 incdep_cache_allocator, (void *)(size_t)i);
732 alloccache_init (&incdep_dep_caches[i], sizeof(struct dep), "incdep dep",
733 incdep_cache_allocator, (void *)(size_t)i);
734 strcache2_init (&incdep_dep_strcaches[i],
735 "incdep dep", /* name */
736 65536, /* hash size */
737 0, /* default segment size*/
738#ifdef HAVE_CASE_INSENSITIVE_FS
739 1, /* case insensitive */
740#else
741 0, /* case insensitive */
742#endif
743 0); /* thread safe */
744
745 strcache2_init (&incdep_var_strcaches[i],
746 "incdep var", /* name */
747 32768, /* hash size */
748 0, /* default segment size*/
749 0, /* case insensitive */
750 0); /* thread safe */
751
752 /* create the thread. */
753#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS)
754 rc = pthread_attr_init (&attr);
755 if (rc)
756 fatal (f, _("pthread_attr_init failed: err=%d"), rc);
757 /*rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); */
758 rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
759 if (rc)
760 fatal (f, _("pthread_attr_setdetachstate failed: err=%d"), rc);
761 rc = pthread_create(&incdep_threads[i], &attr,
762 incdep_worker_pthread, (void *)(size_t)i);
763 if (rc)
764 fatal (f, _("pthread_mutex_init failed: err=%d"), rc);
765 pthread_attr_destroy (&attr);
766
767#elif defined (WINDOWS32)
768 tid = 0;
769 hThread = _beginthreadex (NULL, 128*1024, incdep_worker_windows,
770 (void *)i, 0, &tid);
771 if (hThread == 0 || hThread == ~(uintptr_t)0)
772 fatal (f, _("_beginthreadex failed: err=%d"), errno);
773 incdep_threads[i] = (HANDLE)hThread;
774
775#elif defined (__OS2__)
776 tid = _beginthread (incdep_worker_os2, NULL, 128*1024, (void *)i);
777 if (tid <= 0)
778 fatal (f, _("_beginthread failed: err=%d"), errno);
779 incdep_threads[i] = tid;
780#endif
781 }
782 }
783 else
784 incdep_num_threads = 0;
785
786 incdep_initialized = 1;
787}
788
789/* Flushes outstanding work and terminates the worker threads.
790 This is called from snap_deps(). */
791void
792incdep_flush_and_term (void)
793{
794 unsigned i;
795
796 if (!incdep_initialized)
797 return;
798
799 /* flush any out standing work */
800
801 incdep_flush_it (NILF);
802
803 /* tell the threads to terminate */
804
805 incdep_lock ();
806 incdep_terminate = 1;
807 incdep_signal_todo ();
808 incdep_unlock ();
809
810 /* wait for the threads to quit */
811
812 for (i = 0; i < incdep_num_threads; i++)
813 {
814 /* more later? */
815
816 /* terminate or join up the allocation caches. */
817 alloccache_term (&incdep_rec_caches[i], incdep_cache_deallocator, (void *)(size_t)i);
818 alloccache_join (&dep_cache, &incdep_dep_caches[i]);
819 strcache2_term (&incdep_dep_strcaches[i]);
820 strcache2_term (&incdep_var_strcaches[i]);
821 }
822 incdep_num_threads = 0;
823
824 /* destroy the lock and condition variables / event objects. */
825
826 /* later */
827
828 incdep_initialized = 0;
829}
830
831#ifdef PARSE_IN_WORKER
832/* Flushes a strcache entry returning the actual string cache entry.
833 The input is freed! */
834static const char *
835incdep_flush_strcache_entry (struct strcache2_entry *entry)
836{
837 if (!entry->user)
838 entry->user = (void *) strcache2_add_hashed_file (&file_strcache,
839 (const char *)(entry + 1),
840 entry->length, entry->hash);
841 return (const char *)entry->user;
842}
843
844/* Flushes the recorded instructions. */
845static void
846incdep_flush_recorded_instructions (struct incdep *cur)
847{
848 struct incdep_variable_in_set *rec_vis;
849 struct incdep_variable_def *rec_vd;
850 struct incdep_recorded_files *rec_f;
851
852 /* define_variable_in_set */
853
854 rec_vis = cur->recorded_variables_in_set_head;
855 cur->recorded_variables_in_set_head = cur->recorded_variables_in_set_tail = NULL;
856 if (rec_vis)
857 do
858 {
859 void *free_me = rec_vis;
860 unsigned int name_length = rec_vis->name_entry->length;
861 define_variable_in_set (incdep_flush_strcache_entry (rec_vis->name_entry),
862 name_length,
863 rec_vis->value,
864 rec_vis->value_length,
865 rec_vis->duplicate_value,
866 rec_vis->origin,
867 rec_vis->recursive,
868 rec_vis->set,
869 rec_vis->flocp);
870 rec_vis = rec_vis->next;
871 incdep_free_rec (cur, free_me);
872 }
873 while (rec_vis);
874
875 /* do_variable_definition */
876
877 rec_vd = cur->recorded_variable_defs_head;
878 cur->recorded_variable_defs_head = cur->recorded_variable_defs_tail = NULL;
879 if (rec_vd)
880 do
881 {
882 void *free_me = rec_vd;
883 do_variable_definition_2 (rec_vd->flocp,
884 incdep_flush_strcache_entry (rec_vd->name_entry),
885 rec_vd->value,
886 rec_vd->value_length,
887 0,
888 rec_vd->value,
889 rec_vd->origin,
890 rec_vd->flavor,
891 rec_vd->target_var);
892 rec_vd = rec_vd->next;
893 incdep_free_rec (cur, free_me);
894 }
895 while (rec_vd);
896
897 /* record_files */
898
899 rec_f = cur->recorded_files_head;
900 cur->recorded_files_head = cur->recorded_files_tail = NULL;
901 if (rec_f)
902 do
903 {
904 void *free_me = rec_f;
905 struct dep *dep;
906 struct nameseq *filenames;
907
908 for (dep = rec_f->deps; dep; dep = dep->next)
909 dep->name = incdep_flush_strcache_entry ((struct strcache2_entry *)dep->name);
910
911 filenames = (struct nameseq *) alloccache_alloc (&nameseq_cache);
912 filenames->next = 0;
913 filenames->name = incdep_flush_strcache_entry (rec_f->filename_entry);
914
915 record_files (filenames,
916 rec_f->pattern,
917 rec_f->pattern_percent,
918 rec_f->deps,
919 rec_f->cmds_started,
920 rec_f->commands,
921 rec_f->commands_idx,
922 rec_f->two_colon,
923 rec_f->flocp);
924
925 rec_f = rec_f->next;
926 incdep_free_rec (cur, free_me);
927 }
928 while (rec_f);
929}
930#endif /* PARSE_IN_WORKER */
931
932/* Record / issue a warning about a misformed dep file. */
933static void
934incdep_warn (struct incdep *cur, unsigned int line_no, const char *msg)
935{
936 if (cur->worker_tid == -1)
937 error (NILF, "%s(%d): %s", cur->name, line_no, msg);
938#ifdef PARSE_IN_WORKER
939 else
940 {
941 cur->err_line_no = line_no;
942 cur->err_msg = msg;
943 }
944#endif
945}
946
947/* Dependency or file strcache allocation / recording. */
948static const char *
949incdep_dep_strcache (struct incdep *cur, const char *str, int len)
950{
951 const char *ret;
952 if (cur->worker_tid == -1)
953 {
954 /* Make sure the string is terminated before we hand it to
955 strcache_add_len so it does have to make a temporary copy
956 of it on the stack. */
957 char ch = str[len];
958 ((char *)str)[len] = '\0';
959 ret = strcache_add_len (str, len);
960 ((char *)str)[len] = ch;
961 }
962 else
963 {
964 /* Add it out the strcache of the thread. */
965 ret = strcache2_add (&incdep_dep_strcaches[cur->worker_tid], str, len);
966 ret = (const char *)strcache2_get_entry(&incdep_dep_strcaches[cur->worker_tid], ret);
967 }
968 return ret;
969}
970
971/* Variable name allocation / recording. */
972static const char *
973incdep_var_strcache (struct incdep *cur, const char *str, int len)
974{
975 const char *ret;
976 if (cur->worker_tid == -1)
977 {
978 /* XXX: we're leaking this memory now! This will be fixed later. */
979 ret = xmalloc (len + 1);
980 memcpy ((char *)ret, str, len);
981 ((char *)ret)[len] = '\0';
982 }
983 else
984 {
985 /* Add it out the strcache of the thread. */
986 ret = strcache2_add (&incdep_var_strcaches[cur->worker_tid], str, len);
987 ret = (const char *)strcache2_get_entry(&incdep_var_strcaches[cur->worker_tid], ret);
988 }
989 return ret;
990}
991
992/* Record / perform a variable definition in a set.
993 The NAME is in the string cache.
994 The VALUE is on the heap.
995 The DUPLICATE_VALUE is always 0. */
996static void
997incdep_record_variable_in_set (struct incdep *cur,
998 const char *name, unsigned int name_length,
999 const char *value,
1000 unsigned int value_length,
1001 int duplicate_value,
1002 enum variable_origin origin,
1003 int recursive,
1004 struct variable_set *set,
1005 const struct floc *flocp)
1006{
1007 assert (!duplicate_value);
1008 if (cur->worker_tid == -1)
1009 define_variable_in_set (name, name_length, value, value_length,
1010 duplicate_value, origin, recursive, set, flocp);
1011#ifdef PARSE_IN_WORKER
1012 else
1013 {
1014 struct incdep_variable_in_set *rec =
1015 (struct incdep_variable_in_set *)incdep_alloc_rec (cur);
1016 rec->name_entry = (struct strcache2_entry *)name;
1017 rec->value = value;
1018 rec->value_length = value_length;
1019 rec->duplicate_value = duplicate_value;
1020 rec->origin = origin;
1021 rec->recursive = recursive;
1022 rec->set = set;
1023 rec->flocp = flocp;
1024
1025 rec->next = NULL;
1026 if (cur->recorded_variables_in_set_tail)
1027 cur->recorded_variables_in_set_tail->next = rec;
1028 else
1029 cur->recorded_variables_in_set_head = rec;
1030 cur->recorded_variables_in_set_tail = rec;
1031 }
1032#endif
1033}
1034
1035/* Record / perform a variable definition. The VALUE should be disposed of. */
1036static void
1037incdep_record_variable_def (struct incdep *cur,
1038 const struct floc *flocp,
1039 const char *name,
1040 unsigned int name_length,
1041 char *value,
1042 unsigned int value_length,
1043 enum variable_origin origin,
1044 enum variable_flavor flavor,
1045 int target_var)
1046{
1047 if (cur->worker_tid == -1)
1048 do_variable_definition_2 (flocp, name, value, value_length, 0, value,
1049 origin, flavor, target_var);
1050#ifdef PARSE_IN_WORKER
1051 else
1052 {
1053 struct incdep_variable_def *rec =
1054 (struct incdep_variable_def *)incdep_alloc_rec (cur);
1055 rec->flocp = flocp;
1056 rec->name_entry = (struct strcache2_entry *)name;
1057 rec->value = value;
1058 rec->value_length = value_length;
1059 rec->origin = origin;
1060 rec->flavor = flavor;
1061 rec->target_var = target_var;
1062
1063 rec->next = NULL;
1064 if (cur->recorded_variable_defs_tail)
1065 cur->recorded_variable_defs_tail->next = rec;
1066 else
1067 cur->recorded_variable_defs_head = rec;
1068 cur->recorded_variable_defs_tail = rec;
1069 }
1070#else
1071 (void)name_length;
1072#endif
1073}
1074
1075/* Record files.*/
1076static void
1077incdep_record_files (struct incdep *cur,
1078 const char *filename, const char *pattern,
1079 const char *pattern_percent, struct dep *deps,
1080 unsigned int cmds_started, char *commands,
1081 unsigned int commands_idx, int two_colon,
1082 const struct floc *flocp)
1083{
1084 if (cur->worker_tid == -1)
1085 {
1086 struct nameseq *filenames = (struct nameseq *) alloccache_alloc (&nameseq_cache);
1087 filenames->next = 0;
1088 filenames->name = filename;
1089 record_files (filenames, pattern, pattern_percent, deps, cmds_started,
1090 commands, commands_idx, two_colon, flocp);
1091 }
1092#ifdef PARSE_IN_WORKER
1093 else
1094 {
1095 struct incdep_recorded_files *rec =
1096 (struct incdep_recorded_files *) incdep_alloc_rec (cur);
1097
1098 rec->filename_entry = (struct strcache2_entry *)filename;
1099 rec->pattern = pattern;
1100 rec->pattern_percent = pattern_percent;
1101 rec->deps = deps;
1102 rec->cmds_started = cmds_started;
1103 rec->commands = commands;
1104 rec->commands_idx = commands_idx;
1105 rec->two_colon = two_colon;
1106 rec->flocp = flocp;
1107
1108 rec->next = NULL;
1109 if (cur->recorded_files_tail)
1110 cur->recorded_files_tail->next = rec;
1111 else
1112 cur->recorded_files_head = rec;
1113 cur->recorded_files_tail = rec;
1114 }
1115#endif
1116}
1117
1118
1119/* no nonsense dependency file including.
1120
1121 Because nobody wants bogus dependency files to break their incremental
1122 builds with hard to comprehend error messages, this function does not
1123 use the normal eval routine but does all the parsing itself. This isn't,
1124 as much work as it sounds, because the necessary feature set is very
1125 limited.
1126
1127 eval_include_dep_file groks:
1128
1129 define var
1130 endef
1131
1132 var [|:|?|>]= value [\]
1133
1134 [\]
1135 file: [deps] [\]
1136
1137 */
1138static void
1139eval_include_dep_file (struct incdep *curdep, struct floc *f)
1140{
1141 unsigned line_no = 1;
1142 const char *file_end = curdep->file_end;
1143 const char *cur = curdep->file_base;
1144 const char *endp;
1145
1146 /* if no file data, just return immediately. */
1147 if (!cur)
1148 return;
1149
1150 /* now parse the file. */
1151 while (cur < file_end)
1152 {
1153 /* skip empty lines */
1154 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
1155 ++cur;
1156 if (cur >= file_end)
1157 break;
1158 if (*cur == '#')
1159 {
1160 cur = memchr (cur, '\n', file_end - cur);
1161 if (!cur)
1162 break;
1163 }
1164 if (*cur == '\\')
1165 {
1166 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
1167 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
1168 : (file_end - cur == 1) ? 1 : 0;
1169 if (eol_len)
1170 {
1171 cur += eol_len;
1172 line_no++;
1173 continue;
1174 }
1175 }
1176 if (*cur == '\n')
1177 {
1178 cur++;
1179 line_no++;
1180 continue;
1181 }
1182
1183 /* define var
1184 ...
1185 endef */
1186 if (strneq (cur, "define ", 7))
1187 {
1188 const char *var;
1189 unsigned var_len;
1190 const char *value_start;
1191 const char *value_end;
1192 char *value;
1193 unsigned value_len;
1194 int found_endef = 0;
1195
1196 /* extract the variable name. */
1197 cur += 7;
1198 while (isblank ((unsigned char)*cur))
1199 ++cur;
1200 value_start = endp = memchr (cur, '\n', file_end - cur);
1201 if (!endp)
1202 endp = cur;
1203 while (endp > cur && isspace ((unsigned char)endp[-1]))
1204 --endp;
1205 var_len = endp - cur;
1206 if (!var_len)
1207 {
1208 incdep_warn (curdep, line_no, "bogus define statement.");
1209 break;
1210 }
1211 var = incdep_var_strcache (curdep, cur, var_len);
1212
1213 /* find the end of the variable. */
1214 cur = value_end = value_start = value_start + 1;
1215 ++line_no;
1216 while (cur < file_end)
1217 {
1218 /* check for endef, don't bother with skipping leading spaces. */
1219 if ( file_end - cur >= 5
1220 && strneq (cur, "endef", 5))
1221 {
1222 endp = cur + 5;
1223 while (endp < file_end && isspace ((unsigned char)*endp) && *endp != '\n')
1224 endp++;
1225 if (endp >= file_end || *endp == '\n')
1226 {
1227 found_endef = 1;
1228 cur = endp >= file_end ? file_end : endp + 1;
1229 break;
1230 }
1231 }
1232
1233 /* skip a line ahead. */
1234 cur = value_end = memchr (cur, '\n', file_end - cur);
1235 if (cur != NULL)
1236 ++cur;
1237 else
1238 cur = value_end = file_end;
1239 ++line_no;
1240 }
1241
1242 if (!found_endef)
1243 {
1244 incdep_warn (curdep, line_no, "missing endef, dropping the rest of the file.");
1245 break;
1246 }
1247 value_len = value_end - value_start;
1248 if (memchr (value_start, '\0', value_len))
1249 {
1250 incdep_warn (curdep, line_no, "'\\0' in define, dropping the rest of the file.");
1251 break;
1252 }
1253
1254 /* make a copy of the value, converting \r\n to \n, and define it. */
1255 value = incdep_xmalloc (curdep, value_len + 1);
1256 endp = memchr (value_start, '\r', value_len);
1257 if (endp)
1258 {
1259 const char *src = value_start;
1260 char *dst = value;
1261 for (;;)
1262 {
1263 size_t len = endp - src;
1264 memcpy (dst, src, len);
1265 dst += len;
1266 src = endp;
1267 if (src + 1 < file_end && src[1] == '\n')
1268 src++; /* skip the '\r' */
1269 if (src >= value_end)
1270 break;
1271 endp = memchr (endp + 1, '\r', src - value_end);
1272 if (!endp)
1273 endp = value_end;
1274 }
1275 value_len = dst - value;
1276 }
1277 else
1278 memcpy (value, value_start, value_len);
1279 value [value_len] = '\0';
1280
1281 incdep_record_variable_in_set (curdep,
1282 var, var_len, value, value_len,
1283 0 /* don't duplicate */, o_file,
1284 0 /* defines are recursive but this is faster */,
1285 NULL /* global set */, f);
1286 }
1287
1288 /* file: deps
1289 OR
1290 variable [:]= value */
1291 else
1292 {
1293 const char *colonp;
1294 const char *equalp;
1295
1296 /* Look for a colon and an equal sign, optimize for colon.
1297 Only one file is support and the colon / equal must be on
1298 the same line. */
1299 colonp = memchr (cur, ':', file_end - cur);
1300#ifdef HAVE_DOS_PATHS
1301 while ( colonp
1302 && colonp + 1 < file_end
1303 && (colonp[1] == '/' || colonp[1] == '\\')
1304 && colonp > cur
1305 && isalpha ((unsigned char)colonp[-1])
1306 && ( colonp == cur + 1
1307 || strchr (" \t(", colonp[-2]) != 0))
1308 colonp = memchr (colonp + 1, ':', file_end - (colonp + 1));
1309#endif
1310 endp = NULL;
1311 if ( !colonp
1312 || (endp = memchr (cur, '\n', colonp - cur)))
1313 {
1314 colonp = NULL;
1315 equalp = memchr (cur, '=', (endp ? endp : file_end) - cur);
1316 if ( !equalp
1317 || (!endp && memchr (cur, '\n', equalp - cur)))
1318 {
1319 incdep_warn (curdep, line_no, "no colon.");
1320 break;
1321 }
1322 }
1323 else
1324 equalp = memchr (cur, '=', (colonp + 2 <= file_end
1325 ? colonp + 2 : file_end) - cur);
1326 if (equalp)
1327 {
1328 /* An assignment of some sort. */
1329 const char *var;
1330 unsigned var_len;
1331 const char *value_start;
1332 const char *value_end;
1333 char *value;
1334 unsigned value_len;
1335 unsigned multi_line = 0;
1336 enum variable_flavor flavor;
1337
1338 /* figure the flavor first. */
1339 flavor = f_recursive;
1340 if (equalp > cur)
1341 {
1342 if (equalp[-1] == ':')
1343 flavor = f_simple;
1344 else if (equalp[-1] == '?')
1345 flavor = f_conditional;
1346 else if (equalp[-1] == '+')
1347 flavor = f_append;
1348 else if (equalp[-1] == '>')
1349 flavor = f_prepend;
1350 }
1351
1352 /* extract the variable name. */
1353 endp = flavor == f_recursive ? equalp : equalp - 1;
1354 while (endp > cur && isblank ((unsigned char)endp[-1]))
1355 --endp;
1356 var_len = endp - cur;
1357 if (!var_len)
1358 {
1359 incdep_warn (curdep, line_no, "empty variable. (includedep)");
1360 break;
1361 }
1362 if ( memchr (cur, '$', var_len)
1363 || memchr (cur, ' ', var_len)
1364 || memchr (cur, '\t', var_len))
1365 {
1366 incdep_warn (curdep, line_no, "fancy variable name. (includedep)");
1367 break;
1368 }
1369 var = incdep_var_strcache (curdep, cur, var_len);
1370
1371 /* find the start of the value. */
1372 cur = equalp + 1;
1373 while (cur < file_end && isblank ((unsigned char)*cur))
1374 cur++;
1375 value_start = cur;
1376
1377 /* find the end of the value / line (this isn't 101% correct). */
1378 value_end = cur;
1379 while (cur < file_end)
1380 {
1381 endp = value_end = memchr (cur, '\n', file_end - cur);
1382 if (!value_end)
1383 value_end = file_end;
1384 if (value_end - 1 >= cur && value_end[-1] == '\r')
1385 --value_end;
1386 if (value_end - 1 < cur || value_end[-1] != '\\')
1387 {
1388 cur = endp ? endp + 1 : file_end;
1389 break;
1390 }
1391 --value_end;
1392 if (value_end - 1 >= cur && value_end[-1] == '\\')
1393 {
1394 incdep_warn (curdep, line_no, "fancy escaping! (includedep)");
1395 cur = NULL;
1396 break;
1397 }
1398 if (!endp)
1399 {
1400 cur = file_end;
1401 break;
1402 }
1403
1404 cur = endp + 1;
1405 ++multi_line;
1406 ++line_no;
1407 }
1408 if (!cur)
1409 break;
1410 ++line_no;
1411
1412 /* make a copy of the value, converting \r\n to \n, and define it. */
1413 value_len = value_end - value_start;
1414 value = incdep_xmalloc (curdep, value_len + 1);
1415 if (!multi_line)
1416 memcpy (value, value_start, value_len);
1417 else
1418 {
1419 /* unescape it */
1420 const char *src = value_start;
1421 char *dst = value;
1422 while (src < value_end)
1423 {
1424 const char *nextp;
1425
1426 endp = memchr (src, '\n', value_end - src);
1427 if (!endp)
1428 nextp = endp = value_end;
1429 else
1430 nextp = endp + 1;
1431 if (endp > src && endp[-1] == '\r')
1432 --endp;
1433 if (endp > src && endp[-1] == '\\')
1434 --endp;
1435
1436 if (src != value_start)
1437 *dst++ = ' ';
1438 memcpy (dst, src, endp - src);
1439 dst += endp - src;
1440 src = nextp;
1441 }
1442 value_len = dst - value;
1443 }
1444 value [value_len] = '\0';
1445
1446 /* do the definition */
1447 if (flavor == f_recursive
1448 || ( flavor == f_simple
1449 && !memchr (value, '$', value_len)))
1450 incdep_record_variable_in_set (curdep,
1451 var, var_len, value, value_len,
1452 0 /* don't duplicate */, o_file,
1453 flavor == f_recursive /* recursive */,
1454 NULL /* global set */, f);
1455 else
1456 incdep_record_variable_def (curdep,
1457 f, var, var_len, value, value_len,
1458 o_file, flavor, 0 /* not target var */);
1459 }
1460 else
1461 {
1462 /* file: dependencies */
1463
1464 const char *filename;
1465 struct dep *deps = 0;
1466 struct dep **nextdep = &deps;
1467 struct dep *dep;
1468
1469 /* extract the filename, ASSUME a single one. */
1470 endp = colonp;
1471 while (endp > cur && isblank ((unsigned char)endp[-1]))
1472 --endp;
1473 if (cur == endp)
1474 {
1475 incdep_warn (curdep, line_no, "empty filename.");
1476 break;
1477 }
1478 if ( memchr (cur, '$', endp - cur)
1479 || memchr (cur, ' ', endp - cur)
1480 || memchr (cur, '\t', endp - cur))
1481 {
1482 incdep_warn (curdep, line_no, "multiple / fancy file name. (includedep)");
1483 break;
1484 }
1485 filename = incdep_dep_strcache (curdep, cur, endp - cur);
1486
1487 /* parse any dependencies. */
1488 cur = colonp + 1;
1489 while (cur < file_end)
1490 {
1491 /* skip blanks and count lines. */
1492 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
1493 ++cur;
1494 if (cur >= file_end)
1495 break;
1496 if (*cur == '\n')
1497 {
1498 cur++;
1499 line_no++;
1500 break;
1501 }
1502
1503 /* continuation + eol? */
1504 if (*cur == '\\')
1505 {
1506 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
1507 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
1508 : (file_end - cur == 1) ? 1 : 0;
1509 if (eol_len)
1510 {
1511 cur += eol_len;
1512 line_no++;
1513 continue;
1514 }
1515 }
1516
1517 /* find the end of the filename */
1518 endp = cur;
1519 while (endp < file_end && !isspace ((unsigned char)*endp))
1520 ++endp;
1521
1522 /* add it to the list. */
1523 *nextdep = dep = incdep_alloc_dep (curdep);
1524 dep->name = incdep_dep_strcache (curdep, cur, endp - cur);
1525 dep->includedep = 1;
1526 nextdep = &dep->next;
1527
1528 cur = endp;
1529 }
1530
1531 /* enter the file with its dependencies. */
1532 incdep_record_files (curdep,
1533 filename, NULL, NULL, deps, 0, NULL, 0, 0, f);
1534 }
1535 }
1536 }
1537
1538 /* free the file data */
1539 incdep_xfree (curdep, curdep->file_base);
1540 curdep->file_base = curdep->file_end = NULL;
1541}
1542
1543/* Flushes the incdep todo and done lists. */
1544static void
1545incdep_flush_it (struct floc *f)
1546{
1547 incdep_lock ();
1548 for (;;)
1549 {
1550 struct incdep *cur = incdep_head_done;
1551
1552 /* if the done list is empty, grab a todo list entry. */
1553 if (!cur && incdep_head_todo)
1554 {
1555 cur = incdep_head_todo;
1556 if (cur->next)
1557 incdep_head_todo = cur->next;
1558 else
1559 incdep_head_todo = incdep_tail_todo = NULL;
1560 incdep_unlock ();
1561
1562 incdep_read_file (cur, f);
1563 eval_include_dep_file (cur, f);
1564 incdep_freeit (cur);
1565
1566 incdep_lock ();
1567 continue;
1568 }
1569
1570 /* if the todo list and done list are empty we're either done
1571 or will have to wait for the thread(s) to finish. */
1572 if (!cur && !incdep_num_reading)
1573 break; /* done */
1574 if (!cur)
1575 {
1576 while (!incdep_head_done)
1577 incdep_wait_done ();
1578 cur = incdep_head_done;
1579 }
1580
1581 /* we grab the entire done list and work thru it. */
1582 incdep_head_done = incdep_tail_done = NULL;
1583 incdep_unlock ();
1584
1585 while (cur)
1586 {
1587 struct incdep *next = cur->next;
1588#ifdef PARSE_IN_WORKER
1589 incdep_flush_recorded_instructions (cur);
1590#else
1591 eval_include_dep_file (cur, f);
1592#endif
1593 incdep_freeit (cur);
1594 cur = next;
1595 }
1596
1597 incdep_lock ();
1598 } /* outer loop */
1599 incdep_unlock ();
1600}
1601
1602
1603/* splits up a list of file names and feeds it to eval_include_dep_file,
1604 employing threads to try speed up the file reading. */
1605void
1606eval_include_dep (const char *names, struct floc *f, enum incdep_op op)
1607{
1608 struct incdep *head = 0;
1609 struct incdep *tail = 0;
1610 struct incdep *cur;
1611 const char *names_iterator = names;
1612 const char *name;
1613 unsigned int name_len;
1614
1615 /* loop through NAMES, creating a todo list out of them. */
1616
1617 while ((name = find_next_token (&names_iterator, &name_len)) != 0)
1618 {
1619 cur = xmalloc (sizeof (*cur) + name_len); /* not incdep_xmalloc here */
1620 cur->file_base = cur->file_end = NULL;
1621 memcpy (cur->name, name, name_len);
1622 cur->name[name_len] = '\0';
1623 cur->worker_tid = -1;
1624#ifdef PARSE_IN_WORKER
1625 cur->err_line_no = 0;
1626 cur->err_msg = NULL;
1627 cur->recorded_variables_in_set_head = NULL;
1628 cur->recorded_variables_in_set_tail = NULL;
1629 cur->recorded_variable_defs_head = NULL;
1630 cur->recorded_variable_defs_tail = NULL;
1631 cur->recorded_files_head = NULL;
1632 cur->recorded_files_tail = NULL;
1633#endif
1634
1635 cur->next = NULL;
1636 if (tail)
1637 tail->next = cur;
1638 else
1639 head = cur;
1640 tail = cur;
1641 }
1642
1643#ifdef ELECTRIC_HEAP
1644 if (1)
1645#else
1646 if (op == incdep_read_it)
1647#endif
1648 {
1649 /* work our way thru the files directly */
1650
1651 cur = head;
1652 while (cur)
1653 {
1654 struct incdep *next = cur->next;
1655 incdep_read_file (cur, f);
1656 eval_include_dep_file (cur, f);
1657 incdep_freeit (cur);
1658 cur = next;
1659 }
1660 }
1661 else
1662 {
1663 /* initialize the worker threads and related stuff the first time around. */
1664
1665 if (!incdep_initialized)
1666 incdep_init (f);
1667
1668 /* queue the files and notify the worker threads. */
1669
1670 incdep_lock ();
1671
1672 if (incdep_tail_todo)
1673 incdep_tail_todo->next = head;
1674 else
1675 incdep_head_todo = head;
1676 incdep_tail_todo = tail;
1677
1678 incdep_signal_todo ();
1679 incdep_unlock ();
1680
1681 /* flush the todo queue if we're requested to do so. */
1682
1683 if (op == incdep_flush)
1684 incdep_flush_it (f);
1685 }
1686}
1687
1688#endif /* CONFIG_WITH_INCLUDEDEP */
1689
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette