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

Last change on this file since 1873 was 1873, checked in by bird, 17 years ago

incdep: free records during flushing.

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