VirtualBox

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

Last change on this file since 2060 was 2053, checked in by bird, 16 years ago

kmk/incdep.c: Check for the environment variables KMK_THREADS_DISABLED / KMK_THREADS_ENABLED to overload the defaults for starting worker threads. Also check for fakeroot and disable all threads if seen - it seems to have trouble with our worker thread or something.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.0 KB
Line 
1#ifdef CONFIG_WITH_INCLUDEDEP
2/* $Id: incdep.c 2053 2008-11-04 00:26:28Z bird $ */
3/** @file
4 * incdep - Simple dependency files.
5 */
6
7/*
8 * Copyright (c) 2007-2008 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#ifdef HAVE_PTHREAD
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#ifdef HAVE_PTHREAD
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#ifdef HAVE_PTHREAD
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#ifdef HAVE_PTHREAD
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#ifdef HAVE_PTHREAD
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#ifdef HAVE_PTHREAD
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 (getenv("KMK_THREADS_DISABLED"))
597 return 0;
598 if (getenv("KMK_THREADS_ENABLED"))
599 return 1;
600#if defined(__gnu_linux__) || defined(__linux__)
601 if (getenv("FAKEROOTKEY"))
602 return 0;
603 if (getenv("FAKEROOTUID"))
604 return 0;
605 if (getenv("FAKEROOTGID"))
606 return 0;
607 if (getenv("FAKEROOTEUID"))
608 return 0;
609 if (getenv("FAKEROOTEGID"))
610 return 0;
611 if (getenv("FAKEROOTSUID"))
612 return 0;
613 if (getenv("FAKEROOTSGID"))
614 return 0;
615 if (getenv("FAKEROOTFUID"))
616 return 0;
617 if (getenv("FAKEROOTFGID"))
618 return 0;
619 if (getenv("FAKEROOTDONTTRYCHOWN"))
620 return 0;
621 if (getenv("FAKEROOT_FD_BASE"))
622 return 0;
623 if (getenv("FAKEROOT_DB_SEARCH_PATHS"))
624 return 0;
625#endif /* GNU/Linux */
626 return 1;
627}
628
629/* Creates the the worker threads. */
630static void
631incdep_init (struct floc *f)
632{
633 unsigned i;
634#ifdef HAVE_PTHREAD
635 int rc;
636 pthread_attr_t attr;
637
638#elif defined (WINDOWS32)
639 unsigned tid;
640 uintptr_t hThread;
641
642#elif defined (__OS2__)
643 int rc;
644 int tid;
645#endif
646
647 /* heap hacks */
648
649#ifdef __APPLE__
650 incdep_zone = malloc_create_zone (0, 0);
651 if (!incdep_zone)
652 incdep_zone = malloc_default_zone ();
653#endif
654
655
656 /* create the mutex and two condition variables / event objects. */
657
658#ifdef HAVE_PTHREAD
659 rc = pthread_mutex_init (&incdep_mtx, NULL);
660 if (rc)
661 fatal (f, _("pthread_mutex_init failed: err=%d"), rc);
662 rc = pthread_cond_init (&incdep_cond_todo, NULL);
663 if (rc)
664 fatal (f, _("pthread_cond_init failed: err=%d"), rc);
665 rc = pthread_cond_init (&incdep_cond_done, NULL);
666 if (rc)
667 fatal (f, _("pthread_cond_init failed: err=%d"), rc);
668
669#elif defined (WINDOWS32)
670 InitializeCriticalSection (&incdep_mtx);
671 incdep_hev_todo = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL);
672 if (!incdep_hev_todo)
673 fatal (f, _("CreateEvent failed: err=%d"), GetLastError());
674 incdep_hev_done = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL);
675 if (!incdep_hev_done)
676 fatal (f, _("CreateEvent failed: err=%d"), GetLastError());
677 incdep_hev_todo_waiters = 0;
678 incdep_hev_done_waiters = 0;
679
680#elif defined (__OS2__)
681 _fmutex_create (&incdep_mtx, 0)
682 rc = DosCreateEventSem (NULL, &incdep_hev_todo, 0, FALSE);
683 if (rc)
684 fatal (f, _("DosCreateEventSem failed: rc=%d"), rc);
685 rc = DosCreateEventSem (NULL, &incdep_hev_done, 0, FALSE);
686 if (rc)
687 fatal (f, _("DosCreateEventSem failed: rc=%d"), rc);
688 incdep_hev_todo_waiters = 0;
689 incdep_hev_done_waiters = 0;
690#endif
691
692 /* create the worker threads and associated per thread data. */
693
694 incdep_terminate = 0;
695 if (incdep_are_threads_enabled())
696 {
697 incdep_num_threads = sizeof (incdep_threads) / sizeof (incdep_threads[0]);
698 if (incdep_num_threads + 1 > job_slots)
699 incdep_num_threads = job_slots <= 1 ? 1 : job_slots - 1;
700 for (i = 0; i < incdep_num_threads; i++)
701 {
702 /* init caches */
703 unsigned rec_size = sizeof (struct incdep_variable_in_set);
704 if (rec_size < sizeof (struct incdep_variable_def))
705 rec_size = sizeof (struct incdep_variable_def);
706 if (rec_size < sizeof (struct incdep_recorded_files))
707 rec_size = sizeof (struct incdep_recorded_files);
708 alloccache_init (&incdep_rec_caches[i], rec_size, "incdep rec",
709 incdep_cache_allocator, (void *)(size_t)i);
710 alloccache_init (&incdep_dep_caches[i], sizeof(struct dep), "incdep dep",
711 incdep_cache_allocator, (void *)(size_t)i);
712 strcache2_init (&incdep_dep_strcaches[i],
713 "incdep dep", /* name */
714 65536, /* hash size */
715 0, /* default segment size*/
716#ifdef HAVE_CASE_INSENSITIVE_FS
717 1, /* case insensitive */
718#else
719 0, /* case insensitive */
720#endif
721 0); /* thread safe */
722
723 strcache2_init (&incdep_var_strcaches[i],
724 "incdep var", /* name */
725 32768, /* hash size */
726 0, /* default segment size*/
727 0, /* case insensitive */
728 0); /* thread safe */
729
730 /* create the thread. */
731#ifdef HAVE_PTHREAD
732 rc = pthread_attr_init (&attr);
733 if (rc)
734 fatal (f, _("pthread_attr_init failed: err=%d"), rc);
735 /*rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); */
736 rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
737 if (rc)
738 fatal (f, _("pthread_attr_setdetachstate failed: err=%d"), rc);
739 rc = pthread_create(&incdep_threads[i], &attr,
740 incdep_worker_pthread, (void *)(size_t)i);
741 if (rc)
742 fatal (f, _("pthread_mutex_init failed: err=%d"), rc);
743 pthread_attr_destroy (&attr);
744
745#elif defined (WINDOWS32)
746 tid = 0;
747 hThread = _beginthreadex (NULL, 128*1024, incdep_worker_windows,
748 (void *)i, 0, &tid);
749 if (hThread == 0 || hThread == ~(uintptr_t)0)
750 fatal (f, _("_beginthreadex failed: err=%d"), errno);
751 incdep_threads[i] = (HANDLE)hThread;
752
753#elif defined (__OS2__)
754 tid = _beginthread (incdep_worker_os2, NULL, 128*1024, (void *)i);
755 if (tid <= 0)
756 fatal (f, _("_beginthread failed: err=%d"), errno);
757 incdep_threads[i] = tid;
758#endif
759 }
760 }
761 else
762 incdep_num_threads = 0;
763
764 incdep_initialized = 1;
765}
766
767/* Flushes outstanding work and terminates the worker threads.
768 This is called from snap_deps(). */
769void
770incdep_flush_and_term (void)
771{
772 unsigned i;
773
774 if (!incdep_initialized)
775 return;
776
777 /* flush any out standing work */
778
779 incdep_flush_it (NILF);
780
781 /* tell the threads to terminate */
782
783 incdep_lock ();
784 incdep_terminate = 1;
785 incdep_signal_todo ();
786 incdep_unlock ();
787
788 /* wait for the threads to quit */
789
790 for (i = 0; i < incdep_num_threads; i++)
791 {
792 /* more later? */
793
794 /* terminate or join up the allocation caches. */
795 alloccache_term (&incdep_rec_caches[i], incdep_cache_deallocator, (void *)(size_t)i);
796 alloccache_join (&dep_cache, &incdep_dep_caches[i]);
797 strcache2_term (&incdep_dep_strcaches[i]);
798 strcache2_term (&incdep_var_strcaches[i]);
799 }
800 incdep_num_threads = 0;
801
802 /* destroy the lock and condition variables / event objects. */
803
804 /* later */
805
806 incdep_initialized = 0;
807}
808
809#ifdef PARSE_IN_WORKER
810/* Flushes a strcache entry returning the actual string cache entry.
811 The input is freed! */
812static const char *
813incdep_flush_strcache_entry (struct strcache2_entry *entry)
814{
815 if (!entry->user)
816 entry->user = (void *) strcache2_add_hashed_file (&file_strcache,
817 (const char *)(entry + 1),
818 entry->length, entry->hash);
819 return (const char *)entry->user;
820}
821
822/* Flushes the recorded instructions. */
823static void
824incdep_flush_recorded_instructions (struct incdep *cur)
825{
826 struct incdep_variable_in_set *rec_vis;
827 struct incdep_variable_def *rec_vd;
828 struct incdep_recorded_files *rec_f;
829
830 /* define_variable_in_set */
831
832 rec_vis = cur->recorded_variables_in_set_head;
833 cur->recorded_variables_in_set_head = cur->recorded_variables_in_set_tail = NULL;
834 if (rec_vis)
835 do
836 {
837 void *free_me = rec_vis;
838 unsigned int name_length = rec_vis->name_entry->length;
839 define_variable_in_set (incdep_flush_strcache_entry (rec_vis->name_entry),
840 name_length,
841 rec_vis->value,
842 rec_vis->value_length,
843 rec_vis->duplicate_value,
844 rec_vis->origin,
845 rec_vis->recursive,
846 rec_vis->set,
847 rec_vis->flocp);
848 rec_vis = rec_vis->next;
849 incdep_free_rec (cur, free_me);
850 }
851 while (rec_vis);
852
853 /* do_variable_definition */
854
855 rec_vd = cur->recorded_variable_defs_head;
856 cur->recorded_variable_defs_head = cur->recorded_variable_defs_tail = NULL;
857 if (rec_vd)
858 do
859 {
860 void *free_me = rec_vd;
861 do_variable_definition_2 (rec_vd->flocp,
862 incdep_flush_strcache_entry (rec_vd->name_entry),
863 rec_vd->value,
864 rec_vd->value_length,
865 0,
866 rec_vd->value,
867 rec_vd->origin,
868 rec_vd->flavor,
869 rec_vd->target_var);
870 rec_vd = rec_vd->next;
871 incdep_free_rec (cur, free_me);
872 }
873 while (rec_vd);
874
875 /* record_files */
876
877 rec_f = cur->recorded_files_head;
878 cur->recorded_files_head = cur->recorded_files_tail = NULL;
879 if (rec_f)
880 do
881 {
882 void *free_me = rec_f;
883 struct dep *dep;
884 struct nameseq *filenames;
885
886 for (dep = rec_f->deps; dep; dep = dep->next)
887 dep->name = incdep_flush_strcache_entry ((struct strcache2_entry *)dep->name);
888
889 filenames = (struct nameseq *) alloccache_alloc (&nameseq_cache);
890 filenames->next = 0;
891 filenames->name = incdep_flush_strcache_entry (rec_f->filename_entry);
892
893 record_files (filenames,
894 rec_f->pattern,
895 rec_f->pattern_percent,
896 rec_f->deps,
897 rec_f->cmds_started,
898 rec_f->commands,
899 rec_f->commands_idx,
900 rec_f->two_colon,
901 rec_f->flocp);
902
903 rec_f = rec_f->next;
904 incdep_free_rec (cur, free_me);
905 }
906 while (rec_f);
907}
908#endif /* PARSE_IN_WORKER */
909
910/* Record / issue a warning about a misformed dep file. */
911static void
912incdep_warn (struct incdep *cur, unsigned int line_no, const char *msg)
913{
914 if (cur->worker_tid == -1)
915 error (NILF, "%s(%d): %s", cur->name, line_no, msg);
916#ifdef PARSE_IN_WORKER
917 else
918 {
919 cur->err_line_no = line_no;
920 cur->err_msg = msg;
921 }
922#endif
923}
924
925/* Dependency or file strcache allocation / recording. */
926static const char *
927incdep_dep_strcache (struct incdep *cur, const char *str, int len)
928{
929 const char *ret;
930 if (cur->worker_tid == -1)
931 {
932 /* Make sure the string is terminated before we hand it to
933 strcache_add_len so it does have to make a temporary copy
934 of it on the stack. */
935 char ch = str[len];
936 ((char *)str)[len] = '\0';
937 ret = strcache_add_len (str, len);
938 ((char *)str)[len] = ch;
939 }
940 else
941 {
942 /* Add it out the strcache of the thread. */
943 ret = strcache2_add (&incdep_dep_strcaches[cur->worker_tid], str, len);
944 ret = (const char *)strcache2_get_entry(&incdep_dep_strcaches[cur->worker_tid], ret);
945 }
946 return ret;
947}
948
949/* Variable name allocation / recording. */
950static const char *
951incdep_var_strcache (struct incdep *cur, const char *str, int len)
952{
953 const char *ret;
954 if (cur->worker_tid == -1)
955 {
956 /* XXX: we're leaking this memory now! This will be fixed later. */
957 ret = xmalloc (len + 1);
958 memcpy ((char *)ret, str, len);
959 ((char *)ret)[len] = '\0';
960 }
961 else
962 {
963 /* Add it out the strcache of the thread. */
964 ret = strcache2_add (&incdep_var_strcaches[cur->worker_tid], str, len);
965 ret = (const char *)strcache2_get_entry(&incdep_var_strcaches[cur->worker_tid], ret);
966 }
967 return ret;
968}
969
970/* Record / perform a variable definition in a set.
971 The NAME is in the string cache.
972 The VALUE is on the heap.
973 The DUPLICATE_VALUE is always 0. */
974static void
975incdep_record_variable_in_set (struct incdep *cur,
976 const char *name, unsigned int name_length,
977 const char *value,
978 unsigned int value_length,
979 int duplicate_value,
980 enum variable_origin origin,
981 int recursive,
982 struct variable_set *set,
983 const struct floc *flocp)
984{
985 assert (!duplicate_value);
986 if (cur->worker_tid == -1)
987 define_variable_in_set (name, name_length, value, value_length,
988 duplicate_value, origin, recursive, set, flocp);
989#ifdef PARSE_IN_WORKER
990 else
991 {
992 struct incdep_variable_in_set *rec =
993 (struct incdep_variable_in_set *)incdep_alloc_rec (cur);
994 rec->name_entry = (struct strcache2_entry *)name;
995 rec->value = value;
996 rec->value_length = value_length;
997 rec->duplicate_value = duplicate_value;
998 rec->origin = origin;
999 rec->recursive = recursive;
1000 rec->set = set;
1001 rec->flocp = flocp;
1002
1003 rec->next = NULL;
1004 if (cur->recorded_variables_in_set_tail)
1005 cur->recorded_variables_in_set_tail->next = rec;
1006 else
1007 cur->recorded_variables_in_set_head = rec;
1008 cur->recorded_variables_in_set_tail = rec;
1009 }
1010#endif
1011}
1012
1013/* Record / perform a variable definition. The VALUE should be disposed of. */
1014static void
1015incdep_record_variable_def (struct incdep *cur,
1016 const struct floc *flocp,
1017 const char *name,
1018 unsigned int name_length,
1019 char *value,
1020 unsigned int value_length,
1021 enum variable_origin origin,
1022 enum variable_flavor flavor,
1023 int target_var)
1024{
1025 if (cur->worker_tid == -1)
1026 do_variable_definition_2 (flocp, name, value, value_length, 0, value,
1027 origin, flavor, target_var);
1028#ifdef PARSE_IN_WORKER
1029 else
1030 {
1031 struct incdep_variable_def *rec =
1032 (struct incdep_variable_def *)incdep_alloc_rec (cur);
1033 rec->flocp = flocp;
1034 rec->name_entry = (struct strcache2_entry *)name;
1035 rec->value = value;
1036 rec->value_length = value_length;
1037 rec->origin = origin;
1038 rec->flavor = flavor;
1039 rec->target_var = target_var;
1040
1041 rec->next = NULL;
1042 if (cur->recorded_variable_defs_tail)
1043 cur->recorded_variable_defs_tail->next = rec;
1044 else
1045 cur->recorded_variable_defs_head = rec;
1046 cur->recorded_variable_defs_tail = rec;
1047 }
1048#else
1049 (void)name_length;
1050#endif
1051}
1052
1053/* Record files.*/
1054static void
1055incdep_record_files (struct incdep *cur,
1056 const char *filename, const char *pattern,
1057 const char *pattern_percent, struct dep *deps,
1058 unsigned int cmds_started, char *commands,
1059 unsigned int commands_idx, int two_colon,
1060 const struct floc *flocp)
1061{
1062 if (cur->worker_tid == -1)
1063 {
1064 struct nameseq *filenames = (struct nameseq *) alloccache_alloc (&nameseq_cache);
1065 filenames->next = 0;
1066 filenames->name = filename;
1067 record_files (filenames, pattern, pattern_percent, deps, cmds_started,
1068 commands, commands_idx, two_colon, flocp);
1069 }
1070#ifdef PARSE_IN_WORKER
1071 else
1072 {
1073 struct incdep_recorded_files *rec =
1074 (struct incdep_recorded_files *) incdep_alloc_rec (cur);
1075
1076 rec->filename_entry = (struct strcache2_entry *)filename;
1077 rec->pattern = pattern;
1078 rec->pattern_percent = pattern_percent;
1079 rec->deps = deps;
1080 rec->cmds_started = cmds_started;
1081 rec->commands = commands;
1082 rec->commands_idx = commands_idx;
1083 rec->two_colon = two_colon;
1084 rec->flocp = flocp;
1085
1086 rec->next = NULL;
1087 if (cur->recorded_files_tail)
1088 cur->recorded_files_tail->next = rec;
1089 else
1090 cur->recorded_files_head = rec;
1091 cur->recorded_files_tail = rec;
1092 }
1093#endif
1094}
1095
1096
1097/* no nonsense dependency file including.
1098
1099 Because nobody wants bogus dependency files to break their incremental
1100 builds with hard to comprehend error messages, this function does not
1101 use the normal eval routine but does all the parsing itself. This isn't,
1102 as much work as it sounds, because the necessary feature set is very
1103 limited.
1104
1105 eval_include_dep_file groks:
1106
1107 define var
1108 endef
1109
1110 var [|:|?|>]= value [\]
1111
1112 [\]
1113 file: [deps] [\]
1114
1115 */
1116static void
1117eval_include_dep_file (struct incdep *curdep, struct floc *f)
1118{
1119 unsigned line_no = 1;
1120 const char *file_end = curdep->file_end;
1121 const char *cur = curdep->file_base;
1122 const char *endp;
1123
1124 /* if no file data, just return immediately. */
1125 if (!cur)
1126 return;
1127
1128 /* now parse the file. */
1129 while (cur < file_end)
1130 {
1131 /* skip empty lines */
1132 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
1133 ++cur;
1134 if (cur >= file_end)
1135 break;
1136 if (*cur == '#')
1137 {
1138 cur = memchr (cur, '\n', file_end - cur);
1139 if (!cur)
1140 break;
1141 }
1142 if (*cur == '\\')
1143 {
1144 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
1145 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
1146 : (file_end - cur == 1) ? 1 : 0;
1147 if (eol_len)
1148 {
1149 cur += eol_len;
1150 line_no++;
1151 continue;
1152 }
1153 }
1154 if (*cur == '\n')
1155 {
1156 cur++;
1157 line_no++;
1158 continue;
1159 }
1160
1161 /* define var
1162 ...
1163 endef */
1164 if (strneq (cur, "define ", 7))
1165 {
1166 const char *var;
1167 unsigned var_len;
1168 const char *value_start;
1169 const char *value_end;
1170 char *value;
1171 unsigned value_len;
1172 int found_endef = 0;
1173
1174 /* extract the variable name. */
1175 cur += 7;
1176 while (isblank ((unsigned char)*cur))
1177 ++cur;
1178 value_start = endp = memchr (cur, '\n', file_end - cur);
1179 if (!endp)
1180 endp = cur;
1181 while (endp > cur && isspace ((unsigned char)endp[-1]))
1182 --endp;
1183 var_len = endp - cur;
1184 if (!var_len)
1185 {
1186 incdep_warn (curdep, line_no, "bogus define statement.");
1187 break;
1188 }
1189 var = incdep_var_strcache (curdep, cur, var_len);
1190
1191 /* find the end of the variable. */
1192 cur = value_end = value_start = value_start + 1;
1193 ++line_no;
1194 while (cur < file_end)
1195 {
1196 /* check for endef, don't bother with skipping leading spaces. */
1197 if ( file_end - cur >= 5
1198 && strneq (cur, "endef", 5))
1199 {
1200 endp = cur + 5;
1201 while (endp < file_end && isspace ((unsigned char)*endp) && *endp != '\n')
1202 endp++;
1203 if (endp >= file_end || *endp == '\n')
1204 {
1205 found_endef = 1;
1206 cur = endp >= file_end ? file_end : endp + 1;
1207 break;
1208 }
1209 }
1210
1211 /* skip a line ahead. */
1212 cur = value_end = memchr (cur, '\n', file_end - cur);
1213 if (cur != NULL)
1214 ++cur;
1215 else
1216 cur = value_end = file_end;
1217 ++line_no;
1218 }
1219
1220 if (!found_endef)
1221 {
1222 incdep_warn (curdep, line_no, "missing endef, dropping the rest of the file.");
1223 break;
1224 }
1225 value_len = value_end - value_start;
1226 if (memchr (value_start, '\0', value_len))
1227 {
1228 incdep_warn (curdep, line_no, "'\\0' in define, dropping the rest of the file.");
1229 break;
1230 }
1231
1232 /* make a copy of the value, converting \r\n to \n, and define it. */
1233 value = incdep_xmalloc (curdep, value_len + 1);
1234 endp = memchr (value_start, '\r', value_len);
1235 if (endp)
1236 {
1237 const char *src = value_start;
1238 char *dst = value;
1239 for (;;)
1240 {
1241 size_t len = endp - src;
1242 memcpy (dst, src, len);
1243 dst += len;
1244 src = endp;
1245 if (src + 1 < file_end && src[1] == '\n')
1246 src++; /* skip the '\r' */
1247 if (src >= value_end)
1248 break;
1249 endp = memchr (endp + 1, '\r', src - value_end);
1250 if (!endp)
1251 endp = value_end;
1252 }
1253 value_len = dst - value;
1254 }
1255 else
1256 memcpy (value, value_start, value_len);
1257 value [value_len] = '\0';
1258
1259 incdep_record_variable_in_set (curdep,
1260 var, var_len, value, value_len,
1261 0 /* don't duplicate */, o_file,
1262 0 /* defines are recursive but this is faster */,
1263 NULL /* global set */, f);
1264 }
1265
1266 /* file: deps
1267 OR
1268 variable [:]= value */
1269 else
1270 {
1271 const char *colonp;
1272 const char *equalp;
1273
1274 /* Look for a colon and an equal sign, optimize for colon.
1275 Only one file is support and the colon / equal must be on
1276 the same line. */
1277 colonp = memchr (cur, ':', file_end - cur);
1278#ifdef HAVE_DOS_PATHS
1279 while ( colonp
1280 && colonp + 1 < file_end
1281 && (colonp[1] == '/' || colonp[1] == '\\')
1282 && colonp > cur
1283 && isalpha ((unsigned char)colonp[-1])
1284 && ( colonp == cur + 1
1285 || strchr (" \t(", colonp[-2]) != 0))
1286 colonp = memchr (colonp + 1, ':', file_end - (colonp + 1));
1287#endif
1288 endp = NULL;
1289 if ( !colonp
1290 || (endp = memchr (cur, '\n', colonp - cur)))
1291 {
1292 colonp = NULL;
1293 equalp = memchr (cur, '=', (endp ? endp : file_end) - cur);
1294 if ( !equalp
1295 || (!endp && memchr (cur, '\n', equalp - cur)))
1296 {
1297 incdep_warn (curdep, line_no, "no colon.");
1298 break;
1299 }
1300 }
1301 else
1302 equalp = memchr (cur, '=', (colonp + 2 <= file_end
1303 ? colonp + 2 : file_end) - cur);
1304 if (equalp)
1305 {
1306 /* An assignment of some sort. */
1307 const char *var;
1308 unsigned var_len;
1309 const char *value_start;
1310 const char *value_end;
1311 char *value;
1312 unsigned value_len;
1313 unsigned multi_line = 0;
1314 enum variable_flavor flavor;
1315
1316 /* figure the flavor first. */
1317 flavor = f_recursive;
1318 if (equalp > cur)
1319 {
1320 if (equalp[-1] == ':')
1321 flavor = f_simple;
1322 else if (equalp[-1] == '?')
1323 flavor = f_conditional;
1324 else if (equalp[-1] == '+')
1325 flavor = f_append;
1326 else if (equalp[-1] == '>')
1327 flavor = f_prepend;
1328 }
1329
1330 /* extract the variable name. */
1331 endp = flavor == f_recursive ? equalp : equalp - 1;
1332 while (endp > cur && isblank ((unsigned char)endp[-1]))
1333 --endp;
1334 var_len = endp - cur;
1335 if (!var_len)
1336 {
1337 incdep_warn (curdep, line_no, "empty variable. (includedep)");
1338 break;
1339 }
1340 if ( memchr (cur, '$', var_len)
1341 || memchr (cur, ' ', var_len)
1342 || memchr (cur, '\t', var_len))
1343 {
1344 incdep_warn (curdep, line_no, "fancy variable name. (includedep)");
1345 break;
1346 }
1347 var = incdep_var_strcache (curdep, cur, var_len);
1348
1349 /* find the start of the value. */
1350 cur = equalp + 1;
1351 while (cur < file_end && isblank ((unsigned char)*cur))
1352 cur++;
1353 value_start = cur;
1354
1355 /* find the end of the value / line (this isn't 101% correct). */
1356 value_end = cur;
1357 while (cur < file_end)
1358 {
1359 endp = value_end = memchr (cur, '\n', file_end - cur);
1360 if (!value_end)
1361 value_end = file_end;
1362 if (value_end - 1 >= cur && value_end[-1] == '\r')
1363 --value_end;
1364 if (value_end - 1 < cur || value_end[-1] != '\\')
1365 {
1366 cur = endp ? endp + 1 : file_end;
1367 break;
1368 }
1369 --value_end;
1370 if (value_end - 1 >= cur && value_end[-1] == '\\')
1371 {
1372 incdep_warn (curdep, line_no, "fancy escaping! (includedep)");
1373 cur = NULL;
1374 break;
1375 }
1376 if (!endp)
1377 {
1378 cur = file_end;
1379 break;
1380 }
1381
1382 cur = endp + 1;
1383 ++multi_line;
1384 ++line_no;
1385 }
1386 if (!cur)
1387 break;
1388 ++line_no;
1389
1390 /* make a copy of the value, converting \r\n to \n, and define it. */
1391 value_len = value_end - value_start;
1392 value = incdep_xmalloc (curdep, value_len + 1);
1393 if (!multi_line)
1394 memcpy (value, value_start, value_len);
1395 else
1396 {
1397 /* unescape it */
1398 const char *src = value_start;
1399 char *dst = value;
1400 while (src < value_end)
1401 {
1402 const char *nextp;
1403
1404 endp = memchr (src, '\n', value_end - src);
1405 if (!endp)
1406 nextp = endp = value_end;
1407 else
1408 nextp = endp + 1;
1409 if (endp > src && endp[-1] == '\r')
1410 --endp;
1411 if (endp > src && endp[-1] == '\\')
1412 --endp;
1413
1414 if (src != value_start)
1415 *dst++ = ' ';
1416 memcpy (dst, src, endp - src);
1417 dst += endp - src;
1418 src = nextp;
1419 }
1420 value_len = dst - value;
1421 }
1422 value [value_len] = '\0';
1423
1424 /* do the definition */
1425 if (flavor == f_recursive
1426 || ( flavor == f_simple
1427 && !memchr (value, '$', value_len)))
1428 incdep_record_variable_in_set (curdep,
1429 var, var_len, value, value_len,
1430 0 /* don't duplicate */, o_file,
1431 flavor == f_recursive /* recursive */,
1432 NULL /* global set */, f);
1433 else
1434 incdep_record_variable_def (curdep,
1435 f, var, var_len, value, value_len,
1436 o_file, flavor, 0 /* not target var */);
1437 }
1438 else
1439 {
1440 /* file: dependencies */
1441
1442 const char *filename;
1443 struct dep *deps = 0;
1444 struct dep **nextdep = &deps;
1445 struct dep *dep;
1446
1447 /* extract the filename, ASSUME a single one. */
1448 endp = colonp;
1449 while (endp > cur && isblank ((unsigned char)endp[-1]))
1450 --endp;
1451 if (cur == endp)
1452 {
1453 incdep_warn (curdep, line_no, "empty filename.");
1454 break;
1455 }
1456 if ( memchr (cur, '$', endp - cur)
1457 || memchr (cur, ' ', endp - cur)
1458 || memchr (cur, '\t', endp - cur))
1459 {
1460 incdep_warn (curdep, line_no, "multiple / fancy file name. (includedep)");
1461 break;
1462 }
1463 filename = incdep_dep_strcache (curdep, cur, endp - cur);
1464
1465 /* parse any dependencies. */
1466 cur = colonp + 1;
1467 while (cur < file_end)
1468 {
1469 /* skip blanks and count lines. */
1470 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
1471 ++cur;
1472 if (cur >= file_end)
1473 break;
1474 if (*cur == '\n')
1475 {
1476 cur++;
1477 line_no++;
1478 break;
1479 }
1480
1481 /* continuation + eol? */
1482 if (*cur == '\\')
1483 {
1484 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
1485 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
1486 : (file_end - cur == 1) ? 1 : 0;
1487 if (eol_len)
1488 {
1489 cur += eol_len;
1490 line_no++;
1491 continue;
1492 }
1493 }
1494
1495 /* find the end of the filename */
1496 endp = cur;
1497 while (endp < file_end && !isspace ((unsigned char)*endp))
1498 ++endp;
1499
1500 /* add it to the list. */
1501 *nextdep = dep = incdep_alloc_dep (curdep);
1502 dep->name = incdep_dep_strcache (curdep, cur, endp - cur);
1503 dep->includedep = 1;
1504 nextdep = &dep->next;
1505
1506 cur = endp;
1507 }
1508
1509 /* enter the file with its dependencies. */
1510 incdep_record_files (curdep,
1511 filename, NULL, NULL, deps, 0, NULL, 0, 0, f);
1512 }
1513 }
1514 }
1515
1516 /* free the file data */
1517 incdep_xfree (curdep, curdep->file_base);
1518 curdep->file_base = curdep->file_end = NULL;
1519}
1520
1521/* Flushes the incdep todo and done lists. */
1522static void
1523incdep_flush_it (struct floc *f)
1524{
1525 incdep_lock ();
1526 for (;;)
1527 {
1528 struct incdep *cur = incdep_head_done;
1529
1530 /* if the done list is empty, grab a todo list entry. */
1531 if (!cur && incdep_head_todo)
1532 {
1533 cur = incdep_head_todo;
1534 if (cur->next)
1535 incdep_head_todo = cur->next;
1536 else
1537 incdep_head_todo = incdep_tail_todo = NULL;
1538 incdep_unlock ();
1539
1540 incdep_read_file (cur, f);
1541 eval_include_dep_file (cur, f);
1542 incdep_freeit (cur);
1543
1544 incdep_lock ();
1545 continue;
1546 }
1547
1548 /* if the todo list and done list are empty we're either done
1549 or will have to wait for the thread(s) to finish. */
1550 if (!cur && !incdep_num_reading)
1551 break; /* done */
1552 if (!cur)
1553 {
1554 while (!incdep_head_done)
1555 incdep_wait_done ();
1556 cur = incdep_head_done;
1557 }
1558
1559 /* we grab the entire done list and work thru it. */
1560 incdep_head_done = incdep_tail_done = NULL;
1561 incdep_unlock ();
1562
1563 while (cur)
1564 {
1565 struct incdep *next = cur->next;
1566#ifdef PARSE_IN_WORKER
1567 incdep_flush_recorded_instructions (cur);
1568#else
1569 eval_include_dep_file (cur, f);
1570#endif
1571 incdep_freeit (cur);
1572 cur = next;
1573 }
1574
1575 incdep_lock ();
1576 } /* outer loop */
1577 incdep_unlock ();
1578}
1579
1580
1581/* splits up a list of file names and feeds it to eval_include_dep_file,
1582 employing threads to try speed up the file reading. */
1583void
1584eval_include_dep (const char *names, struct floc *f, enum incdep_op op)
1585{
1586 struct incdep *head = 0;
1587 struct incdep *tail = 0;
1588 struct incdep *cur;
1589 const char *names_iterator = names;
1590 const char *name;
1591 unsigned int name_len;
1592
1593 /* loop through NAMES, creating a todo list out of them. */
1594
1595 while ((name = find_next_token (&names_iterator, &name_len)) != 0)
1596 {
1597 cur = xmalloc (sizeof (*cur) + name_len); /* not incdep_xmalloc here */
1598 cur->file_base = cur->file_end = NULL;
1599 memcpy (cur->name, name, name_len);
1600 cur->name[name_len] = '\0';
1601 cur->worker_tid = -1;
1602#ifdef PARSE_IN_WORKER
1603 cur->err_line_no = 0;
1604 cur->err_msg = NULL;
1605 cur->recorded_variables_in_set_head = NULL;
1606 cur->recorded_variables_in_set_tail = NULL;
1607 cur->recorded_variable_defs_head = NULL;
1608 cur->recorded_variable_defs_tail = NULL;
1609 cur->recorded_files_head = NULL;
1610 cur->recorded_files_tail = NULL;
1611#endif
1612
1613 cur->next = NULL;
1614 if (tail)
1615 tail->next = cur;
1616 else
1617 head = cur;
1618 tail = cur;
1619 }
1620
1621#ifdef ELECTRIC_HEAP
1622 if (1)
1623#else
1624 if (op == incdep_read_it)
1625#endif
1626 {
1627 /* work our way thru the files directly */
1628
1629 cur = head;
1630 while (cur)
1631 {
1632 struct incdep *next = cur->next;
1633 incdep_read_file (cur, f);
1634 eval_include_dep_file (cur, f);
1635 incdep_freeit (cur);
1636 cur = next;
1637 }
1638 }
1639 else
1640 {
1641 /* initialize the worker threads and related stuff the first time around. */
1642
1643 if (!incdep_initialized)
1644 incdep_init (f);
1645
1646 /* queue the files and notify the worker threads. */
1647
1648 incdep_lock ();
1649
1650 if (incdep_tail_todo)
1651 incdep_tail_todo->next = head;
1652 else
1653 incdep_head_todo = head;
1654 incdep_tail_todo = tail;
1655
1656 incdep_signal_todo ();
1657 incdep_unlock ();
1658
1659 /* flush the todo queue if we're requested to do so. */
1660
1661 if (op == incdep_flush)
1662 incdep_flush_it (f);
1663 }
1664}
1665
1666#endif /* CONFIG_WITH_INCLUDEDEP */
1667
Note: See TracBrowser for help on using the repository browser.

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