VirtualBox

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

Last change on this file since 2745 was 2745, checked in by bird, 10 years ago

Some heap stats stuff.

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