source: trunk/src/kmk/output.c@ 3181

Last change on this file since 3181 was 3156, checked in by bird, 7 years ago

kmk/win: Reworking child process handling. This effort will hopefully handle processor groups better and allow executing internal function off the main thread.

  • Property svn:eol-style set to native
File size: 17.6 KB
Line 
1/* Output to stdout / stderr for GNU make
2Copyright (C) 2013-2016 Free Software Foundation, Inc.
3This file is part of GNU Make.
4
5GNU Make is free software; you can redistribute it and/or modify it under the
6terms of the GNU General Public License as published by the Free Software
7Foundation; either version 3 of the License, or (at your option) any later
8version.
9
10GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "makeint.h"
18#include "job.h"
19
20/* GNU make no longer supports pre-ANSI89 environments. */
21
22#include <assert.h>
23#include <stdio.h>
24#include <stdarg.h>
25
26#ifdef HAVE_UNISTD_H
27# include <unistd.h>
28#endif
29
30#ifdef HAVE_FCNTL_H
31# include <fcntl.h>
32#else
33# include <sys/file.h>
34#endif
35
36#ifdef WINDOWS32
37# include <windows.h>
38# include <io.h>
39# ifndef CONFIG_NEW_WIN_CHILDREN
40# include "sub_proc.h"
41# else
42# include "w32/winchildren.h"
43# endif
44#endif /* WINDOWS32 */
45
46struct output *output_context = NULL;
47unsigned int stdio_traced = 0;
48
49#define OUTPUT_NONE (-1)
50
51#define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0)
52
53#ifdef HAVE_FCNTL_H
54# define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
55#else
56# define STREAM_OK(_s) 1
57#endif
58
59/* Write a string to the current STDOUT or STDERR. */
60static void
61_outputs (struct output *out, int is_err, const char *msg)
62{
63 if (! out || ! out->syncout)
64 {
65 FILE *f = is_err ? stderr : stdout;
66#ifdef KBUILD_OS_WINDOWS
67 /** @todo check if fputs is also subject to char-by-char stupidity */
68 extern size_t maybe_con_fwrite(void const *, size_t, size_t, FILE *);
69 maybe_con_fwrite(msg, strlen(msg), 1, f);
70#else
71 fputs (msg, f);
72#endif
73 fflush (f);
74 }
75 else
76 {
77 int fd = is_err ? out->err : out->out;
78 int len = strlen (msg);
79 int r;
80
81 EINTRLOOP (r, lseek (fd, 0, SEEK_END));
82 while (1)
83 {
84 EINTRLOOP (r, write (fd, msg, len));
85 if (r == len || r <= 0)
86 break;
87 len -= r;
88 msg += r;
89 }
90 }
91}
92
93
94/* Write a message indicating that we've just entered or
95 left (according to ENTERING) the current directory. */
96
97static int
98log_working_directory (int entering)
99{
100 static char *buf = NULL;
101 static unsigned int len = 0;
102 unsigned int need;
103 const char *fmt;
104 char *p;
105
106 /* Get enough space for the longest possible output. */
107 need = strlen (program) + INTSTR_LENGTH + 2 + 1;
108 if (starting_directory)
109 need += strlen (starting_directory);
110
111 /* Use entire sentences to give the translators a fighting chance. */
112 if (makelevel == 0)
113 if (starting_directory == 0)
114 if (entering)
115 fmt = _("%s: Entering an unknown directory\n");
116 else
117 fmt = _("%s: Leaving an unknown directory\n");
118 else
119 if (entering)
120 fmt = _("%s: Entering directory '%s'\n");
121 else
122 fmt = _("%s: Leaving directory '%s'\n");
123 else
124 if (starting_directory == 0)
125 if (entering)
126 fmt = _("%s[%u]: Entering an unknown directory\n");
127 else
128 fmt = _("%s[%u]: Leaving an unknown directory\n");
129 else
130 if (entering)
131 fmt = _("%s[%u]: Entering directory '%s'\n");
132 else
133 fmt = _("%s[%u]: Leaving directory '%s'\n");
134
135 need += strlen (fmt);
136
137 if (need > len)
138 {
139 buf = xrealloc (buf, need);
140 len = need;
141 }
142
143 p = buf;
144 if (print_data_base_flag)
145 {
146 *(p++) = '#';
147 *(p++) = ' ';
148 }
149
150 if (makelevel == 0)
151 if (starting_directory == 0)
152 sprintf (p, fmt , program);
153 else
154 sprintf (p, fmt, program, starting_directory);
155 else if (starting_directory == 0)
156 sprintf (p, fmt, program, makelevel);
157 else
158 sprintf (p, fmt, program, makelevel, starting_directory);
159
160 _outputs (NULL, 0, buf);
161
162 return 1;
163}
164
165/* Set a file descriptor to be in O_APPEND mode.
166 If it fails, just ignore it. */
167
168static void
169set_append_mode (int fd)
170{
171#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
172 int flags = fcntl (fd, F_GETFL, 0);
173 if (flags >= 0)
174 fcntl (fd, F_SETFL, flags | O_APPEND);
175#endif
176}
177
178
179
180#ifndef NO_OUTPUT_SYNC
181
182/* Semaphore for use in -j mode with output_sync. */
183static sync_handle_t sync_handle = -1;
184
185#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
186
187/* Set up the sync handle. Disables output_sync on error. */
188static int
189sync_init (void)
190{
191 int combined_output = 0;
192
193#ifdef WINDOWS32
194 if ((!STREAM_OK (stdout) && !STREAM_OK (stderr))
195 || (sync_handle = create_mutex ()) == -1)
196 {
197 perror_with_name ("output-sync suppressed: ", "stderr");
198 output_sync = 0;
199 }
200 else
201 {
202 combined_output = same_stream (stdout, stderr);
203 prepare_mutex_handle_string (sync_handle);
204 }
205
206#else
207 if (STREAM_OK (stdout))
208 {
209 struct stat stbuf_o, stbuf_e;
210
211 sync_handle = fileno (stdout);
212 combined_output = (fstat (fileno (stdout), &stbuf_o) == 0
213 && fstat (fileno (stderr), &stbuf_e) == 0
214 && stbuf_o.st_dev == stbuf_e.st_dev
215 && stbuf_o.st_ino == stbuf_e.st_ino);
216 }
217 else if (STREAM_OK (stderr))
218 sync_handle = fileno (stderr);
219 else
220 {
221 perror_with_name ("output-sync suppressed: ", "stderr");
222 output_sync = 0;
223 }
224#endif
225
226 return combined_output;
227}
228
229/* Support routine for output_sync() */
230static void
231pump_from_tmp (int from, FILE *to)
232{
233 static char buffer[8192];
234
235#ifdef WINDOWS32
236 int prev_mode;
237
238 /* "from" is opened by open_tmpfd, which does it in binary mode, so
239 we need the mode of "to" to match that. */
240 prev_mode = _setmode (fileno (to), _O_BINARY);
241#endif
242
243 if (lseek (from, 0, SEEK_SET) == -1)
244 perror ("lseek()");
245
246 while (1)
247 {
248 int len;
249 EINTRLOOP (len, read (from, buffer, sizeof (buffer)));
250 if (len < 0)
251 perror ("read()");
252 if (len <= 0)
253 break;
254 if (fwrite (buffer, len, 1, to) < 1)
255 {
256 perror ("fwrite()");
257 break;
258 }
259 fflush (to);
260 }
261
262#ifdef WINDOWS32
263 /* Switch "to" back to its original mode, so that log messages by
264 Make have the same EOL format as without --output-sync. */
265 _setmode (fileno (to), prev_mode);
266#endif
267}
268
269/* Obtain the lock for writing output. */
270static void *
271acquire_semaphore (void)
272{
273 static struct flock fl;
274
275 fl.l_type = F_WRLCK;
276 fl.l_whence = SEEK_SET;
277 fl.l_start = 0;
278 fl.l_len = 1;
279 if (fcntl (sync_handle, F_SETLKW, &fl) != -1)
280 return &fl;
281 perror ("fcntl()");
282 return NULL;
283}
284
285/* Release the lock for writing output. */
286static void
287release_semaphore (void *sem)
288{
289 struct flock *flp = (struct flock *)sem;
290 flp->l_type = F_UNLCK;
291 if (fcntl (sync_handle, F_SETLKW, flp) == -1)
292 perror ("fcntl()");
293}
294
295/* Returns a file descriptor to a temporary file. The file is automatically
296 closed/deleted on exit. Don't use a FILE* stream. */
297int
298output_tmpfd (void)
299{
300 int fd = -1;
301 FILE *tfile = tmpfile ();
302
303 if (! tfile)
304 pfatal_with_name ("tmpfile");
305
306 /* Create a duplicate so we can close the stream. */
307 fd = dup (fileno (tfile));
308 if (fd < 0)
309 pfatal_with_name ("dup");
310
311 fclose (tfile);
312
313 set_append_mode (fd);
314
315 return fd;
316}
317
318/* Adds file descriptors to the child structure to support output_sync; one
319 for stdout and one for stderr as long as they are open. If stdout and
320 stderr share a device they can share a temp file too.
321 Will reset output_sync on error. */
322static void
323setup_tmpfile (struct output *out)
324{
325 /* Is make's stdout going to the same place as stderr? */
326 static int combined_output = -1;
327
328 if (combined_output < 0)
329 combined_output = sync_init ();
330
331 if (STREAM_OK (stdout))
332 {
333 int fd = output_tmpfd ();
334 if (fd < 0)
335 goto error;
336 CLOSE_ON_EXEC (fd);
337 out->out = fd;
338 }
339
340 if (STREAM_OK (stderr))
341 {
342 if (out->out != OUTPUT_NONE && combined_output)
343 out->err = out->out;
344 else
345 {
346 int fd = output_tmpfd ();
347 if (fd < 0)
348 goto error;
349 CLOSE_ON_EXEC (fd);
350 out->err = fd;
351 }
352 }
353
354 return;
355
356 /* If we failed to create a temp file, disable output sync going forward. */
357 error:
358 output_close (out);
359 output_sync = OUTPUT_SYNC_NONE;
360}
361
362/* Synchronize the output of jobs in -j mode to keep the results of
363 each job together. This is done by holding the results in temp files,
364 one for stdout and potentially another for stderr, and only releasing
365 them to "real" stdout/stderr when a semaphore can be obtained. */
366
367void
368output_dump (struct output *out)
369{
370 int outfd_not_empty = FD_NOT_EMPTY (out->out);
371 int errfd_not_empty = FD_NOT_EMPTY (out->err);
372
373 if (outfd_not_empty || errfd_not_empty)
374 {
375 int traced = 0;
376
377 /* Try to acquire the semaphore. If it fails, dump the output
378 unsynchronized; still better than silently discarding it.
379 We want to keep this lock for as little time as possible. */
380 void *sem = acquire_semaphore ();
381
382 /* Log the working directory for this dump. */
383 if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
384 traced = log_working_directory (1);
385
386 if (outfd_not_empty)
387 pump_from_tmp (out->out, stdout);
388 if (errfd_not_empty && out->err != out->out)
389 pump_from_tmp (out->err, stderr);
390
391 if (traced)
392 log_working_directory (0);
393
394 /* Exit the critical section. */
395 if (sem)
396 release_semaphore (sem);
397
398 /* Truncate and reset the output, in case we use it again. */
399 if (out->out != OUTPUT_NONE)
400 {
401 int e;
402 lseek (out->out, 0, SEEK_SET);
403 EINTRLOOP (e, ftruncate (out->out, 0));
404 }
405 if (out->err != OUTPUT_NONE && out->err != out->out)
406 {
407 int e;
408 lseek (out->err, 0, SEEK_SET);
409 EINTRLOOP (e, ftruncate (out->err, 0));
410 }
411 }
412}
413#endif /* NO_OUTPUT_SYNC */
414
415
416
417/* Provide support for temporary files. */
418
419#ifndef HAVE_STDLIB_H
420# ifdef HAVE_MKSTEMP
421int mkstemp (char *template);
422# else
423char *mktemp (char *template);
424# endif
425#endif
426
427FILE *
428output_tmpfile (char **name, const char *template)
429{
430#ifdef HAVE_FDOPEN
431 int fd;
432#endif
433
434#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
435# define TEMPLATE_LEN strlen (template)
436#else
437# define TEMPLATE_LEN L_tmpnam
438#endif
439 *name = xmalloc (TEMPLATE_LEN + 1);
440 strcpy (*name, template);
441
442#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
443 /* It's safest to use mkstemp(), if we can. */
444 fd = mkstemp (*name);
445 if (fd == -1)
446 return 0;
447 return fdopen (fd, "w");
448#else
449# ifdef HAVE_MKTEMP
450 (void) mktemp (*name);
451# else
452 (void) tmpnam (*name);
453# endif
454
455# ifdef HAVE_FDOPEN
456 /* Can't use mkstemp(), but guard against a race condition. */
457 EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600));
458 if (fd == -1)
459 return 0;
460 return fdopen (fd, "w");
461# else
462 /* Not secure, but what can we do? */
463 return fopen (*name, "w");
464# endif
465#endif
466}
467
468
469
470/* This code is stolen from gnulib.
471 If/when we abandon the requirement to work with K&R compilers, we can
472 remove this (and perhaps other parts of GNU make!) and migrate to using
473 gnulib directly.
474
475 This is called only through atexit(), which means die() has already been
476 invoked. So, call exit() here directly. Apparently that works...?
477*/
478
479/* Close standard output, exiting with status 'exit_failure' on failure.
480 If a program writes *anything* to stdout, that program should close
481 stdout and make sure that it succeeds before exiting. Otherwise,
482 suppose that you go to the extreme of checking the return status
483 of every function that does an explicit write to stdout. The last
484 printf can succeed in writing to the internal stream buffer, and yet
485 the fclose(stdout) could still fail (due e.g., to a disk full error)
486 when it tries to write out that buffered data. Thus, you would be
487 left with an incomplete output file and the offending program would
488 exit successfully. Even calling fflush is not always sufficient,
489 since some file systems (NFS and CODA) buffer written/flushed data
490 until an actual close call.
491
492 Besides, it's wasteful to check the return value from every call
493 that writes to stdout -- just let the internal stream state record
494 the failure. That's what the ferror test is checking below.
495
496 It's important to detect such failures and exit nonzero because many
497 tools (most notably 'make' and other build-management systems) depend
498 on being able to detect failure in other tools via their exit status. */
499
500static void
501close_stdout (void)
502{
503 int prev_fail = ferror (stdout);
504 int fclose_fail = fclose (stdout);
505
506 if (prev_fail || fclose_fail)
507 {
508 if (fclose_fail)
509 perror_with_name (_("write error: stdout"), "");
510 else
511 O (error, NILF, _("write error: stdout"));
512 exit (MAKE_TROUBLE);
513 }
514}
515
516
517
518void
519output_init (struct output *out)
520{
521 if (out)
522 {
523 out->out = out->err = OUTPUT_NONE;
524 out->syncout = !!output_sync;
525 return;
526 }
527
528 /* Configure this instance of make. Be sure stdout is line-buffered. */
529
530#ifdef HAVE_SETVBUF
531# ifdef SETVBUF_REVERSED
532 setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
533# else /* setvbuf not reversed. */
534 /* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
535 setvbuf (stdout, 0, _IOLBF, BUFSIZ);
536# endif /* setvbuf reversed. */
537#elif HAVE_SETLINEBUF
538 setlinebuf (stdout);
539#endif /* setlinebuf missing. */
540
541 /* Force stdout/stderr into append mode. This ensures parallel jobs won't
542 lose output due to overlapping writes. */
543 set_append_mode (fileno (stdout));
544 set_append_mode (fileno (stderr));
545
546#ifdef HAVE_ATEXIT
547 if (STREAM_OK (stdout))
548 atexit (close_stdout);
549#endif
550}
551
552void
553output_close (struct output *out)
554{
555 if (! out)
556 {
557 if (stdio_traced)
558 log_working_directory (0);
559 return;
560 }
561
562#ifndef NO_OUTPUT_SYNC
563 output_dump (out);
564#endif
565
566 if (out->out >= 0)
567 close (out->out);
568 if (out->err >= 0 && out->err != out->out)
569 close (out->err);
570
571 output_init (out);
572}
573
574/* We're about to generate output: be sure it's set up. */
575void
576output_start (void)
577{
578#ifndef NO_OUTPUT_SYNC
579 /* If we're syncing output make sure the temporary file is set up. */
580 if (output_context && output_context->syncout)
581 if (! OUTPUT_ISSET(output_context))
582 setup_tmpfile (output_context);
583#endif
584
585 /* If we're not syncing this output per-line or per-target, make sure we emit
586 the "Entering..." message where appropriate. */
587 if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
588 if (! stdio_traced && print_directory_flag)
589 stdio_traced = log_working_directory (1);
590}
591
592void
593outputs (int is_err, const char *msg)
594{
595 if (! msg || *msg == '\0')
596 return;
597
598 output_start ();
599
600 _outputs (output_context, is_err, msg);
601}
602
603
604
605static struct fmtstring
606 {
607 char *buffer;
608 size_t size;
609 } fmtbuf = { NULL, 0 };
610
611static char *
612get_buffer (size_t need)
613{
614 /* Make sure we have room. NEED includes space for \0. */
615 if (need > fmtbuf.size)
616 {
617 fmtbuf.size += need * 2;
618 fmtbuf.buffer = xrealloc (fmtbuf.buffer, fmtbuf.size);
619 }
620
621 fmtbuf.buffer[need-1] = '\0';
622
623 return fmtbuf.buffer;
624}
625
626/* Print a message on stdout. */
627
628void
629message (int prefix, size_t len, const char *fmt, ...)
630{
631 va_list args;
632 char *p;
633
634 len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1;
635 p = get_buffer (len);
636
637 if (prefix)
638 {
639 if (makelevel == 0)
640 sprintf (p, "%s: ", program);
641 else
642 sprintf (p, "%s[%u]: ", program, makelevel);
643 p += strlen (p);
644 }
645
646 va_start (args, fmt);
647 vsprintf (p, fmt, args);
648 va_end (args);
649
650 strcat (p, "\n");
651
652 assert (fmtbuf.buffer[len-1] == '\0');
653 outputs (0, fmtbuf.buffer);
654}
655
656/* Print an error message. */
657
658void
659error (const floc *flocp, size_t len, const char *fmt, ...)
660{
661 va_list args;
662 char *p;
663
664 len += (strlen (fmt) + strlen (program)
665 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
666 + INTSTR_LENGTH + 4 + 1 + 1);
667 p = get_buffer (len);
668
669 if (flocp && flocp->filenm)
670 sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset);
671 else if (makelevel == 0)
672 sprintf (p, "%s: ", program);
673 else
674 sprintf (p, "%s[%u]: ", program, makelevel);
675 p += strlen (p);
676
677 va_start (args, fmt);
678 vsprintf (p, fmt, args);
679 va_end (args);
680
681 strcat (p, "\n");
682
683 assert (fmtbuf.buffer[len-1] == '\0');
684 outputs (1, fmtbuf.buffer);
685}
686
687/* Print an error message and exit. */
688
689void
690fatal (const floc *flocp, size_t len, const char *fmt, ...)
691{
692 va_list args;
693 const char *stop = _(". Stop.\n");
694 char *p;
695
696 len += (strlen (fmt) + strlen (program)
697 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
698 + INTSTR_LENGTH + 8 + strlen (stop) + 1);
699 p = get_buffer (len);
700
701 if (flocp && flocp->filenm)
702 sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset);
703 else if (makelevel == 0)
704 sprintf (p, "%s: *** ", program);
705 else
706 sprintf (p, "%s[%u]: *** ", program, makelevel);
707 p += strlen (p);
708
709 va_start (args, fmt);
710 vsprintf (p, fmt, args);
711 va_end (args);
712
713 strcat (p, stop);
714
715 assert (fmtbuf.buffer[len-1] == '\0');
716 outputs (1, fmtbuf.buffer);
717
718 die (MAKE_FAILURE);
719}
720
721/* Print an error message from errno. */
722
723void
724perror_with_name (const char *str, const char *name)
725{
726 const char *err = strerror (errno);
727 OSSS (error, NILF, _("%s%s: %s"), str, name, err);
728}
729
730/* Print an error message from errno and exit. */
731
732void
733pfatal_with_name (const char *name)
734{
735 const char *err = strerror (errno);
736 OSS (fatal, NILF, _("%s: %s"), name, err);
737
738 /* NOTREACHED */
739}
Note: See TracBrowser for help on using the repository browser.