Changeset 3004 for trunk/src/lib/nt/fts-nt.c
- Timestamp:
- Nov 6, 2016, 12:18:51 AM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/lib/nt/fts-nt.c
r3002 r3004 90 90 static FTSENT *fts_alloc_ansi(FTS *sp, char const *name, size_t namelen); 91 91 static FTSENT *fts_alloc_utf16(FTS *sp, wchar_t const *wcsname, size_t cwcname); 92 static void nt_fts_free_alloc_cache(FTS *sp); 92 93 static FTSENT *fts_build(FTS *, int); 93 94 static void fts_lfree(FTSENT *); … … 117 118 #define MAX(a, b) ( (a) >= (b) ? (a) : (b) ) 118 119 119 #define FTS_NT_DUMMY_SYMFD_VALUE ((HANDLE)~(intptr_t)(2)) /* current process */ 120 #define FTS_WITH_ALLOC_CACHE 121 /** Number of size buckets for the FTSENT allocation cache. */ 122 #define FTS_NUM_FREE_BUCKETS 64 123 /** Shift for converting size to free bucket index. */ 124 #define FTS_FREE_BUCKET_SHIFT 4 125 /** The FTSENT allocation alignment. */ 126 #define FTS_ALIGN_FTSENT (1U << FTS_FREE_BUCKET_SHIFT) 127 /** Enables allocation statistics. */ 128 //#define FTS_WITH_STATISTICS 120 129 121 130 /* … … 126 135 struct _fts_private { 127 136 FTS ftsp_fts; 137 #ifdef FTS_WITH_ALLOC_CACHE 138 /** Number of free entries in the above buckets. */ 139 size_t numfree; 140 # ifdef FTS_WITH_STATISTICS 141 size_t allocs; 142 size_t hits; 143 size_t misses; 144 # endif 145 /** Free FTSENT buckets (by size). 146 * This is to avoid hitting the heap, which is a little sluggish on windows. */ 147 struct 148 { 149 FTSENT *head; 150 } freebuckets[FTS_NUM_FREE_BUCKETS]; 151 #endif 128 152 }; 129 153 … … 338 362 } 339 363 364 340 365 int FTSCALL 341 366 nt_fts_close(FTS *sp) … … 365 390 free(sp->fts_path); 366 391 free(sp->fts_wcspath); 392 #ifdef FTS_WITH_ALLOC_CACHE 393 # ifdef FTS_WITH_STATISTICS 394 { 395 struct _fts_private *priv = (struct _fts_private *)sp; 396 fprintf(stderr, "numfree=%u allocs=%u hits=%u (%uppt) misses=%u (%uppt) other=%u\n", 397 priv->numfree, priv->allocs, 398 priv->hits, (unsigned)((double)priv->hits * 1000.0 / priv->allocs), 399 priv->misses, (unsigned)((double)priv->misses * 1000.0 / priv->allocs), 400 priv->allocs - priv->misses - priv->hits); 401 } 402 # endif 403 #endif 404 nt_fts_free_alloc_cache(sp); 367 405 368 406 /* Free up the stream pointer. */ … … 371 409 } 372 410 411 412 /** 413 * Frees a FTSENT structure by way of the allocation cache. 414 */ 415 static void 416 fts_free_entry(FTS *sp, FTSENT *tmp) 417 { 418 if (tmp != NULL) { 419 struct _fts_private *priv = (struct _fts_private *)sp; 420 #ifdef FTS_WITH_ALLOC_CACHE 421 size_t idx; 422 #endif 423 424 if (tmp->fts_dirfd == INVALID_HANDLE_VALUE) { 425 /* There are probably more files than directories out there. */ 426 } else { 427 birdCloseFile(tmp->fts_dirfd); 428 tmp->fts_dirfd = INVALID_HANDLE_VALUE; 429 } 430 431 #ifdef FTS_WITH_ALLOC_CACHE 432 idx = (tmp->fts_alloc_size - sizeof(FTSENT)) >> FTS_FREE_BUCKET_SHIFT; 433 if (idx < FTS_NUM_FREE_BUCKETS) { 434 tmp->fts_link = priv->freebuckets[idx].head; 435 priv->freebuckets[idx].head = tmp; 436 } else { 437 tmp->fts_link = priv->freebuckets[FTS_NUM_FREE_BUCKETS - 1].head; 438 priv->freebuckets[FTS_NUM_FREE_BUCKETS - 1].head = tmp; 439 } 440 441 priv->numfree++; 442 #else 443 free(tmp); 444 #endif 445 } 446 } 447 448 373 449 /* 374 450 * Special case of "/" at the end of the path so that slashes aren't … … 377 453 #define NAPPEND(p) ( p->fts_pathlen - (p->fts_path[p->fts_pathlen - 1] == '/') ) 378 454 #define NAPPENDW(p) ( p->fts_cwcpath - (p->fts_wcspath[p->fts_cwcpath - 1] == L'/') ) 379 380 static void381 fts_free_entry(FTSENT *tmp)382 {383 if (tmp != NULL) {384 if (tmp->fts_dirfd != INVALID_HANDLE_VALUE) {385 birdCloseFile(tmp->fts_dirfd);386 tmp->fts_dirfd = INVALID_HANDLE_VALUE;387 }388 free(tmp);389 }390 }391 455 392 456 FTSENT * FTSCALL … … 420 484 * pointer, follow fails. 421 485 * 422 * NT: Since we don't change directory, we just set fts_symfd to a 423 * placeholder value handle value here in case a API client 424 * checks it. Ditto FTS_SYMFOLLOW. 486 * NT: Since we don't change directory, we just set FTS_SYMFOLLOW 487 * here in case a API client checks it. 425 488 */ 426 489 if (instr == FTS_FOLLOW && … … 428 491 p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE); 429 492 if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) { 430 p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE;431 493 p->fts_flags |= FTS_SYMFOLLOW; 432 494 } … … 439 501 if (instr == FTS_SKIP || 440 502 (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { 441 if (p->fts_flags & FTS_SYMFOLLOW) {442 p->fts_symfd = INVALID_HANDLE_VALUE;443 }444 503 if (sp->fts_child) { 445 504 fts_lfree(sp->fts_child); … … 489 548 */ 490 549 if (p->fts_level == FTS_ROOTLEVEL) { 491 fts_free_entry( tmp);550 fts_free_entry(sp, tmp); 492 551 fts_load(sp, p); 493 552 return (sp->fts_cur = p); … … 500 559 */ 501 560 if (p->fts_instr == FTS_SKIP) { 502 fts_free_entry( tmp);561 fts_free_entry(sp, tmp); 503 562 goto next; 504 563 } 505 564 if (p->fts_instr == FTS_FOLLOW) { 506 565 p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE); 507 /* NT: See above regarding fts_symfd. */ 508 if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) { 509 p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE; 566 /* NT: See above regarding fts_flags. */ 567 if (p->fts_info == FTS_D) { 510 568 p->fts_flags |= FTS_SYMFOLLOW; 511 569 } … … 513 571 } 514 572 515 fts_free_entry( tmp);573 fts_free_entry(sp, tmp); 516 574 517 575 name: … … 535 593 * can distinguish between error and EOF. 536 594 */ 537 fts_free_entry( tmp);538 fts_free_entry( p);595 fts_free_entry(sp, tmp); 596 fts_free_entry(sp, p); 539 597 errno = 0; 540 598 return (sp->fts_cur = NULL); … … 551 609 * one directory. 552 610 * 553 * NT: We're doing no fchdir, but we need to close the directory handle 554 * and clear fts_symfd now. 555 */ 556 if (p->fts_flags & FTS_SYMFOLLOW) 557 p->fts_symfd = INVALID_HANDLE_VALUE; 611 * NT: We're doing no fchdir, but we need to close the directory handle. 612 */ 558 613 if (p->fts_dirfd != INVALID_HANDLE_VALUE) { 559 614 birdCloseFile(p->fts_dirfd); 560 615 p->fts_dirfd = INVALID_HANDLE_VALUE; 561 616 } 562 fts_free_entry( tmp);617 fts_free_entry(sp, tmp); 563 618 p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; 564 619 return (sp->fts_cur = p); … … 685 740 fts_build(FTS *sp, int type) 686 741 { 687 BirdDirEntry_T *dp; 688 FTSENT *p, *head; 689 FTSENT *cur, *tail; 742 BirdDirEntryW_T *dp; 743 FTSENT *p, *head, *cur, **tailp; 690 744 DIR *dirp; 691 745 int saved_errno, doadjust, doadjust_utf16; … … 751 805 */ 752 806 if (sp->fts_options & FTS_NO_ANSI) { 753 len = maxlen = 0; 807 len = 0; 808 maxlen = 0x10000; 754 809 } else { 755 810 len = NAPPEND(cur); … … 766 821 /* Read the directory, attaching each entry to the `link' pointer. */ 767 822 doadjust = doadjust_utf16 = 0; 768 for (head = tail = NULL, nitems = 0; dirp && (dp = birdDirRead(dirp));) { 769 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) 823 nitems = 0; 824 head = NULL; 825 tailp = &head; 826 while ((dp = birdDirReadW(dirp)) != NULL) { 827 if (ISSET(FTS_SEEDOT) || !ISDOT(dp->d_name)) { 828 /* assume dirs have two or more entries */ 829 } else { 770 830 continue; 771 772 if ((p = fts_alloc_ansi(sp, dp->d_name, dp->d_namlen)) == NULL) 831 } 832 833 if ((p = fts_alloc_utf16(sp, dp->d_name, dp->d_namlen)) != NULL) { 834 /* likely */ 835 } else { 773 836 goto mem1; 774 775 if (p->fts_namelen >= maxlen 776 || p->fts_cwcname >= cwcmax) { /* include space for NUL */ 837 } 838 839 /* include space for NUL */ 840 if (p->fts_namelen < maxlen && p->fts_cwcname < cwcmax) { 841 /* likely */ 842 } else { 777 843 void *oldaddr = sp->fts_path; 778 844 wchar_t *oldwcspath = sp->fts_wcspath; 779 845 if (fts_palloc(sp, 780 p->fts_namelen >= maxlen ? len + p->fts_namelen + 1 : 0, 781 p->fts_cwcname >= cwcmax ? cwcdir + p->fts_cwcname + 1 : 0)) { 846 p->fts_namelen >= maxlen ? len + p->fts_namelen + 1 : 0, 847 p->fts_cwcname >= cwcmax ? cwcdir + p->fts_cwcname + 1 : 0)) { 848 mem1: 782 849 /* 783 850 * No more memory for path or structures. Save … … 785 852 * structures already allocated. 786 853 */ 787 mem1:saved_errno = errno;854 saved_errno = errno; 788 855 if (p) 789 856 free(p); … … 815 882 /* We walk in directory order so "ls -f" doesn't get upset. */ 816 883 p->fts_link = NULL; 817 if (head == NULL) 818 head = tail = p; 819 else { 820 tail->fts_link = p; 821 tail = p; 822 } 884 *tailp = p; 885 tailp = &p->fts_link; 823 886 ++nitems; 824 887 } … … 910 973 p->fts_nlink = sbp->st_nlink; 911 974 912 if (ISDOT(p->fts_ name))975 if (ISDOT(p->fts_wcsname)) 913 976 return (FTS_DOT); 914 977 … … 986 1049 fts_alloc(FTS *sp, char const *name, size_t namelen, wchar_t const *wcsname, size_t cwcname) 987 1050 { 1051 struct _fts_private *priv = (struct _fts_private *)sp; 988 1052 FTSENT *p; 989 1053 size_t len; 990 1054 #ifdef FTS_WITH_ALLOC_CACHE 1055 size_t aligned; 1056 size_t idx; 1057 #endif 1058 1059 #if defined(FTS_WITH_STATISTICS) && defined(FTS_WITH_ALLOC_CACHE) 1060 priv->allocs++; 1061 #endif 991 1062 /* 992 1063 * The file name is a variable length array. Allocate the FTSENT … … 996 1067 if (!(sp->fts_options & FTS_NO_ANSI)) 997 1068 len += namelen + 1; 1069 1070 /* 1071 * To speed things up we cache entries. This code is a little insane, 1072 * but that's preferable to slow code. 1073 */ 1074 #ifdef FTS_WITH_ALLOC_CACHE 1075 aligned = (len + FTS_ALIGN_FTSENT + 1) & ~(size_t)(FTS_ALIGN_FTSENT - 1); 1076 idx = ((aligned - sizeof(FTSENT)) >> FTS_FREE_BUCKET_SHIFT); 1077 if ( idx < FTS_NUM_FREE_BUCKETS 1078 && (p = priv->freebuckets[idx].head) 1079 && p->fts_alloc_size >= len) { 1080 priv->freebuckets[idx].head = p->fts_link; 1081 priv->numfree--; 1082 # ifdef FTS_WITH_STATISTICS 1083 priv->hits++; 1084 # endif 1085 1086 } else { 1087 # ifdef FTS_WITH_STATISTICS 1088 priv->misses++; 1089 # endif 1090 p = malloc(aligned); 1091 if (p) { 1092 p->fts_alloc_size = (unsigned)aligned; 1093 } else { 1094 nt_fts_free_alloc_cache(sp); 1095 p = malloc(len); 1096 if (!p) 1097 return NULL; 1098 p->fts_alloc_size = (unsigned)len; 1099 } 1100 } 1101 #else /* !FTS_WITH_ALLOC_CACHE */ 998 1102 p = malloc(len); 999 1103 if (p) { 1000 /* Copy the names and guarantee NUL termination. */ 1001 p->fts_wcsname = (wchar_t *)(p + 1); 1002 memcpy(p->fts_wcsname, wcsname, cwcname * sizeof(wchar_t)); 1003 p->fts_wcsname[cwcname] = '\0'; 1004 p->fts_cwcname = cwcname; 1005 if (!(sp->fts_options & FTS_NO_ANSI)) { 1006 p->fts_name = (char *)(p->fts_wcsname + cwcname + 1); 1007 memcpy(p->fts_name, name, namelen); 1008 p->fts_name[namelen] = '\0'; 1009 p->fts_namelen = namelen; 1010 } else { 1011 p->fts_name = NULL; 1012 p->fts_namelen = 0; 1013 } 1014 1015 p->fts_path = sp->fts_path; 1016 p->fts_wcspath = sp->fts_wcspath; 1017 p->fts_statp = &p->fts_stat; 1018 p->fts_errno = 0; 1019 p->fts_flags = 0; 1020 p->fts_instr = FTS_NOINSTR; 1021 p->fts_number = 0; 1022 p->fts_pointer = NULL; 1023 p->fts_fts = sp; 1024 p->fts_symfd = INVALID_HANDLE_VALUE; 1025 p->fts_dirfd = INVALID_HANDLE_VALUE; 1026 } 1104 p->fts_alloc_size = (unsigned)len; 1105 } else { 1106 return NULL; 1107 } 1108 #endif /* !FTS_WITH_ALLOC_CACHE */ 1109 1110 /* Copy the names and guarantee NUL termination. */ 1111 p->fts_wcsname = (wchar_t *)(p + 1); 1112 memcpy(p->fts_wcsname, wcsname, cwcname * sizeof(wchar_t)); 1113 p->fts_wcsname[cwcname] = '\0'; 1114 p->fts_cwcname = cwcname; 1115 if (!(sp->fts_options & FTS_NO_ANSI)) { 1116 p->fts_name = (char *)(p->fts_wcsname + cwcname + 1); 1117 memcpy(p->fts_name, name, namelen); 1118 p->fts_name[namelen] = '\0'; 1119 p->fts_namelen = namelen; 1120 } else { 1121 p->fts_name = NULL; 1122 p->fts_namelen = 0; 1123 } 1124 1125 p->fts_path = sp->fts_path; 1126 p->fts_wcspath = sp->fts_wcspath; 1127 p->fts_statp = &p->fts_stat; 1128 p->fts_errno = 0; 1129 p->fts_flags = 0; 1130 p->fts_instr = FTS_NOINSTR; 1131 p->fts_number = 0; 1132 p->fts_pointer = NULL; 1133 p->fts_fts = sp; 1134 p->fts_dirfd = INVALID_HANDLE_VALUE; 1027 1135 return (p); 1028 1136 } … … 1068 1176 * @returns Pointer to allocated and mostly initialized FTSENT structure on 1069 1177 * success. NULL on failure, caller needs to record it. 1070 * @param sp Pointer to FTS instance.1178 * @param sp Pointer to the FTS instance. 1071 1179 * @param wcsname The UTF-16 name. 1072 1180 * @param cwcname The UTF-16 name length. … … 1099 1207 } 1100 1208 return pRet; 1209 } 1210 1211 1212 /** 1213 * Frees up the FTSENT allocation cache. 1214 * 1215 * Used by nt_fts_close, but also called by fts_alloc on alloc failure. 1216 * 1217 * @param sp Pointer to the FTS instance. 1218 */ 1219 static void nt_fts_free_alloc_cache(FTS *sp) 1220 { 1221 #ifdef FTS_WITH_ALLOC_CACHE 1222 struct _fts_private *priv = (struct _fts_private *)sp; 1223 unsigned i = K_ELEMENTS(priv->freebuckets); 1224 while (i-- > 0) { 1225 FTSENT *cur = priv->freebuckets[i].head; 1226 priv->freebuckets[i].head = NULL; 1227 while (cur) { 1228 FTSENT *freeit = cur; 1229 cur = cur->fts_link; 1230 free(freeit); 1231 } 1232 } 1233 priv->numfree = 0; 1234 #else 1235 (void)sp; 1236 #endif 1101 1237 } 1102 1238
Note:
See TracChangeset
for help on using the changeset viewer.