source: trunk/src/kmk/incdep.c@ 2553

Last change on this file since 2553 was 2546, checked in by bird, 14 years ago

Applied modified patches for Haiku support from Mike Smith.

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