diff options
Diffstat (limited to 'src/sort.c')
-rw-r--r-- | src/sort.c | 79 |
1 files changed, 60 insertions, 19 deletions
@@ -1,5 +1,5 @@ /* sort - sort lines of text (with all kinds of options). - Copyright (C) 1988-2013 Free Software Foundation, Inc. + Copyright (C) 1988-2014 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -221,7 +221,7 @@ struct keyfield bool general_numeric; /* Flag for general, numeric comparison. Handle numbers in exponential notation. */ bool human_numeric; /* Flag for sorting by human readable - units with either SI xor IEC prefixes. */ + units with either SI or IEC prefixes. */ bool month; /* Flag for comparison by month name. */ bool reverse; /* Reverse the sense of comparison. */ bool version; /* sort by version number */ @@ -373,6 +373,34 @@ static bool debug; number are present, temp files will be used. */ static unsigned int nmerge = NMERGE_DEFAULT; +/* Output an error to stderr using async-signal-safe routines, and _exit(). + This can be used safely from signal handlers, + and between fork() and exec() of multithreaded processes. */ + +static void async_safe_die (int, const char *) ATTRIBUTE_NORETURN; +static void +async_safe_die (int errnum, const char *errstr) +{ + ignore_value (write (STDERR_FILENO, errstr, strlen (errstr))); + + /* Even if defined HAVE_STRERROR_R, we can't use it, + as it may return a translated string etc. and even if not + may malloc() which is unsafe. We might improve this + by testing for sys_errlist and using that if available. + For now just report the error number. */ + if (errnum) + { + char errbuf[INT_BUFSIZE_BOUND (errnum)]; + char *p = inttostr (errnum, errbuf); + ignore_value (write (STDERR_FILENO, ": errno ", 8)); + ignore_value (write (STDERR_FILENO, p, strlen (p))); + } + + ignore_value (write (STDERR_FILENO, "\n", 1)); + + _exit (SORT_FAILURE); +} + /* Report MESSAGE for FILE, then clean up and exit. If FILE is null, it represents standard output. */ @@ -476,7 +504,7 @@ Other options:\n\ \n\ "), DEFAULT_TMPDIR); fputs (_("\ - -z, --zero-terminated end lines with 0 byte, not newline\n\ + -z, --zero-terminated line delimiter is NUL, not newline\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -982,8 +1010,8 @@ move_fd_or_die (int oldfd, int newfd) { if (oldfd != newfd) { - if (dup2 (oldfd, newfd) < 0) - error (SORT_FAILURE, errno, _("dup2 failed")); + /* This should never fail for our usage. */ + dup2 (oldfd, newfd); close (oldfd); } } @@ -1095,13 +1123,15 @@ maybe_create_temp (FILE **pfp, bool survive_fd_exhaustion) } else if (node->pid == 0) { + /* Being the child of a multithreaded program before exec(), + we're restricted to calling async-signal-safe routines here. */ close (pipefds[1]); move_fd_or_die (tempfd, STDOUT_FILENO); move_fd_or_die (pipefds[0], STDIN_FILENO); - if (execlp (compress_program, compress_program, (char *) NULL) < 0) - error (SORT_FAILURE, errno, _("couldn't execute %s"), - compress_program); + execlp (compress_program, compress_program, (char *) NULL); + + async_safe_die (errno, "couldn't execute compress program"); } } @@ -1153,13 +1183,15 @@ open_temp (struct tempnode *temp) break; case 0: + /* Being the child of a multithreaded program before exec(), + we're restricted to calling async-signal-safe routines here. */ close (pipefds[0]); move_fd_or_die (tempfd, STDIN_FILENO); move_fd_or_die (pipefds[1], STDOUT_FILENO); execlp (compress_program, compress_program, "-d", (char *) NULL); - error (SORT_FAILURE, errno, _("couldn't execute %s -d"), - compress_program); + + async_safe_die (errno, "couldn't execute compress program (with -d)"); default: temp->pid = child; @@ -1557,7 +1589,8 @@ initbuf (struct buffer *buf, size_t line_bytes, size_t alloc) static inline struct line * buffer_linelim (struct buffer const *buf) { - return (struct line *) (buf->buf + buf->alloc); + void *linelim = buf->buf + buf->alloc; + return linelim; } /* Return a pointer to the first character of the field specified @@ -3204,8 +3237,17 @@ merge_tree_init (size_t nthreads, size_t nlines, struct line *dest) /* Destroy the merge tree. */ static void -merge_tree_destroy (struct merge_node *merge_tree) +merge_tree_destroy (size_t nthreads, struct merge_node *merge_tree) { + size_t n_nodes = nthreads * 2; + struct merge_node *node = merge_tree; + + while (n_nodes--) + { + pthread_mutex_destroy (&node->lock); + node++; + } + free (merge_tree); } @@ -3321,8 +3363,8 @@ queue_insert (struct merge_node_queue *queue, struct merge_node *node) pthread_mutex_lock (&queue->mutex); heap_insert (queue->priority_queue, node); node->queued = true; - pthread_mutex_unlock (&queue->mutex); pthread_cond_signal (&queue->cond); + pthread_mutex_unlock (&queue->mutex); } /* Pop the top node off the priority QUEUE, lock the node, return it. */ @@ -3607,8 +3649,6 @@ sortlines (struct line *restrict lines, size_t nthreads, queue_insert (queue, node); merge_loop (queue, total_lines, tfp, temp_output); } - - pthread_mutex_destroy (&node->lock); } /* Scan through FILES[NTEMPS .. NFILES-1] looking for files that are @@ -3912,13 +3952,14 @@ sort (char *const *files, size_t nfiles, char const *output_file, queue_init (&queue, nthreads); struct merge_node *merge_tree = merge_tree_init (nthreads, buf.nlines, line); - struct merge_node *root = merge_tree + 1; - sortlines (line, nthreads, buf.nlines, root, + sortlines (line, nthreads, buf.nlines, merge_tree + 1, &queue, tfp, temp_output); + +#ifdef lint + merge_tree_destroy (nthreads, merge_tree); queue_destroy (&queue); - pthread_mutex_destroy (&root->lock); - merge_tree_destroy (merge_tree); +#endif } else write_unique (line - 1, tfp, temp_output); |