xref: /freebsd-src/usr.bin/sort/radixsort.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1c66bbc91SGabor Kovesdan /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4c859c6ddSGabor Kovesdan  * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
5c66bbc91SGabor Kovesdan  * Copyright (C) 2012 Gabor Kovesdan <gabor@FreeBSD.org>
6c66bbc91SGabor Kovesdan  * All rights reserved.
7c66bbc91SGabor Kovesdan  *
8c66bbc91SGabor Kovesdan  * Redistribution and use in source and binary forms, with or without
9c66bbc91SGabor Kovesdan  * modification, are permitted provided that the following conditions
10c66bbc91SGabor Kovesdan  * are met:
11c66bbc91SGabor Kovesdan  * 1. Redistributions of source code must retain the above copyright
12c66bbc91SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer.
13c66bbc91SGabor Kovesdan  * 2. Redistributions in binary form must reproduce the above copyright
14c66bbc91SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer in the
15c66bbc91SGabor Kovesdan  *    documentation and/or other materials provided with the distribution.
16c66bbc91SGabor Kovesdan  *
17c66bbc91SGabor Kovesdan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18c66bbc91SGabor Kovesdan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19c66bbc91SGabor Kovesdan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20c66bbc91SGabor Kovesdan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21c66bbc91SGabor Kovesdan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22c66bbc91SGabor Kovesdan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23c66bbc91SGabor Kovesdan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24c66bbc91SGabor Kovesdan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25c66bbc91SGabor Kovesdan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26c66bbc91SGabor Kovesdan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27c66bbc91SGabor Kovesdan  * SUCH DAMAGE.
28c66bbc91SGabor Kovesdan  */
29c66bbc91SGabor Kovesdan 
30c66bbc91SGabor Kovesdan #include <sys/cdefs.h>
31c66bbc91SGabor Kovesdan #include <errno.h>
32c66bbc91SGabor Kovesdan #include <err.h>
33c66bbc91SGabor Kovesdan #include <langinfo.h>
34c66bbc91SGabor Kovesdan #include <math.h>
35c66bbc91SGabor Kovesdan #if defined(SORT_THREADS)
36c66bbc91SGabor Kovesdan #include <pthread.h>
37c66bbc91SGabor Kovesdan #include <semaphore.h>
38c66bbc91SGabor Kovesdan #endif
39c66bbc91SGabor Kovesdan #include <stdlib.h>
40c66bbc91SGabor Kovesdan #include <string.h>
41c66bbc91SGabor Kovesdan #include <wchar.h>
42c66bbc91SGabor Kovesdan #include <wctype.h>
43c66bbc91SGabor Kovesdan #include <unistd.h>
44c66bbc91SGabor Kovesdan 
45c66bbc91SGabor Kovesdan #include "coll.h"
46c66bbc91SGabor Kovesdan #include "radixsort.h"
47c66bbc91SGabor Kovesdan 
485d5151aeSGabor Kovesdan #define DEFAULT_SORT_FUNC_RADIXSORT mergesort
495d5151aeSGabor Kovesdan 
50c66bbc91SGabor Kovesdan #define TINY_NODE(sl) ((sl)->tosort_num < 65)
51c66bbc91SGabor Kovesdan #define SMALL_NODE(sl) ((sl)->tosort_num < 5)
52c66bbc91SGabor Kovesdan 
53c66bbc91SGabor Kovesdan /* are we sorting in reverse order ? */
54ce1e997fSGabor Kovesdan static bool reverse_sort;
55c66bbc91SGabor Kovesdan 
56c66bbc91SGabor Kovesdan /* sort sub-levels array size */
57c66bbc91SGabor Kovesdan static const size_t slsz = 256 * sizeof(struct sort_level*);
58c66bbc91SGabor Kovesdan 
59c66bbc91SGabor Kovesdan /* one sort level structure */
60c66bbc91SGabor Kovesdan struct sort_level
61c66bbc91SGabor Kovesdan {
62c66bbc91SGabor Kovesdan 	struct sort_level	**sublevels;
63c66bbc91SGabor Kovesdan 	struct sort_list_item	**leaves;
64c66bbc91SGabor Kovesdan 	struct sort_list_item	**sorted;
65c66bbc91SGabor Kovesdan 	struct sort_list_item	**tosort;
66c66bbc91SGabor Kovesdan 	size_t			  leaves_num;
67c66bbc91SGabor Kovesdan 	size_t			  leaves_sz;
68c66bbc91SGabor Kovesdan 	size_t			  level;
69c66bbc91SGabor Kovesdan 	size_t			  real_sln;
70c66bbc91SGabor Kovesdan 	size_t			  start_position;
71c66bbc91SGabor Kovesdan 	size_t			  sln;
72c66bbc91SGabor Kovesdan 	size_t			  tosort_num;
73c66bbc91SGabor Kovesdan 	size_t			  tosort_sz;
74c66bbc91SGabor Kovesdan };
75c66bbc91SGabor Kovesdan 
76c66bbc91SGabor Kovesdan /* stack of sort levels ready to be sorted */
77c66bbc91SGabor Kovesdan struct level_stack {
78c66bbc91SGabor Kovesdan 	struct level_stack	 *next;
79c66bbc91SGabor Kovesdan 	struct sort_level	 *sl;
80c66bbc91SGabor Kovesdan };
81c66bbc91SGabor Kovesdan 
82ce1e997fSGabor Kovesdan static struct level_stack *g_ls;
83c66bbc91SGabor Kovesdan 
84c66bbc91SGabor Kovesdan #if defined(SORT_THREADS)
85c66bbc91SGabor Kovesdan /* stack guarding mutex */
86692cd1a3SPedro F. Giffuni static pthread_cond_t g_ls_cond;
87c66bbc91SGabor Kovesdan static pthread_mutex_t g_ls_mutex;
88c66bbc91SGabor Kovesdan 
89c66bbc91SGabor Kovesdan /* counter: how many items are left */
90ce1e997fSGabor Kovesdan static size_t sort_left;
91c66bbc91SGabor Kovesdan /* guarding mutex */
92c66bbc91SGabor Kovesdan 
93c66bbc91SGabor Kovesdan /* semaphore to count threads */
94c66bbc91SGabor Kovesdan static sem_t mtsem;
95c66bbc91SGabor Kovesdan 
96c66bbc91SGabor Kovesdan /*
97c66bbc91SGabor Kovesdan  * Decrement items counter
98c66bbc91SGabor Kovesdan  */
99c66bbc91SGabor Kovesdan static inline void
sort_left_dec(size_t n)100c66bbc91SGabor Kovesdan sort_left_dec(size_t n)
101c66bbc91SGabor Kovesdan {
102692cd1a3SPedro F. Giffuni 	pthread_mutex_lock(&g_ls_mutex);
103c66bbc91SGabor Kovesdan 	sort_left -= n;
104692cd1a3SPedro F. Giffuni 	if (sort_left == 0 && nthreads > 1)
105692cd1a3SPedro F. Giffuni 		pthread_cond_broadcast(&g_ls_cond);
106692cd1a3SPedro F. Giffuni 	pthread_mutex_unlock(&g_ls_mutex);
107c66bbc91SGabor Kovesdan }
108c66bbc91SGabor Kovesdan 
109c66bbc91SGabor Kovesdan /*
110c66bbc91SGabor Kovesdan  * Do we have something to sort ?
111692cd1a3SPedro F. Giffuni  *
112692cd1a3SPedro F. Giffuni  * This routine does not need to be locked.
113c66bbc91SGabor Kovesdan  */
114c66bbc91SGabor Kovesdan static inline bool
have_sort_left(void)115c66bbc91SGabor Kovesdan have_sort_left(void)
116c66bbc91SGabor Kovesdan {
117c66bbc91SGabor Kovesdan 	bool ret;
118c66bbc91SGabor Kovesdan 
119c66bbc91SGabor Kovesdan 	ret = (sort_left > 0);
120692cd1a3SPedro F. Giffuni 
121c66bbc91SGabor Kovesdan 	return (ret);
122c66bbc91SGabor Kovesdan }
123c66bbc91SGabor Kovesdan 
124c66bbc91SGabor Kovesdan #else
125c66bbc91SGabor Kovesdan 
126c66bbc91SGabor Kovesdan #define sort_left_dec(n)
127c66bbc91SGabor Kovesdan 
128c66bbc91SGabor Kovesdan #endif /* SORT_THREADS */
129c66bbc91SGabor Kovesdan 
1307f180c0fSMark Johnston static void
_push_ls(struct level_stack * ls)1317f180c0fSMark Johnston _push_ls(struct level_stack *ls)
1327f180c0fSMark Johnston {
1337f180c0fSMark Johnston 
1347f180c0fSMark Johnston 	ls->next = g_ls;
1357f180c0fSMark Johnston 	g_ls = ls;
1367f180c0fSMark Johnston }
1377f180c0fSMark Johnston 
138c66bbc91SGabor Kovesdan /*
139c66bbc91SGabor Kovesdan  * Push sort level to the stack
140c66bbc91SGabor Kovesdan  */
141c66bbc91SGabor Kovesdan static inline void
push_ls(struct sort_level * sl)142c66bbc91SGabor Kovesdan push_ls(struct sort_level *sl)
143c66bbc91SGabor Kovesdan {
144c66bbc91SGabor Kovesdan 	struct level_stack *new_ls;
145c66bbc91SGabor Kovesdan 
146c66bbc91SGabor Kovesdan 	new_ls = sort_malloc(sizeof(struct level_stack));
147c66bbc91SGabor Kovesdan 	new_ls->sl = sl;
148c66bbc91SGabor Kovesdan 
149c66bbc91SGabor Kovesdan #if defined(SORT_THREADS)
1507f180c0fSMark Johnston 	if (nthreads > 1) {
151c66bbc91SGabor Kovesdan 		pthread_mutex_lock(&g_ls_mutex);
1527f180c0fSMark Johnston 		_push_ls(new_ls);
153692cd1a3SPedro F. Giffuni 		pthread_cond_signal(&g_ls_cond);
154c66bbc91SGabor Kovesdan 		pthread_mutex_unlock(&g_ls_mutex);
1557f180c0fSMark Johnston 	} else
156c66bbc91SGabor Kovesdan #endif
1577f180c0fSMark Johnston 		_push_ls(new_ls);
158c66bbc91SGabor Kovesdan }
159c66bbc91SGabor Kovesdan 
160c66bbc91SGabor Kovesdan /*
161c66bbc91SGabor Kovesdan  * Pop sort level from the stack (single-threaded style)
162c66bbc91SGabor Kovesdan  */
163c66bbc91SGabor Kovesdan static inline struct sort_level*
pop_ls_st(void)164c66bbc91SGabor Kovesdan pop_ls_st(void)
165c66bbc91SGabor Kovesdan {
166c66bbc91SGabor Kovesdan 	struct sort_level *sl;
167c66bbc91SGabor Kovesdan 
168c66bbc91SGabor Kovesdan 	if (g_ls) {
169c66bbc91SGabor Kovesdan 		struct level_stack *saved_ls;
170c66bbc91SGabor Kovesdan 
171c66bbc91SGabor Kovesdan 		sl = g_ls->sl;
172c66bbc91SGabor Kovesdan 		saved_ls = g_ls;
173c66bbc91SGabor Kovesdan 		g_ls = g_ls->next;
174c66bbc91SGabor Kovesdan 		sort_free(saved_ls);
175c66bbc91SGabor Kovesdan 	} else
176c66bbc91SGabor Kovesdan 		sl = NULL;
177c66bbc91SGabor Kovesdan 
178c66bbc91SGabor Kovesdan 	return (sl);
179c66bbc91SGabor Kovesdan }
180c66bbc91SGabor Kovesdan 
18177f98fbbSDimitry Andric #if defined(SORT_THREADS)
18277f98fbbSDimitry Andric 
183c66bbc91SGabor Kovesdan /*
184c66bbc91SGabor Kovesdan  * Pop sort level from the stack (multi-threaded style)
185c66bbc91SGabor Kovesdan  */
186c66bbc91SGabor Kovesdan static inline struct sort_level*
pop_ls_mt(void)187c66bbc91SGabor Kovesdan pop_ls_mt(void)
188c66bbc91SGabor Kovesdan {
189c66bbc91SGabor Kovesdan 	struct level_stack *saved_ls;
190c66bbc91SGabor Kovesdan 	struct sort_level *sl;
191c66bbc91SGabor Kovesdan 
192c66bbc91SGabor Kovesdan 	pthread_mutex_lock(&g_ls_mutex);
193c66bbc91SGabor Kovesdan 
194692cd1a3SPedro F. Giffuni 	for (;;) {
195c66bbc91SGabor Kovesdan 		if (g_ls) {
196c66bbc91SGabor Kovesdan 			sl = g_ls->sl;
197c66bbc91SGabor Kovesdan 			saved_ls = g_ls;
198c66bbc91SGabor Kovesdan 			g_ls = g_ls->next;
199692cd1a3SPedro F. Giffuni 			break;
200692cd1a3SPedro F. Giffuni 		}
201c66bbc91SGabor Kovesdan 		sl = NULL;
202c66bbc91SGabor Kovesdan 		saved_ls = NULL;
203692cd1a3SPedro F. Giffuni 
204692cd1a3SPedro F. Giffuni 		if (have_sort_left() == 0)
205692cd1a3SPedro F. Giffuni 			break;
206692cd1a3SPedro F. Giffuni 		pthread_cond_wait(&g_ls_cond, &g_ls_mutex);
207c66bbc91SGabor Kovesdan 	}
208c66bbc91SGabor Kovesdan 
209c66bbc91SGabor Kovesdan 	pthread_mutex_unlock(&g_ls_mutex);
210c66bbc91SGabor Kovesdan 
211c66bbc91SGabor Kovesdan 	sort_free(saved_ls);
212c66bbc91SGabor Kovesdan 
213c66bbc91SGabor Kovesdan 	return (sl);
214c66bbc91SGabor Kovesdan }
215c66bbc91SGabor Kovesdan 
21677f98fbbSDimitry Andric #endif /* defined(SORT_THREADS) */
21777f98fbbSDimitry Andric 
218c66bbc91SGabor Kovesdan static void
add_to_sublevel(struct sort_level * sl,struct sort_list_item * item,size_t indx)219e8da8c74SGabor Kovesdan add_to_sublevel(struct sort_level *sl, struct sort_list_item *item, size_t indx)
220c66bbc91SGabor Kovesdan {
221c66bbc91SGabor Kovesdan 	struct sort_level *ssl;
222c66bbc91SGabor Kovesdan 
223c66bbc91SGabor Kovesdan 	ssl = sl->sublevels[indx];
224c66bbc91SGabor Kovesdan 
225c66bbc91SGabor Kovesdan 	if (ssl == NULL) {
226ecc3c291SBaptiste Daroussin 		ssl = sort_calloc(1, sizeof(struct sort_level));
227c66bbc91SGabor Kovesdan 
228c66bbc91SGabor Kovesdan 		ssl->level = sl->level + 1;
229c66bbc91SGabor Kovesdan 		sl->sublevels[indx] = ssl;
230c66bbc91SGabor Kovesdan 
231c66bbc91SGabor Kovesdan 		++(sl->real_sln);
232c66bbc91SGabor Kovesdan 	}
233c66bbc91SGabor Kovesdan 
234c66bbc91SGabor Kovesdan 	if (++(ssl->tosort_num) > ssl->tosort_sz) {
235c66bbc91SGabor Kovesdan 		ssl->tosort_sz = ssl->tosort_num + 128;
236c66bbc91SGabor Kovesdan 		ssl->tosort = sort_realloc(ssl->tosort,
237c66bbc91SGabor Kovesdan 		    sizeof(struct sort_list_item*) * (ssl->tosort_sz));
238c66bbc91SGabor Kovesdan 	}
239c66bbc91SGabor Kovesdan 
240c66bbc91SGabor Kovesdan 	ssl->tosort[ssl->tosort_num - 1] = item;
241c66bbc91SGabor Kovesdan }
242c66bbc91SGabor Kovesdan 
243c66bbc91SGabor Kovesdan static inline void
add_leaf(struct sort_level * sl,struct sort_list_item * item)244c66bbc91SGabor Kovesdan add_leaf(struct sort_level *sl, struct sort_list_item *item)
245c66bbc91SGabor Kovesdan {
246e5f71a07SPedro F. Giffuni 
247c66bbc91SGabor Kovesdan 	if (++(sl->leaves_num) > sl->leaves_sz) {
248c66bbc91SGabor Kovesdan 		sl->leaves_sz = sl->leaves_num + 128;
249c66bbc91SGabor Kovesdan 		sl->leaves = sort_realloc(sl->leaves,
250c66bbc91SGabor Kovesdan 		    (sizeof(struct sort_list_item*) * (sl->leaves_sz)));
251c66bbc91SGabor Kovesdan 	}
252c66bbc91SGabor Kovesdan 	sl->leaves[sl->leaves_num - 1] = item;
253c66bbc91SGabor Kovesdan }
254c66bbc91SGabor Kovesdan 
255c66bbc91SGabor Kovesdan static inline int
get_wc_index(struct sort_list_item * sli,size_t level)256c66bbc91SGabor Kovesdan get_wc_index(struct sort_list_item *sli, size_t level)
257c66bbc91SGabor Kovesdan {
25871ec05a2SCyril Zhang 	const size_t wcfact = (mb_cur_max == 1) ? 1 : sizeof(wchar_t);
259ed7aec1eSMarius Strobl 	const struct key_value *kv;
260c66bbc91SGabor Kovesdan 	const struct bwstring *bws;
261c66bbc91SGabor Kovesdan 
262ed7aec1eSMarius Strobl 	kv = get_key_from_keys_array(&sli->ka, 0);
263ed7aec1eSMarius Strobl 	bws = kv->k;
264c66bbc91SGabor Kovesdan 
2659f7e5bdaSConrad Meyer 	if ((BWSLEN(bws) * wcfact > level)) {
2669f7e5bdaSConrad Meyer 		wchar_t res;
2679f7e5bdaSConrad Meyer 
2689f7e5bdaSConrad Meyer 		/*
2699f7e5bdaSConrad Meyer 		 * Sort wchar strings a byte at a time, rather than a single
2709f7e5bdaSConrad Meyer 		 * byte from each wchar.
2719f7e5bdaSConrad Meyer 		 */
2729f7e5bdaSConrad Meyer 		res = (wchar_t)BWS_GET(bws, level / wcfact);
2739f7e5bdaSConrad Meyer 		/* Sort most-significant byte first. */
2749f7e5bdaSConrad Meyer 		if (level % wcfact < wcfact - 1)
2759f7e5bdaSConrad Meyer 			res = (res >> (8 * (wcfact - 1 - (level % wcfact))));
2769f7e5bdaSConrad Meyer 
2779f7e5bdaSConrad Meyer 		return (res & 0xff);
2789f7e5bdaSConrad Meyer 	}
2799f7e5bdaSConrad Meyer 
280c66bbc91SGabor Kovesdan 	return (-1);
281c66bbc91SGabor Kovesdan }
282c66bbc91SGabor Kovesdan 
283c66bbc91SGabor Kovesdan static void
place_item(struct sort_level * sl,size_t item)284c66bbc91SGabor Kovesdan place_item(struct sort_level *sl, size_t item)
285c66bbc91SGabor Kovesdan {
286c66bbc91SGabor Kovesdan 	struct sort_list_item *sli;
287c66bbc91SGabor Kovesdan 	int c;
288c66bbc91SGabor Kovesdan 
289c66bbc91SGabor Kovesdan 	sli = sl->tosort[item];
290c66bbc91SGabor Kovesdan 	c = get_wc_index(sli, sl->level);
291c66bbc91SGabor Kovesdan 
292c66bbc91SGabor Kovesdan 	if (c == -1)
293c66bbc91SGabor Kovesdan 		add_leaf(sl, sli);
294c66bbc91SGabor Kovesdan 	else
295c66bbc91SGabor Kovesdan 		add_to_sublevel(sl, sli, c);
296c66bbc91SGabor Kovesdan }
297c66bbc91SGabor Kovesdan 
298c66bbc91SGabor Kovesdan static void
free_sort_level(struct sort_level * sl)299c66bbc91SGabor Kovesdan free_sort_level(struct sort_level *sl)
300c66bbc91SGabor Kovesdan {
301e5f71a07SPedro F. Giffuni 
302c66bbc91SGabor Kovesdan 	if (sl) {
303c66bbc91SGabor Kovesdan 		if (sl->leaves)
304c66bbc91SGabor Kovesdan 			sort_free(sl->leaves);
305c66bbc91SGabor Kovesdan 
306c66bbc91SGabor Kovesdan 		if (sl->level > 0)
307c66bbc91SGabor Kovesdan 			sort_free(sl->tosort);
308c66bbc91SGabor Kovesdan 
309c66bbc91SGabor Kovesdan 		if (sl->sublevels) {
310c66bbc91SGabor Kovesdan 			struct sort_level *slc;
311c66bbc91SGabor Kovesdan 			size_t sln;
312c66bbc91SGabor Kovesdan 
313c66bbc91SGabor Kovesdan 			sln = sl->sln;
314c66bbc91SGabor Kovesdan 
315c66bbc91SGabor Kovesdan 			for (size_t i = 0; i < sln; ++i) {
316c66bbc91SGabor Kovesdan 				slc = sl->sublevels[i];
317c66bbc91SGabor Kovesdan 				if (slc)
318c66bbc91SGabor Kovesdan 					free_sort_level(slc);
319c66bbc91SGabor Kovesdan 			}
320c66bbc91SGabor Kovesdan 
321c66bbc91SGabor Kovesdan 			sort_free(sl->sublevels);
322c66bbc91SGabor Kovesdan 		}
323c66bbc91SGabor Kovesdan 
324c66bbc91SGabor Kovesdan 		sort_free(sl);
325c66bbc91SGabor Kovesdan 	}
326c66bbc91SGabor Kovesdan }
327c66bbc91SGabor Kovesdan 
328c66bbc91SGabor Kovesdan static void
run_sort_level_next(struct sort_level * sl)329c66bbc91SGabor Kovesdan run_sort_level_next(struct sort_level *sl)
330c66bbc91SGabor Kovesdan {
33171ec05a2SCyril Zhang 	const size_t wcfact = (mb_cur_max == 1) ? 1 : sizeof(wchar_t);
332c66bbc91SGabor Kovesdan 	struct sort_level *slc;
333c66bbc91SGabor Kovesdan 	size_t i, sln, tosort_num;
334c66bbc91SGabor Kovesdan 
335c66bbc91SGabor Kovesdan 	if (sl->sublevels) {
336c66bbc91SGabor Kovesdan 		sort_free(sl->sublevels);
337c66bbc91SGabor Kovesdan 		sl->sublevels = NULL;
338c66bbc91SGabor Kovesdan 	}
339c66bbc91SGabor Kovesdan 
340c66bbc91SGabor Kovesdan 	switch (sl->tosort_num) {
341c66bbc91SGabor Kovesdan 	case 0:
342c66bbc91SGabor Kovesdan 		goto end;
343c66bbc91SGabor Kovesdan 	case (1):
344c66bbc91SGabor Kovesdan 		sl->sorted[sl->start_position] = sl->tosort[0];
345c66bbc91SGabor Kovesdan 		sort_left_dec(1);
346c66bbc91SGabor Kovesdan 		goto end;
347c66bbc91SGabor Kovesdan 	case (2):
3489f7e5bdaSConrad Meyer 		/*
3499f7e5bdaSConrad Meyer 		 * Radixsort only processes a single byte at a time.  In wchar
3509f7e5bdaSConrad Meyer 		 * mode, this can be a subset of the length of a character.
3519f7e5bdaSConrad Meyer 		 * list_coll_offset() offset is in units of wchar, not bytes.
3529f7e5bdaSConrad Meyer 		 * So to calculate the offset, we must divide by
3539f7e5bdaSConrad Meyer 		 * sizeof(wchar_t) and round down to the index of the first
3549f7e5bdaSConrad Meyer 		 * character this level references.
3559f7e5bdaSConrad Meyer 		 */
356c66bbc91SGabor Kovesdan 		if (list_coll_offset(&(sl->tosort[0]), &(sl->tosort[1]),
3579f7e5bdaSConrad Meyer 		    sl->level / wcfact) > 0) {
358c66bbc91SGabor Kovesdan 			sl->sorted[sl->start_position++] = sl->tosort[1];
359c66bbc91SGabor Kovesdan 			sl->sorted[sl->start_position] = sl->tosort[0];
360c66bbc91SGabor Kovesdan 		} else {
361c66bbc91SGabor Kovesdan 			sl->sorted[sl->start_position++] = sl->tosort[0];
362c66bbc91SGabor Kovesdan 			sl->sorted[sl->start_position] = sl->tosort[1];
363c66bbc91SGabor Kovesdan 		}
364c66bbc91SGabor Kovesdan 		sort_left_dec(2);
365c66bbc91SGabor Kovesdan 
366c66bbc91SGabor Kovesdan 		goto end;
367c66bbc91SGabor Kovesdan 	default:
368c66bbc91SGabor Kovesdan 		if (TINY_NODE(sl) || (sl->level > 15)) {
369c66bbc91SGabor Kovesdan 			listcoll_t func;
370c66bbc91SGabor Kovesdan 
3719f7e5bdaSConrad Meyer 			/*
3729f7e5bdaSConrad Meyer 			 * Collate comparison offset is in units of
3739f7e5bdaSConrad Meyer 			 * character-width, so we must divide the level (bytes)
3749f7e5bdaSConrad Meyer 			 * by operating character width (wchar_t or char).  See
3759f7e5bdaSConrad Meyer 			 * longer comment above.
3769f7e5bdaSConrad Meyer 			 */
3779f7e5bdaSConrad Meyer 			func = get_list_call_func(sl->level / wcfact);
378c66bbc91SGabor Kovesdan 
379c66bbc91SGabor Kovesdan 			sl->leaves = sl->tosort;
380c66bbc91SGabor Kovesdan 			sl->leaves_num = sl->tosort_num;
381c66bbc91SGabor Kovesdan 			sl->leaves_sz = sl->leaves_num;
382c66bbc91SGabor Kovesdan 			sl->leaves = sort_realloc(sl->leaves,
383c66bbc91SGabor Kovesdan 			    (sizeof(struct sort_list_item *) *
384c66bbc91SGabor Kovesdan 			    (sl->leaves_sz)));
385c66bbc91SGabor Kovesdan 			sl->tosort = NULL;
386c66bbc91SGabor Kovesdan 			sl->tosort_num = 0;
387c66bbc91SGabor Kovesdan 			sl->tosort_sz = 0;
388c66bbc91SGabor Kovesdan 			sl->sln = 0;
389c66bbc91SGabor Kovesdan 			sl->real_sln = 0;
390c66bbc91SGabor Kovesdan 			if (sort_opts_vals.sflag) {
391c66bbc91SGabor Kovesdan 				if (mergesort(sl->leaves, sl->leaves_num,
392c66bbc91SGabor Kovesdan 				    sizeof(struct sort_list_item *),
393c66bbc91SGabor Kovesdan 				    (int(*)(const void *, const void *)) func) == -1)
394c66bbc91SGabor Kovesdan 					/* NOTREACHED */
395c66bbc91SGabor Kovesdan 					err(2, "Radix sort error 3");
396c66bbc91SGabor Kovesdan 			} else
3975d5151aeSGabor Kovesdan 				DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
398c66bbc91SGabor Kovesdan 				    sizeof(struct sort_list_item *),
399c66bbc91SGabor Kovesdan 				    (int(*)(const void *, const void *)) func);
400c66bbc91SGabor Kovesdan 
401c66bbc91SGabor Kovesdan 			memcpy(sl->sorted + sl->start_position,
402c66bbc91SGabor Kovesdan 			    sl->leaves, sl->leaves_num *
403c66bbc91SGabor Kovesdan 			    sizeof(struct sort_list_item*));
404c66bbc91SGabor Kovesdan 
405c66bbc91SGabor Kovesdan 			sort_left_dec(sl->leaves_num);
406c66bbc91SGabor Kovesdan 
407c66bbc91SGabor Kovesdan 			goto end;
408c66bbc91SGabor Kovesdan 		} else {
409c66bbc91SGabor Kovesdan 			sl->tosort_sz = sl->tosort_num;
410c66bbc91SGabor Kovesdan 			sl->tosort = sort_realloc(sl->tosort,
411c66bbc91SGabor Kovesdan 			    sizeof(struct sort_list_item*) * (sl->tosort_sz));
412c66bbc91SGabor Kovesdan 		}
413c66bbc91SGabor Kovesdan 	}
414c66bbc91SGabor Kovesdan 
415c66bbc91SGabor Kovesdan 	sl->sln = 256;
416ecc3c291SBaptiste Daroussin 	sl->sublevels = sort_calloc(1, slsz);
417c66bbc91SGabor Kovesdan 
418c66bbc91SGabor Kovesdan 	sl->real_sln = 0;
419c66bbc91SGabor Kovesdan 
420c66bbc91SGabor Kovesdan 	tosort_num = sl->tosort_num;
421c66bbc91SGabor Kovesdan 	for (i = 0; i < tosort_num; ++i)
422c66bbc91SGabor Kovesdan 		place_item(sl, i);
423c66bbc91SGabor Kovesdan 
424c66bbc91SGabor Kovesdan 	sort_free(sl->tosort);
425c66bbc91SGabor Kovesdan 	sl->tosort = NULL;
426c66bbc91SGabor Kovesdan 	sl->tosort_num = 0;
427c66bbc91SGabor Kovesdan 	sl->tosort_sz = 0;
428c66bbc91SGabor Kovesdan 
429c66bbc91SGabor Kovesdan 	if (sl->leaves_num > 1) {
430c66bbc91SGabor Kovesdan 		if (keys_num > 1) {
431c66bbc91SGabor Kovesdan 			if (sort_opts_vals.sflag) {
432c66bbc91SGabor Kovesdan 				mergesort(sl->leaves, sl->leaves_num,
433c66bbc91SGabor Kovesdan 				    sizeof(struct sort_list_item *),
434c66bbc91SGabor Kovesdan 				    (int(*)(const void *, const void *)) list_coll);
435c66bbc91SGabor Kovesdan 			} else {
4365d5151aeSGabor Kovesdan 				DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
437c66bbc91SGabor Kovesdan 				    sizeof(struct sort_list_item *),
438c66bbc91SGabor Kovesdan 				    (int(*)(const void *, const void *)) list_coll);
439c66bbc91SGabor Kovesdan 			}
440c66bbc91SGabor Kovesdan 		} else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) {
4415d5151aeSGabor Kovesdan 			DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
442c66bbc91SGabor Kovesdan 			    sizeof(struct sort_list_item *),
443c66bbc91SGabor Kovesdan 			    (int(*)(const void *, const void *)) list_coll_by_str_only);
444c66bbc91SGabor Kovesdan 		}
445c66bbc91SGabor Kovesdan 	}
446c66bbc91SGabor Kovesdan 
447c66bbc91SGabor Kovesdan 	sl->leaves_sz = sl->leaves_num;
448c66bbc91SGabor Kovesdan 	sl->leaves = sort_realloc(sl->leaves, (sizeof(struct sort_list_item *) *
449c66bbc91SGabor Kovesdan 	    (sl->leaves_sz)));
450c66bbc91SGabor Kovesdan 
451c66bbc91SGabor Kovesdan 	if (!reverse_sort) {
452c66bbc91SGabor Kovesdan 		memcpy(sl->sorted + sl->start_position, sl->leaves,
453c66bbc91SGabor Kovesdan 		    sl->leaves_num * sizeof(struct sort_list_item*));
454c66bbc91SGabor Kovesdan 		sl->start_position += sl->leaves_num;
455c66bbc91SGabor Kovesdan 		sort_left_dec(sl->leaves_num);
456c66bbc91SGabor Kovesdan 
457c66bbc91SGabor Kovesdan 		sort_free(sl->leaves);
458c66bbc91SGabor Kovesdan 		sl->leaves = NULL;
459c66bbc91SGabor Kovesdan 		sl->leaves_num = 0;
460c66bbc91SGabor Kovesdan 		sl->leaves_sz = 0;
461c66bbc91SGabor Kovesdan 
462c66bbc91SGabor Kovesdan 		sln = sl->sln;
463c66bbc91SGabor Kovesdan 
464c66bbc91SGabor Kovesdan 		for (i = 0; i < sln; ++i) {
465c66bbc91SGabor Kovesdan 			slc = sl->sublevels[i];
466c66bbc91SGabor Kovesdan 
467c66bbc91SGabor Kovesdan 			if (slc) {
468c66bbc91SGabor Kovesdan 				slc->sorted = sl->sorted;
469c66bbc91SGabor Kovesdan 				slc->start_position = sl->start_position;
470c66bbc91SGabor Kovesdan 				sl->start_position += slc->tosort_num;
471c66bbc91SGabor Kovesdan 				if (SMALL_NODE(slc))
472c66bbc91SGabor Kovesdan 					run_sort_level_next(slc);
473c66bbc91SGabor Kovesdan 				else
474c66bbc91SGabor Kovesdan 					push_ls(slc);
475c66bbc91SGabor Kovesdan 				sl->sublevels[i] = NULL;
476c66bbc91SGabor Kovesdan 			}
477c66bbc91SGabor Kovesdan 		}
478c66bbc91SGabor Kovesdan 
479c66bbc91SGabor Kovesdan 	} else {
480c66bbc91SGabor Kovesdan 		size_t n;
481c66bbc91SGabor Kovesdan 
482c66bbc91SGabor Kovesdan 		sln = sl->sln;
483c66bbc91SGabor Kovesdan 
484c66bbc91SGabor Kovesdan 		for (i = 0; i < sln; ++i) {
485c66bbc91SGabor Kovesdan 			n = sln - i - 1;
486c66bbc91SGabor Kovesdan 			slc = sl->sublevels[n];
487c66bbc91SGabor Kovesdan 
488c66bbc91SGabor Kovesdan 			if (slc) {
489c66bbc91SGabor Kovesdan 				slc->sorted = sl->sorted;
490c66bbc91SGabor Kovesdan 				slc->start_position = sl->start_position;
491c66bbc91SGabor Kovesdan 				sl->start_position += slc->tosort_num;
492c66bbc91SGabor Kovesdan 				if (SMALL_NODE(slc))
493c66bbc91SGabor Kovesdan 					run_sort_level_next(slc);
494c66bbc91SGabor Kovesdan 				else
495c66bbc91SGabor Kovesdan 					push_ls(slc);
496c66bbc91SGabor Kovesdan 				sl->sublevels[n] = NULL;
497c66bbc91SGabor Kovesdan 			}
498c66bbc91SGabor Kovesdan 		}
499c66bbc91SGabor Kovesdan 
500c66bbc91SGabor Kovesdan 		memcpy(sl->sorted + sl->start_position, sl->leaves,
501c66bbc91SGabor Kovesdan 		    sl->leaves_num * sizeof(struct sort_list_item*));
502c66bbc91SGabor Kovesdan 		sort_left_dec(sl->leaves_num);
503c66bbc91SGabor Kovesdan 	}
504c66bbc91SGabor Kovesdan 
505c66bbc91SGabor Kovesdan end:
506c66bbc91SGabor Kovesdan 	free_sort_level(sl);
507c66bbc91SGabor Kovesdan }
508c66bbc91SGabor Kovesdan 
509c66bbc91SGabor Kovesdan /*
510c66bbc91SGabor Kovesdan  * Single-threaded sort cycle
511c66bbc91SGabor Kovesdan  */
512c66bbc91SGabor Kovesdan static void
run_sort_cycle_st(void)513c66bbc91SGabor Kovesdan run_sort_cycle_st(void)
514c66bbc91SGabor Kovesdan {
515c66bbc91SGabor Kovesdan 	struct sort_level *slc;
516c66bbc91SGabor Kovesdan 
517c66bbc91SGabor Kovesdan 	for (;;) {
518c66bbc91SGabor Kovesdan 		slc = pop_ls_st();
519c66bbc91SGabor Kovesdan 		if (slc == NULL) {
520c66bbc91SGabor Kovesdan 			break;
521c66bbc91SGabor Kovesdan 		}
522c66bbc91SGabor Kovesdan 		run_sort_level_next(slc);
523c66bbc91SGabor Kovesdan 	}
524c66bbc91SGabor Kovesdan }
525c66bbc91SGabor Kovesdan 
526c66bbc91SGabor Kovesdan #if defined(SORT_THREADS)
527c66bbc91SGabor Kovesdan 
528c66bbc91SGabor Kovesdan /*
529c66bbc91SGabor Kovesdan  * Multi-threaded sort cycle
530c66bbc91SGabor Kovesdan  */
531c66bbc91SGabor Kovesdan static void
run_sort_cycle_mt(void)532c66bbc91SGabor Kovesdan run_sort_cycle_mt(void)
533c66bbc91SGabor Kovesdan {
534c66bbc91SGabor Kovesdan 	struct sort_level *slc;
535c66bbc91SGabor Kovesdan 
536c66bbc91SGabor Kovesdan 	for (;;) {
537c66bbc91SGabor Kovesdan 		slc = pop_ls_mt();
538692cd1a3SPedro F. Giffuni 		if (slc == NULL)
539c66bbc91SGabor Kovesdan 			break;
540c66bbc91SGabor Kovesdan 		run_sort_level_next(slc);
541c66bbc91SGabor Kovesdan 	}
542c66bbc91SGabor Kovesdan }
543c66bbc91SGabor Kovesdan 
544c66bbc91SGabor Kovesdan /*
545c66bbc91SGabor Kovesdan  * Sort cycle thread (in multi-threaded mode)
546c66bbc91SGabor Kovesdan  */
547c66bbc91SGabor Kovesdan static void*
sort_thread(void * arg)548c66bbc91SGabor Kovesdan sort_thread(void* arg)
549c66bbc91SGabor Kovesdan {
550c66bbc91SGabor Kovesdan 	run_sort_cycle_mt();
551c66bbc91SGabor Kovesdan 	sem_post(&mtsem);
552c66bbc91SGabor Kovesdan 
553c66bbc91SGabor Kovesdan 	return (arg);
554c66bbc91SGabor Kovesdan }
555c66bbc91SGabor Kovesdan 
556c66bbc91SGabor Kovesdan #endif /* defined(SORT_THREADS) */
557c66bbc91SGabor Kovesdan 
558c66bbc91SGabor Kovesdan static void
run_top_sort_level(struct sort_level * sl)559c66bbc91SGabor Kovesdan run_top_sort_level(struct sort_level *sl)
560c66bbc91SGabor Kovesdan {
561c66bbc91SGabor Kovesdan 	struct sort_level *slc;
562c66bbc91SGabor Kovesdan 
563c66bbc91SGabor Kovesdan 	reverse_sort = sort_opts_vals.kflag ? keys[0].sm.rflag :
564c66bbc91SGabor Kovesdan 	    default_sort_mods->rflag;
565c66bbc91SGabor Kovesdan 
566c66bbc91SGabor Kovesdan 	sl->start_position = 0;
567c66bbc91SGabor Kovesdan 	sl->sln = 256;
568ecc3c291SBaptiste Daroussin 	sl->sublevels = sort_calloc(1, slsz);
569c66bbc91SGabor Kovesdan 
570c66bbc91SGabor Kovesdan 	for (size_t i = 0; i < sl->tosort_num; ++i)
571c66bbc91SGabor Kovesdan 		place_item(sl, i);
572c66bbc91SGabor Kovesdan 
573c66bbc91SGabor Kovesdan 	if (sl->leaves_num > 1) {
574c66bbc91SGabor Kovesdan 		if (keys_num > 1) {
575c66bbc91SGabor Kovesdan 			if (sort_opts_vals.sflag) {
576c66bbc91SGabor Kovesdan 				mergesort(sl->leaves, sl->leaves_num,
577c66bbc91SGabor Kovesdan 				    sizeof(struct sort_list_item *),
578c66bbc91SGabor Kovesdan 				    (int(*)(const void *, const void *)) list_coll);
579c66bbc91SGabor Kovesdan 			} else {
5805d5151aeSGabor Kovesdan 				DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
581c66bbc91SGabor Kovesdan 				    sizeof(struct sort_list_item *),
582c66bbc91SGabor Kovesdan 				    (int(*)(const void *, const void *)) list_coll);
583c66bbc91SGabor Kovesdan 			}
584c66bbc91SGabor Kovesdan 		} else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) {
5855d5151aeSGabor Kovesdan 			DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
586c66bbc91SGabor Kovesdan 			    sizeof(struct sort_list_item *),
587c66bbc91SGabor Kovesdan 			    (int(*)(const void *, const void *)) list_coll_by_str_only);
588c66bbc91SGabor Kovesdan 		}
589c66bbc91SGabor Kovesdan 	}
590c66bbc91SGabor Kovesdan 
591c66bbc91SGabor Kovesdan 	if (!reverse_sort) {
592c66bbc91SGabor Kovesdan 		memcpy(sl->tosort + sl->start_position, sl->leaves,
593c66bbc91SGabor Kovesdan 		    sl->leaves_num * sizeof(struct sort_list_item*));
594c66bbc91SGabor Kovesdan 		sl->start_position += sl->leaves_num;
595c66bbc91SGabor Kovesdan 		sort_left_dec(sl->leaves_num);
596c66bbc91SGabor Kovesdan 
597c66bbc91SGabor Kovesdan 		for (size_t i = 0; i < sl->sln; ++i) {
598c66bbc91SGabor Kovesdan 			slc = sl->sublevels[i];
599c66bbc91SGabor Kovesdan 
600c66bbc91SGabor Kovesdan 			if (slc) {
601c66bbc91SGabor Kovesdan 				slc->sorted = sl->tosort;
602c66bbc91SGabor Kovesdan 				slc->start_position = sl->start_position;
603c66bbc91SGabor Kovesdan 				sl->start_position += slc->tosort_num;
604c66bbc91SGabor Kovesdan 				push_ls(slc);
605c66bbc91SGabor Kovesdan 				sl->sublevels[i] = NULL;
606c66bbc91SGabor Kovesdan 			}
607c66bbc91SGabor Kovesdan 		}
608c66bbc91SGabor Kovesdan 
609c66bbc91SGabor Kovesdan 	} else {
610c66bbc91SGabor Kovesdan 		size_t n;
611c66bbc91SGabor Kovesdan 
612c66bbc91SGabor Kovesdan 		for (size_t i = 0; i < sl->sln; ++i) {
613c66bbc91SGabor Kovesdan 
614c66bbc91SGabor Kovesdan 			n = sl->sln - i - 1;
615c66bbc91SGabor Kovesdan 			slc = sl->sublevels[n];
616c66bbc91SGabor Kovesdan 
617c66bbc91SGabor Kovesdan 			if (slc) {
618c66bbc91SGabor Kovesdan 				slc->sorted = sl->tosort;
619c66bbc91SGabor Kovesdan 				slc->start_position = sl->start_position;
620c66bbc91SGabor Kovesdan 				sl->start_position += slc->tosort_num;
621c66bbc91SGabor Kovesdan 				push_ls(slc);
622c66bbc91SGabor Kovesdan 				sl->sublevels[n] = NULL;
623c66bbc91SGabor Kovesdan 			}
624c66bbc91SGabor Kovesdan 		}
625c66bbc91SGabor Kovesdan 
626c66bbc91SGabor Kovesdan 		memcpy(sl->tosort + sl->start_position, sl->leaves,
627c66bbc91SGabor Kovesdan 		    sl->leaves_num * sizeof(struct sort_list_item*));
628c66bbc91SGabor Kovesdan 
629c66bbc91SGabor Kovesdan 		sort_left_dec(sl->leaves_num);
630c66bbc91SGabor Kovesdan 	}
631c66bbc91SGabor Kovesdan 
632c66bbc91SGabor Kovesdan #if defined(SORT_THREADS)
633c66bbc91SGabor Kovesdan 	if (nthreads < 2) {
634c66bbc91SGabor Kovesdan #endif
635c66bbc91SGabor Kovesdan 		run_sort_cycle_st();
636c66bbc91SGabor Kovesdan #if defined(SORT_THREADS)
637c66bbc91SGabor Kovesdan 	} else {
638c66bbc91SGabor Kovesdan 		size_t i;
639c66bbc91SGabor Kovesdan 
640c66bbc91SGabor Kovesdan 		for(i = 0; i < nthreads; ++i) {
641c66bbc91SGabor Kovesdan 			pthread_attr_t attr;
642c66bbc91SGabor Kovesdan 			pthread_t pth;
643c66bbc91SGabor Kovesdan 
644c66bbc91SGabor Kovesdan 			pthread_attr_init(&attr);
645692cd1a3SPedro F. Giffuni 			pthread_attr_setdetachstate(&attr, PTHREAD_DETACHED);
646c66bbc91SGabor Kovesdan 
6475ca724dcSGabor Kovesdan 			for (;;) {
6485ca724dcSGabor Kovesdan 				int res = pthread_create(&pth, &attr,
6495ca724dcSGabor Kovesdan 				    sort_thread, NULL);
6505ca724dcSGabor Kovesdan 				if (res >= 0)
6515ca724dcSGabor Kovesdan 					break;
6525ca724dcSGabor Kovesdan 				if (errno == EAGAIN) {
6535ca724dcSGabor Kovesdan 					pthread_yield();
6545ca724dcSGabor Kovesdan 					continue;
6555ca724dcSGabor Kovesdan 				}
6565ca724dcSGabor Kovesdan 				err(2, NULL);
6575ca724dcSGabor Kovesdan 			}
658c66bbc91SGabor Kovesdan 
659c66bbc91SGabor Kovesdan 			pthread_attr_destroy(&attr);
660c66bbc91SGabor Kovesdan 		}
661c66bbc91SGabor Kovesdan 
662c66bbc91SGabor Kovesdan 		for (i = 0; i < nthreads; ++i)
663c66bbc91SGabor Kovesdan 			sem_wait(&mtsem);
664c66bbc91SGabor Kovesdan 	}
665c66bbc91SGabor Kovesdan #endif /* defined(SORT_THREADS) */
666c66bbc91SGabor Kovesdan }
667c66bbc91SGabor Kovesdan 
668c66bbc91SGabor Kovesdan static void
run_sort(struct sort_list_item ** base,size_t nmemb)669c66bbc91SGabor Kovesdan run_sort(struct sort_list_item **base, size_t nmemb)
670c66bbc91SGabor Kovesdan {
671c66bbc91SGabor Kovesdan 	struct sort_level *sl;
672c66bbc91SGabor Kovesdan 
673c66bbc91SGabor Kovesdan #if defined(SORT_THREADS)
6745ca724dcSGabor Kovesdan 	size_t nthreads_save = nthreads;
6755ca724dcSGabor Kovesdan 	if (nmemb < MT_SORT_THRESHOLD)
6765ca724dcSGabor Kovesdan 		nthreads = 1;
6775ca724dcSGabor Kovesdan 
678c66bbc91SGabor Kovesdan 	if (nthreads > 1) {
679c66bbc91SGabor Kovesdan 		pthread_mutexattr_t mattr;
680c66bbc91SGabor Kovesdan 
681c66bbc91SGabor Kovesdan 		pthread_mutexattr_init(&mattr);
682c66bbc91SGabor Kovesdan 		pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ADAPTIVE_NP);
683c66bbc91SGabor Kovesdan 
684c66bbc91SGabor Kovesdan 		pthread_mutex_init(&g_ls_mutex, &mattr);
685692cd1a3SPedro F. Giffuni 		pthread_cond_init(&g_ls_cond, NULL);
686c66bbc91SGabor Kovesdan 
687c66bbc91SGabor Kovesdan 		pthread_mutexattr_destroy(&mattr);
688c66bbc91SGabor Kovesdan 
689c66bbc91SGabor Kovesdan 		sem_init(&mtsem, 0, 0);
690c66bbc91SGabor Kovesdan 
691c66bbc91SGabor Kovesdan 	}
692c66bbc91SGabor Kovesdan #endif
693c66bbc91SGabor Kovesdan 
694ecc3c291SBaptiste Daroussin 	sl = sort_calloc(1, sizeof(struct sort_level));
695c66bbc91SGabor Kovesdan 
696c66bbc91SGabor Kovesdan 	sl->tosort = base;
697c66bbc91SGabor Kovesdan 	sl->tosort_num = nmemb;
698c66bbc91SGabor Kovesdan 	sl->tosort_sz = nmemb;
699c66bbc91SGabor Kovesdan 
700c66bbc91SGabor Kovesdan #if defined(SORT_THREADS)
701c66bbc91SGabor Kovesdan 	sort_left = nmemb;
702c66bbc91SGabor Kovesdan #endif
703c66bbc91SGabor Kovesdan 
704c66bbc91SGabor Kovesdan 	run_top_sort_level(sl);
705c66bbc91SGabor Kovesdan 
706c66bbc91SGabor Kovesdan 	free_sort_level(sl);
707c66bbc91SGabor Kovesdan 
708c66bbc91SGabor Kovesdan #if defined(SORT_THREADS)
709c66bbc91SGabor Kovesdan 	if (nthreads > 1) {
710c66bbc91SGabor Kovesdan 		sem_destroy(&mtsem);
711c66bbc91SGabor Kovesdan 		pthread_mutex_destroy(&g_ls_mutex);
712c66bbc91SGabor Kovesdan 	}
7135ca724dcSGabor Kovesdan 	nthreads = nthreads_save;
714c66bbc91SGabor Kovesdan #endif
715c66bbc91SGabor Kovesdan }
716c66bbc91SGabor Kovesdan 
717c66bbc91SGabor Kovesdan void
rxsort(struct sort_list_item ** base,size_t nmemb)718c66bbc91SGabor Kovesdan rxsort(struct sort_list_item **base, size_t nmemb)
719c66bbc91SGabor Kovesdan {
720c66bbc91SGabor Kovesdan 
721c66bbc91SGabor Kovesdan 	run_sort(base, nmemb);
722c66bbc91SGabor Kovesdan }
723