VirtualBox

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

最後變更 在這個檔案從3316是 3316,由 bird 提交於 5 年 前

kmk/incdep.c: Working on parsing filenames with spaces and what-not in them. (needs more testing)

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 66.3 KB
 
1#ifdef CONFIG_WITH_INCLUDEDEP
2/* $Id: incdep.c 3316 2020-03-31 01:13:22Z 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 "makeint.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 "filedef.h"
51#include "dep.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 floc *flocp; /* NILF */
111};
112
113struct incdep_variable_def
114{
115 struct incdep_variable_def *next;
116 /* the parameters */
117 const 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 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 (floc *);
241static void eval_include_dep_file (struct incdep *, floc *);
242static void incdep_commit_recorded_file (const char *filename, struct dep *deps,
243 const 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 O (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, 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 OSS (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 OSS (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 OSS (error, f, "%s: read: %s", cur->name, strerror (errno));
554 incdep_xfree (cur, cur->file_base);
555 }
556 else
557 OSS (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 O (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__) || defined(__GLIBC__)
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 O (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 O (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 (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 ON (fatal, f, _("pthread_mutex_init failed: err=%d"), rc);
757 rc = pthread_cond_init (&incdep_cond_todo, NULL);
758 if (rc)
759 ON (fatal, f, _("pthread_cond_init failed: err=%d"), rc);
760 rc = pthread_cond_init (&incdep_cond_done, NULL);
761 if (rc)
762 ON (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 ON (fatal, f, _("CreateEvent failed: err=%d"), GetLastError());
769 incdep_hev_done = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL);
770 if (!incdep_hev_done)
771 ON (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 ON (fatal, f, _("DosCreateEventSem failed: rc=%d"), rc);
780 rc = DosCreateEventSem (NULL, &incdep_hev_done, 0, FALSE);
781 if (rc)
782 ON (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 ON (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 ON (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 ON (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 ON (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 ON (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 OSSNS (error, NILF, "%s/%s(%d): %s", cur->pFileObj->pParent->Obj.pszName, cur->pFileObj->pszName,
930 cur->err_line_no, cur->err_msg);
931#else
932 OSNS (error,NILF, "%s(%d): %s", cur->name, cur->err_line_no, cur->err_msg);
933#endif
934
935
936 /* define_variable_in_set */
937
938 rec_vis = cur->recorded_variables_in_set_head;
939 cur->recorded_variables_in_set_head = cur->recorded_variables_in_set_tail = NULL;
940 if (rec_vis)
941 do
942 {
943 void *free_me = rec_vis;
944 unsigned int name_length = rec_vis->name_entry->length;
945 define_variable_in_set (incdep_flush_strcache_entry (rec_vis->name_entry),
946 name_length,
947 rec_vis->value,
948 rec_vis->value_length,
949 rec_vis->duplicate_value,
950 rec_vis->origin,
951 rec_vis->recursive,
952 rec_vis->set,
953 rec_vis->flocp);
954 rec_vis = rec_vis->next;
955 incdep_free_rec (cur, free_me);
956 }
957 while (rec_vis);
958
959 /* do_variable_definition */
960
961 rec_vd = cur->recorded_variable_defs_head;
962 cur->recorded_variable_defs_head = cur->recorded_variable_defs_tail = NULL;
963 if (rec_vd)
964 do
965 {
966 void *free_me = rec_vd;
967 do_variable_definition_2 (rec_vd->flocp,
968 incdep_flush_strcache_entry (rec_vd->name_entry),
969 rec_vd->value,
970 rec_vd->value_length,
971 0,
972 rec_vd->value,
973 rec_vd->origin,
974 rec_vd->flavor,
975 rec_vd->target_var);
976 rec_vd = rec_vd->next;
977 incdep_free_rec (cur, free_me);
978 }
979 while (rec_vd);
980
981 /* record_files */
982
983 rec_f = cur->recorded_file_head;
984 cur->recorded_file_head = cur->recorded_file_tail = NULL;
985 if (rec_f)
986 do
987 {
988 void *free_me = rec_f;
989 struct dep *dep;
990
991 for (dep = rec_f->deps; dep; dep = dep->next)
992 dep->name = incdep_flush_strcache_entry ((struct strcache2_entry *)dep->name);
993
994 incdep_commit_recorded_file (incdep_flush_strcache_entry (rec_f->filename_entry),
995 rec_f->deps,
996 rec_f->flocp);
997
998 rec_f = rec_f->next;
999 incdep_free_rec (cur, free_me);
1000 }
1001 while (rec_f);
1002}
1003#endif /* PARSE_IN_WORKER */
1004
1005/* Record / issue a warning about a misformed dep file. */
1006static void
1007incdep_warn (struct incdep *cur, unsigned int line_no, const char *msg)
1008{
1009 if (cur->worker_tid == -1)
1010#ifdef INCDEP_USE_KFSCACHE
1011 OSSNS (error,NILF, "%s/%s(%d): %s", cur->pFileObj->pParent->Obj.pszName, cur->pFileObj->pszName, line_no, msg);
1012#else
1013 OSNS (error, NILF, "%s(%d): %s", cur->name, line_no, msg);
1014#endif
1015#ifdef PARSE_IN_WORKER
1016 else
1017 {
1018 cur->err_line_no = line_no;
1019 cur->err_msg = msg;
1020 }
1021#endif
1022}
1023
1024/* Dependency or file strcache allocation / recording. */
1025static const char *
1026incdep_dep_strcache (struct incdep *cur, const char *str, int len)
1027{
1028 const char *ret;
1029 if (cur->worker_tid == -1)
1030 {
1031 /* Make sure the string is terminated before we hand it to
1032 strcache_add_len so it does have to make a temporary copy
1033 of it on the stack. */
1034 char ch = str[len];
1035 ((char *)str)[len] = '\0';
1036 ret = strcache_add_len (str, len);
1037 ((char *)str)[len] = ch;
1038 }
1039 else
1040 {
1041 /* Add it out the strcache of the thread. */
1042 ret = strcache2_add (&incdep_dep_strcaches[cur->worker_tid], str, len);
1043 ret = (const char *)strcache2_get_entry(&incdep_dep_strcaches[cur->worker_tid], ret);
1044 }
1045 return ret;
1046}
1047
1048/* Variable name allocation / recording. */
1049static const char *
1050incdep_var_strcache (struct incdep *cur, const char *str, int len)
1051{
1052 const char *ret;
1053 if (cur->worker_tid == -1)
1054 {
1055 /* XXX: we're leaking this memory now! This will be fixed later. */
1056 ret = xmalloc (len + 1);
1057 memcpy ((char *)ret, str, len);
1058 ((char *)ret)[len] = '\0';
1059 }
1060 else
1061 {
1062 /* Add it out the strcache of the thread. */
1063 ret = strcache2_add (&incdep_var_strcaches[cur->worker_tid], str, len);
1064 ret = (const char *)strcache2_get_entry(&incdep_var_strcaches[cur->worker_tid], ret);
1065 }
1066 return ret;
1067}
1068
1069/* Record / perform a variable definition in a set.
1070 The NAME is in the string cache.
1071 The VALUE is on the heap.
1072 The DUPLICATE_VALUE is always 0. */
1073static void
1074incdep_record_variable_in_set (struct incdep *cur,
1075 const char *name, unsigned int name_length,
1076 const char *value,
1077 unsigned int value_length,
1078 int duplicate_value,
1079 enum variable_origin origin,
1080 int recursive,
1081 struct variable_set *set,
1082 const floc *flocp)
1083{
1084 assert (!duplicate_value);
1085 if (cur->worker_tid == -1)
1086 define_variable_in_set (name, name_length, value, value_length,
1087 duplicate_value, origin, recursive, set, flocp);
1088#ifdef PARSE_IN_WORKER
1089 else
1090 {
1091 struct incdep_variable_in_set *rec =
1092 (struct incdep_variable_in_set *)incdep_alloc_rec (cur);
1093 rec->name_entry = (struct strcache2_entry *)name;
1094 rec->value = value;
1095 rec->value_length = value_length;
1096 rec->duplicate_value = duplicate_value;
1097 rec->origin = origin;
1098 rec->recursive = recursive;
1099 rec->set = set;
1100 rec->flocp = flocp;
1101
1102 rec->next = NULL;
1103 if (cur->recorded_variables_in_set_tail)
1104 cur->recorded_variables_in_set_tail->next = rec;
1105 else
1106 cur->recorded_variables_in_set_head = rec;
1107 cur->recorded_variables_in_set_tail = rec;
1108 }
1109#endif
1110}
1111
1112/* Record / perform a variable definition. The VALUE should be disposed of. */
1113static void
1114incdep_record_variable_def (struct incdep *cur,
1115 const floc *flocp,
1116 const char *name,
1117 unsigned int name_length,
1118 char *value,
1119 unsigned int value_length,
1120 enum variable_origin origin,
1121 enum variable_flavor flavor,
1122 int target_var)
1123{
1124 if (cur->worker_tid == -1)
1125 do_variable_definition_2 (flocp, name, value, value_length, 0, value,
1126 origin, flavor, target_var);
1127#ifdef PARSE_IN_WORKER
1128 else
1129 {
1130 struct incdep_variable_def *rec =
1131 (struct incdep_variable_def *)incdep_alloc_rec (cur);
1132 rec->flocp = flocp;
1133 rec->name_entry = (struct strcache2_entry *)name;
1134 rec->value = value;
1135 rec->value_length = value_length;
1136 rec->origin = origin;
1137 rec->flavor = flavor;
1138 rec->target_var = target_var;
1139
1140 rec->next = NULL;
1141 if (cur->recorded_variable_defs_tail)
1142 cur->recorded_variable_defs_tail->next = rec;
1143 else
1144 cur->recorded_variable_defs_head = rec;
1145 cur->recorded_variable_defs_tail = rec;
1146 }
1147#else
1148 (void)name_length;
1149#endif
1150}
1151
1152/* Similar to record_files in read.c, only much much simpler. */
1153static void
1154incdep_commit_recorded_file (const char *filename, struct dep *deps,
1155 const floc *flocp)
1156{
1157 struct file *f;
1158
1159 /* Perform some validations. */
1160 if (filename[0] == '.'
1161 && ( streq(filename, ".POSIX")
1162 || streq(filename, ".EXPORT_ALL_VARIABLES")
1163 || streq(filename, ".INTERMEDIATE")
1164 || streq(filename, ".LOW_RESOLUTION_TIME")
1165 || streq(filename, ".NOTPARALLEL")
1166 || streq(filename, ".ONESHELL")
1167 || streq(filename, ".PHONY")
1168 || streq(filename, ".PRECIOUS")
1169 || streq(filename, ".SECONDARY")
1170 || streq(filename, ".SECONDTARGETEXPANSION")
1171 || streq(filename, ".SILENT")
1172 || streq(filename, ".SHELLFLAGS")
1173 || streq(filename, ".SUFFIXES")
1174 )
1175 )
1176 {
1177 OS (error, flocp, _("reserved filename '%s' used in dependency file, ignored"), filename);
1178 return;
1179 }
1180
1181 /* Lookup or create an entry in the database. */
1182 f = enter_file (filename);
1183 if (f->double_colon)
1184 {
1185 OS (error, flocp, _("dependency file '%s' has a double colon entry already, ignoring"), filename);
1186 return;
1187 }
1188 f->is_target = 1;
1189
1190 /* Append dependencies. */
1191 deps = enter_prereqs (deps, NULL);
1192 if (deps)
1193 {
1194 struct dep *last = f->deps;
1195 if (!last)
1196 f->deps = deps;
1197 else
1198 {
1199 while (last->next)
1200 last = last->next;
1201 last->next = deps;
1202 }
1203 }
1204}
1205
1206/* Record a file.*/
1207static void
1208incdep_record_file (struct incdep *cur,
1209 const char *filename,
1210 struct dep *deps,
1211 const floc *flocp)
1212{
1213 if (cur->worker_tid == -1)
1214 incdep_commit_recorded_file (filename, deps, flocp);
1215#ifdef PARSE_IN_WORKER
1216 else
1217 {
1218 struct incdep_recorded_file *rec =
1219 (struct incdep_recorded_file *) incdep_alloc_rec (cur);
1220
1221 rec->filename_entry = (struct strcache2_entry *)filename;
1222 rec->deps = deps;
1223 rec->flocp = flocp;
1224
1225 rec->next = NULL;
1226 if (cur->recorded_file_tail)
1227 cur->recorded_file_tail->next = rec;
1228 else
1229 cur->recorded_file_head = rec;
1230 cur->recorded_file_tail = rec;
1231 }
1232#endif
1233}
1234
1235/* Counts slashes backwards from SLASH, stopping at START. */
1236static size_t incdep_count_slashes_backwards(const char *slash, const char *start)
1237{
1238 size_t slashes = 1;
1239 assert (*slash == '\\');
1240 while ((uintptr_t)slash > (uintptr_t)start && slash[0 - slashes] == '\\')
1241 slashes++;
1242 return slashes;
1243}
1244
1245/* Whitespace cannot be escaped at the end of a line, there has to be
1246 some stuff following it other than a line continuation slash.
1247
1248 So, we look ahead and makes sure that there is something non-whitespaced
1249 following this allegedly escaped whitespace.
1250
1251 This code ASSUMES the file content is zero terminated! */
1252static int incdep_verify_escaped_whitespace(const char *ws)
1253{
1254 char ch;
1255
1256 assert(ws[-1] == '\\');
1257 assert(ISBLANK((unsigned int)ws[0]));
1258
1259 /* If the character following the '\ ' sequence is not a whitespace,
1260 another escape character or null terminator, we're good. */
1261 ws += 2;
1262 ch = *ws;
1263 if (ch != '\\' && !ISSPACE((unsigned int)ch) && ch != '\0')
1264 return 1;
1265
1266 /* Otherwise we'll have to parse forward till we hit the end of the
1267 line/file or something. */
1268 while ((ch = *ws++) != '\0')
1269 {
1270 if (ch == '\\')
1271 {
1272 /* escaped newline? */
1273 ch = *ws;
1274 if (ch == '\n')
1275 ws++;
1276 else if (ch == '\r' && ws[1] == '\n')
1277 ws += 2;
1278 else
1279 return 1;
1280 }
1281 else if (ISBLANK((unsigned int)ch))
1282 { /* contine */ }
1283 else if (!ISSPACE((unsigned int)ch))
1284 return 1;
1285 else
1286 return 0; /* newline; all trailing whitespace will be ignored. */
1287 }
1288
1289 return 0;
1290}
1291
1292/* Unescapes the next filename and returns cached copy.
1293
1294 Modifies the input string that START points to.
1295
1296 When NEXTP is not NULL, ASSUME target filename and that END isn't entirely
1297 accurate in case the filename ends with a trailing backslash. There can be
1298 more than one filename in a this case. NEXTP will be set to the first
1299 character after then filename.
1300
1301 When NEXTP is NULL, ASSUME exactly one dependency filename and that END is
1302 accurately deliminating the string.
1303 */
1304static const char *
1305incdep_unescape_and_cache_filename(struct incdep *curdep,
1306 char *start, const char *end, const char **nextp)
1307{
1308 int const is_dep = nextp == NULL;
1309 unsigned const esc_mask = MAP_BLANK /* ' ' + '\t' */
1310 | MAP_COLON /* ':' */
1311 | MAP_COMMENT /* '#' */
1312 | MAP_EQUALS /* '=' */
1313 | MAP_SEMI /* ';' */
1314 | ( is_dep
1315 ? MAP_PIPE /* '|' */
1316 : MAP_PERCENT); /* '%' */
1317 unsigned const all_esc_mask = esc_mask | MAP_BLANK | MAP_NEWLINE;
1318 unsigned const stop_mask = nextp ? MAP_BLANK | MAP_NEWLINE | MAP_COLON : 0;
1319 char volatile *src;
1320 char volatile *dst;
1321
1322 /*
1323 * Skip forward to the first escaped character so we can avoid unnecessary shifting.
1324 */
1325#if 1
1326 src = start;
1327 dst = start;
1328#elif 1
1329 static const char s_szStop[] = "\n\r\t ";
1330
1331 src = memchr(start, '$', end - start);
1332 dst = memchr(start, '\\', end - start);
1333 if (src && ((uintptr_t)src < (uintptr_t)dst || dst == NULL))
1334 dst = src;
1335 else if (dst && ((uintptr_t)dst < (uintptr_t)src || src == NULL))
1336 src = dst;
1337 else
1338 {
1339 assert(src == NULL && dst == NULL);
1340 if (nextp)
1341 {
1342 int i = sizeof(s_szStop);
1343 while (i-- > 0)
1344 {
1345 char *stop = memchr(start, s_szStop[i], end - start);
1346 if (stop)
1347 end = stop;
1348 }
1349 *nextp = end;
1350 }
1351 return incdep_dep_strcache (curdep, start, end - start);
1352 }
1353 if (nextp)
1354 {
1355 char *stop = src;
1356 int i = sizeof(s_szStop);
1357 while (i-- > 0)
1358 {
1359 char *stop2 = memchr(start, s_szStop[i], stop - start);
1360 if (stop2)
1361 stop = stop2;
1362 }
1363 if (stop != src)
1364 {
1365 *nextp = stop;
1366 return incdep_dep_strcache (curdep, start, stop - start);
1367 }
1368 }
1369#endif
1370
1371 /*
1372 * Copy char-by-char, undoing escaping as we go along.
1373 */
1374 while ((uintptr_t)src < (uintptr_t)end)
1375 {
1376 const char ch = *src++;
1377 if (ch != '\\' && ch != '$')
1378 {
1379 if (!STOP_SET (ch, stop_mask))
1380 *dst++ = ch;
1381 else
1382 {
1383 src--;
1384 break;
1385 }
1386 }
1387 else
1388 {
1389 const char ch2 = *src++; /* No bounds checking to handle "/dir/file\ : ..." when end points at " :". */
1390 if (ch == '$')
1391 {
1392 if (ch2 != '$') /* $$ -> $ - Ignores secondary expansion! */
1393 src--;
1394 *dst++ = ch;
1395 }
1396 else
1397 {
1398 unsigned int const ch2_map = stopchar_map[(unsigned char)ch2];
1399 if (ch2_map & all_esc_mask)
1400 {
1401 /* Count preceeding slashes, unwind half of them regardless of odd/even count. */
1402 size_t const max_slashes = src - start - 1;
1403 size_t slashes = 1;
1404 while (slashes < max_slashes && src[-2 - slashes] == '\\')
1405 slashes++;
1406
1407 /* Non-whitespace is simple: Slash slashes, output or stop. */
1408 if (!(ch2_map & (MAP_BLANK | MAP_NEWLINE)))
1409 {
1410 assert(ch2_map & esc_mask);
1411 dst -= slashes / 2;
1412 if ((slashes & 1) || !(stop_mask & ch2_map))
1413 *dst++ = ch2;
1414 else
1415 {
1416 src--;
1417 break;
1418 }
1419 }
1420 /* Escaped blanks or newlines.
1421
1422 We have to pretent that we've already replaced any escaped newlines
1423 and associated whitespace with a single space here. We also have to
1424 pretend trailing whitespace doesn't exist when IS_DEP is non-zero.
1425 This makes for pretty interesting times... */
1426 else
1427 {
1428 char ch3;
1429
1430 /* An Escaped blank is interesting because it is striped unconditionally
1431 at the end of a line, regardless of how many escaped newlines may
1432 following it. We join the escaped newline handling if we fine one
1433 following us. */
1434 if (ch2_map & MAP_BLANK)
1435 {
1436 /* skip whitespace and check for escaped newline. */
1437 volatile char * const src_saved = src;
1438 while ((ch3 = *src) != '\0' && ISBLANK(ch3))
1439 src++;
1440 if (ch3 == '\\' && src[1] == '\n')
1441 src += 2; /* Escaped blank & newline joins into single space. */
1442 else if (ch3 == '\\' && src[1] == '\r' && src[1] == '\n')
1443 src += 3; /* -> Join the escaped newline code below on the next line. */
1444 else
1445 {
1446 src = src_saved;
1447 dst -= slashes / 2;
1448 if (slashes & 1)
1449 {
1450 *dst++ = ch2;
1451 continue;
1452 }
1453 assert(nextp);
1454 break;
1455 }
1456 }
1457 /* Escaped newlines get special treatment as they an any adjacent whitespace
1458 gets reduced to a single space, including subsequent escaped newlines.
1459 In addition, if this is the final dependency/file and there is no
1460 significant new characters following this escaped newline, the replacement
1461 space will also be stripped and we won't have anything to escape, meaning
1462 that the slashes will remain as is. Finally, none of this space stuff can
1463 be stop characters, unless of course a newline isn't escaped. */
1464 else
1465 {
1466 assert(ch2_map & MAP_NEWLINE);
1467 if (ch2 == '\r' && *src == '\n')
1468 src++;
1469 }
1470
1471 /* common space/newline code */
1472 for (;;)
1473 {
1474 while ((uintptr_t)src < (uintptr_t)end && ISBLANK(*src))
1475 src++;
1476 if ((uintptr_t)src >= (uintptr_t)end)
1477 {
1478 ch3 = '\0';
1479 break;
1480 }
1481 ch3 = *src;
1482 if (ch3 != '\\')
1483 break;
1484 ch3 = src[1];
1485 if (ch3 == '\n')
1486 src += 2;
1487 else if (ch3 == '\r' && src[1] == '\n')
1488 src += 3;
1489 else
1490 break;
1491 }
1492
1493 if (!ch3 && is_dep)
1494 break; /* last thing on the line. */
1495 dst -= slashes / 2;
1496 if (slashes & 1)
1497 *dst++ = ' ';
1498 else
1499 {
1500 assert(nextp);
1501 break;
1502 }
1503 }
1504 }
1505 /* Just output the slash if non-escapable character: */
1506 else
1507 {
1508 src--;
1509 *dst++ = ch;
1510 }
1511 }
1512 }
1513 }
1514
1515 if (nextp)
1516 *nextp = (const char *)src;
1517 return incdep_dep_strcache(curdep, start, dst - start);
1518}
1519
1520/* no nonsense dependency file including.
1521
1522 Because nobody wants bogus dependency files to break their incremental
1523 builds with hard to comprehend error messages, this function does not
1524 use the normal eval routine but does all the parsing itself. This isn't,
1525 as much work as it sounds, because the necessary feature set is very
1526 limited.
1527
1528 eval_include_dep_file groks:
1529
1530 define var
1531 endef
1532
1533 var [|:|?|>]= value [\]
1534
1535 [\]
1536 file: [deps] [\]
1537
1538 */
1539static void
1540eval_include_dep_file (struct incdep *curdep, floc *f)
1541{
1542 unsigned line_no = 1;
1543 const char *file_end = curdep->file_end;
1544 const char *cur = curdep->file_base;
1545 const char *endp;
1546
1547 /* if no file data, just return immediately. */
1548 if (!cur)
1549 return;
1550
1551 /* now parse the file. */
1552 while ((uintptr_t)cur < (uintptr_t)file_end)
1553 {
1554 /* skip empty lines */
1555 while ((uintptr_t)cur < (uintptr_t)file_end && ISSPACE (*cur) && *cur != '\n')
1556 ++cur;
1557 if ((uintptr_t)cur >= (uintptr_t)file_end)
1558 break;
1559 if (*cur == '#')
1560 {
1561 cur = memchr (cur, '\n', file_end - cur);
1562 if (!cur)
1563 break;
1564 }
1565 if (*cur == '\\')
1566 {
1567 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
1568 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
1569 : (file_end - cur == 1) ? 1 : 0;
1570 if (eol_len)
1571 {
1572 cur += eol_len;
1573 line_no++;
1574 continue;
1575 }
1576 }
1577 if (*cur == '\n')
1578 {
1579 cur++;
1580 line_no++;
1581 continue;
1582 }
1583
1584 /* define var
1585 ...
1586 endef */
1587 if (strneq (cur, "define ", 7))
1588 {
1589 const char *var;
1590 unsigned var_len;
1591 const char *value_start;
1592 const char *value_end;
1593 char *value;
1594 unsigned value_len;
1595 int found_endef = 0;
1596
1597 /* extract the variable name. */
1598 cur += 7;
1599 while (ISBLANK (*cur))
1600 ++cur;
1601 value_start = endp = memchr (cur, '\n', file_end - cur);
1602 if (!endp)
1603 endp = cur;
1604 while (endp > cur && ISSPACE (endp[-1]))
1605 --endp;
1606 var_len = endp - cur;
1607 if (!var_len)
1608 {
1609 incdep_warn (curdep, line_no, "bogus define statement.");
1610 break;
1611 }
1612 var = incdep_var_strcache (curdep, cur, var_len);
1613
1614 /* find the end of the variable. */
1615 cur = value_end = value_start = value_start + 1;
1616 ++line_no;
1617 while ((uintptr_t)cur < (uintptr_t)file_end)
1618 {
1619 /* check for endef, don't bother with skipping leading spaces. */
1620 if ( file_end - cur >= 5
1621 && strneq (cur, "endef", 5))
1622 {
1623 endp = cur + 5;
1624 while ((uintptr_t)endp < (uintptr_t)file_end && ISSPACE (*endp) && *endp != '\n')
1625 endp++;
1626 if ((uintptr_t)endp >= (uintptr_t)file_end || *endp == '\n')
1627 {
1628 found_endef = 1;
1629 cur = (uintptr_t)endp >= (uintptr_t)file_end ? file_end : endp + 1;
1630 break;
1631 }
1632 }
1633
1634 /* skip a line ahead. */
1635 cur = value_end = memchr (cur, '\n', file_end - cur);
1636 if (cur != NULL)
1637 ++cur;
1638 else
1639 cur = value_end = file_end;
1640 ++line_no;
1641 }
1642
1643 if (!found_endef)
1644 {
1645 incdep_warn (curdep, line_no, "missing endef, dropping the rest of the file.");
1646 break;
1647 }
1648 value_len = value_end - value_start;
1649 if (memchr (value_start, '\0', value_len))
1650 {
1651 incdep_warn (curdep, line_no, "'\\0' in define, dropping the rest of the file.");
1652 break;
1653 }
1654
1655 /* make a copy of the value, converting \r\n to \n, and define it. */
1656 value = incdep_xmalloc (curdep, value_len + 1);
1657 endp = memchr (value_start, '\r', value_len);
1658 if (endp)
1659 {
1660 const char *src = value_start;
1661 char *dst = value;
1662 for (;;)
1663 {
1664 size_t len = endp - src;
1665 memcpy (dst, src, len);
1666 dst += len;
1667 src = endp;
1668 if ((uintptr_t)src + 1 < (uintptr_t)file_end && src[1] == '\n')
1669 src++; /* skip the '\r' */
1670 if (src >= value_end)
1671 break;
1672 endp = memchr (endp + 1, '\r', src - value_end);
1673 if (!endp)
1674 endp = value_end;
1675 }
1676 value_len = dst - value;
1677 }
1678 else
1679 memcpy (value, value_start, value_len);
1680 value [value_len] = '\0';
1681
1682 incdep_record_variable_in_set (curdep,
1683 var, var_len, value, value_len,
1684 0 /* don't duplicate */, o_file,
1685 0 /* defines are recursive but this is faster */,
1686 NULL /* global set */, f);
1687 }
1688
1689 /* file: deps
1690 OR
1691 variable [:]= value */
1692 else
1693 {
1694 const char *equalp;
1695 const char *eol;
1696
1697 /* Look for a colon or an equal sign. In the assignment case, we
1698 require it to be on the same line as the variable name to simplify
1699 the code. Because of clang, we cannot make the same assumptions
1700 with file dependencies. So, start with the equal. */
1701
1702 assert (*cur != '\n');
1703 eol = memchr (cur, '\n', file_end - cur);
1704 if (!eol)
1705 eol = file_end;
1706 equalp = memchr (cur, '=', eol - cur);
1707 if (equalp && equalp != cur && (ISSPACE(equalp[-1]) || equalp[-1] != '\\'))
1708 {
1709 /* An assignment of some sort. */
1710 const char *var;
1711 unsigned var_len;
1712 const char *value_start;
1713 const char *value_end;
1714 char *value;
1715 unsigned value_len;
1716 unsigned multi_line = 0;
1717 enum variable_flavor flavor;
1718
1719 /* figure the flavor first. */
1720 flavor = f_recursive;
1721 if (equalp > cur)
1722 {
1723 if (equalp[-1] == ':')
1724 flavor = f_simple;
1725 else if (equalp[-1] == '?')
1726 flavor = f_conditional;
1727 else if (equalp[-1] == '+')
1728 flavor = f_append;
1729 else if (equalp[-1] == '>')
1730 flavor = f_prepend;
1731 }
1732
1733 /* extract the variable name. */
1734 endp = flavor == f_recursive ? equalp : equalp - 1;
1735 while (endp > cur && ISBLANK (endp[-1]))
1736 --endp;
1737 var_len = endp - cur;
1738 if (!var_len)
1739 {
1740 incdep_warn (curdep, line_no, "empty variable. (includedep)");
1741 break;
1742 }
1743 if ( memchr (cur, '$', var_len)
1744 || memchr (cur, ' ', var_len)
1745 || memchr (cur, '\t', var_len))
1746 {
1747 incdep_warn (curdep, line_no, "fancy variable name. (includedep)");
1748 break;
1749 }
1750 var = incdep_var_strcache (curdep, cur, var_len);
1751
1752 /* find the start of the value. */
1753 cur = equalp + 1;
1754 while ((uintptr_t)cur < (uintptr_t)file_end && ISBLANK (*cur))
1755 cur++;
1756 value_start = cur;
1757
1758 /* find the end of the value / line (this isn't 101% correct). */
1759 value_end = cur;
1760 while ((uintptr_t)cur < (uintptr_t)file_end)
1761 {
1762 endp = value_end = memchr (cur, '\n', file_end - cur);
1763 if (!value_end)
1764 value_end = file_end;
1765 if (value_end - 1 >= cur && value_end[-1] == '\r')
1766 --value_end;
1767 if (value_end - 1 < cur || value_end[-1] != '\\')
1768 {
1769 cur = endp ? endp + 1 : file_end;
1770 break;
1771 }
1772 --value_end;
1773 if (value_end - 1 >= cur && value_end[-1] == '\\')
1774 {
1775 incdep_warn (curdep, line_no, "fancy escaping! (includedep)");
1776 cur = NULL;
1777 break;
1778 }
1779 if (!endp)
1780 {
1781 cur = file_end;
1782 break;
1783 }
1784
1785 cur = endp + 1;
1786 ++multi_line;
1787 ++line_no;
1788 }
1789 if (!cur)
1790 break;
1791 ++line_no;
1792
1793 /* make a copy of the value, converting \r\n to \n, and define it. */
1794 value_len = value_end - value_start;
1795 value = incdep_xmalloc (curdep, value_len + 1);
1796 if (!multi_line)
1797 memcpy (value, value_start, value_len);
1798 else
1799 {
1800 /* unescape it */
1801 const char *src = value_start;
1802 char *dst = value;
1803 while (src < value_end)
1804 {
1805 const char *nextp;
1806
1807 endp = memchr (src, '\n', value_end - src);
1808 if (!endp)
1809 nextp = endp = value_end;
1810 else
1811 nextp = endp + 1;
1812 if (endp > src && endp[-1] == '\r')
1813 --endp;
1814 if (endp > src && endp[-1] == '\\')
1815 --endp;
1816
1817 if (src != value_start)
1818 *dst++ = ' ';
1819 memcpy (dst, src, endp - src);
1820 dst += endp - src;
1821 src = nextp;
1822 }
1823 value_len = dst - value;
1824 }
1825 value [value_len] = '\0';
1826
1827 /* do the definition */
1828 if (flavor == f_recursive
1829 || ( flavor == f_simple
1830 && !memchr (value, '$', value_len)))
1831 incdep_record_variable_in_set (curdep,
1832 var, var_len, value, value_len,
1833 0 /* don't duplicate */, o_file,
1834 flavor == f_recursive /* recursive */,
1835 NULL /* global set */, f);
1836 else
1837 incdep_record_variable_def (curdep,
1838 f, var, var_len, value, value_len,
1839 o_file, flavor, 0 /* not target var */);
1840 }
1841 else
1842 {
1843 /* Expecting: file: dependencies */
1844
1845 int unescape_filename = 0;
1846 const char *filename;
1847 const char *fnnext;
1848 const char *fnend;
1849 const char *colonp;
1850 struct dep *deps = 0;
1851 struct dep **nextdep = &deps;
1852 struct dep *dep;
1853
1854
1855 /* Locate the next file colon. If it's not within the bounds of
1856 the current line, check that all new line chars are escaped,
1857 and simplify them while we're at it. */
1858
1859 colonp = memchr (cur, ':', file_end - cur);
1860 while ( colonp
1861 && ( ( colonp != cur
1862 && colonp[-1] == '\\'
1863 && incdep_count_slashes_backwards (&colonp[-1], cur) & 1)
1864#ifdef HAVE_DOS_PATHS
1865 || ( colonp + 1 < file_end
1866 && (colonp[1] == '/' || colonp[1] == '\\')
1867 && colonp > cur
1868 && isalpha ((unsigned char)colonp[-1])
1869 && ( colonp == cur + 1
1870 || ISBLANK ((unsigned char)colonp[-2])))
1871#endif
1872 )
1873 )
1874 colonp = memchr (colonp + 1, ':', file_end - (colonp + 1));
1875 if (!colonp)
1876 {
1877 incdep_warn (curdep, line_no, "no colon.");
1878 break;
1879 }
1880 if ((uintptr_t)colonp >= (uintptr_t)eol)
1881 {
1882 const char *sol;
1883
1884 if (memchr (eol, '=', colonp - eol))
1885 {
1886 incdep_warn (curdep, line_no, "multi line assignment / dependency confusion.");
1887 break;
1888 }
1889
1890 sol = cur;
1891 do
1892 {
1893 char *eol2 = (char *)eol - 1;
1894 if ((uintptr_t)eol2 >= (uintptr_t)sol && *eol2 == '\r') /* DOS line endings. */
1895 eol2--;
1896 if ((uintptr_t)eol2 < (uintptr_t)sol || *eol2 != '\\')
1897 incdep_warn (curdep, line_no, "no colon.");
1898 else if (eol2 != sol && eol2[-1] == '\\')
1899 incdep_warn (curdep, line_no, "fancy EOL escape. (includedep)");
1900 else
1901 {
1902 eol2[0] = ' ';
1903 eol2[1] = ' ';
1904 if (eol2 != eol - 1)
1905 eol2[2] = ' ';
1906 line_no++;
1907
1908 sol = eol + 1;
1909 eol = memchr (sol, '\n', colonp - sol);
1910 continue;
1911 }
1912 sol = NULL;
1913 break;
1914 }
1915 while (eol != NULL);
1916 if (!sol)
1917 break;
1918 }
1919
1920 /* Extract the first filename after trimming and basic checks. */
1921 fnend = colonp;
1922 while ((uintptr_t)fnend > (uintptr_t)cur && ISBLANK (fnend[-1]))
1923 --fnend;
1924 if (cur == fnend)
1925 {
1926 incdep_warn (curdep, line_no, "empty filename.");
1927 break;
1928 }
1929 fnnext = cur;
1930 if ( !memchr (cur, '\\', fnend - cur)
1931 && !memchr (cur, '$', fnend - cur))
1932 {
1933 while (fnnext != fnend && !ISBLANK (*fnnext))
1934 fnnext++;
1935 filename = incdep_dep_strcache (curdep, cur, fnnext - cur);
1936 }
1937 else
1938 {
1939 filename = incdep_unescape_and_cache_filename (curdep, (char *)fnnext, fnend, &fnnext);
1940 unescape_filename = 1;
1941 }
1942
1943 /* parse any dependencies. */
1944 cur = colonp + 1;
1945 while ((uintptr_t)cur < (uintptr_t)file_end)
1946 {
1947 /* skip blanks and count lines. */
1948 while ((uintptr_t)cur < (uintptr_t)file_end && ISSPACE (*cur) && *cur != '\n')
1949 ++cur;
1950 if ((uintptr_t)cur >= (uintptr_t)file_end)
1951 break;
1952 if (*cur == '\n')
1953 {
1954 cur++;
1955 line_no++;
1956 break;
1957 }
1958
1959 /* continuation + eol? */
1960 if (*cur == '\\')
1961 {
1962 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
1963 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
1964 : (file_end - cur == 1) ? 1 : 0;
1965 if (eol_len)
1966 {
1967 cur += eol_len;
1968 line_no++;
1969 continue;
1970 }
1971 }
1972
1973 /* find the end of the filename */
1974 endp = cur;
1975 while ( (uintptr_t)endp < (uintptr_t)file_end
1976 && ( !ISSPACE (*endp)
1977 || (endp[-1] == '\\' && incdep_count_slashes_backwards(&endp[-1], cur) & 1)))
1978 ++endp;
1979
1980 /* add it to the list. */
1981 *nextdep = dep = incdep_alloc_dep (curdep);
1982 dep->includedep = 1;
1983 if ( !memchr (cur, '\\', endp - cur)
1984 && !memchr (cur, '$', endp - cur))
1985 dep->name = incdep_dep_strcache(curdep, cur, endp - cur);
1986 else
1987 dep->name = incdep_unescape_and_cache_filename (curdep, (char *)cur, endp, NULL);
1988 nextdep = &dep->next;
1989
1990 cur = endp;
1991 }
1992
1993 /* enter the file with its dependencies. */
1994 incdep_record_file (curdep, filename, deps, f);
1995
1996 /* More files? Record them with the same dependency list. */
1997 if ((uintptr_t)fnnext < (uintptr_t)fnend)
1998 for (;;)
1999 {
2000 const char *filename_prev = filename;
2001 while (fnnext != fnend && ISBLANK (*fnnext))
2002 fnnext++;
2003 if (fnnext == fnend)
2004 break;
2005
2006 if (!unescape_filename)
2007 {
2008 const char *fnstart = fnnext;
2009 while (fnnext != fnend && !ISBLANK (*fnnext))
2010 fnnext++;
2011 filename = incdep_dep_strcache (curdep, fnstart, fnnext - fnstart);
2012 }
2013 else
2014 filename = incdep_unescape_and_cache_filename (curdep, (char *)fnnext, fnend, &fnnext);
2015 if (filename != filename_prev) /* clang optimization. */
2016 incdep_record_file (curdep, filename, incdep_dup_dep_list (curdep, deps), f);
2017 }
2018 }
2019 }
2020 }
2021
2022 /* free the file data */
2023 incdep_xfree (curdep, curdep->file_base);
2024 curdep->file_base = curdep->file_end = NULL;
2025}
2026
2027/* Flushes the incdep todo and done lists. */
2028static void
2029incdep_flush_it (floc *f)
2030{
2031 incdep_lock ();
2032 for (;;)
2033 {
2034 struct incdep *cur = incdep_head_done;
2035
2036 /* if the done list is empty, grab a todo list entry. */
2037 if (!cur && incdep_head_todo)
2038 {
2039 cur = incdep_head_todo;
2040 if (cur->next)
2041 incdep_head_todo = cur->next;
2042 else
2043 incdep_head_todo = incdep_tail_todo = NULL;
2044 incdep_unlock ();
2045
2046 incdep_read_file (cur, f);
2047 eval_include_dep_file (cur, f);
2048 incdep_freeit (cur);
2049
2050 incdep_lock ();
2051 continue;
2052 }
2053
2054 /* if the todo list and done list are empty we're either done
2055 or will have to wait for the thread(s) to finish. */
2056 if (!cur && !incdep_num_reading)
2057 break; /* done */
2058 if (!cur)
2059 {
2060 while (!incdep_head_done)
2061 incdep_wait_done ();
2062 cur = incdep_head_done;
2063 }
2064
2065 /* we grab the entire done list and work thru it. */
2066 incdep_head_done = incdep_tail_done = NULL;
2067 incdep_unlock ();
2068
2069 while (cur)
2070 {
2071 struct incdep *next = cur->next;
2072#ifdef PARSE_IN_WORKER
2073 incdep_flush_recorded_instructions (cur);
2074#else
2075 eval_include_dep_file (cur, f);
2076#endif
2077 incdep_freeit (cur);
2078 cur = next;
2079 }
2080
2081 incdep_lock ();
2082 } /* outer loop */
2083 incdep_unlock ();
2084}
2085
2086
2087/* splits up a list of file names and feeds it to eval_include_dep_file,
2088 employing threads to try speed up the file reading. */
2089void
2090eval_include_dep (const char *names, floc *f, enum incdep_op op)
2091{
2092 struct incdep *head = 0;
2093 struct incdep *tail = 0;
2094 struct incdep *cur;
2095 const char *names_iterator = names;
2096 const char *name;
2097 unsigned int name_len;
2098
2099 /* loop through NAMES, creating a todo list out of them. */
2100
2101 while ((name = find_next_token (&names_iterator, &name_len)) != 0)
2102 {
2103#ifdef INCDEP_USE_KFSCACHE
2104 KFSLOOKUPERROR enmError;
2105 PKFSOBJ pFileObj = kFsCacheLookupWithLengthA (g_pFsCache, name, name_len, &enmError);
2106 if (!pFileObj)
2107 continue;
2108 if (pFileObj->bObjType != KFSOBJ_TYPE_FILE)
2109 {
2110 kFsCacheObjRelease (g_pFsCache, pFileObj);
2111 continue;
2112 }
2113
2114 cur = xmalloc (sizeof (*cur)); /* not incdep_xmalloc here */
2115 cur->pFileObj = pFileObj;
2116#else
2117 cur = xmalloc (sizeof (*cur) + name_len); /* not incdep_xmalloc here */
2118 memcpy (cur->name, name, name_len);
2119 cur->name[name_len] = '\0';
2120#endif
2121
2122 cur->file_base = cur->file_end = NULL;
2123 cur->worker_tid = -1;
2124#ifdef PARSE_IN_WORKER
2125 cur->err_line_no = 0;
2126 cur->err_msg = NULL;
2127 cur->recorded_variables_in_set_head = NULL;
2128 cur->recorded_variables_in_set_tail = NULL;
2129 cur->recorded_variable_defs_head = NULL;
2130 cur->recorded_variable_defs_tail = NULL;
2131 cur->recorded_file_head = NULL;
2132 cur->recorded_file_tail = NULL;
2133#endif
2134
2135 cur->next = NULL;
2136 if (tail)
2137 tail->next = cur;
2138 else
2139 head = cur;
2140 tail = cur;
2141 }
2142
2143#ifdef ELECTRIC_HEAP
2144 if (1)
2145#else
2146 if (op == incdep_read_it)
2147#endif
2148 {
2149 /* work our way thru the files directly */
2150
2151 cur = head;
2152 while (cur)
2153 {
2154 struct incdep *next = cur->next;
2155 incdep_read_file (cur, f);
2156 eval_include_dep_file (cur, f);
2157 incdep_freeit (cur);
2158 cur = next;
2159 }
2160 }
2161 else
2162 {
2163 /* initialize the worker threads and related stuff the first time around. */
2164
2165 if (!incdep_initialized)
2166 incdep_init (f);
2167
2168 /* queue the files and notify the worker threads. */
2169
2170 incdep_lock ();
2171
2172 if (incdep_tail_todo)
2173 incdep_tail_todo->next = head;
2174 else
2175 incdep_head_todo = head;
2176 incdep_tail_todo = tail;
2177
2178 incdep_signal_todo ();
2179 incdep_unlock ();
2180
2181 /* flush the todo queue if we're requested to do so. */
2182
2183 if (op == incdep_flush)
2184 incdep_flush_it (f);
2185 }
2186}
2187
2188#endif /* CONFIG_WITH_INCLUDEDEP */
2189
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette