1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com> 5 * Copyright (C) 2012 Gabor Kovesdan <gabor@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <errno.h> 34 #include <err.h> 35 #include <langinfo.h> 36 #include <math.h> 37 #if defined(SORT_THREADS) 38 #include <pthread.h> 39 #include <semaphore.h> 40 #endif 41 #include <stdlib.h> 42 #include <string.h> 43 #include <wchar.h> 44 #include <wctype.h> 45 #include <unistd.h> 46 47 #include "coll.h" 48 #include "radixsort.h" 49 50 #define DEFAULT_SORT_FUNC_RADIXSORT mergesort 51 52 #define TINY_NODE(sl) ((sl)->tosort_num < 65) 53 #define SMALL_NODE(sl) ((sl)->tosort_num < 5) 54 55 /* are we sorting in reverse order ? */ 56 static bool reverse_sort; 57 58 /* sort sub-levels array size */ 59 static const size_t slsz = 256 * sizeof(struct sort_level*); 60 61 /* one sort level structure */ 62 struct sort_level 63 { 64 struct sort_level **sublevels; 65 struct sort_list_item **leaves; 66 struct sort_list_item **sorted; 67 struct sort_list_item **tosort; 68 size_t leaves_num; 69 size_t leaves_sz; 70 size_t level; 71 size_t real_sln; 72 size_t start_position; 73 size_t sln; 74 size_t tosort_num; 75 size_t tosort_sz; 76 }; 77 78 /* stack of sort levels ready to be sorted */ 79 struct level_stack { 80 struct level_stack *next; 81 struct sort_level *sl; 82 }; 83 84 static struct level_stack *g_ls; 85 86 #if defined(SORT_THREADS) 87 /* stack guarding mutex */ 88 static pthread_cond_t g_ls_cond; 89 static pthread_mutex_t g_ls_mutex; 90 91 /* counter: how many items are left */ 92 static size_t sort_left; 93 /* guarding mutex */ 94 95 /* semaphore to count threads */ 96 static sem_t mtsem; 97 98 /* 99 * Decrement items counter 100 */ 101 static inline void 102 sort_left_dec(size_t n) 103 { 104 pthread_mutex_lock(&g_ls_mutex); 105 sort_left -= n; 106 if (sort_left == 0 && nthreads > 1) 107 pthread_cond_broadcast(&g_ls_cond); 108 pthread_mutex_unlock(&g_ls_mutex); 109 } 110 111 /* 112 * Do we have something to sort ? 113 * 114 * This routine does not need to be locked. 115 */ 116 static inline bool 117 have_sort_left(void) 118 { 119 bool ret; 120 121 ret = (sort_left > 0); 122 123 return (ret); 124 } 125 126 #else 127 128 #define sort_left_dec(n) 129 130 #endif /* SORT_THREADS */ 131 132 /* 133 * Push sort level to the stack 134 */ 135 static inline void 136 push_ls(struct sort_level *sl) 137 { 138 struct level_stack *new_ls; 139 140 new_ls = sort_malloc(sizeof(struct level_stack)); 141 new_ls->sl = sl; 142 143 #if defined(SORT_THREADS) 144 if (nthreads > 1) 145 pthread_mutex_lock(&g_ls_mutex); 146 #endif 147 148 new_ls->next = g_ls; 149 g_ls = new_ls; 150 151 #if defined(SORT_THREADS) 152 if (nthreads > 1) 153 pthread_cond_signal(&g_ls_cond); 154 #endif 155 156 #if defined(SORT_THREADS) 157 if (nthreads > 1) 158 pthread_mutex_unlock(&g_ls_mutex); 159 #endif 160 } 161 162 /* 163 * Pop sort level from the stack (single-threaded style) 164 */ 165 static inline struct sort_level* 166 pop_ls_st(void) 167 { 168 struct sort_level *sl; 169 170 if (g_ls) { 171 struct level_stack *saved_ls; 172 173 sl = g_ls->sl; 174 saved_ls = g_ls; 175 g_ls = g_ls->next; 176 sort_free(saved_ls); 177 } else 178 sl = NULL; 179 180 return (sl); 181 } 182 183 #if defined(SORT_THREADS) 184 185 /* 186 * Pop sort level from the stack (multi-threaded style) 187 */ 188 static inline struct sort_level* 189 pop_ls_mt(void) 190 { 191 struct level_stack *saved_ls; 192 struct sort_level *sl; 193 194 pthread_mutex_lock(&g_ls_mutex); 195 196 for (;;) { 197 if (g_ls) { 198 sl = g_ls->sl; 199 saved_ls = g_ls; 200 g_ls = g_ls->next; 201 break; 202 } 203 sl = NULL; 204 saved_ls = NULL; 205 206 if (have_sort_left() == 0) 207 break; 208 pthread_cond_wait(&g_ls_cond, &g_ls_mutex); 209 } 210 211 pthread_mutex_unlock(&g_ls_mutex); 212 213 sort_free(saved_ls); 214 215 return (sl); 216 } 217 218 #endif /* defined(SORT_THREADS) */ 219 220 static void 221 add_to_sublevel(struct sort_level *sl, struct sort_list_item *item, size_t indx) 222 { 223 struct sort_level *ssl; 224 225 ssl = sl->sublevels[indx]; 226 227 if (ssl == NULL) { 228 ssl = sort_malloc(sizeof(struct sort_level)); 229 memset(ssl, 0, sizeof(struct sort_level)); 230 231 ssl->level = sl->level + 1; 232 sl->sublevels[indx] = ssl; 233 234 ++(sl->real_sln); 235 } 236 237 if (++(ssl->tosort_num) > ssl->tosort_sz) { 238 ssl->tosort_sz = ssl->tosort_num + 128; 239 ssl->tosort = sort_realloc(ssl->tosort, 240 sizeof(struct sort_list_item*) * (ssl->tosort_sz)); 241 } 242 243 ssl->tosort[ssl->tosort_num - 1] = item; 244 } 245 246 static inline void 247 add_leaf(struct sort_level *sl, struct sort_list_item *item) 248 { 249 250 if (++(sl->leaves_num) > sl->leaves_sz) { 251 sl->leaves_sz = sl->leaves_num + 128; 252 sl->leaves = sort_realloc(sl->leaves, 253 (sizeof(struct sort_list_item*) * (sl->leaves_sz))); 254 } 255 sl->leaves[sl->leaves_num - 1] = item; 256 } 257 258 static inline int 259 get_wc_index(struct sort_list_item *sli, size_t level) 260 { 261 const struct key_value *kv; 262 const struct bwstring *bws; 263 264 kv = get_key_from_keys_array(&sli->ka, 0); 265 bws = kv->k; 266 267 if ((BWSLEN(bws) > level)) 268 return (unsigned char) BWS_GET(bws,level); 269 return (-1); 270 } 271 272 static void 273 place_item(struct sort_level *sl, size_t item) 274 { 275 struct sort_list_item *sli; 276 int c; 277 278 sli = sl->tosort[item]; 279 c = get_wc_index(sli, sl->level); 280 281 if (c == -1) 282 add_leaf(sl, sli); 283 else 284 add_to_sublevel(sl, sli, c); 285 } 286 287 static void 288 free_sort_level(struct sort_level *sl) 289 { 290 291 if (sl) { 292 if (sl->leaves) 293 sort_free(sl->leaves); 294 295 if (sl->level > 0) 296 sort_free(sl->tosort); 297 298 if (sl->sublevels) { 299 struct sort_level *slc; 300 size_t sln; 301 302 sln = sl->sln; 303 304 for (size_t i = 0; i < sln; ++i) { 305 slc = sl->sublevels[i]; 306 if (slc) 307 free_sort_level(slc); 308 } 309 310 sort_free(sl->sublevels); 311 } 312 313 sort_free(sl); 314 } 315 } 316 317 static void 318 run_sort_level_next(struct sort_level *sl) 319 { 320 struct sort_level *slc; 321 size_t i, sln, tosort_num; 322 323 if (sl->sublevels) { 324 sort_free(sl->sublevels); 325 sl->sublevels = NULL; 326 } 327 328 switch (sl->tosort_num) { 329 case 0: 330 goto end; 331 case (1): 332 sl->sorted[sl->start_position] = sl->tosort[0]; 333 sort_left_dec(1); 334 goto end; 335 case (2): 336 if (list_coll_offset(&(sl->tosort[0]), &(sl->tosort[1]), 337 sl->level) > 0) { 338 sl->sorted[sl->start_position++] = sl->tosort[1]; 339 sl->sorted[sl->start_position] = sl->tosort[0]; 340 } else { 341 sl->sorted[sl->start_position++] = sl->tosort[0]; 342 sl->sorted[sl->start_position] = sl->tosort[1]; 343 } 344 sort_left_dec(2); 345 346 goto end; 347 default: 348 if (TINY_NODE(sl) || (sl->level > 15)) { 349 listcoll_t func; 350 351 func = get_list_call_func(sl->level); 352 353 sl->leaves = sl->tosort; 354 sl->leaves_num = sl->tosort_num; 355 sl->leaves_sz = sl->leaves_num; 356 sl->leaves = sort_realloc(sl->leaves, 357 (sizeof(struct sort_list_item *) * 358 (sl->leaves_sz))); 359 sl->tosort = NULL; 360 sl->tosort_num = 0; 361 sl->tosort_sz = 0; 362 sl->sln = 0; 363 sl->real_sln = 0; 364 if (sort_opts_vals.sflag) { 365 if (mergesort(sl->leaves, sl->leaves_num, 366 sizeof(struct sort_list_item *), 367 (int(*)(const void *, const void *)) func) == -1) 368 /* NOTREACHED */ 369 err(2, "Radix sort error 3"); 370 } else 371 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num, 372 sizeof(struct sort_list_item *), 373 (int(*)(const void *, const void *)) func); 374 375 memcpy(sl->sorted + sl->start_position, 376 sl->leaves, sl->leaves_num * 377 sizeof(struct sort_list_item*)); 378 379 sort_left_dec(sl->leaves_num); 380 381 goto end; 382 } else { 383 sl->tosort_sz = sl->tosort_num; 384 sl->tosort = sort_realloc(sl->tosort, 385 sizeof(struct sort_list_item*) * (sl->tosort_sz)); 386 } 387 } 388 389 sl->sln = 256; 390 sl->sublevels = sort_malloc(slsz); 391 memset(sl->sublevels, 0, slsz); 392 393 sl->real_sln = 0; 394 395 tosort_num = sl->tosort_num; 396 for (i = 0; i < tosort_num; ++i) 397 place_item(sl, i); 398 399 sort_free(sl->tosort); 400 sl->tosort = NULL; 401 sl->tosort_num = 0; 402 sl->tosort_sz = 0; 403 404 if (sl->leaves_num > 1) { 405 if (keys_num > 1) { 406 if (sort_opts_vals.sflag) { 407 mergesort(sl->leaves, sl->leaves_num, 408 sizeof(struct sort_list_item *), 409 (int(*)(const void *, const void *)) list_coll); 410 } else { 411 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num, 412 sizeof(struct sort_list_item *), 413 (int(*)(const void *, const void *)) list_coll); 414 } 415 } else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) { 416 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num, 417 sizeof(struct sort_list_item *), 418 (int(*)(const void *, const void *)) list_coll_by_str_only); 419 } 420 } 421 422 sl->leaves_sz = sl->leaves_num; 423 sl->leaves = sort_realloc(sl->leaves, (sizeof(struct sort_list_item *) * 424 (sl->leaves_sz))); 425 426 if (!reverse_sort) { 427 memcpy(sl->sorted + sl->start_position, sl->leaves, 428 sl->leaves_num * sizeof(struct sort_list_item*)); 429 sl->start_position += sl->leaves_num; 430 sort_left_dec(sl->leaves_num); 431 432 sort_free(sl->leaves); 433 sl->leaves = NULL; 434 sl->leaves_num = 0; 435 sl->leaves_sz = 0; 436 437 sln = sl->sln; 438 439 for (i = 0; i < sln; ++i) { 440 slc = sl->sublevels[i]; 441 442 if (slc) { 443 slc->sorted = sl->sorted; 444 slc->start_position = sl->start_position; 445 sl->start_position += slc->tosort_num; 446 if (SMALL_NODE(slc)) 447 run_sort_level_next(slc); 448 else 449 push_ls(slc); 450 sl->sublevels[i] = NULL; 451 } 452 } 453 454 } else { 455 size_t n; 456 457 sln = sl->sln; 458 459 for (i = 0; i < sln; ++i) { 460 n = sln - i - 1; 461 slc = sl->sublevels[n]; 462 463 if (slc) { 464 slc->sorted = sl->sorted; 465 slc->start_position = sl->start_position; 466 sl->start_position += slc->tosort_num; 467 if (SMALL_NODE(slc)) 468 run_sort_level_next(slc); 469 else 470 push_ls(slc); 471 sl->sublevels[n] = NULL; 472 } 473 } 474 475 memcpy(sl->sorted + sl->start_position, sl->leaves, 476 sl->leaves_num * sizeof(struct sort_list_item*)); 477 sort_left_dec(sl->leaves_num); 478 } 479 480 end: 481 free_sort_level(sl); 482 } 483 484 /* 485 * Single-threaded sort cycle 486 */ 487 static void 488 run_sort_cycle_st(void) 489 { 490 struct sort_level *slc; 491 492 for (;;) { 493 slc = pop_ls_st(); 494 if (slc == NULL) { 495 break; 496 } 497 run_sort_level_next(slc); 498 } 499 } 500 501 #if defined(SORT_THREADS) 502 503 /* 504 * Multi-threaded sort cycle 505 */ 506 static void 507 run_sort_cycle_mt(void) 508 { 509 struct sort_level *slc; 510 511 for (;;) { 512 slc = pop_ls_mt(); 513 if (slc == NULL) 514 break; 515 run_sort_level_next(slc); 516 } 517 } 518 519 /* 520 * Sort cycle thread (in multi-threaded mode) 521 */ 522 static void* 523 sort_thread(void* arg) 524 { 525 run_sort_cycle_mt(); 526 sem_post(&mtsem); 527 528 return (arg); 529 } 530 531 #endif /* defined(SORT_THREADS) */ 532 533 static void 534 run_top_sort_level(struct sort_level *sl) 535 { 536 struct sort_level *slc; 537 538 reverse_sort = sort_opts_vals.kflag ? keys[0].sm.rflag : 539 default_sort_mods->rflag; 540 541 sl->start_position = 0; 542 sl->sln = 256; 543 sl->sublevels = sort_malloc(slsz); 544 memset(sl->sublevels, 0, slsz); 545 546 for (size_t i = 0; i < sl->tosort_num; ++i) 547 place_item(sl, i); 548 549 if (sl->leaves_num > 1) { 550 if (keys_num > 1) { 551 if (sort_opts_vals.sflag) { 552 mergesort(sl->leaves, sl->leaves_num, 553 sizeof(struct sort_list_item *), 554 (int(*)(const void *, const void *)) list_coll); 555 } else { 556 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num, 557 sizeof(struct sort_list_item *), 558 (int(*)(const void *, const void *)) list_coll); 559 } 560 } else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) { 561 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num, 562 sizeof(struct sort_list_item *), 563 (int(*)(const void *, const void *)) list_coll_by_str_only); 564 } 565 } 566 567 if (!reverse_sort) { 568 memcpy(sl->tosort + sl->start_position, sl->leaves, 569 sl->leaves_num * sizeof(struct sort_list_item*)); 570 sl->start_position += sl->leaves_num; 571 sort_left_dec(sl->leaves_num); 572 573 for (size_t i = 0; i < sl->sln; ++i) { 574 slc = sl->sublevels[i]; 575 576 if (slc) { 577 slc->sorted = sl->tosort; 578 slc->start_position = sl->start_position; 579 sl->start_position += slc->tosort_num; 580 push_ls(slc); 581 sl->sublevels[i] = NULL; 582 } 583 } 584 585 } else { 586 size_t n; 587 588 for (size_t i = 0; i < sl->sln; ++i) { 589 590 n = sl->sln - i - 1; 591 slc = sl->sublevels[n]; 592 593 if (slc) { 594 slc->sorted = sl->tosort; 595 slc->start_position = sl->start_position; 596 sl->start_position += slc->tosort_num; 597 push_ls(slc); 598 sl->sublevels[n] = NULL; 599 } 600 } 601 602 memcpy(sl->tosort + sl->start_position, sl->leaves, 603 sl->leaves_num * sizeof(struct sort_list_item*)); 604 605 sort_left_dec(sl->leaves_num); 606 } 607 608 #if defined(SORT_THREADS) 609 if (nthreads < 2) { 610 #endif 611 run_sort_cycle_st(); 612 #if defined(SORT_THREADS) 613 } else { 614 size_t i; 615 616 for(i = 0; i < nthreads; ++i) { 617 pthread_attr_t attr; 618 pthread_t pth; 619 620 pthread_attr_init(&attr); 621 pthread_attr_setdetachstate(&attr, PTHREAD_DETACHED); 622 623 for (;;) { 624 int res = pthread_create(&pth, &attr, 625 sort_thread, NULL); 626 if (res >= 0) 627 break; 628 if (errno == EAGAIN) { 629 pthread_yield(); 630 continue; 631 } 632 err(2, NULL); 633 } 634 635 pthread_attr_destroy(&attr); 636 } 637 638 for (i = 0; i < nthreads; ++i) 639 sem_wait(&mtsem); 640 } 641 #endif /* defined(SORT_THREADS) */ 642 } 643 644 static void 645 run_sort(struct sort_list_item **base, size_t nmemb) 646 { 647 struct sort_level *sl; 648 649 #if defined(SORT_THREADS) 650 size_t nthreads_save = nthreads; 651 if (nmemb < MT_SORT_THRESHOLD) 652 nthreads = 1; 653 654 if (nthreads > 1) { 655 pthread_mutexattr_t mattr; 656 657 pthread_mutexattr_init(&mattr); 658 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ADAPTIVE_NP); 659 660 pthread_mutex_init(&g_ls_mutex, &mattr); 661 pthread_cond_init(&g_ls_cond, NULL); 662 663 pthread_mutexattr_destroy(&mattr); 664 665 sem_init(&mtsem, 0, 0); 666 667 } 668 #endif 669 670 sl = sort_malloc(sizeof(struct sort_level)); 671 memset(sl, 0, sizeof(struct sort_level)); 672 673 sl->tosort = base; 674 sl->tosort_num = nmemb; 675 sl->tosort_sz = nmemb; 676 677 #if defined(SORT_THREADS) 678 sort_left = nmemb; 679 #endif 680 681 run_top_sort_level(sl); 682 683 free_sort_level(sl); 684 685 #if defined(SORT_THREADS) 686 if (nthreads > 1) { 687 sem_destroy(&mtsem); 688 pthread_mutex_destroy(&g_ls_mutex); 689 } 690 nthreads = nthreads_save; 691 #endif 692 } 693 694 void 695 rxsort(struct sort_list_item **base, size_t nmemb) 696 { 697 698 run_sort(base, nmemb); 699 } 700