source: trunk/src/kmk/incdep.c@ 1824

Last change on this file since 1824 was 1824, checked in by bird, 17 years ago

kmk: includedep - use do_variable_definition_2.

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