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

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

kmk: moved eval_include_dep into incdep.c (was in read.c) and implemented background file reading. 'includedep-queue' and 'includedep-flush' are new directives, which along with 'includedep', all take a list of dependency files (used to only take a single file).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.6 KB
Line 
1#ifdef CONFIG_WITH_INCLUDEDEP
2/* $Id: incdep.c 1797 2008-09-21 01:05:36Z bird $ */
3/** @file
4 * expreval - 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 <Windows.h>
65#endif
66
67#ifdef __OS2__
68# include <os2.h>
69# include <sys/fmutex.h>
70#endif
71
72#ifdef HAVE_PTHREAD
73# include <pthread.h>
74#endif
75
76
77/*******************************************************************************
78* Structures and Typedefs *
79*******************************************************************************/
80/* per dep file structure. */
81struct incdep
82{
83 struct incdep *next;
84 char *file_base;
85 char *file_end;
86 char name[1];
87};
88
89
90/*******************************************************************************
91* Internal Functions *
92*******************************************************************************/
93static void incdep_flush_it (struct floc *);
94
95
96/*******************************************************************************
97* Global Variables *
98*******************************************************************************/
99
100/* mutex protecting the globals and an associated condition/event. */
101#ifdef HAVE_PTHREAD
102static pthread_mutex_t incdep_mtx;
103static pthread_cond_t incdep_cond_todo;
104static pthread_cond_t incdep_cond_done;
105
106#elif defined (WINDOWS32)
107static CRITICAL_SECTION incdep_mtx;
108static HANDLE incdep_hev_todo;
109static HANDLE incdep_hev_done;
110static int volatile incdep_hev_todo_waiters;
111static int volatile incdep_hev_done_waiters;
112
113#elif defined (__OS2__)
114static fmutex incdep_mtx;
115static HEV incdep_hev_todo;
116static HEV incdep_hev_done;
117static int volatile incdep_hev_todo_waiters;
118static int volatile incdep_hev_done_waiters;
119#endif
120
121/* flag indicating whether the threads, lock and event/condvars has
122 been initialized or not. */
123static int incdep_initialized;
124
125/* the list of files that needs reading. */
126static struct incdep * volatile incdep_head_todo;
127static struct incdep * volatile incdep_tail_todo;
128
129/* the number of files that are currently being read. */
130static int volatile incdep_num_reading;
131
132/* the list of files that have been read. */
133static struct incdep * volatile incdep_head_done;
134static struct incdep * volatile incdep_tail_done;
135
136/* The handles to the worker threads. */
137#ifdef HAVE_PTHREAD
138static pthread_t incdep_threads[1];
139#elif defined (WINDOWS32)
140static HANDLE incdep_threads[1];
141#elif defined (__OS2__)
142static TID incdep_threads[1];
143#endif
144
145/* flag indicating whether the worker threads should terminate or not. */
146static int volatile incdep_terminate;
147
148
149
150
151/* acquires the lock */
152void
153incdep_lock(void)
154{
155#ifdef HAVE_PTHREAD
156 pthread_mutex_lock (&incdep_mtx);
157#elif defined (WINDOWS32)
158 EnterCriticalSection (&incdep_mtx);
159#elif defined (__OS2__)
160 _fmutex_request (&incdep_mtx, 0)
161#endif
162}
163
164/* releases the lock */
165void
166incdep_unlock(void)
167{
168#ifdef HAVE_PTHREAD
169 pthread_mutex_unlock (&incdep_mtx);
170#elif defined(WINDOWS32)
171 LeaveCriticalSection (&incdep_mtx);
172#elif defined(__OS2__)
173 _fmutex_release (&incdep_mtx)
174#endif
175}
176
177/* signals the main thread that there is stuff todo. caller owns the lock. */
178static void
179incdep_signal_done (void)
180{
181#ifdef HAVE_PTHREAD
182 pthread_cond_broadcast (&incdep_cond_done);
183#elif defined (WINDOWS32)
184 if (incdep_hev_done_waiters)
185 SetEvent (incdep_hev_done);
186#elif defined (__OS2__)
187 if (incdep_hev_done_waiters)
188 DosPostEventSem (incdep_hev_done);
189#endif
190}
191
192/* waits for a reader to finish reading. caller owns the lock. */
193static void
194incdep_wait_done (void)
195{
196#ifdef HAVE_PTHREAD
197 pthread_cond_wait (&incdep_cond_done, &incdep_mtx);
198
199#elif defined (WINDOWS32)
200 ResetEvent (incdep_hev_done);
201 incdep_hev_done_waiters++;
202 incdep_unlock ();
203 WaitForSingleObject (incdep_hev_done, INFINITE);
204 incdep_lock ();
205 incdep_hev_done_waiters--;
206
207#elif defined (__OS2__)
208 ULONG ulIgnore;
209 DosResetEventSem (incdep_hev_done, &ulIgnore);
210 incdep_hev_done_waiters++;
211 incdep_unlock ();
212 DosWaitEventSem (incdep_hev_done, SEM_INDEFINITE_WAIT);
213 incdep_lock ();
214 incdep_hev_done_waiters--;
215#endif
216}
217
218/* signals the worker threads. caller owns the lock. */
219static void
220incdep_signal_todo (void)
221{
222#ifdef HAVE_PTHREAD
223 pthread_cond_broadcast (&incdep_cond_todo);
224#elif defined(WINDOWS32)
225 if (incdep_hev_todo_waiters)
226 SetEvent (incdep_hev_todo);
227#elif defined(__OS2__)
228 if (incdep_hev_todo_waiters)
229 DosPostEventSem (incdep_hev_todo);
230#endif
231}
232
233/* waits for stuff to arrive in the todo list. caller owns the lock. */
234static void
235incdep_wait_todo (void)
236{
237#ifdef HAVE_PTHREAD
238 pthread_cond_wait (&incdep_cond_todo, &incdep_mtx);
239
240#elif defined (WINDOWS32)
241 ResetEvent (incdep_hev_todo);
242 incdep_hev_todo_waiters++;
243 incdep_unlock ();
244 WaitForSingleObject (incdep_hev_todo, INFINITE);
245 incdep_lock ();
246 incdep_hev_todo_waiters--;
247
248#elif defined (__OS2__)
249 ULONG ulIgnore;
250 DosResetEventSem (incdep_hev_todo, &ulIgnore);
251 incdep_hev_todo_waiters++;
252 incdep_unlock ();
253 DosWaitEventSem (incdep_hev_todo, SEM_INDEFINITE_WAIT);
254 incdep_lock ();
255 incdep_hev_todo_waiters--;
256#endif
257}
258
259/* Reads a dep file into memory. */
260static int
261incdep_read_file (struct incdep *cur, struct floc *f)
262{
263 int fd;
264 struct stat st;
265
266 errno = 0;
267#ifdef O_BINARY
268 fd = open (cur->name, O_RDONLY | O_BINARY, 0);
269#else
270 fd = open (cur->name, O_RDONLY, 0);
271#endif
272 if (fd < 0)
273 {
274 /* ignore non-existing dependency files. */
275 int err = errno;
276 if (err == ENOENT || stat (cur->name, &st) != 0)
277 return 1;
278 error (f, "%s: %s", cur->name, strerror (err));
279 return -1;
280 }
281 if (!fstat (fd, &st))
282 {
283 cur->file_base = xmalloc (st.st_size + 1);
284 if (read (fd, cur->file_base, st.st_size) == st.st_size)
285 {
286 close (fd);
287 cur->file_end = cur->file_base + st.st_size;
288 cur->file_base[st.st_size] = '\0';
289 return 0;
290 }
291
292 /* bail out */
293
294 error (f, "%s: read: %s", cur->name, strerror (errno));
295 free (cur->file_base);
296 }
297 else
298 error (f, "%s: fstat: %s", cur->name, strerror (errno));
299
300 close (fd);
301 cur->file_base = cur->file_end = NULL;
302 return -1;
303}
304
305/* A worker thread. */
306void
307incdep_worker (void)
308{
309 incdep_lock ();
310
311 while (!incdep_terminate)
312 {
313 /* get job from the todo list. */
314
315 struct incdep *cur = incdep_head_todo;
316 if (!cur)
317 {
318 incdep_wait_todo ();
319 continue;
320 }
321 if (cur->next)
322 incdep_head_todo = cur->next;
323 else
324 incdep_head_todo = incdep_tail_todo = NULL;
325 incdep_num_reading++;
326
327 /* read the file. */
328
329 incdep_unlock ();
330 incdep_read_file (cur, NILF);
331 incdep_lock ();
332
333 /* insert finished job into the done list. */
334
335 incdep_num_reading--;
336 cur->next = NULL;
337 if (incdep_tail_done)
338 incdep_tail_done->next = cur;
339 else
340 incdep_head_done = cur;
341 incdep_tail_done = cur;
342
343 incdep_signal_done ();
344 }
345
346 incdep_unlock ();
347}
348
349#ifdef HAVE_PTHREAD
350static void *
351incdep_worker_pthread (void *ignore)
352{
353 incdep_worker ();
354 (void)ignore;
355 return NULL;
356}
357
358#elif defined (WINDOWS32)
359static unsigned __stdcall
360incdep_worker_windows (void *ignore)
361{
362 incdep_worker ();
363 (void)ignore;
364 return 0;
365}
366
367#elif defined (__OS2__)
368static void
369incdep_worker_os2 (void *ignore)
370{
371 incdep_worker ();
372 (void)ignore;
373}
374#endif
375
376
377/* Creates the the worker threads. */
378static void
379incdep_init (struct floc *f)
380{
381 unsigned i;
382#ifdef HAVE_PTHREAD
383 int rc;
384 pthread_attr_t attr;
385
386#elif defined (WINDOWS32)
387 unsigned tid;
388 uintptr_t hThread;
389
390#elif defined (__OS2__)
391 int rc;
392 int tid;
393#endif
394
395 /* create the mutex and two condition variables / event objects. */
396
397#ifdef HAVE_PTHREAD
398 rc = pthread_mutex_init (&incdep_mtx, NULL);
399 if (rc)
400 fatal (f, _("pthread_mutex_init failed: err=%d"), rc);
401 rc = pthread_cond_init (&incdep_cond_todo, NULL);
402 if (rc)
403 fatal (f, _("pthread_cond_init failed: err=%d"), rc);
404 rc = pthread_cond_init (&incdep_cond_done, NULL);
405 if (rc)
406 fatal (f, _("pthread_cond_init failed: err=%d"), rc);
407
408#elif defined (WINDOWS32)
409 InitializeCriticalSection (&incdep_mtx);
410 incdep_hev_todo = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL);
411 if (!incdep_hev_todo)
412 fatal (f, _("CreateEvent failed: err=%d"), GetLastError());
413 incdep_hev_done = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL);
414 if (!incdep_hev_done)
415 fatal (f, _("CreateEvent failed: err=%d"), GetLastError());
416 incdep_hev_todo_waiters = 0;
417 incdep_hev_done_waiters = 0;
418
419#elif defined (__OS2__)
420 _fmutex_create (&incdep_mtx, 0)
421 rc = DosCreateEventSem (NULL, &incdep_hev_todo, 0, FALSE);
422 if (rc)
423 fatal (f, _("DosCreateEventSem failed: rc=%d"), rc);
424 rc = DosCreateEventSem (NULL, &incdep_hev_done, 0, FALSE);
425 if (rc)
426 fatal (f, _("DosCreateEventSem failed: rc=%d"), rc);
427 incdep_hev_todo_waiters = 0;
428 incdep_hev_done_waiters = 0;
429#endif
430
431 /* create the worker threads. */
432
433 incdep_terminate = 0;
434 for (i = 0; i < sizeof (incdep_threads) / sizeof (incdep_threads[0]); i++)
435 {
436#ifdef HAVE_PTHREAD
437 rc = pthread_attr_init (&attr);
438 if (rc)
439 fatal (f, _("pthread_attr_init failed: err=%d"), rc);
440 /*rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); */
441 rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
442 if (rc)
443 fatal (f, _("pthread_attr_setdetachstate failed: err=%d"), rc);
444 rc = pthread_create (&incdep_threads[i], &attr,
445 incdep_worker_pthread, f);
446 if (rc)
447 fatal (f, _("pthread_mutex_init failed: err=%d"), rc);
448 pthread_attr_destroy (&attr);
449
450#elif defined (WINDOWS32)
451 tid = 0;
452 hThread = _beginthreadex (NULL, 128*1024, incdep_worker_windows,
453 NULL, 0, &tid);
454 if (hThread != 0 && hThread != ~(uintptr_t)0)
455 fatal (f, _("_beginthreadex failed: err=%d"), errno);
456 incdep_threads[i] = (HANDLE)hThread;
457
458#elif defined (__OS2__)
459 tid = _beginthread (incdep_worker_os2, NULL, 128*1024, NULL);
460 if (tid <= 0)
461 fatal (f, _("_beginthread failed: err=%d"), errno);
462 incdep_threads[i] = tid;
463#endif
464 }
465
466 incdep_initialized = 1;
467}
468
469/* Flushes outstanding work and terminates the worker threads. */
470void
471incdep_flush_and_term (void)
472{
473 unsigned i;
474
475 if (!incdep_initialized)
476 return;
477
478 /* flush any out standing work */
479
480 incdep_flush_it (NILF);
481
482 /* tell the threads to terminate */
483
484 incdep_lock ();
485 incdep_terminate = 1;
486 incdep_signal_todo ();
487 incdep_unlock ();
488
489 /* wait for the threads to quit */
490
491 for (i = 0; i < sizeof (incdep_threads) / sizeof (incdep_threads[0]); i++)
492 {
493 /* later */
494 }
495
496 /* destroy the lock and condition variables / event objects. */
497
498 /* later */
499
500 incdep_initialized = 0;
501}
502
503/* no nonsense dependency file including.
504
505 Because nobody wants bogus dependency files to break their incremental
506 builds with hard to comprehend error messages, this function does not
507 use the normal eval routine but does all the parsing itself. This isn't,
508 as much work as it sounds, because the necessary feature set is very
509 limited.
510
511 eval_include_dep_file groks:
512
513 define var
514 endef
515
516 var [|:|?|>]= value [\]
517
518 [\]
519 file: [deps] [\]
520
521 */
522static void
523eval_include_dep_file (struct incdep *curdep, struct floc *f)
524{
525 unsigned line_no = 1;
526 const char *file_end = curdep->file_end;
527 const char *cur = curdep->file_base;
528 const char *endp;
529
530 /* if no file data, just return immediately. */
531 if (!cur)
532 {
533fprintf (stderr, "empty: %s\n", curdep->name);
534 free (curdep);
535 return;
536 }
537
538 /* now parse the file. */
539 while (cur < file_end)
540 {
541 /* skip empty lines */
542 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
543 ++cur;
544 if (cur >= file_end)
545 break;
546 if (*cur == '#')
547 {
548 cur = memchr (cur, '\n', file_end - cur);
549 if (!cur)
550 break;
551 }
552 if (*cur == '\\')
553 {
554 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
555 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
556 : (file_end - cur == 1) ? 1 : 0;
557 if (eol_len)
558 {
559 cur += eol_len;
560 line_no++;
561 continue;
562 }
563 }
564 if (*cur == '\n')
565 {
566 cur++;
567 line_no++;
568 continue;
569 }
570
571 /* define var
572 ...
573 endef */
574 if (strneq (cur, "define ", 7))
575 {
576 const char *var;
577 unsigned var_len;
578 const char *value_start;
579 const char *value_end;
580 char *value;
581 unsigned value_len;
582 int found_endef = 0;
583
584 /* extract the variable name. */
585 cur += 7;
586 while (isblank ((unsigned char)*cur))
587 ++cur;
588 value_start = endp = memchr (cur, '\n', file_end - cur);
589 if (!endp)
590 endp = cur;
591 while (endp > cur && isspace ((unsigned char)endp[-1]))
592 --endp;
593 var_len = endp - cur;
594 if (!var_len)
595 {
596 error (f, "%s(%d): bogus define statement.",
597 curdep->name, line_no);
598 break;
599 }
600 var = strcache_add_len (cur, var_len);
601
602 /* find the end of the variable. */
603 cur = value_end = value_start = value_start + 1;
604 ++line_no;
605 while (cur < file_end)
606 {
607 /* check for endef, don't bother with skipping leading spaces. */
608 if ( file_end - cur >= 5
609 && strneq (cur, "endef", 5))
610 {
611 endp = cur + 5;
612 while (endp < file_end && isspace ((unsigned char)*endp) && *endp != '\n')
613 endp++;
614 if (endp >= file_end || *endp == '\n')
615 {
616 found_endef = 1;
617 cur = endp >= file_end ? file_end : endp + 1;
618 break;
619 }
620 }
621
622 /* skip a line ahead. */
623 cur = value_end = memchr (cur, '\n', file_end - cur);
624 if (cur != NULL)
625 ++cur;
626 else
627 cur = value_end = file_end;
628 ++line_no;
629 }
630
631 if (!found_endef)
632 {
633 error (f, "%s(%d): missing endef, dropping the rest of the file.",
634 curdep->name, line_no);
635 break;
636 }
637 value_len = value_end - value_start;
638 if (memchr (value_start, '\0', value_len))
639 {
640 error (f, "%s(%d): '\\0' in define, dropping the rest of the file.",
641 curdep->name, line_no);
642 break;
643 }
644
645 /* make a copy of the value, converting \r\n to \n, and define it. */
646 value = xmalloc (value_len + 1);
647 endp = memchr (value_start, '\r', value_len);
648 if (endp)
649 {
650 const char *src = value_start;
651 char *dst = value;
652 for (;;)
653 {
654 size_t len = endp - src;
655 memcpy (dst, src, len);
656 dst += len;
657 src = endp;
658 if (src + 1 < file_end && src[1] == '\n')
659 src++; /* skip the '\r' */
660 if (src >= value_end)
661 break;
662 endp = memchr (endp + 1, '\r', src - value_end);
663 if (!endp)
664 endp = value_end;
665 }
666 value_len = dst - value;
667 }
668 else
669 memcpy (value, value_start, value_len);
670 value [value_len] = '\0';
671
672 define_variable_in_set (var, var_len, value, value_len,
673 0 /* don't duplicate */, o_file,
674 0 /* defines are recursive but this is faster */,
675 NULL /* global set */, f);
676 }
677
678 /* file: deps
679 OR
680 variable [:]= value */
681 else
682 {
683 const char *colonp;
684 const char *equalp;
685
686 /* Look for a colon and an equal sign, optimize for colon.
687 Only one file is support and the colon / equal must be on
688 the same line. */
689 colonp = memchr (cur, ':', file_end - cur);
690#ifdef HAVE_DOS_PATHS
691 while ( colonp
692 && colonp + 1 < file_end
693 && (colonp[1] == '/' || colonp[1] == '\\')
694 && colonp > cur
695 && isalpha ((unsigned char)colonp[-1])
696 && ( colonp == cur + 1
697 || strchr (" \t(", colonp[-2]) != 0))
698 colonp = memchr (colonp + 1, ':', file_end - (colonp + 1));
699#endif
700 endp = NULL;
701 if ( !colonp
702 || (endp = memchr (cur, '\n', colonp - cur)))
703 {
704 colonp = NULL;
705 equalp = memchr (cur, '=', (endp ? endp : file_end) - cur);
706 if ( !equalp
707 || (!endp && memchr (cur, '\n', equalp - cur)))
708 {
709 error (f, "%s(%d): no colon.",
710 curdep->name, line_no);
711 break;
712 }
713 }
714 else
715 equalp = memchr (cur, '=', (colonp + 2 <= file_end
716 ? colonp + 2 : file_end) - cur);
717 if (equalp)
718 {
719 /* An assignment of some sort. */
720 const char *var;
721 unsigned var_len;
722 const char *value_start;
723 const char *value_end;
724 char *value;
725 unsigned value_len;
726 unsigned multi_line = 0;
727 enum variable_flavor flavor;
728
729 /* figure the flavor first. */
730 flavor = f_recursive;
731 if (equalp > cur)
732 {
733 if (equalp[-1] == ':')
734 flavor = f_simple;
735 else if (equalp[-1] == '?')
736 flavor = f_conditional;
737 else if (equalp[-1] == '+')
738 flavor = f_append;
739 else if (equalp[-1] == '>')
740 flavor = f_prepend;
741 }
742
743 /* extract the variable name. */
744 endp = flavor == f_recursive ? equalp : equalp - 1;
745 while (endp > cur && isblank ((unsigned char)endp[-1]))
746 --endp;
747 var_len = endp - cur;
748 if (!var_len)
749 {
750 error (f, "%s(%d): empty variable. (includedep)",
751 curdep->name, line_no);
752 break;
753 }
754 if ( memchr (cur, '$', var_len)
755 || memchr (cur, ' ', var_len)
756 || memchr (cur, '\t', var_len))
757 {
758 error (f, "%s(%d): fancy variable name. (includedep)",
759 curdep->name, line_no);
760 break;
761 }
762 var = strcache_add_len (cur, var_len);
763
764 /* find the start of the value. */
765 cur = equalp + 1;
766 while (cur < file_end && isblank ((unsigned char)*cur))
767 cur++;
768 value_start = cur;
769
770 /* find the end of the value / line (this isn't 101% correct). */
771 value_end = cur;
772 while (cur < file_end)
773 {
774 endp = value_end = memchr (cur, '\n', file_end - cur);
775 if (!value_end)
776 value_end = file_end;
777 if (value_end - 1 >= cur && value_end[-1] == '\r')
778 --value_end;
779 if (value_end - 1 < cur || value_end[-1] != '\\')
780 {
781 cur = endp ? endp + 1 : file_end;
782 break;
783 }
784 --value_end;
785 if (value_end - 1 >= cur && value_end[-1] == '\\')
786 {
787 error (f, "%s(%d): fancy escaping! (includedep)",
788 curdep->name, line_no);
789 cur = NULL;
790 break;
791 }
792 if (!endp)
793 {
794 cur = file_end;
795 break;
796 }
797
798 cur = endp + 1;
799 ++multi_line;
800 ++line_no;
801 }
802 if (!cur)
803 break;
804 ++line_no;
805
806 /* make a copy of the value, converting \r\n to \n, and define it. */
807 value_len = value_end - value_start;
808 value = xmalloc (value_len + 1);
809 if (!multi_line)
810 memcpy (value, value_start, value_len);
811 else
812 {
813 /* unescape it */
814 const char *src = value_start;
815 char *dst = value;
816 while (src < value_end)
817 {
818 const char *nextp;
819
820 endp = memchr (src, '\n', value_end - src);
821 if (!endp)
822 nextp = endp = value_end;
823 else
824 nextp = endp + 1;
825 if (endp > src && endp[-1] == '\r')
826 --endp;
827 if (endp > src && endp[-1] == '\\')
828 --endp;
829
830 if (src != value_start)
831 *dst++ = ' ';
832 memcpy (dst, src, endp - src);
833 dst += endp - src;
834 src = nextp;
835 }
836 value_len = dst - value;
837 }
838 value [value_len] = '\0';
839
840 /* do the definition */
841 if (flavor == f_recursive
842 || ( flavor == f_simple
843 && !memchr (value, '$', value_len)))
844 define_variable_in_set (var, var_len, value, value_len,
845 0 /* don't duplicate */, o_file,
846 flavor == f_recursive /* recursive */,
847 NULL /* global set */, f);
848 else
849 {
850 do_variable_definition (f, var, value, o_file, flavor,
851 0 /* not target var */);
852 free (value);
853 }
854 }
855 else
856 {
857 /* file: dependencies */
858
859 struct nameseq *filenames = 0;
860 struct dep *deps = 0;
861 struct dep **nextdep = &deps;
862 struct dep *dep;
863/* int next_line = 1; */
864
865 /* extract the filename, ASSUME a single one. */
866 endp = colonp;
867 while (endp > cur && isblank ((unsigned char)endp[-1]))
868 --endp;
869 if (cur == endp)
870 {
871 error (f, "%s(%d): empty filename.",
872 curdep->name, line_no);
873 break;
874 }
875 if ( memchr (cur, '$', endp - cur)
876 || memchr (cur, ' ', endp - cur)
877 || memchr (cur, '\t', endp - cur))
878 {
879 error (f, "%s(%d): multiple / fancy file name. (includedep)",
880 curdep->name, line_no);
881 break;
882 }
883 filenames = xmalloc (sizeof (struct nameseq));
884 memset (filenames, 0, sizeof (*filenames));
885 filenames->name = strcache_add_len (cur, endp - cur);
886
887 /* parse any dependencies. */
888 cur = colonp + 1;
889 while (cur < file_end)
890 {
891 /* skip blanks and count lines. */
892 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
893 ++cur;
894 if (cur >= file_end)
895 break;
896 if (*cur == '\n')
897 {
898 cur++;
899 line_no++;
900 break;
901 }
902
903 /* continuation + eol? */
904 if (*cur == '\\')
905 {
906 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
907 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
908 : (file_end - cur == 1) ? 1 : 0;
909 if (eol_len)
910 {
911 cur += eol_len;
912 line_no++;
913 continue;
914 }
915 }
916
917 /* find the end of the filename */
918 endp = cur;
919 while (endp < file_end && !isspace ((unsigned char)*endp))
920 ++endp;
921
922 /* add it to the list. */
923 *nextdep = dep = alloc_dep ();
924 dep->name = strcache_add_len (cur, endp - cur);
925 nextdep = &dep->next;
926
927 cur = endp;
928 }
929
930 /* enter the file with its dependencies. */
931 record_files (filenames, NULL, NULL, deps, 0, NULL, 0, 0, f);
932 }
933 }
934 }
935
936 free (curdep->file_base);
937 free (curdep);
938}
939
940/* Flushes the incdep todo and done lists. */
941static void
942incdep_flush_it (struct floc *f)
943{
944 incdep_lock ();
945 for (;;)
946 {
947 struct incdep *cur = incdep_head_done;
948
949 /* if the done list is empty, grab a todo list entry. */
950 if (!cur && incdep_head_todo)
951 {
952 cur = incdep_head_todo;
953 if (cur->next)
954 incdep_head_todo = cur->next;
955 else
956 incdep_head_todo = incdep_tail_todo = NULL;
957 incdep_unlock ();
958
959 incdep_read_file (cur, f);
960 eval_include_dep_file (cur, f); /* eats cur */
961
962 incdep_lock ();
963 continue;
964 }
965
966 /* if the todo list and done list are empty we're either done
967 or will have to wait for the thread(s) to finish. */
968 if (!cur && !incdep_num_reading)
969 break; /* done */
970 if (!cur)
971 {
972 while (!incdep_head_done)
973 incdep_wait_done ();
974 cur = incdep_head_done;
975 }
976
977 /* we grab the entire done list and work thru it. */
978 incdep_head_done = incdep_tail_done = NULL;
979 incdep_unlock ();
980
981 while (cur)
982 {
983 struct incdep *next = cur->next;
984 eval_include_dep_file (cur, f); /* eats cur */
985 cur = next;
986 }
987
988 incdep_lock ();
989 } /* outer loop */
990 incdep_unlock ();
991}
992
993
994/* splits up a list of file names and feeds it to eval_include_dep_file,
995 employing threads to try speed up the file reading. */
996void
997eval_include_dep (const char *names, struct floc *f, enum incdep_op op)
998{
999 struct incdep *head = 0;
1000 struct incdep *tail = 0;
1001 struct incdep *cur;
1002 const char *names_iterator = names;
1003 const char *name;
1004 unsigned int name_len;
1005
1006 /* loop through NAMES, creating a todo list out of them. */
1007
1008 while ((name = find_next_token (&names_iterator, &name_len)) != 0)
1009 {
1010 cur = xmalloc (sizeof (*cur) + name_len);
1011 cur->file_base = cur->file_end = NULL;
1012 memcpy (cur->name, name, name_len);
1013 cur->name[name_len] = '\0';
1014
1015 cur->next = NULL;
1016 if (tail)
1017 tail->next = cur;
1018 else
1019 head = cur;
1020 tail = cur;
1021 }
1022
1023 if (op == incdep_read_it)
1024 {
1025 /* work our way thru the files directly */
1026
1027 cur = head;
1028 while (cur)
1029 {
1030 struct incdep *next = cur->next;
1031 incdep_read_file (cur, f);
1032 eval_include_dep_file (cur, f); /* eats cur */
1033 cur = next;
1034 }
1035 }
1036 else
1037 {
1038 /* initialize the worker threads and related stuff the first time around. */
1039
1040 if (!incdep_initialized)
1041 incdep_init (f);
1042
1043 /* queue the files and notify the worker threads. */
1044
1045 incdep_lock ();
1046
1047 if (incdep_tail_todo)
1048 incdep_tail_todo->next = head;
1049 else
1050 incdep_head_todo = head;
1051 incdep_tail_todo = tail;
1052
1053 incdep_signal_todo ();
1054 incdep_unlock ();
1055
1056 /* flush the todo queue if we're requested to do so. */
1057
1058 if (op == incdep_flush)
1059 incdep_flush_it (f);
1060 }
1061}
1062
1063#endif
1064
Note: See TracBrowser for help on using the repository browser.