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

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

incdep: weeny strcache_add_len optimization.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 30.3 KB
Line 
1#ifdef CONFIG_WITH_INCLUDEDEP
2/* $Id: incdep.c 1800 2008-09-21 01:43:59Z 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/* A quick wrapper around strcache_add_len which avoid the unnecessary
504 copying of the string in order to terminate it. The incdep buffer is
505 always writable, but the eval function like to use const char to avoid
506 silly mistakes and encourage compiler optimizations. */
507static char *
508incdep_strcache_add_len (const char *str, int len)
509{
510#if 1
511 char *ret;
512 char ch = str[len];
513 ((char *)str)[len] = '\0';
514 ret = strcache_add_len (str, len);
515 ((char *)str)[len] = ch;
516 return ret;
517#else
518 return strcache_add_len (str, len);
519#endif
520}
521
522/* no nonsense dependency file including.
523
524 Because nobody wants bogus dependency files to break their incremental
525 builds with hard to comprehend error messages, this function does not
526 use the normal eval routine but does all the parsing itself. This isn't,
527 as much work as it sounds, because the necessary feature set is very
528 limited.
529
530 eval_include_dep_file groks:
531
532 define var
533 endef
534
535 var [|:|?|>]= value [\]
536
537 [\]
538 file: [deps] [\]
539
540 */
541static void
542eval_include_dep_file (struct incdep *curdep, struct floc *f)
543{
544 unsigned line_no = 1;
545 const char *file_end = curdep->file_end;
546 const char *cur = curdep->file_base;
547 const char *endp;
548
549 /* if no file data, just return immediately. */
550 if (!cur)
551 {
552 free (curdep);
553 return;
554 }
555
556 /* now parse the file. */
557 while (cur < file_end)
558 {
559 /* skip empty lines */
560 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
561 ++cur;
562 if (cur >= file_end)
563 break;
564 if (*cur == '#')
565 {
566 cur = memchr (cur, '\n', file_end - cur);
567 if (!cur)
568 break;
569 }
570 if (*cur == '\\')
571 {
572 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
573 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
574 : (file_end - cur == 1) ? 1 : 0;
575 if (eol_len)
576 {
577 cur += eol_len;
578 line_no++;
579 continue;
580 }
581 }
582 if (*cur == '\n')
583 {
584 cur++;
585 line_no++;
586 continue;
587 }
588
589 /* define var
590 ...
591 endef */
592 if (strneq (cur, "define ", 7))
593 {
594 const char *var;
595 unsigned var_len;
596 const char *value_start;
597 const char *value_end;
598 char *value;
599 unsigned value_len;
600 int found_endef = 0;
601
602 /* extract the variable name. */
603 cur += 7;
604 while (isblank ((unsigned char)*cur))
605 ++cur;
606 value_start = endp = memchr (cur, '\n', file_end - cur);
607 if (!endp)
608 endp = cur;
609 while (endp > cur && isspace ((unsigned char)endp[-1]))
610 --endp;
611 var_len = endp - cur;
612 if (!var_len)
613 {
614 error (f, "%s(%d): bogus define statement.",
615 curdep->name, line_no);
616 break;
617 }
618 var = incdep_strcache_add_len (cur, var_len);
619
620 /* find the end of the variable. */
621 cur = value_end = value_start = value_start + 1;
622 ++line_no;
623 while (cur < file_end)
624 {
625 /* check for endef, don't bother with skipping leading spaces. */
626 if ( file_end - cur >= 5
627 && strneq (cur, "endef", 5))
628 {
629 endp = cur + 5;
630 while (endp < file_end && isspace ((unsigned char)*endp) && *endp != '\n')
631 endp++;
632 if (endp >= file_end || *endp == '\n')
633 {
634 found_endef = 1;
635 cur = endp >= file_end ? file_end : endp + 1;
636 break;
637 }
638 }
639
640 /* skip a line ahead. */
641 cur = value_end = memchr (cur, '\n', file_end - cur);
642 if (cur != NULL)
643 ++cur;
644 else
645 cur = value_end = file_end;
646 ++line_no;
647 }
648
649 if (!found_endef)
650 {
651 error (f, "%s(%d): missing endef, dropping the rest of the file.",
652 curdep->name, line_no);
653 break;
654 }
655 value_len = value_end - value_start;
656 if (memchr (value_start, '\0', value_len))
657 {
658 error (f, "%s(%d): '\\0' in define, dropping the rest of the file.",
659 curdep->name, line_no);
660 break;
661 }
662
663 /* make a copy of the value, converting \r\n to \n, and define it. */
664 value = xmalloc (value_len + 1);
665 endp = memchr (value_start, '\r', value_len);
666 if (endp)
667 {
668 const char *src = value_start;
669 char *dst = value;
670 for (;;)
671 {
672 size_t len = endp - src;
673 memcpy (dst, src, len);
674 dst += len;
675 src = endp;
676 if (src + 1 < file_end && src[1] == '\n')
677 src++; /* skip the '\r' */
678 if (src >= value_end)
679 break;
680 endp = memchr (endp + 1, '\r', src - value_end);
681 if (!endp)
682 endp = value_end;
683 }
684 value_len = dst - value;
685 }
686 else
687 memcpy (value, value_start, value_len);
688 value [value_len] = '\0';
689
690 define_variable_in_set (var, var_len, value, value_len,
691 0 /* don't duplicate */, o_file,
692 0 /* defines are recursive but this is faster */,
693 NULL /* global set */, f);
694 }
695
696 /* file: deps
697 OR
698 variable [:]= value */
699 else
700 {
701 const char *colonp;
702 const char *equalp;
703
704 /* Look for a colon and an equal sign, optimize for colon.
705 Only one file is support and the colon / equal must be on
706 the same line. */
707 colonp = memchr (cur, ':', file_end - cur);
708#ifdef HAVE_DOS_PATHS
709 while ( colonp
710 && colonp + 1 < file_end
711 && (colonp[1] == '/' || colonp[1] == '\\')
712 && colonp > cur
713 && isalpha ((unsigned char)colonp[-1])
714 && ( colonp == cur + 1
715 || strchr (" \t(", colonp[-2]) != 0))
716 colonp = memchr (colonp + 1, ':', file_end - (colonp + 1));
717#endif
718 endp = NULL;
719 if ( !colonp
720 || (endp = memchr (cur, '\n', colonp - cur)))
721 {
722 colonp = NULL;
723 equalp = memchr (cur, '=', (endp ? endp : file_end) - cur);
724 if ( !equalp
725 || (!endp && memchr (cur, '\n', equalp - cur)))
726 {
727 error (f, "%s(%d): no colon.",
728 curdep->name, line_no);
729 break;
730 }
731 }
732 else
733 equalp = memchr (cur, '=', (colonp + 2 <= file_end
734 ? colonp + 2 : file_end) - cur);
735 if (equalp)
736 {
737 /* An assignment of some sort. */
738 const char *var;
739 unsigned var_len;
740 const char *value_start;
741 const char *value_end;
742 char *value;
743 unsigned value_len;
744 unsigned multi_line = 0;
745 enum variable_flavor flavor;
746
747 /* figure the flavor first. */
748 flavor = f_recursive;
749 if (equalp > cur)
750 {
751 if (equalp[-1] == ':')
752 flavor = f_simple;
753 else if (equalp[-1] == '?')
754 flavor = f_conditional;
755 else if (equalp[-1] == '+')
756 flavor = f_append;
757 else if (equalp[-1] == '>')
758 flavor = f_prepend;
759 }
760
761 /* extract the variable name. */
762 endp = flavor == f_recursive ? equalp : equalp - 1;
763 while (endp > cur && isblank ((unsigned char)endp[-1]))
764 --endp;
765 var_len = endp - cur;
766 if (!var_len)
767 {
768 error (f, "%s(%d): empty variable. (includedep)",
769 curdep->name, line_no);
770 break;
771 }
772 if ( memchr (cur, '$', var_len)
773 || memchr (cur, ' ', var_len)
774 || memchr (cur, '\t', var_len))
775 {
776 error (f, "%s(%d): fancy variable name. (includedep)",
777 curdep->name, line_no);
778 break;
779 }
780 var = incdep_strcache_add_len (cur, var_len);
781
782 /* find the start of the value. */
783 cur = equalp + 1;
784 while (cur < file_end && isblank ((unsigned char)*cur))
785 cur++;
786 value_start = cur;
787
788 /* find the end of the value / line (this isn't 101% correct). */
789 value_end = cur;
790 while (cur < file_end)
791 {
792 endp = value_end = memchr (cur, '\n', file_end - cur);
793 if (!value_end)
794 value_end = file_end;
795 if (value_end - 1 >= cur && value_end[-1] == '\r')
796 --value_end;
797 if (value_end - 1 < cur || value_end[-1] != '\\')
798 {
799 cur = endp ? endp + 1 : file_end;
800 break;
801 }
802 --value_end;
803 if (value_end - 1 >= cur && value_end[-1] == '\\')
804 {
805 error (f, "%s(%d): fancy escaping! (includedep)",
806 curdep->name, line_no);
807 cur = NULL;
808 break;
809 }
810 if (!endp)
811 {
812 cur = file_end;
813 break;
814 }
815
816 cur = endp + 1;
817 ++multi_line;
818 ++line_no;
819 }
820 if (!cur)
821 break;
822 ++line_no;
823
824 /* make a copy of the value, converting \r\n to \n, and define it. */
825 value_len = value_end - value_start;
826 value = xmalloc (value_len + 1);
827 if (!multi_line)
828 memcpy (value, value_start, value_len);
829 else
830 {
831 /* unescape it */
832 const char *src = value_start;
833 char *dst = value;
834 while (src < value_end)
835 {
836 const char *nextp;
837
838 endp = memchr (src, '\n', value_end - src);
839 if (!endp)
840 nextp = endp = value_end;
841 else
842 nextp = endp + 1;
843 if (endp > src && endp[-1] == '\r')
844 --endp;
845 if (endp > src && endp[-1] == '\\')
846 --endp;
847
848 if (src != value_start)
849 *dst++ = ' ';
850 memcpy (dst, src, endp - src);
851 dst += endp - src;
852 src = nextp;
853 }
854 value_len = dst - value;
855 }
856 value [value_len] = '\0';
857
858 /* do the definition */
859 if (flavor == f_recursive
860 || ( flavor == f_simple
861 && !memchr (value, '$', value_len)))
862 define_variable_in_set (var, var_len, value, value_len,
863 0 /* don't duplicate */, o_file,
864 flavor == f_recursive /* recursive */,
865 NULL /* global set */, f);
866 else
867 {
868 do_variable_definition (f, var, value, o_file, flavor,
869 0 /* not target var */);
870 free (value);
871 }
872 }
873 else
874 {
875 /* file: dependencies */
876
877 struct nameseq *filenames = 0;
878 struct dep *deps = 0;
879 struct dep **nextdep = &deps;
880 struct dep *dep;
881/* int next_line = 1; */
882
883 /* extract the filename, ASSUME a single one. */
884 endp = colonp;
885 while (endp > cur && isblank ((unsigned char)endp[-1]))
886 --endp;
887 if (cur == endp)
888 {
889 error (f, "%s(%d): empty filename.",
890 curdep->name, line_no);
891 break;
892 }
893 if ( memchr (cur, '$', endp - cur)
894 || memchr (cur, ' ', endp - cur)
895 || memchr (cur, '\t', endp - cur))
896 {
897 error (f, "%s(%d): multiple / fancy file name. (includedep)",
898 curdep->name, line_no);
899 break;
900 }
901 filenames = xmalloc (sizeof (struct nameseq));
902 memset (filenames, 0, sizeof (*filenames));
903 filenames->name = incdep_strcache_add_len (cur, endp - cur);
904
905 /* parse any dependencies. */
906 cur = colonp + 1;
907 while (cur < file_end)
908 {
909 /* skip blanks and count lines. */
910 while (cur < file_end && isspace ((unsigned char)*cur) && *cur != '\n')
911 ++cur;
912 if (cur >= file_end)
913 break;
914 if (*cur == '\n')
915 {
916 cur++;
917 line_no++;
918 break;
919 }
920
921 /* continuation + eol? */
922 if (*cur == '\\')
923 {
924 unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2
925 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3
926 : (file_end - cur == 1) ? 1 : 0;
927 if (eol_len)
928 {
929 cur += eol_len;
930 line_no++;
931 continue;
932 }
933 }
934
935 /* find the end of the filename */
936 endp = cur;
937 while (endp < file_end && !isspace ((unsigned char)*endp))
938 ++endp;
939
940 /* add it to the list. */
941 *nextdep = dep = alloc_dep ();
942 dep->name = incdep_strcache_add_len (cur, endp - cur);
943 nextdep = &dep->next;
944
945 cur = endp;
946 }
947
948 /* enter the file with its dependencies. */
949 record_files (filenames, NULL, NULL, deps, 0, NULL, 0, 0, f);
950 }
951 }
952 }
953
954 free (curdep->file_base);
955 free (curdep);
956}
957
958/* Flushes the incdep todo and done lists. */
959static void
960incdep_flush_it (struct floc *f)
961{
962 incdep_lock ();
963 for (;;)
964 {
965 struct incdep *cur = incdep_head_done;
966
967 /* if the done list is empty, grab a todo list entry. */
968 if (!cur && incdep_head_todo)
969 {
970 cur = incdep_head_todo;
971 if (cur->next)
972 incdep_head_todo = cur->next;
973 else
974 incdep_head_todo = incdep_tail_todo = NULL;
975 incdep_unlock ();
976
977 incdep_read_file (cur, f);
978 eval_include_dep_file (cur, f); /* eats cur */
979
980 incdep_lock ();
981 continue;
982 }
983
984 /* if the todo list and done list are empty we're either done
985 or will have to wait for the thread(s) to finish. */
986 if (!cur && !incdep_num_reading)
987 break; /* done */
988 if (!cur)
989 {
990 while (!incdep_head_done)
991 incdep_wait_done ();
992 cur = incdep_head_done;
993 }
994
995 /* we grab the entire done list and work thru it. */
996 incdep_head_done = incdep_tail_done = NULL;
997 incdep_unlock ();
998
999 while (cur)
1000 {
1001 struct incdep *next = cur->next;
1002 eval_include_dep_file (cur, f); /* eats cur */
1003 cur = next;
1004 }
1005
1006 incdep_lock ();
1007 } /* outer loop */
1008 incdep_unlock ();
1009}
1010
1011
1012/* splits up a list of file names and feeds it to eval_include_dep_file,
1013 employing threads to try speed up the file reading. */
1014void
1015eval_include_dep (const char *names, struct floc *f, enum incdep_op op)
1016{
1017 struct incdep *head = 0;
1018 struct incdep *tail = 0;
1019 struct incdep *cur;
1020 const char *names_iterator = names;
1021 const char *name;
1022 unsigned int name_len;
1023
1024 /* loop through NAMES, creating a todo list out of them. */
1025
1026 while ((name = find_next_token (&names_iterator, &name_len)) != 0)
1027 {
1028 cur = xmalloc (sizeof (*cur) + name_len);
1029 cur->file_base = cur->file_end = NULL;
1030 memcpy (cur->name, name, name_len);
1031 cur->name[name_len] = '\0';
1032
1033 cur->next = NULL;
1034 if (tail)
1035 tail->next = cur;
1036 else
1037 head = cur;
1038 tail = cur;
1039 }
1040
1041 if (op == incdep_read_it)
1042 {
1043 /* work our way thru the files directly */
1044
1045 cur = head;
1046 while (cur)
1047 {
1048 struct incdep *next = cur->next;
1049 incdep_read_file (cur, f);
1050 eval_include_dep_file (cur, f); /* eats cur */
1051 cur = next;
1052 }
1053 }
1054 else
1055 {
1056 /* initialize the worker threads and related stuff the first time around. */
1057
1058 if (!incdep_initialized)
1059 incdep_init (f);
1060
1061 /* queue the files and notify the worker threads. */
1062
1063 incdep_lock ();
1064
1065 if (incdep_tail_todo)
1066 incdep_tail_todo->next = head;
1067 else
1068 incdep_head_todo = head;
1069 incdep_tail_todo = tail;
1070
1071 incdep_signal_todo ();
1072 incdep_unlock ();
1073
1074 /* flush the todo queue if we're requested to do so. */
1075
1076 if (op == incdep_flush)
1077 incdep_flush_it (f);
1078 }
1079}
1080
1081#endif /* CONFIG_WITH_INCLUDEDEP */
1082
Note: See TracBrowser for help on using the repository browser.