VirtualBox

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

Last change on this file since 2657 was 2591, checked in by bird, 13 years ago

kmk: Merged in changes from GNU make 3.82. Previous GNU make base version was gnumake-2008-10-28-CVS.

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