VirtualBox

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

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

kmk: Don't bootstrap with threads and disable them for FreeBSD.x86 since that doesn't work in my 6.3 jail.

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