Ignore:
Timestamp:
Nov 6, 2016, 12:18:51 AM (9 years ago)
Author:
bird
Message:

fts-nt.c: Wide char support, part 3.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/lib/nt/fts-nt.c

    r3002 r3004  
    9090static FTSENT   *fts_alloc_ansi(FTS *sp, char const *name, size_t namelen);
    9191static FTSENT   *fts_alloc_utf16(FTS *sp, wchar_t const *wcsname, size_t cwcname);
     92static void      nt_fts_free_alloc_cache(FTS *sp);
    9293static FTSENT   *fts_build(FTS *, int);
    9394static void      fts_lfree(FTSENT *);
     
    117118#define MAX(a, b)  ( (a) >= (b) ? (a) : (b) )
    118119
    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
    120129
    121130/*
     
    126135struct _fts_private {
    127136        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
    128152};
    129153
     
    338362}
    339363
     364
    340365int FTSCALL
    341366nt_fts_close(FTS *sp)
     
    365390        free(sp->fts_path);
    366391        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);
    367405
    368406        /* Free up the stream pointer. */
     
    371409}
    372410
     411
     412/**
     413 * Frees a FTSENT structure by way of the allocation cache.
     414 */
     415static void
     416fts_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
    373449/*
    374450 * Special case of "/" at the end of the path so that slashes aren't
     
    377453#define NAPPEND(p)  ( p->fts_pathlen - (p->fts_path[p->fts_pathlen - 1]    ==  '/') )
    378454#define NAPPENDW(p) ( p->fts_cwcpath - (p->fts_wcspath[p->fts_cwcpath - 1] == L'/') )
    379 
    380 static void
    381 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 }
    391455
    392456FTSENT * FTSCALL
     
    420484         * pointer, follow fails.
    421485         *
    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.
    425488         */
    426489        if (instr == FTS_FOLLOW &&
     
    428491                p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE);
    429492                if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) {
    430                         p->fts_symfd = FTS_NT_DUMMY_SYMFD_VALUE;
    431493                        p->fts_flags |= FTS_SYMFOLLOW;
    432494                }
     
    439501                if (instr == FTS_SKIP ||
    440502                    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
    441                         if (p->fts_flags & FTS_SYMFOLLOW) {
    442                                 p->fts_symfd = INVALID_HANDLE_VALUE;
    443                         }
    444503                        if (sp->fts_child) {
    445504                                fts_lfree(sp->fts_child);
     
    489548                 */
    490549                if (p->fts_level == FTS_ROOTLEVEL) {
    491                         fts_free_entry(tmp);
     550                        fts_free_entry(sp, tmp);
    492551                        fts_load(sp, p);
    493552                        return (sp->fts_cur = p);
     
    500559                 */
    501560                if (p->fts_instr == FTS_SKIP) {
    502                         fts_free_entry(tmp);
     561                        fts_free_entry(sp, tmp);
    503562                        goto next;
    504563                }
    505564                if (p->fts_instr == FTS_FOLLOW) {
    506565                        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) {
    510568                                p->fts_flags |= FTS_SYMFOLLOW;
    511569                        }
     
    513571                }
    514572
    515                 fts_free_entry(tmp);
     573                fts_free_entry(sp, tmp);
    516574
    517575name:
     
    535593                 * can distinguish between error and EOF.
    536594                 */
    537                 fts_free_entry(tmp);
    538                 fts_free_entry(p);
     595                fts_free_entry(sp, tmp);
     596                fts_free_entry(sp, p);
    539597                errno = 0;
    540598                return (sp->fts_cur = NULL);
     
    551609         * one directory.
    552610         *
    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         */
    558613        if (p->fts_dirfd != INVALID_HANDLE_VALUE) {
    559614                birdCloseFile(p->fts_dirfd);
    560615                p->fts_dirfd = INVALID_HANDLE_VALUE;
    561616        }
    562         fts_free_entry(tmp);
     617        fts_free_entry(sp, tmp);
    563618        p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
    564619        return (sp->fts_cur = p);
     
    685740fts_build(FTS *sp, int type)
    686741{
    687         BirdDirEntry_T *dp;
    688         FTSENT *p, *head;
    689         FTSENT *cur, *tail;
     742        BirdDirEntryW_T *dp;
     743        FTSENT *p, *head, *cur, **tailp;
    690744        DIR *dirp;
    691745        int saved_errno, doadjust, doadjust_utf16;
     
    751805         */
    752806        if (sp->fts_options & FTS_NO_ANSI) {
    753                 len = maxlen = 0;
     807                len = 0;
     808                maxlen = 0x10000;
    754809        } else {
    755810                len = NAPPEND(cur);
     
    766821        /* Read the directory, attaching each entry to the `link' pointer. */
    767822        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 {
    770830                        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 {
    773836                        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 {
    777843                        void *oldaddr = sp->fts_path;
    778844                        wchar_t *oldwcspath = sp->fts_wcspath;
    779845                        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)) {
     848mem1:
    782849                                /*
    783850                                 * No more memory for path or structures.  Save
     
    785852                                 * structures already allocated.
    786853                                 */
    787 mem1:                           saved_errno = errno;
     854                                saved_errno = errno;
    788855                                if (p)
    789856                                        free(p);
     
    815882                /* We walk in directory order so "ls -f" doesn't get upset. */
    816883                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;
    823886                ++nitems;
    824887        }
     
    910973                p->fts_nlink = sbp->st_nlink;
    911974
    912                 if (ISDOT(p->fts_name))
     975                if (ISDOT(p->fts_wcsname))
    913976                        return (FTS_DOT);
    914977
     
    9861049fts_alloc(FTS *sp, char const *name, size_t namelen, wchar_t const *wcsname, size_t cwcname)
    9871050{
     1051        struct _fts_private *priv = (struct _fts_private *)sp;
    9881052        FTSENT *p;
    9891053        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
    9911062        /*
    9921063         * The file name is a variable length array.  Allocate the FTSENT
     
    9961067        if (!(sp->fts_options & FTS_NO_ANSI))
    9971068                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 */
    9981102        p = malloc(len);
    9991103        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;
    10271135        return (p);
    10281136}
     
    10681176 * @returns Pointer to allocated and mostly initialized FTSENT structure on
    10691177 *          success.  NULL on failure, caller needs to record it.
    1070  * @param   sp                  Pointer to FTS instance.
     1178 * @param   sp                  Pointer to the FTS instance.
    10711179 * @param   wcsname             The UTF-16 name.
    10721180 * @param   cwcname             The UTF-16 name length.
     
    10991207        }
    11001208        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 */
     1219static 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
    11011237}
    11021238
Note: See TracChangeset for help on using the changeset viewer.