VirtualBox

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

Last change on this file since 2869 was 2869, checked in by bird, 8 years ago

updates

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