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

Last change on this file since 3667 was 3666, checked in by bird, 5 months ago

kmk: More debugging code for the mysterious 'kmk: write error: stdout' problem...

  • Property svn:eol-style set to native
File size: 39.9 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#ifdef KBUILD_OS_WINDOWS
46# include "console.h"
47#endif
48
49struct output *output_context = NULL;
50unsigned int stdio_traced = 0;
51
52#define OUTPUT_NONE (-1)
53
54#define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0)
55
56#ifdef HAVE_FCNTL_H
57# define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
58#else
59# define STREAM_OK(_s) 1
60#endif
61
62#ifdef DEBUG_STDOUT_CLOSE_ISSUE
63/* fflush wrapper w/ error checking + reporting for stdout.
64 This is to debug the mysterious 'kmk: write error: stdout' errors. */
65int g_fStdOutError = 0;
66
67static void my_stdout_error (const char *pszOperation, const char *pszMessage)
68{
69# ifdef KBUILD_OS_WINDOWS
70 DWORD const dwErr = GetLastError ();
71# endif
72 int const iErrNo = errno;
73 int const fdFile = fileno (stdout);
74# ifdef KBUILD_OS_WINDOWS
75 HANDLE const hNative = (HANDLE)_get_osfhandle (_fileno (stdout));
76 DWORD const dwType = GetFileType (hNative);
77 fprintf (stderr, "kmk[%u]: %s: %s! (lasterr=%u errno=%d fileno=%d native=%p type=%#x)\n",
78 makelevel, pszOperation, pszMessage, dwErr, iErrNo, fdFile, hNative, dwType);
79# else
80 fprintf (stderr, "kmk[%u]: %s: %s! (lasterr=%u errno=%d fileno=%d)\n",
81 makelevel, pszOperation, pszMessage, dwErr, iErrNo, fdFile);
82# endif
83}
84
85static int my_fflush (FILE *pFile)
86{
87 if (pFile == stdout && !g_fStdOutError)
88 {
89 if (!ferror (pFile))
90 {
91 int rcRet = fflush (pFile);
92 g_fStdOutError = ferror (pFile);
93 if (rcRet != EOF && !g_fStdOutError)
94 { /* likely */ }
95 else if (rcRet == EOF)
96 my_stdout_error ("fflush(stdout)", "flush failed!");
97 else
98 my_stdout_error ("fflush(stdout)", "error pending after successful flush!");
99
100 return rcRet;
101 }
102 else
103 {
104 my_stdout_error ("fflush(stdout)", "error pending on entry!");
105 g_fStdOutError = 1;
106 }
107
108 }
109 return fflush (pFile);
110}
111
112# undef fflush
113# define fflush(a_pFile) my_fflush(a_pFile)
114
115/* Preserves errno and win32 last error. */
116void my_check_stdout (const char *pszWhere)
117{
118 if (!g_fStdOutError)
119 {
120# ifdef KBUILD_OS_WINDOWS
121 DWORD const dwErrSaved = GetLastError();
122# endif
123 int const iErrNoSaved = errno;
124
125 if (ferror (stdout))
126 {
127 my_stdout_error (pszWhere, "error pending!");
128 g_fStdOutError = 1;
129 }
130
131 errno = iErrNoSaved;
132# ifdef KBUILD_OS_WINDOWS
133 SetLastError(dwErrSaved);
134# endif
135 }
136}
137
138#endif /* DEBUG_STDOUT_CLOSE_ISSUE */
139
140
141#if defined(KMK) && !defined(NO_OUTPUT_SYNC)
142/* Non-negative if we're counting output lines.
143
144 This is used by die_with_job_output to decide whether the initial build
145 error needs to be repeated because there was too much output from parallel
146 jobs between it and the actual make termination. */
147int output_metered = -1;
148
149static void meter_output_block (char const *buffer, size_t len)
150{
151 while (len > 0)
152 {
153 char *nl = (char *)memchr (buffer, '\n', len);
154 size_t linelen;
155 if (nl)
156 {
157 linelen = nl - buffer + 1;
158 output_metered++;
159 }
160 else
161 linelen = len;
162 output_metered += linelen / 132;
163
164 /* advance */
165 buffer += linelen;
166 len -= linelen;
167 }
168}
169#endif
170
171
172#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
173# define MEMBUF_MIN_SEG_SIZE 4096
174# define MEMBUF_MAX_SEG_SIZE (512*1024)
175# define MEMBUF_MAX_MOVE_LEN ( MEMBUF_MIN_SEG_SIZE \
176 - offsetof (struct output_segment, runs) \
177 - sizeof (struct output_run))
178# define MEMBUF_MAX_TOTAL ( sizeof (void *) <= 4 \
179 ? (size_t)512*1024 : (size_t)16*1024*1024 )
180
181static void *acquire_semaphore (void);
182static void release_semaphore (void *);
183static int log_working_directory (int);
184
185/* Is make's stdout going to the same place as stderr?
186 Also, did we already sync_init (== -1)? */
187static int combined_output = -1;
188
189/* Helper for membuf_reset and output_reset */
190static membuf_reset (struct output *out)
191{
192 struct output_segment *seg;
193 while ((seg = out->out.head_seg))
194 {
195 out->out.head_seg = seg->next;
196 free (seg);
197 }
198 out->out.tail_seg = NULL;
199 out->out.tail_run = NULL;
200 out->out.head_run = NULL;
201 out->out.left = 0;
202 out->out.total = 0;
203
204 while ((seg = out->err.head_seg))
205 {
206 out->err.head_seg = seg->next;
207 free (seg);
208 }
209 out->err.tail_seg = NULL;
210 out->err.tail_run = NULL;
211 out->err.head_run = NULL;
212 out->err.left = 0;
213 out->err.total = 0;
214
215 out->seqno = 0;
216}
217
218/* Used by die_with_job_output to suppress output when it shouldn't be repeated. */
219void output_reset (struct output *out)
220{
221 if (out && (out->out.total || out->err.total))
222 membuf_reset (out);
223}
224
225/* Internal worker for output_dump and membuf_dump_most. */
226static void membuf_dump (struct output *out)
227{
228 if (out->out.total || out->err.total)
229 {
230 int traced = 0;
231 struct output_run *err_run;
232 struct output_run *out_run;
233 FILE *prevdst;
234
235 /* Try to acquire the semaphore. If it fails, dump the output
236 unsynchronized; still better than silently discarding it.
237 We want to keep this lock for as little time as possible. */
238 void *sem = acquire_semaphore ();
239# if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS)
240 int prev_mode_out = _setmode (fileno (stdout), _O_BINARY);
241 int prev_mode_err = _setmode (fileno (stderr), _O_BINARY);
242# endif
243
244# ifndef KMK /* this drives me bananas. */
245 /* Log the working directory for this dump. */
246 if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
247 traced = log_working_directory (1);
248# endif
249
250 /* Work the out and err sequences in parallel. */
251 out_run = out->out.head_run;
252 err_run = out->err.head_run;
253 prevdst = NULL;
254 while (err_run || out_run)
255 {
256 FILE *dst;
257 const void *src;
258 size_t len;
259 if (out_run && (!err_run || out_run->seqno <= err_run->seqno))
260 {
261 src = out_run + 1;
262 len = out_run->len;
263 dst = stdout;
264 out_run = out_run->next;
265 }
266 else
267 {
268 src = err_run + 1;
269 len = err_run->len;
270 dst = stderr;
271 err_run = err_run->next;
272 }
273 if (dst != prevdst)
274 fflush (prevdst);
275 prevdst = dst;
276#ifdef KMK
277 if (output_metered < 0)
278 { /* likely */ }
279 else
280 meter_output_block (src, len);
281#endif
282# if 0 /* for debugging */
283 while (len > 0)
284 {
285 const char *nl = (const char *)memchr (src, '\n', len);
286 size_t line_len = nl ? nl - (const char *)src + 1 : len;
287 char *tmp = (char *)xmalloc (1 + line_len + 1 + 1);
288 tmp[0] = '{';
289 memcpy (&tmp[1], src, line_len);
290 tmp[1 + line_len] = '}';
291# ifdef KBUILD_OS_WINDOWS
292 maybe_con_fwrite (tmp, 1 + line_len + 1, 1, dst);
293# else
294 fwrite (tmp, 1 + line_len + 1, 1, dst);
295# endif
296 free (tmp);
297 src = (const char *)src + line_len;
298 len -= line_len;
299 }
300#else
301# ifdef KBUILD_OS_WINDOWS
302 maybe_con_fwrite (src, len, 1, dst);
303# else
304 fwrite (src, len, 1, dst);
305# endif
306# endif
307 }
308 if (prevdst)
309 fflush (prevdst);
310
311# ifndef KMK /* this drives me bananas. */
312 if (traced)
313 log_working_directory (0);
314# endif
315
316 /* Exit the critical section. */
317# if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS)
318 if (prev_mode_out != -1)
319 _setmode (fileno (stdout), prev_mode_out);
320 if (prev_mode_err != -1)
321 _setmode (fileno (stderr), prev_mode_err);
322# endif
323 if (sem)
324 release_semaphore (sem);
325
326# ifdef KMK
327 if (!out->dont_truncate)
328 { /* likely */ }
329 else return;
330# endif
331
332 /* Free the segments and reset the state. */
333 membuf_reset (out);
334 }
335 else
336 assert (out->out.head_seg == NULL && out->err.head_seg == NULL);
337}
338
339/* Writes up to LEN bytes to the given segment.
340 Returns how much was actually written. */
341static size_t
342membuf_write_segment (struct output_membuf *membuf, struct output_segment *seg,
343 const char *src, size_t len, unsigned int *pseqno)
344{
345 size_t written = 0;
346 if (seg && membuf->left > 0)
347 {
348 struct output_run *run = membuf->tail_run;
349 char *dst = (char *)(run + 1) + run->len;
350 assert ((uintptr_t)run - (uintptr_t)seg < seg->size);
351
352 /* If the sequence number didn't change, then we can append
353 to the current run without further considerations. */
354 if (run->seqno == *pseqno)
355 written = len;
356 /* If the current run does not end with a newline, don't start a new
357 run till we encounter one. */
358 else if (dst[-1] != '\n')
359 {
360 char const *srcnl = (const char *)memchr (src, '\n', len);
361 written = srcnl ? srcnl - src + 1 : len;
362 }
363 /* Try create a new empty run and append to it. */
364 else
365 {
366 size_t const offnextrun = ( (uintptr_t)dst - (uintptr_t)(seg)
367 + sizeof(void *) - 1)
368 & ~(sizeof(void *) - 1);
369 if (offnextrun > seg->size - sizeof (struct output_run) * 2)
370 return 0; /* need new segment */
371
372 run = run->next = (struct output_run *)((char *)seg + offnextrun);
373 run->next = NULL;
374 run->seqno = ++(*pseqno);
375 run->len = 0;
376 membuf->tail_run = run;
377 membuf->left = seg->size - (offnextrun + sizeof (*run));
378 dst = (char *)(run + 1);
379 written = len;
380 }
381
382 /* Append to the current run. */
383 if (written > membuf->left)
384 written = membuf->left;
385 memcpy (dst, src, written);
386 run->len += written;
387 membuf->left -= written;
388 }
389 return written;
390}
391
392/* Helper for membuf_write_new_segment and membuf_dump_most that figures out
393 now much data needs to be moved from the previous run in order to make it
394 end with a newline. */
395static size_t membuf_calc_move_len (struct output_run *tail_run)
396{
397 size_t to_move = 0;
398 if (tail_run)
399 {
400 const char *data = (const char *)(tail_run + 1);
401 size_t off = tail_run->len;
402 while (off > 0 && data[off - 1] != '\n')
403 off--;
404 to_move = tail_run->len - off;
405 if (to_move >= MEMBUF_MAX_MOVE_LEN)
406 to_move = 0;
407 }
408 return to_move;
409}
410
411/* Allocates a new segment and writes to it.
412 This will take care to make sure the previous run terminates with
413 a newline so that we pass whole lines to fwrite when dumping. */
414static size_t
415membuf_write_new_segment (struct output_membuf *membuf, const char *src,
416 size_t len, unsigned int *pseqno)
417{
418 struct output_run *prev_run = membuf->tail_run;
419 struct output_segment *prev_seg = membuf->tail_seg;
420 size_t const to_move = membuf_calc_move_len (prev_run);
421 struct output_segment *new_seg;
422 size_t written;
423 char *dst;
424
425 /* Figure the the segment size. We start with MEMBUF_MIN_SEG_SIZE and double
426 it each time till we reach MEMBUF_MAX_SEG_SIZE. */
427 size_t const offset_runs = offsetof (struct output_segment, runs);
428 size_t segsize = !prev_seg ? MEMBUF_MIN_SEG_SIZE
429 : prev_seg->size >= MEMBUF_MAX_SEG_SIZE ? MEMBUF_MAX_SEG_SIZE
430 : prev_seg->size * 2;
431 while ( segsize < to_move + len + offset_runs + sizeof (struct output_run) * 2
432 && segsize < MEMBUF_MAX_SEG_SIZE)
433 segsize *= 2;
434
435 /* Allocate the segment and link it and the first run. */
436 new_seg = (struct output_segment *)xmalloc (segsize);
437 new_seg->size = segsize;
438 new_seg->next = NULL;
439 new_seg->runs[0].next = NULL;
440 if (!prev_seg)
441 {
442 membuf->head_seg = new_seg;
443 membuf->head_run = &new_seg->runs[0];
444 }
445 else
446 {
447 prev_seg->next = new_seg;
448 prev_run->next = &new_seg->runs[0];
449 }
450 membuf->tail_seg = new_seg;
451 membuf->tail_run = &new_seg->runs[0];
452 membuf->total += segsize;
453 membuf->left = segsize - sizeof (struct output_run) - offset_runs;
454
455 /* Initialize and write data to the first run. */
456 dst = (char *)&new_seg->runs[0]; /* Try bypass gcc array size cleverness. */
457 dst += sizeof (struct output_run);
458 assert (MEMBUF_MAX_MOVE_LEN < MEMBUF_MIN_SEG_SIZE);
459 if (to_move > 0)
460 {
461 /* Move to_move bytes from the previous run in hope that we'll get a
462 newline to soon. Afterwards call membuf_segment_write to work SRC. */
463 assert (prev_run != NULL);
464 assert (membuf->left >= to_move);
465 prev_run->len -= to_move;
466 new_seg->runs[0].len = to_move;
467 new_seg->runs[0].seqno = prev_run->seqno;
468 memcpy (dst, (const char *)(prev_run + 1) + prev_run->len, to_move);
469 membuf->left -= to_move;
470
471 written = membuf_write_segment (membuf, new_seg, src, len, pseqno);
472 }
473 else
474 {
475 /* Create a run with up to LEN from SRC. */
476 written = len;
477 if (written > membuf->left)
478 written = membuf->left;
479 new_seg->runs[0].len = written;
480 new_seg->runs[0].seqno = ++(*pseqno);
481 memcpy (dst, src, written);
482 membuf->left -= written;
483 }
484 return written;
485}
486
487/* Worker for output_write that will dump most of the output when we hit
488 MEMBUF_MAX_TOTAL on either of the two membuf structures, then free all the
489 output segments. Incomplete lines will be held over to the next buffers
490 and copied into new segments. */
491static void
492membuf_dump_most (struct output *out)
493{
494 size_t out_to_move = membuf_calc_move_len (out->out.tail_run);
495 size_t err_to_move = membuf_calc_move_len (out->err.tail_run);
496 if (!out_to_move && !err_to_move)
497 membuf_dump (out);
498 else
499 {
500 /* Allocate a stack buffer for holding incomplete lines. This should be
501 fine since we're only talking about max 2 * MEMBUF_MAX_MOVE_LEN.
502 The -1 on the sequence numbers, ise because membuf_write_new_segment
503 will increment them before use. */
504 unsigned int out_seqno = out_to_move ? out->out.tail_run->seqno - 1 : 0;
505 unsigned int err_seqno = err_to_move ? out->err.tail_run->seqno - 1 : 0;
506 char *tmp = alloca (out_to_move + err_to_move);
507 if (out_to_move)
508 {
509 out->out.tail_run->len -= out_to_move;
510 memcpy (tmp,
511 (char *)(out->out.tail_run + 1) + out->out.tail_run->len,
512 out_to_move);
513 }
514 if (err_to_move)
515 {
516 out->err.tail_run->len -= err_to_move;
517 memcpy (tmp + out_to_move,
518 (char *)(out->err.tail_run + 1) + out->err.tail_run->len,
519 err_to_move);
520 }
521
522 membuf_dump (out);
523
524 if (out_to_move)
525 {
526 size_t written = membuf_write_new_segment (&out->out, tmp,
527 out_to_move, &out_seqno);
528 assert (written == out_to_move); (void)written;
529 }
530 if (err_to_move)
531 {
532 size_t written = membuf_write_new_segment (&out->err,
533 tmp + out_to_move,
534 err_to_move, &err_seqno);
535 assert (written == err_to_move); (void)written;
536 }
537 }
538}
539
540
541
542/* write/fwrite like function, binary mode. */
543ssize_t
544output_write_bin (struct output *out, int is_err, const char *src, size_t len)
545{
546 size_t ret = len;
547 if (!out || !out->syncout)
548 {
549 FILE *f = is_err ? stderr : stdout;
550# if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS)
551 /* On DOS platforms we need to disable \n -> \r\n converts that is common on
552 standard output/error. Also optimize for console output. */
553 int saved_errno;
554 int fd = fileno (f);
555 int prev_mode = _setmode (fd, _O_BINARY);
556 maybe_con_fwrite (src, len, 1, f);
557 if (fflush (f) == EOF)
558 ret = -1;
559 saved_errno = errno;
560 _setmode (fd, prev_mode);
561 errno = saved_errno;
562# else
563 fwrite (src, len, 1, f);
564 if (fflush (f) == EOF)
565 ret = -1;
566# endif
567 }
568 else
569 {
570 struct output_membuf *membuf = is_err ? &out->err : &out->out;
571 while (len > 0)
572 {
573 size_t runlen = membuf_write_segment (membuf, membuf->tail_seg, src, len, &out->seqno);
574 if (!runlen)
575 {
576 if (membuf->total < MEMBUF_MAX_TOTAL)
577 runlen = membuf_write_new_segment (membuf, src, len, &out->seqno);
578 else
579 membuf_dump_most (out);
580 }
581 /* advance */
582 len -= runlen;
583 src += runlen;
584 }
585 }
586 return ret;
587}
588
589#endif /* CONFIG_WITH_OUTPUT_IN_MEMORY */
590
591/* write/fwrite like function, text mode. */
592ssize_t
593output_write_text (struct output *out, int is_err, const char *src, size_t len)
594{
595#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
596# if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS)
597 ssize_t ret = len;
598 if (!out || !out->syncout)
599 {
600 /* ASSUME fwrite does the desired conversion. */
601 FILE *f = is_err ? stderr : stdout;
602# ifdef KBUILD_OS_WINDOWS
603 if (maybe_con_fwrite (src, len, 1, f) < 0)
604 ret = -1;
605# else
606 fwrite (src, len, 1, f);
607# endif
608 if (fflush (f) == EOF)
609 ret = -1;
610 }
611 else
612 {
613 /* Work the buffer line by line, replacing each \n with \r\n. */
614 while (len > 0)
615 {
616 const char *nl = memchr (src, '\n', len);
617 size_t line_len = nl ? nl - src : len;
618 output_write_bin (out, is_err, src, line_len);
619 if (!nl)
620 break;
621 output_write_bin (out, is_err, "\r\n", 2);
622 len -= line_len + 1;
623 src += line_len + 1;
624 }
625 }
626 return ret;
627# else
628 return output_write_bin (out, is_err, src, len);
629# endif
630#else
631 ssize_t ret = len;
632 if (! out || ! out->syncout)
633 {
634 FILE *f = is_err ? stderr : stdout;
635# ifdef KBUILD_OS_WINDOWS
636 maybe_con_fwrite(src, len, 1, f);
637# else
638 fwrite (src, len, 1, f);
639# endif
640 fflush (f);
641 }
642 else
643 {
644 int fd = is_err ? out->err : out->out;
645 int r;
646
647 EINTRLOOP (r, lseek (fd, 0, SEEK_END));
648 while (1)
649 {
650 EINTRLOOP (r, write (fd, src, len));
651 if ((size_t)r == len || r <= 0)
652 break;
653 len -= r;
654 src += r;
655 }
656 }
657 return ret;
658#endif
659}
660
661
662
663/* Write a string to the current STDOUT or STDERR. */
664static void
665_outputs (struct output *out, int is_err, const char *msg)
666{
667#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
668 output_write_text (out, is_err, msg, strlen (msg));
669#else /* !CONFIG_WITH_OUTPUT_IN_MEMORY */
670 if (! out || ! out->syncout)
671 {
672 FILE *f = is_err ? stderr : stdout;
673# ifdef KBUILD_OS_WINDOWS
674 maybe_con_fwrite(msg, strlen(msg), 1, f);
675# else
676 fputs (msg, f);
677# endif
678 fflush (f);
679 }
680 else
681 {
682 int fd = is_err ? out->err : out->out;
683 int len = strlen (msg);
684 int r;
685
686 EINTRLOOP (r, lseek (fd, 0, SEEK_END));
687 while (1)
688 {
689 EINTRLOOP (r, write (fd, msg, len));
690 if (r == len || r <= 0)
691 break;
692 len -= r;
693 msg += r;
694 }
695 }
696#endif /* !CONFIG_WITH_OUTPUT_IN_MEMORY */
697}
698
699
700/* Write a message indicating that we've just entered or
701 left (according to ENTERING) the current directory. */
702
703static int
704log_working_directory (int entering)
705{
706 static char *buf = NULL;
707 static unsigned int len = 0;
708 unsigned int need;
709 const char *fmt;
710 char *p;
711
712 /* Get enough space for the longest possible output. */
713 need = strlen (program) + INTSTR_LENGTH + 2 + 1;
714 if (starting_directory)
715 need += strlen (starting_directory);
716
717 /* Use entire sentences to give the translators a fighting chance. */
718 if (makelevel == 0)
719 if (starting_directory == 0)
720 if (entering)
721 fmt = _("%s: Entering an unknown directory\n");
722 else
723 fmt = _("%s: Leaving an unknown directory\n");
724 else
725 if (entering)
726 fmt = _("%s: Entering directory '%s'\n");
727 else
728 fmt = _("%s: Leaving directory '%s'\n");
729 else
730 if (starting_directory == 0)
731 if (entering)
732 fmt = _("%s[%u]: Entering an unknown directory\n");
733 else
734 fmt = _("%s[%u]: Leaving an unknown directory\n");
735 else
736 if (entering)
737 fmt = _("%s[%u]: Entering directory '%s'\n");
738 else
739 fmt = _("%s[%u]: Leaving directory '%s'\n");
740
741 need += strlen (fmt);
742
743 if (need > len)
744 {
745 buf = xrealloc (buf, need);
746 len = need;
747 }
748
749 p = buf;
750 if (print_data_base_flag)
751 {
752 *(p++) = '#';
753 *(p++) = ' ';
754 }
755
756 if (makelevel == 0)
757 if (starting_directory == 0)
758 sprintf (p, fmt , program);
759 else
760 sprintf (p, fmt, program, starting_directory);
761 else if (starting_directory == 0)
762 sprintf (p, fmt, program, makelevel);
763 else
764 sprintf (p, fmt, program, makelevel, starting_directory);
765
766 _outputs (NULL, 0, buf);
767
768 return 1;
769}
770
771/* Set a file descriptor to be in O_APPEND mode.
772 If it fails, just ignore it. */
773
774static void
775set_append_mode (int fd)
776{
777#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
778 int flags = fcntl (fd, F_GETFL, 0);
779 if (flags >= 0)
780 fcntl (fd, F_SETFL, flags | O_APPEND);
781#endif
782}
783
784
785
786#ifndef NO_OUTPUT_SYNC
787
788/* Semaphore for use in -j mode with output_sync. */
789static sync_handle_t sync_handle = -1;
790
791#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
792
793/* Set up the sync handle. Disables output_sync on error. */
794static int
795sync_init (void)
796{
797 int combined_output = 0;
798
799#ifdef WINDOWS32
800# ifdef CONFIG_NEW_WIN_CHILDREN
801 if (STREAM_OK (stdout))
802 {
803 if (STREAM_OK (stderr))
804 {
805 char mtxname[256];
806 sync_handle = create_mutex (mtxname, sizeof (mtxname));
807 if (sync_handle != -1)
808 {
809 prepare_mutex_handle_string (mtxname);
810 return same_stream (stdout, stderr);
811 }
812 perror_with_name ("output-sync suppressed: ", "create_mutex");
813 }
814 else
815 perror_with_name ("output-sync suppressed: ", "stderr");
816 }
817 else
818 perror_with_name ("output-sync suppressed: ", "stdout");
819 output_sync = OUTPUT_SYNC_NONE;
820
821# else /* !CONFIG_NEW_WIN_CHILDREN */
822 if ((!STREAM_OK (stdout) && !STREAM_OK (stderr))
823 || (sync_handle = create_mutex ()) == -1)
824 {
825 perror_with_name ("output-sync suppressed: ", "stderr");
826 output_sync = 0;
827 }
828 else
829 {
830 combined_output = same_stream (stdout, stderr);
831 prepare_mutex_handle_string (sync_handle);
832 }
833# endif /* !CONFIG_NEW_WIN_CHILDREN */
834
835#else
836 if (STREAM_OK (stdout))
837 {
838 struct stat stbuf_o, stbuf_e;
839
840 sync_handle = fileno (stdout);
841 combined_output = (fstat (fileno (stdout), &stbuf_o) == 0
842 && fstat (fileno (stderr), &stbuf_e) == 0
843 && stbuf_o.st_dev == stbuf_e.st_dev
844 && stbuf_o.st_ino == stbuf_e.st_ino);
845 }
846 else if (STREAM_OK (stderr))
847 sync_handle = fileno (stderr);
848 else
849 {
850 perror_with_name ("output-sync suppressed: ", "stderr");
851 output_sync = 0;
852 }
853#endif
854
855 return combined_output;
856}
857
858#ifndef CONFIG_WITH_OUTPUT_IN_MEMORY
859/* Support routine for output_sync() */
860static void
861pump_from_tmp (int from, FILE *to)
862{
863# ifdef KMK
864 char buffer[8192];
865# else
866 static char buffer[8192];
867#endif
868
869# if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS)
870 int prev_mode;
871
872 /* "from" is opened by open_tmpfd, which does it in binary mode, so
873 we need the mode of "to" to match that. */
874 prev_mode = _setmode (fileno (to), O_BINARY);
875#endif
876
877 if (lseek (from, 0, SEEK_SET) == -1)
878 perror ("lseek()");
879
880 while (1)
881 {
882 int len;
883 EINTRLOOP (len, read (from, buffer, sizeof (buffer)));
884 if (len < 0)
885 perror ("read()");
886 if (len <= 0)
887 break;
888#ifdef KMK
889 if (output_metered < 0)
890 { /* likely */ }
891 else
892 meter_output_block (buffer, len);
893#endif
894 if (fwrite (buffer, len, 1, to) < 1)
895 {
896 perror ("fwrite()");
897 break;
898 }
899 fflush (to);
900 }
901
902# if defined (KBUILD_OS_WINDOWS) || defined (KBUILD_OS_OS2) || defined (KBUILD_OS_DOS)
903 /* Switch "to" back to its original mode, so that log messages by
904 Make have the same EOL format as without --output-sync. */
905 _setmode (fileno (to), prev_mode);
906#endif
907}
908#endif /* CONFIG_WITH_OUTPUT_IN_MEMORY */
909
910/* Obtain the lock for writing output. */
911static void *
912acquire_semaphore (void)
913{
914 static struct flock fl;
915
916 fl.l_type = F_WRLCK;
917 fl.l_whence = SEEK_SET;
918 fl.l_start = 0;
919 fl.l_len = 1;
920 if (fcntl (sync_handle, F_SETLKW, &fl) != -1)
921 return &fl;
922#ifdef KBUILD_OS_DARWIN /* F_SETLKW isn't supported on pipes */
923 if (errno != EBADF)
924#endif
925 perror ("fcntl()");
926 return NULL;
927}
928
929/* Release the lock for writing output. */
930static void
931release_semaphore (void *sem)
932{
933 struct flock *flp = (struct flock *)sem;
934 flp->l_type = F_UNLCK;
935 if (fcntl (sync_handle, F_SETLKW, flp) == -1)
936 perror ("fcntl()");
937}
938
939#ifndef CONFIG_WITH_OUTPUT_IN_MEMORY
940
941/* Returns a file descriptor to a temporary file. The file is automatically
942 closed/deleted on exit. Don't use a FILE* stream. */
943int
944output_tmpfd (void)
945{
946 int fd = -1;
947 FILE *tfile = tmpfile ();
948
949 if (! tfile)
950 {
951#ifdef KMK
952 if (output_context && output_context->syncout)
953 output_context->syncout = 0; /* Avoid inifinit recursion. */
954#endif
955 pfatal_with_name ("tmpfile");
956 }
957
958 /* Create a duplicate so we can close the stream. */
959 fd = dup (fileno (tfile));
960 if (fd < 0)
961 {
962#ifdef KMK
963 if (output_context && output_context->syncout)
964 output_context->syncout = 0; /* Avoid inifinit recursion. */
965#endif
966 pfatal_with_name ("dup");
967 }
968
969 fclose (tfile);
970
971 set_append_mode (fd);
972
973 return fd;
974}
975
976/* Adds file descriptors to the child structure to support output_sync; one
977 for stdout and one for stderr as long as they are open. If stdout and
978 stderr share a device they can share a temp file too.
979 Will reset output_sync on error. */
980static void
981setup_tmpfile (struct output *out)
982{
983 /* Is make's stdout going to the same place as stderr? */
984 static int combined_output = -1;
985
986 if (combined_output < 0)
987 {
988#ifdef KMK /* prevent infinite recursion if sync_init() calls perror_with_name. */
989 combined_output = 0;
990#endif
991 combined_output = sync_init ();
992 }
993
994 if (STREAM_OK (stdout))
995 {
996 int fd = output_tmpfd ();
997 if (fd < 0)
998 goto error;
999 CLOSE_ON_EXEC (fd);
1000 out->out = fd;
1001 }
1002
1003 if (STREAM_OK (stderr))
1004 {
1005 if (out->out != OUTPUT_NONE && combined_output)
1006 out->err = out->out;
1007 else
1008 {
1009 int fd = output_tmpfd ();
1010 if (fd < 0)
1011 goto error;
1012 CLOSE_ON_EXEC (fd);
1013 out->err = fd;
1014 }
1015 }
1016
1017 return;
1018
1019 /* If we failed to create a temp file, disable output sync going forward. */
1020 error:
1021 output_close (out);
1022 output_sync = OUTPUT_SYNC_NONE;
1023}
1024
1025#endif /* !CONFIG_WITH_OUTPUT_IN_MEMORY */
1026
1027/* Synchronize the output of jobs in -j mode to keep the results of
1028 each job together. This is done by holding the results in temp files,
1029 one for stdout and potentially another for stderr, and only releasing
1030 them to "real" stdout/stderr when a semaphore can be obtained. */
1031
1032void
1033output_dump (struct output *out)
1034{
1035#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
1036 membuf_dump (out);
1037#else
1038 int outfd_not_empty = FD_NOT_EMPTY (out->out);
1039 int errfd_not_empty = FD_NOT_EMPTY (out->err);
1040
1041 if (outfd_not_empty || errfd_not_empty)
1042 {
1043# ifndef KMK /* this drives me bananas. */
1044 int traced = 0;
1045# endif
1046
1047 /* Try to acquire the semaphore. If it fails, dump the output
1048 unsynchronized; still better than silently discarding it.
1049 We want to keep this lock for as little time as possible. */
1050 void *sem = acquire_semaphore ();
1051
1052# ifndef KMK /* this drives me bananas. */
1053 /* Log the working directory for this dump. */
1054 if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
1055 traced = log_working_directory (1);
1056# endif
1057
1058 if (outfd_not_empty)
1059 pump_from_tmp (out->out, stdout);
1060 if (errfd_not_empty && out->err != out->out)
1061 pump_from_tmp (out->err, stderr);
1062
1063# ifndef KMK /* this drives me bananas. */
1064 if (traced)
1065 log_working_directory (0);
1066# endif
1067
1068 /* Exit the critical section. */
1069 if (sem)
1070 release_semaphore (sem);
1071
1072# ifdef KMK
1073 if (!out->dont_truncate)
1074 { /* likely */ }
1075 else return;
1076# endif
1077 /* Truncate and reset the output, in case we use it again. */
1078 if (out->out != OUTPUT_NONE)
1079 {
1080 int e;
1081 lseek (out->out, 0, SEEK_SET);
1082 EINTRLOOP (e, ftruncate (out->out, 0));
1083 }
1084 if (out->err != OUTPUT_NONE && out->err != out->out)
1085 {
1086 int e;
1087 lseek (out->err, 0, SEEK_SET);
1088 EINTRLOOP (e, ftruncate (out->err, 0));
1089 }
1090 }
1091#endif
1092}
1093
1094# if defined(KMK) && !defined(CONFIG_WITH_OUTPUT_IN_MEMORY)
1095/* Used by die_with_job_output to suppress output when it shouldn't be repeated. */
1096void output_reset (struct output *out)
1097{
1098 if (out)
1099 {
1100 if (out->out != OUTPUT_NONE)
1101 {
1102 int e;
1103 lseek (out->out, 0, SEEK_SET);
1104 EINTRLOOP (e, ftruncate (out->out, 0));
1105 }
1106 if (out->err != OUTPUT_NONE && out->err != out->out)
1107 {
1108 int e;
1109 lseek (out->err, 0, SEEK_SET);
1110 EINTRLOOP (e, ftruncate (out->err, 0));
1111 }
1112 }
1113}
1114# endif
1115#endif /* NO_OUTPUT_SYNC */
1116
1117
1118
1119/* Provide support for temporary files. */
1120
1121#ifndef HAVE_STDLIB_H
1122# ifdef HAVE_MKSTEMP
1123int mkstemp (char *template);
1124# else
1125char *mktemp (char *template);
1126# endif
1127#endif
1128
1129FILE *
1130output_tmpfile (char **name, const char *template)
1131{
1132#ifdef HAVE_FDOPEN
1133 int fd;
1134#endif
1135
1136#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
1137# define TEMPLATE_LEN strlen (template)
1138#else
1139# define TEMPLATE_LEN L_tmpnam
1140#endif
1141 *name = xmalloc (TEMPLATE_LEN + 1);
1142 strcpy (*name, template);
1143
1144#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
1145 /* It's safest to use mkstemp(), if we can. */
1146 fd = mkstemp (*name);
1147 if (fd == -1)
1148 return 0;
1149 return fdopen (fd, "w");
1150#else
1151# ifdef HAVE_MKTEMP
1152 (void) mktemp (*name);
1153# else
1154 (void) tmpnam (*name);
1155# endif
1156
1157# ifdef HAVE_FDOPEN
1158 /* Can't use mkstemp(), but guard against a race condition. */
1159 EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600));
1160 if (fd == -1)
1161 return 0;
1162 return fdopen (fd, "w");
1163# else
1164 /* Not secure, but what can we do? */
1165 return fopen (*name, "w");
1166# endif
1167#endif
1168}
1169
1170
1171
1172/* This code is stolen from gnulib.
1173 If/when we abandon the requirement to work with K&R compilers, we can
1174 remove this (and perhaps other parts of GNU make!) and migrate to using
1175 gnulib directly.
1176
1177 This is called only through atexit(), which means die() has already been
1178 invoked. So, call exit() here directly. Apparently that works...?
1179*/
1180
1181/* Close standard output, exiting with status 'exit_failure' on failure.
1182 If a program writes *anything* to stdout, that program should close
1183 stdout and make sure that it succeeds before exiting. Otherwise,
1184 suppose that you go to the extreme of checking the return status
1185 of every function that does an explicit write to stdout. The last
1186 printf can succeed in writing to the internal stream buffer, and yet
1187 the fclose(stdout) could still fail (due e.g., to a disk full error)
1188 when it tries to write out that buffered data. Thus, you would be
1189 left with an incomplete output file and the offending program would
1190 exit successfully. Even calling fflush is not always sufficient,
1191 since some file systems (NFS and CODA) buffer written/flushed data
1192 until an actual close call.
1193
1194 Besides, it's wasteful to check the return value from every call
1195 that writes to stdout -- just let the internal stream state record
1196 the failure. That's what the ferror test is checking below.
1197
1198 It's important to detect such failures and exit nonzero because many
1199 tools (most notably 'make' and other build-management systems) depend
1200 on being able to detect failure in other tools via their exit status. */
1201
1202static void
1203close_stdout (void)
1204{
1205 int prev_fail = ferror (stdout);
1206#ifdef DEBUG_STDOUT_CLOSE_ISSUE
1207 if (prev_fail)
1208 my_stdout_error ("close_stdout", "error pending on entry!");
1209 errno = 0; SetLastError (0);
1210#endif
1211 int fclose_fail = fclose (stdout);
1212
1213 if (prev_fail || fclose_fail)
1214 {
1215#ifdef DEBUG_STDOUT_CLOSE_ISSUE
1216 if (fclose_fail)
1217 my_stdout_error ("close_stdout", "fclose failed!");
1218#endif
1219 if (fclose_fail)
1220 perror_with_name (_("write error: stdout"), "");
1221 else
1222 O (error, NILF, _("write error: stdout"));
1223 exit (MAKE_TROUBLE);
1224 }
1225}
1226
1227
1228
1229void
1230output_init (struct output *out)
1231{
1232#ifdef DEBUG_STDOUT_CLOSE_ISSUE
1233 if (STREAM_OK (stdout) && ferror (stdout))
1234 my_stdout_error (out ? "output_init(out)" : "output_init(NULL)", "error pending entry!");
1235#endif
1236
1237 if (out)
1238 {
1239#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
1240 out->out.head_seg = NULL;
1241 out->out.tail_seg = NULL;
1242 out->out.head_run = NULL;
1243 out->out.tail_run = NULL;
1244 out->err.head_seg = NULL;
1245 out->err.tail_seg = NULL;
1246 out->err.head_run = NULL;
1247 out->err.tail_run = NULL;
1248 out->err.total = 0;
1249 out->out.total = 0;
1250 out->seqno = 0;
1251#else
1252 out->out = out->err = OUTPUT_NONE;
1253#endif
1254 out->syncout = !!output_sync;
1255#ifdef KMK
1256 out->dont_truncate = 0;
1257#endif
1258 return;
1259 }
1260
1261 /* Configure this instance of make. Be sure stdout is line-buffered. */
1262
1263#ifdef HAVE_SETVBUF
1264# ifdef SETVBUF_REVERSED
1265 setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
1266# else /* setvbuf not reversed. */
1267 /* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
1268 setvbuf (stdout, 0, _IOLBF, BUFSIZ);
1269# endif /* setvbuf reversed. */
1270#elif HAVE_SETLINEBUF
1271 setlinebuf (stdout);
1272#endif /* setlinebuf missing. */
1273
1274 /* Force stdout/stderr into append mode. This ensures parallel jobs won't
1275 lose output due to overlapping writes. */
1276 set_append_mode (fileno (stdout));
1277 set_append_mode (fileno (stderr));
1278
1279#ifdef DEBUG_STDOUT_CLOSE_ISSUE
1280 if (ferror (stdout))
1281 my_stdout_error ("output_init", "error pending on exit!");
1282#endif
1283#ifdef HAVE_ATEXIT
1284 if (STREAM_OK (stdout))
1285 atexit (close_stdout);
1286#endif
1287}
1288
1289void
1290output_close (struct output *out)
1291{
1292 if (! out)
1293 {
1294 if (stdio_traced)
1295 log_working_directory (0);
1296 return;
1297 }
1298
1299#ifndef NO_OUTPUT_SYNC
1300 output_dump (out);
1301#endif
1302
1303#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
1304 assert (out->out.total == 0);
1305 assert (out->out.head_seg == NULL);
1306 assert (out->err.total == 0);
1307 assert (out->err.head_seg == NULL);
1308#else
1309 if (out->out >= 0)
1310 close (out->out);
1311 if (out->err >= 0 && out->err != out->out)
1312 close (out->err);
1313#endif
1314
1315 output_init (out);
1316}
1317
1318/* We're about to generate output: be sure it's set up. */
1319void
1320output_start (void)
1321{
1322#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY
1323 /* If we're syncing output make sure the sempahore (win) is set up. */
1324 if (output_context && output_context->syncout)
1325 if (combined_output < 0)
1326 {
1327 combined_output = 0;
1328 combined_output = sync_init ();
1329 }
1330#else
1331#ifndef NO_OUTPUT_SYNC
1332 /* If we're syncing output make sure the temporary file is set up. */
1333 if (output_context && output_context->syncout)
1334 if (! OUTPUT_ISSET(output_context))
1335 setup_tmpfile (output_context);
1336#endif
1337#endif
1338
1339#ifndef KMK
1340 /* If we're not syncing this output per-line or per-target, make sure we emit
1341 the "Entering..." message where appropriate. */
1342 if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
1343#else
1344 /* Indiscriminately output "Entering..." and "Leaving..." message for each
1345 command line or target is plain annoying! And when there is no recursion
1346 it's actually inappropriate. Haven't got a simple way of detecting that,
1347 so back to the old behavior for now. [bird] */
1348#endif
1349 if (! stdio_traced && print_directory_flag)
1350 stdio_traced = log_working_directory (1);
1351}
1352
1353void
1354outputs (int is_err, const char *msg)
1355{
1356 if (! msg || *msg == '\0')
1357 return;
1358
1359 output_start ();
1360
1361 _outputs (output_context, is_err, msg);
1362}
1363
1364
1365
1366static struct fmtstring
1367 {
1368 char *buffer;
1369 size_t size;
1370 } fmtbuf = { NULL, 0 };
1371
1372static char *
1373get_buffer (size_t need)
1374{
1375 /* Make sure we have room. NEED includes space for \0. */
1376 if (need > fmtbuf.size)
1377 {
1378 fmtbuf.size += need * 2;
1379 fmtbuf.buffer = xrealloc (fmtbuf.buffer, fmtbuf.size);
1380 }
1381
1382 fmtbuf.buffer[need-1] = '\0';
1383
1384 return fmtbuf.buffer;
1385}
1386
1387/* Print a message on stdout. */
1388
1389void
1390message (int prefix, size_t len, const char *fmt, ...)
1391{
1392 va_list args;
1393 char *p;
1394
1395 len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1;
1396 p = get_buffer (len);
1397
1398 if (prefix)
1399 {
1400 if (makelevel == 0)
1401 sprintf (p, "%s: ", program);
1402 else
1403 sprintf (p, "%s[%u]: ", program, makelevel);
1404 p += strlen (p);
1405 }
1406
1407 va_start (args, fmt);
1408 vsprintf (p, fmt, args);
1409 va_end (args);
1410
1411 strcat (p, "\n");
1412
1413 assert (fmtbuf.buffer[len-1] == '\0');
1414 outputs (0, fmtbuf.buffer);
1415}
1416
1417/* Print an error message. */
1418
1419void
1420error (const floc *flocp, size_t len, const char *fmt, ...)
1421{
1422 va_list args;
1423 char *p;
1424
1425 len += (strlen (fmt) + strlen (program)
1426 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
1427 + INTSTR_LENGTH + 4 + 1 + 1);
1428 p = get_buffer (len);
1429
1430 if (flocp && flocp->filenm)
1431 sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset);
1432 else if (makelevel == 0)
1433 sprintf (p, "%s: ", program);
1434 else
1435 sprintf (p, "%s[%u]: ", program, makelevel);
1436 p += strlen (p);
1437
1438 va_start (args, fmt);
1439 vsprintf (p, fmt, args);
1440 va_end (args);
1441
1442 strcat (p, "\n");
1443
1444 assert (fmtbuf.buffer[len-1] == '\0');
1445 outputs (1, fmtbuf.buffer);
1446}
1447
1448/* Print an error message and exit. */
1449
1450void
1451fatal (const floc *flocp, size_t len, const char *fmt, ...)
1452{
1453 va_list args;
1454 const char *stop = _(". Stop.\n");
1455 char *p;
1456
1457 len += (strlen (fmt) + strlen (program)
1458 + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
1459 + INTSTR_LENGTH + 8 + strlen (stop) + 1);
1460 p = get_buffer (len);
1461
1462 if (flocp && flocp->filenm)
1463 sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset);
1464 else if (makelevel == 0)
1465 sprintf (p, "%s: *** ", program);
1466 else
1467 sprintf (p, "%s[%u]: *** ", program, makelevel);
1468 p += strlen (p);
1469
1470 va_start (args, fmt);
1471 vsprintf (p, fmt, args);
1472 va_end (args);
1473
1474 strcat (p, stop);
1475
1476 assert (fmtbuf.buffer[len-1] == '\0');
1477 outputs (1, fmtbuf.buffer);
1478
1479 die (MAKE_FAILURE);
1480}
1481
1482/* Print an error message from errno. */
1483
1484void
1485perror_with_name (const char *str, const char *name)
1486{
1487 const char *err = strerror (errno);
1488 OSSS (error, NILF, _("%s%s: %s"), str, name, err);
1489}
1490
1491/* Print an error message from errno and exit. */
1492
1493void
1494pfatal_with_name (const char *name)
1495{
1496 const char *err = strerror (errno);
1497 OSS (fatal, NILF, _("%s: %s"), name, err);
1498
1499 /* NOTREACHED */
1500}
Note: See TracBrowser for help on using the repository browser.