On Tue, Aug 6, 2019, 12:13 PM Rich Felker wrote: > > diff --git a/src/legacy/error.c b/src/legacy/error.c > > new file mode 100644 > > index 00000000..c5000fa4 > > --- /dev/null > > +++ b/src/legacy/error.c > > @@ -0,0 +1,69 @@ > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include "libc.h" > > + > > +void (*error_print_progname) (void) = 0; > > +unsigned int error_message_count = 0; > > +int error_one_per_line = 0; > > + > > +static unsigned int saved_linenum = 0; > > +static const char *saved_file = 0; > > + > > +static void errorv(int status, int errnum, const char *file, unsigned > int linenum, const char *fmt, va_list ap) > > +{ > > + ++error_message_count; > > + > > + fflush(stdout); > > + flockfile(stderr); > > + > > + if (error_print_progname) > > + error_print_progname(); > > + else { > > + fprintf(stderr, "%s:", __progname_full); > > + if (!file) > > + fputc(' ', stderr); > > + } > > + > > + if (file) > > + fprintf(stderr, "%s:%u: ", file, linenum); > > + > > + vfprintf(stderr, fmt, ap); > > + if (errnum) > > + fprintf(stderr, ": %s", strerror(errnum)); > > + fputc('\n', stderr); > > + > > + funlockfile(stderr); > > + > > + if (status) > > + exit(status); > > +} > > + > > +void error(int status, int errnum, const char *fmt, ...) > > +{ > > + va_list ap; > > + va_start(ap, fmt); > > + errorv(status, errnum, NULL, 0, fmt, ap); > > + va_end(ap); > > +} > > + > > +void error_at_line(int status, int errnum, const char *file, unsigned > int linenum, const char *fmt, ...) > > +{ > > + if (error_one_per_line) { > > + if(saved_linenum == linenum && file != NULL && > > + saved_file != NULL && !strcmp(file, saved_file)) > > + return; > > + saved_linenum = linenum; > > + // Assuming that the lifetime of the passed in file name > extends > > + // until the next call is rather questionable, but appears > to be > > + // the expected semantics. > > + saved_file = file; > > + } > > + > > + va_list ap; > > + va_start(ap, fmt); > > + errorv(status, errnum, file, linenum, fmt, ap); > > + va_end(ap); > > +} > > -- > > 2.22.0.709.g102302147b-goog > > One other question: what is the thread-safety of these interfaces > supposed to be? The globals are accessed without any synchronization, > but flockfile is used to synchronize with concurrent access to stderr. > This is plausibly correct (if the error.h functions themselves can't > be used from multiple threads, but can be used in a multithreaded > application), but at least questionable. > > The error_at_line stuff is probably not possible to make thread-safe > without thread-local state for saved_file/linenum, which would be a > disproportionate cost for these interfaces. > > I'm not objecting to anything with these comments, just wanting to > confirm that you think it's reasonable as-is. > Hmm, good question! I expect most uses are single threaded but it's better not to be thread-unsafe. So, I think it's probably best to move everything within the stderr lock (which means moving the flockfile out to the error and error_at_line functions). That at least makes these safe w.r.t. themselves. Users accessing the public globals will still have to take care, which is unavoidable and fine. I just noticed this is still using '__progname_full' instead of the public 'program_invocation_name', which I should also fix. (But I'm out and won't be able to update anything for a couple weeks, sorry!) >