VirtualBox

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

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

kmk/incdep: buildfix.

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