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

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

kmk: minor incdep adjustments.

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