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

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

incdep: make thread count relative to the job slots.

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