VirtualBox

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

Last change on this file since 3141 was 3141, checked in by bird, 7 years ago

kmk: linux merge fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.8 KB
Line 
1#ifdef CONFIG_WITH_INCLUDEDEP
2/* $Id: incdep.c 3141 2018-03-14 21:58:32Z 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 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
1236/* no nonsense dependency file including.
1237
1238 Because nobody wants bogus dependency files to break their incremental
1239 builds with hard to comprehend error messages, this function does not
1240 use the normal eval routine but does all the parsing itself. This isn't,
1241 as much work as it sounds, because the necessary feature set is very
1242 limited.
1243
1244 eval_include_dep_file groks:
1245
1246 define var
1247 endef
1248
1249 var [|:|?|>]= value [\]
1250
1251 [\]
1252 file: [deps] [\]
1253
1254 */
1255static void
1256eval_include_dep_file (struct incdep *curdep, floc *f)
1257{
1258 unsigned line_no = 1;
1259 const char *file_end = curdep->file_end;
1260 const char *cur = curdep->file_base;
1261 const char *endp;
1262
1263 /* if no file data, just return immediately. */
1264 if (!cur)
1265 return;
1266
1267 /* now parse the file. */
1268 while (cur < file_end)
1269 {
1270 /* skip empty lines */
1271 while (cur < file_end && ISSPACE (*cur) && *cur != '\n')
1272 ++cur;
1273 if (cur >= file_end)
1274 break;
1275 if (*cur == '#')
1276 {
1277 cur = memchr (cur, '\n', file_end - cur);
1278 if (!cur)
1279 break;
1280 }
1281 if (*cur == '\\')
1282 {
1283 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
1284 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
1285 : (file_end - cur == 1) ? 1 : 0;
1286 if (eol_len)
1287 {
1288 cur += eol_len;
1289 line_no++;
1290 continue;
1291 }
1292 }
1293 if (*cur == '\n')
1294 {
1295 cur++;
1296 line_no++;
1297 continue;
1298 }
1299
1300 /* define var
1301 ...
1302 endef */
1303 if (strneq (cur, "define ", 7))
1304 {
1305 const char *var;
1306 unsigned var_len;
1307 const char *value_start;
1308 const char *value_end;
1309 char *value;
1310 unsigned value_len;
1311 int found_endef = 0;
1312
1313 /* extract the variable name. */
1314 cur += 7;
1315 while (ISBLANK (*cur))
1316 ++cur;
1317 value_start = endp = memchr (cur, '\n', file_end - cur);
1318 if (!endp)
1319 endp = cur;
1320 while (endp > cur && ISSPACE (endp[-1]))
1321 --endp;
1322 var_len = endp - cur;
1323 if (!var_len)
1324 {
1325 incdep_warn (curdep, line_no, "bogus define statement.");
1326 break;
1327 }
1328 var = incdep_var_strcache (curdep, cur, var_len);
1329
1330 /* find the end of the variable. */
1331 cur = value_end = value_start = value_start + 1;
1332 ++line_no;
1333 while (cur < file_end)
1334 {
1335 /* check for endef, don't bother with skipping leading spaces. */
1336 if ( file_end - cur >= 5
1337 && strneq (cur, "endef", 5))
1338 {
1339 endp = cur + 5;
1340 while (endp < file_end && ISSPACE (*endp) && *endp != '\n')
1341 endp++;
1342 if (endp >= file_end || *endp == '\n')
1343 {
1344 found_endef = 1;
1345 cur = endp >= file_end ? file_end : endp + 1;
1346 break;
1347 }
1348 }
1349
1350 /* skip a line ahead. */
1351 cur = value_end = memchr (cur, '\n', file_end - cur);
1352 if (cur != NULL)
1353 ++cur;
1354 else
1355 cur = value_end = file_end;
1356 ++line_no;
1357 }
1358
1359 if (!found_endef)
1360 {
1361 incdep_warn (curdep, line_no, "missing endef, dropping the rest of the file.");
1362 break;
1363 }
1364 value_len = value_end - value_start;
1365 if (memchr (value_start, '\0', value_len))
1366 {
1367 incdep_warn (curdep, line_no, "'\\0' in define, dropping the rest of the file.");
1368 break;
1369 }
1370
1371 /* make a copy of the value, converting \r\n to \n, and define it. */
1372 value = incdep_xmalloc (curdep, value_len + 1);
1373 endp = memchr (value_start, '\r', value_len);
1374 if (endp)
1375 {
1376 const char *src = value_start;
1377 char *dst = value;
1378 for (;;)
1379 {
1380 size_t len = endp - src;
1381 memcpy (dst, src, len);
1382 dst += len;
1383 src = endp;
1384 if (src + 1 < file_end && src[1] == '\n')
1385 src++; /* skip the '\r' */
1386 if (src >= value_end)
1387 break;
1388 endp = memchr (endp + 1, '\r', src - value_end);
1389 if (!endp)
1390 endp = value_end;
1391 }
1392 value_len = dst - value;
1393 }
1394 else
1395 memcpy (value, value_start, value_len);
1396 value [value_len] = '\0';
1397
1398 incdep_record_variable_in_set (curdep,
1399 var, var_len, value, value_len,
1400 0 /* don't duplicate */, o_file,
1401 0 /* defines are recursive but this is faster */,
1402 NULL /* global set */, f);
1403 }
1404
1405 /* file: deps
1406 OR
1407 variable [:]= value */
1408 else
1409 {
1410 const char *equalp;
1411 const char *eol;
1412
1413 /* Look for a colon or and equal sign. In the assignment case, we
1414 require it to be on the same line as the variable name to simplify
1415 the code. Because of clang, we cannot make the same assumptions
1416 with file dependencies. So, start with the equal. */
1417
1418 assert (*cur != '\n');
1419 eol = memchr (cur, '\n', file_end - cur);
1420 if (!eol)
1421 eol = file_end;
1422 equalp = memchr (cur, '=', eol - cur);
1423 if (equalp)
1424 {
1425 /* An assignment of some sort. */
1426 const char *var;
1427 unsigned var_len;
1428 const char *value_start;
1429 const char *value_end;
1430 char *value;
1431 unsigned value_len;
1432 unsigned multi_line = 0;
1433 enum variable_flavor flavor;
1434
1435 /* figure the flavor first. */
1436 flavor = f_recursive;
1437 if (equalp > cur)
1438 {
1439 if (equalp[-1] == ':')
1440 flavor = f_simple;
1441 else if (equalp[-1] == '?')
1442 flavor = f_conditional;
1443 else if (equalp[-1] == '+')
1444 flavor = f_append;
1445 else if (equalp[-1] == '>')
1446 flavor = f_prepend;
1447 }
1448
1449 /* extract the variable name. */
1450 endp = flavor == f_recursive ? equalp : equalp - 1;
1451 while (endp > cur && ISBLANK (endp[-1]))
1452 --endp;
1453 var_len = endp - cur;
1454 if (!var_len)
1455 {
1456 incdep_warn (curdep, line_no, "empty variable. (includedep)");
1457 break;
1458 }
1459 if ( memchr (cur, '$', var_len)
1460 || memchr (cur, ' ', var_len)
1461 || memchr (cur, '\t', var_len))
1462 {
1463 incdep_warn (curdep, line_no, "fancy variable name. (includedep)");
1464 break;
1465 }
1466 var = incdep_var_strcache (curdep, cur, var_len);
1467
1468 /* find the start of the value. */
1469 cur = equalp + 1;
1470 while (cur < file_end && ISBLANK (*cur))
1471 cur++;
1472 value_start = cur;
1473
1474 /* find the end of the value / line (this isn't 101% correct). */
1475 value_end = cur;
1476 while (cur < file_end)
1477 {
1478 endp = value_end = memchr (cur, '\n', file_end - cur);
1479 if (!value_end)
1480 value_end = file_end;
1481 if (value_end - 1 >= cur && value_end[-1] == '\r')
1482 --value_end;
1483 if (value_end - 1 < cur || value_end[-1] != '\\')
1484 {
1485 cur = endp ? endp + 1 : file_end;
1486 break;
1487 }
1488 --value_end;
1489 if (value_end - 1 >= cur && value_end[-1] == '\\')
1490 {
1491 incdep_warn (curdep, line_no, "fancy escaping! (includedep)");
1492 cur = NULL;
1493 break;
1494 }
1495 if (!endp)
1496 {
1497 cur = file_end;
1498 break;
1499 }
1500
1501 cur = endp + 1;
1502 ++multi_line;
1503 ++line_no;
1504 }
1505 if (!cur)
1506 break;
1507 ++line_no;
1508
1509 /* make a copy of the value, converting \r\n to \n, and define it. */
1510 value_len = value_end - value_start;
1511 value = incdep_xmalloc (curdep, value_len + 1);
1512 if (!multi_line)
1513 memcpy (value, value_start, value_len);
1514 else
1515 {
1516 /* unescape it */
1517 const char *src = value_start;
1518 char *dst = value;
1519 while (src < value_end)
1520 {
1521 const char *nextp;
1522
1523 endp = memchr (src, '\n', value_end - src);
1524 if (!endp)
1525 nextp = endp = value_end;
1526 else
1527 nextp = endp + 1;
1528 if (endp > src && endp[-1] == '\r')
1529 --endp;
1530 if (endp > src && endp[-1] == '\\')
1531 --endp;
1532
1533 if (src != value_start)
1534 *dst++ = ' ';
1535 memcpy (dst, src, endp - src);
1536 dst += endp - src;
1537 src = nextp;
1538 }
1539 value_len = dst - value;
1540 }
1541 value [value_len] = '\0';
1542
1543 /* do the definition */
1544 if (flavor == f_recursive
1545 || ( flavor == f_simple
1546 && !memchr (value, '$', value_len)))
1547 incdep_record_variable_in_set (curdep,
1548 var, var_len, value, value_len,
1549 0 /* don't duplicate */, o_file,
1550 flavor == f_recursive /* recursive */,
1551 NULL /* global set */, f);
1552 else
1553 incdep_record_variable_def (curdep,
1554 f, var, var_len, value, value_len,
1555 o_file, flavor, 0 /* not target var */);
1556 }
1557 else
1558 {
1559 /* Expecting: file: dependencies */
1560
1561 const char *filename;
1562 const char *fnnext;
1563 const char *fnend;
1564 const char *colonp;
1565 struct dep *deps = 0;
1566 struct dep **nextdep = &deps;
1567 struct dep *dep;
1568
1569
1570 /* Locate the next file colon. If it's not within the bounds of
1571 the current line, check that all new line chars are escaped,
1572 and simplify them while we're at it. */
1573
1574 colonp = memchr (cur, ':', file_end - cur);
1575#ifdef HAVE_DOS_PATHS
1576 while ( colonp
1577 && colonp + 1 < file_end
1578 && (colonp[1] == '/' || colonp[1] == '\\')
1579 && colonp > cur
1580 && isalpha ((unsigned char)colonp[-1])
1581 && ( colonp == cur + 1
1582 || strchr (" \t(", colonp[-2]) != 0))
1583 colonp = memchr (colonp + 1, ':', file_end - (colonp + 1));
1584#endif
1585 if (!colonp)
1586 {
1587 incdep_warn (curdep, line_no, "no colon.");
1588 break;
1589 }
1590 if ((uintptr_t)colonp >= (uintptr_t)eol)
1591 {
1592 const char *sol;
1593
1594 if (memchr (eol, '=', colonp - eol))
1595 {
1596 incdep_warn (curdep, line_no, "multi line assignment / dependency confusion.");
1597 break;
1598 }
1599
1600 sol = cur;
1601 do
1602 {
1603 char *eol2 = (char *)eol - 1;
1604 if ((uintptr_t)eol2 >= (uintptr_t)sol && *eol2 == '\r') /* DOS line endings. */
1605 eol2--;
1606 if ((uintptr_t)eol2 < (uintptr_t)sol || *eol2 != '\\')
1607 incdep_warn (curdep, line_no, "no colon.");
1608 else if (eol2 != sol && eol2[-1] == '\\')
1609 incdep_warn (curdep, line_no, "fancy EOL escape. (includedep)");
1610 else
1611 {
1612 eol2[0] = ' ';
1613 eol2[1] = ' ';
1614 if (eol2 != eol - 1)
1615 eol2[2] = ' ';
1616 line_no++;
1617
1618 sol = eol + 1;
1619 eol = memchr (sol, '\n', colonp - sol);
1620 continue;
1621 }
1622 sol = NULL;
1623 break;
1624 }
1625 while (eol != NULL);
1626 if (!sol)
1627 break;
1628 }
1629
1630 /* Extract the first filename after trimming and basic checks. */
1631 fnend = colonp;
1632 while ((uintptr_t)fnend > (uintptr_t)cur && ISBLANK (fnend[-1]))
1633 --fnend;
1634 if (cur == fnend)
1635 {
1636 incdep_warn (curdep, line_no, "empty filename.");
1637 break;
1638 }
1639 if (memchr (cur, '$', fnend - cur))
1640 {
1641 incdep_warn (curdep, line_no, "fancy file name. (includedep)");
1642 break;
1643 }
1644
1645 fnnext = cur;
1646 while (fnnext != fnend && !ISBLANK (*fnnext))
1647 fnnext++;
1648 filename = incdep_dep_strcache (curdep, cur, fnnext - cur);
1649
1650 /* parse any dependencies. */
1651 cur = colonp + 1;
1652 while (cur < file_end)
1653 {
1654 /* skip blanks and count lines. */
1655 while (cur < file_end && ISSPACE (*cur) && *cur != '\n')
1656 ++cur;
1657 if (cur >= file_end)
1658 break;
1659 if (*cur == '\n')
1660 {
1661 cur++;
1662 line_no++;
1663 break;
1664 }
1665
1666 /* continuation + eol? */
1667 if (*cur == '\\')
1668 {
1669 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
1670 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
1671 : (file_end - cur == 1) ? 1 : 0;
1672 if (eol_len)
1673 {
1674 cur += eol_len;
1675 line_no++;
1676 continue;
1677 }
1678 }
1679
1680 /* find the end of the filename */
1681 endp = cur;
1682 while (endp < file_end && !ISSPACE (*endp))
1683 ++endp;
1684
1685 /* add it to the list. */
1686 *nextdep = dep = incdep_alloc_dep (curdep);
1687 dep->name = incdep_dep_strcache (curdep, cur, endp - cur);
1688 dep->includedep = 1;
1689 nextdep = &dep->next;
1690
1691 cur = endp;
1692 }
1693
1694 /* enter the file with its dependencies. */
1695 incdep_record_file (curdep, filename, deps, f);
1696
1697 /* More files? Record them with the same dependency list. */
1698 if (fnnext != fnend)
1699 for (;;)
1700 {
1701 const char *filename_prev = filename;
1702 const char *fnstart;
1703 while (fnnext != fnend && ISBLANK (*fnnext))
1704 fnnext++;
1705 if (fnnext == fnend)
1706 break;
1707
1708 fnstart = fnnext;
1709 while (fnnext != fnend && !ISBLANK (*fnnext))
1710 fnnext++;
1711
1712 filename = incdep_dep_strcache (curdep, fnstart, fnnext - fnstart);
1713 if (filename != filename_prev) /* clang optimization. */
1714 incdep_record_file (curdep, filename, incdep_dup_dep_list (curdep, deps), f);
1715 }
1716 }
1717 }
1718 }
1719
1720 /* free the file data */
1721 incdep_xfree (curdep, curdep->file_base);
1722 curdep->file_base = curdep->file_end = NULL;
1723}
1724
1725/* Flushes the incdep todo and done lists. */
1726static void
1727incdep_flush_it (floc *f)
1728{
1729 incdep_lock ();
1730 for (;;)
1731 {
1732 struct incdep *cur = incdep_head_done;
1733
1734 /* if the done list is empty, grab a todo list entry. */
1735 if (!cur && incdep_head_todo)
1736 {
1737 cur = incdep_head_todo;
1738 if (cur->next)
1739 incdep_head_todo = cur->next;
1740 else
1741 incdep_head_todo = incdep_tail_todo = NULL;
1742 incdep_unlock ();
1743
1744 incdep_read_file (cur, f);
1745 eval_include_dep_file (cur, f);
1746 incdep_freeit (cur);
1747
1748 incdep_lock ();
1749 continue;
1750 }
1751
1752 /* if the todo list and done list are empty we're either done
1753 or will have to wait for the thread(s) to finish. */
1754 if (!cur && !incdep_num_reading)
1755 break; /* done */
1756 if (!cur)
1757 {
1758 while (!incdep_head_done)
1759 incdep_wait_done ();
1760 cur = incdep_head_done;
1761 }
1762
1763 /* we grab the entire done list and work thru it. */
1764 incdep_head_done = incdep_tail_done = NULL;
1765 incdep_unlock ();
1766
1767 while (cur)
1768 {
1769 struct incdep *next = cur->next;
1770#ifdef PARSE_IN_WORKER
1771 incdep_flush_recorded_instructions (cur);
1772#else
1773 eval_include_dep_file (cur, f);
1774#endif
1775 incdep_freeit (cur);
1776 cur = next;
1777 }
1778
1779 incdep_lock ();
1780 } /* outer loop */
1781 incdep_unlock ();
1782}
1783
1784
1785/* splits up a list of file names and feeds it to eval_include_dep_file,
1786 employing threads to try speed up the file reading. */
1787void
1788eval_include_dep (const char *names, floc *f, enum incdep_op op)
1789{
1790 struct incdep *head = 0;
1791 struct incdep *tail = 0;
1792 struct incdep *cur;
1793 const char *names_iterator = names;
1794 const char *name;
1795 unsigned int name_len;
1796
1797 /* loop through NAMES, creating a todo list out of them. */
1798
1799 while ((name = find_next_token (&names_iterator, &name_len)) != 0)
1800 {
1801#ifdef INCDEP_USE_KFSCACHE
1802 KFSLOOKUPERROR enmError;
1803 PKFSOBJ pFileObj = kFsCacheLookupWithLengthA (g_pFsCache, name, name_len, &enmError);
1804 if (!pFileObj)
1805 continue;
1806 if (pFileObj->bObjType != KFSOBJ_TYPE_FILE)
1807 {
1808 kFsCacheObjRelease (g_pFsCache, pFileObj);
1809 continue;
1810 }
1811
1812 cur = xmalloc (sizeof (*cur)); /* not incdep_xmalloc here */
1813 cur->pFileObj = pFileObj;
1814#else
1815 cur = xmalloc (sizeof (*cur) + name_len); /* not incdep_xmalloc here */
1816 memcpy (cur->name, name, name_len);
1817 cur->name[name_len] = '\0';
1818#endif
1819
1820 cur->file_base = cur->file_end = NULL;
1821 cur->worker_tid = -1;
1822#ifdef PARSE_IN_WORKER
1823 cur->err_line_no = 0;
1824 cur->err_msg = NULL;
1825 cur->recorded_variables_in_set_head = NULL;
1826 cur->recorded_variables_in_set_tail = NULL;
1827 cur->recorded_variable_defs_head = NULL;
1828 cur->recorded_variable_defs_tail = NULL;
1829 cur->recorded_file_head = NULL;
1830 cur->recorded_file_tail = NULL;
1831#endif
1832
1833 cur->next = NULL;
1834 if (tail)
1835 tail->next = cur;
1836 else
1837 head = cur;
1838 tail = cur;
1839 }
1840
1841#ifdef ELECTRIC_HEAP
1842 if (1)
1843#else
1844 if (op == incdep_read_it)
1845#endif
1846 {
1847 /* work our way thru the files directly */
1848
1849 cur = head;
1850 while (cur)
1851 {
1852 struct incdep *next = cur->next;
1853 incdep_read_file (cur, f);
1854 eval_include_dep_file (cur, f);
1855 incdep_freeit (cur);
1856 cur = next;
1857 }
1858 }
1859 else
1860 {
1861 /* initialize the worker threads and related stuff the first time around. */
1862
1863 if (!incdep_initialized)
1864 incdep_init (f);
1865
1866 /* queue the files and notify the worker threads. */
1867
1868 incdep_lock ();
1869
1870 if (incdep_tail_todo)
1871 incdep_tail_todo->next = head;
1872 else
1873 incdep_head_todo = head;
1874 incdep_tail_todo = tail;
1875
1876 incdep_signal_todo ();
1877 incdep_unlock ();
1878
1879 /* flush the todo queue if we're requested to do so. */
1880
1881 if (op == incdep_flush)
1882 incdep_flush_it (f);
1883 }
1884}
1885
1886#endif /* CONFIG_WITH_INCLUDEDEP */
1887
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