Ignore:
Timestamp:
Sep 14, 2020, 7:34:28 PM (5 years ago)
Author:
bird
Message:

kash: New parser allocator for non-forked-mode.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kash/memalloc.c

    r3456 r3457  
    4242
    4343#include <stdlib.h>
     44#include <stddef.h>
    4445#include <assert.h>
    4546
     
    183184        mark->stacknleft = psh->stacknleft;
    184185        mark->marknext = psh->markp;
     186#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     187        mark->pstacksize = psh->pstacksize;
     188#endif
    185189        psh->markp = mark;
    186190}
     
    201205        psh->stacknxt = mark->stacknxt;
    202206        psh->stacknleft = mark->stacknleft;
     207
     208#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     209        assert(mark->pstacksize <= psh->pstacksize);
     210        while (mark->pstacksize < psh->pstacksize) {
     211                unsigned idx = --psh->pstacksize;
     212                pstack_block *psk = psh->pstack[idx];
     213                psh->pstack[idx] = NULL;
     214                if (psh->curpstack == psk)
     215                    psh->curpstack = idx > 0 ? psh->pstack[idx - 1] : NULL;
     216                pstackrelease(psh, psk);
     217        }
     218
     219# ifndef NDEBUG
     220        if (psh->curpstack) {
     221                unsigned i;
     222                for (i = 0; i < psh->pstacksize; i++)
     223                        if (psh->curpstack == psh->pstack[i])
     224                                break;
     225                assert(i < psh->pstacksize);
     226        }
     227# endif
     228#endif
    203229        INTON;
    204230}
     
    354380 * Parser stack allocator.
    355381 */
     382#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     383
     384unsigned pstackretain(pstack_block *pst)
     385{
     386        unsigned refs = sh_atomic_inc(&pst->refs);
     387        assert(refs > 1);
     388        assert(refs < 256 /* bogus, but useful */);
     389        return refs;
     390}
     391
     392unsigned pstackrelease(shinstance *psh, pstack_block *pst)
     393{
     394        unsigned refs;
     395        if (pst) {
     396                refs = sh_atomic_dec(&pst->refs);
     397                if (refs == 0) {
     398                        shinstance * const psh = shthread_get_shell();
     399                        struct stack_block *top;
     400                        while ((top = pst->top) != &pst->first)
     401                        {
     402                            pst->top = top->prev;
     403                            assert(pst->top);
     404                            top->prev = NULL;
     405                            sh_free(psh, top);
     406                        }
     407                        pst->nextbyte = NULL;
     408                        pst->top = NULL;
     409                        sh_free(psh, pst);
     410                }
     411        } else
     412                refs = 0;
     413        return refs;
     414}
     415
     416pstack_block *pstackpush(shinstance *psh)
     417{
     418        size_t const blocksize = offsetof(pstack_block, first.space) + MINSIZE;
     419        pstack_block *pst;
     420        unsigned i;
     421
     422        INTOFF;
     423
     424        /*
     425         * Allocate and initialize it.
     426         */
     427        pst = (pstack_block *)ckmalloc(psh, blocksize);
     428        pst->nextbyte          = &pst->first.space[0];
     429        pst->avail             = blocksize - offsetof(pstack_block, first.space);
     430        pst->topsize           = blocksize - offsetof(pstack_block, first.space);
     431        pst->strleft           = 0;
     432        pst->top               = &pst->first;
     433        pst->allocations       = 0;
     434        pst->bytesalloced      = 0;
     435        pst->nodesalloced      = 0;
     436        pst->entriesalloced    = 0;
     437        pst->strbytesalloced   = 0;
     438        pst->blocks            = 0;
     439        pst->fragmentation     = 0;
     440        pst->refs              = 1;
     441        pst->padding           = 42;
     442        pst->first.prev        = NULL;
     443
     444        /*
     445         * Push it onto the stack.
     446         */
     447        i = psh->pstacksize;
     448        if (i + 1 < psh->pstackalloced) {
     449                /* likely, except for the first time */
     450        } else {
     451                psh->pstack = (pstack_block **)ckrealloc(psh, psh->pstack, sizeof(psh->pstack[0]) * (i + 32));
     452                memset(&psh->pstack[i], 0, sizeof(psh->pstack[0]) * 32);
     453        }
     454        psh->pstack[i] = pst;
     455        psh->pstacksize = i + 1;
     456        psh->curpstack = pst;
     457
     458        INTON;
     459        return pst;
     460}
     461
     462/**
     463 * Allocates and pushes a new block onto the stack, min payload size @a nbytes.
     464 */
     465static void pstallocnewblock(shinstance *psh, pstack_block *pst, size_t nbytes)
     466{
     467        /* Allocate a new stack node. */
     468        struct stack_block *sp;
     469        size_t const blocksize = nbytes <= MINSIZE
     470                               ? offsetof(struct stack_block, space) + MINSIZE
     471                               : K_ALIGN_Z(nbytes + offsetof(struct stack_block, space), 1024);
     472
     473        INTOFF;
     474        sp = ckmalloc(psh, blocksize);
     475        sp->prev = pst->top;
     476        pst->fragmentation += pst->avail;
     477        pst->topsize        = blocksize - offsetof(struct stack_block, space);
     478        pst->avail          = blocksize - offsetof(struct stack_block, space);
     479        pst->nextbyte       = sp->space;
     480        pst->top            = sp;
     481        pst->blocks        += 1;
     482        INTON;
     483}
     484
     485/**
     486 * Tries to grow the current stack block to hold a minimum of @a nbytes,
     487 * will allocate a new block and copy over pending string bytes if that's not
     488 * possible.
     489 */
     490static void pstgrowblock(shinstance *psh, pstack_block *pst, size_t nbytes, size_t tocopy)
     491{
     492        struct stack_block *top = pst->top;
     493        size_t blocksize;
     494
     495        assert(pst->avail < nbytes); /* only called when we need more space */
     496        assert(tocopy <= pst->avail);
     497
     498        /* Double the size used thus far and add some fudge and alignment.  Make
     499           sure to at least allocate MINSIZE. */
     500        blocksize = K_MAX(K_ALIGN_Z(pst->avail * 2 + 100 + offsetof(struct stack_block, space), 64), MINSIZE);
     501
     502        /* If that isn't sufficient, do request size w/ some fudge and alignment. */
     503        if (blocksize < nbytes + offsetof(struct stack_block, space))
     504            blocksize = K_ALIGN_Z(nbytes + offsetof(struct stack_block, space) + 100, 1024);
     505
     506        /*
     507         * Reallocate the current stack node if we can.
     508         */
     509        if (   pst->nextbyte == &top->space[0] /* can't have anything else in the block */
     510            && top->prev != NULL /* first block is embedded in pst and cannot be reallocated */ ) {
     511                top = (struct stack_block *)ckrealloc(psh, top, blocksize);
     512                pst->top      = top;
     513                pst->topsize  = blocksize - offsetof(struct stack_block, space);
     514                pst->avail    = blocksize - offsetof(struct stack_block, space);
     515                pst->nextbyte = top->space;
     516        }
     517        /*
     518         * Otherwise allocate a new node and copy over the avail bytes
     519         * from the old one.
     520         */
     521        else {
     522                char const * const copysrc = pst->nextbyte;
     523                pstallocnewblock(psh, pst, nbytes);
     524                assert(pst->avail >= nbytes);
     525                assert(pst->avail >= tocopy);
     526                memcpy(pst->nextbyte, copysrc, tocopy);
     527        }
     528}
     529
     530K_INLINE void *pstallocint(shinstance *psh, pstack_block *pst, size_t nbytes)
     531{
     532        void *ret;
     533
     534        /*
     535         * Align the size and make sure we've got sufficient bytes available:
     536         */
     537        nbytes = SHELL_ALIGN(nbytes);
     538        if (pst->avail >= nbytes && (ssize_t)pst->avail >= 0) { /* likely*/ }
     539        else pstallocnewblock(psh, pst, nbytes);
     540
     541        /*
     542         * Carve out the return block.
     543         */
     544        ret = pst->nextbyte;
     545        pst->nextbyte     += nbytes;
     546        pst->avail        -= nbytes;
     547        pst->bytesalloced += nbytes;
     548        pst->allocations  += 1;
     549        return ret;
     550}
     551
     552#endif KASH_SEPARATE_PARSER_ALLOCATOR
     553
     554
    356555void *pstalloc(struct shinstance *psh, size_t nbytes)
    357556{
     557#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     558        return pstallocint(psh, psh->curpstack, nbytes);
     559#else
    358560        return stalloc(psh, nbytes);
     561#endif
    359562}
    360563
    361564union node *pstallocnode(struct shinstance *psh, size_t nbytes)
    362565{
     566#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     567        pstack_block *pst = psh->curpstack;
     568        pst->nodesalloced++;
     569        return (union node *)pstallocint(psh, pst, nbytes);
     570#else
    363571        return (union node *)pstalloc(psh, nbytes);
     572#endif
    364573}
    365574
    366575struct nodelist *pstalloclist(struct shinstance *psh)
    367576{
     577#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     578        pstack_block *pst = psh->curpstack;
     579        pst->entriesalloced++;
     580        return (struct nodelist *)pstallocint(psh, pst, sizeof(struct nodelist));
     581#endif
    368582        return (struct nodelist *)pstalloc(psh, sizeof(struct nodelist));
    369583}
     
    372586{
    373587        if (str) {
    374                 size_t nbytes = strlen(str) + 1;
     588                size_t const nbytes = strlen(str) + 1;
     589#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     590                pstack_block *pst = psh->curpstack;
     591                pst->strbytesalloced += SHELL_ALIGN(nbytes);
     592                return (char *)memcpy(pstallocint(psh, pst, nbytes), str, nbytes);
     593#else
    375594                return (char *)memcpy(pstalloc(psh, nbytes), str, nbytes);
     595#endif
    376596        }
    377597        return NULL;
     
    380600char *pstmakestrspace(struct shinstance *psh, size_t minbytes, char *end)
    381601{
     602#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     603        pstack_block *pst = psh->curpstack;
     604        size_t const len = end - pst->nextbyte;
     605
     606        assert(pst->avail - pst->strleft == len);
     607        TRACE2((psh, "pstmakestrspace: len=%u minbytes=%u (=> %u)\n", len, minbytes, len + minbytes));
     608
     609        pstgrowblock(psh, pst, minbytes + len, len);
     610
     611        pst->strleft = pst->avail - len;
     612        return pst->nextbyte + len;
     613
     614#else
    382615        size_t const len = end - stackblock(psh);
     616
    383617        assert(stackblocksize(psh) - psh->sstrnleft == len);
    384 TRACE2((psh, "pstmakestrspace: len=%u minbytes=%u (=> %u)\n", len, minbytes, len + minbytes));
     618        TRACE2((psh, "pstmakestrspace: len=%u minbytes=%u (=> %u)\n", len, minbytes, len + minbytes));
     619
    385620        minbytes += len;
    386621        while (stackblocksize(psh) < minbytes)
    387622                growstackblock(psh);
     623
    388624        psh->sstrnleft = (int)(stackblocksize(psh) - len);
    389625        return (char *)stackblock(psh) + len;
     626#endif
    390627}
    391628
     
    393630char *pstputcgrow(shinstance *psh, char *end, char c)
    394631{
    395         psh->sstrnleft++; /* PSTPUTC() already incremented it. */
     632#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     633        pstack_block *pst = psh->curpstack;
     634        pst->strleft++;         /* PSTPUTC() already incremented it. */
     635        end = pstmakestrspace(psh, 1, end);
     636        assert(pst->strleft > 0);
     637        pst->strleft--;
     638#else
     639        psh->sstrnleft++;       /* PSTPUTC() already incremented it. */
    396640        end = pstmakestrspace(psh, 1, end);
    397641        assert(psh->sstrnleft > 0);
    398642        psh->sstrnleft--;
     643#endif
    399644        *end++ = c;
    400645        return end;
     
    404649char *pstgrabstr(struct shinstance *psh, char *end)
    405650{
     651#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
     652        pstack_block *pst = psh->curpstack;
     653        char * const pstart = pst->nextbyte;
     654        size_t nbytes = (size_t)(end - pstart);
     655
     656        assert((uintptr_t)end > (uintptr_t)pstart);
     657        assert(end[-1] == '\0');
     658        assert(SHELL_ALIGN((uintptr_t)pstart) == (uintptr_t)pstart);
     659        assert(pst->avail - pst->strleft >= nbytes);
     660
     661        nbytes = SHELL_ALIGN(nbytes); /** @todo don't align strings, align the other allocations. */
     662        pst->nextbyte += nbytes;
     663        pst->avail    -= nbytes;
     664        pst->strbytesalloced += nbytes;
     665
     666        return pstart;
     667
     668#else
    406669        char * const pstart = stackblock(psh);
    407670        size_t nbytes = (size_t)(end - pstart);
     
    417680
    418681        return pstart;
    419 }
    420 
     682#endif
     683}
     684
Note: See TracChangeset for help on using the changeset viewer.