Annotation of coherent/b/STREAMS/conf/streams/src/kmem.c, revision 1.1

1.1     ! root        1: #define        _DDI_DKI        1
        !             2: #define        _SYSV4          1
        !             3: 
        !             4: /*
        !             5:  * STREAMS memory management code.
        !             6:  *
        !             7:  * This is layered on top of the fast first-fit heap allocator whose
        !             8:  * implementation is described in <sys/st_alloc.h>. The particulars of how
        !             9:  * STREAMS memory is allocated (including synchronisation and watermarks)
        !            10:  * is kept here so that the generic allocator is just that, generic.
        !            11:  */
        !            12: 
        !            13: /*
        !            14:  *-IMPORTS:
        !            15:  *     <common/ccompat.h>
        !            16:  *             __USE_PROTO__
        !            17:  *             __ARGS ()
        !            18:  *     <common/ccompat.h>
        !            19:  *             __LOCAL__
        !            20:  *     <sys/debug.h>
        !            21:  *             ASSERT ()
        !            22:  *     <sys/types.h>
        !            23:  *             _VOID
        !            24:  *             size_t
        !            25:  *     <sys/ksynch.h>
        !            26:  *             lock_t
        !            27:  *             LOCK_ALLOC ()
        !            28:  *             LOCK ()
        !            29:  *             UNLOCK ()
        !            30:  *     <sys/cmn_err.h>
        !            31:  *             CE_WARN
        !            32:  *             cmn_err ()
        !            33:  */
        !            34: 
        !            35: #include <common/ccompat.h>
        !            36: #include <kernel/ddi_lock.h>
        !            37: #include <sys/types.h>
        !            38: #include <sys/debug.h>
        !            39: #include <sys/ksynch.h>
        !            40: #include <sys/cmn_err.h>
        !            41: 
        !            42: #include <sys/kmem.h>
        !            43: #include <kernel/strmlib.h>
        !            44: #include <string.h>
        !            45: 
        !            46: 
        !            47: /*
        !            48:  * Number of segments in the streams memory heap.
        !            49:  *
        !            50:  * For now, we'll just specify 256 segments, but this should probably be based
        !            51:  * on the log of the total number of words available.
        !            52:  */
        !            53: 
        !            54: enum { str_segments = 256 };
        !            55: 
        !            56: 
        !            57: /*
        !            58:  * Here we'll define the actual instance of the streams memory control
        !            59:  * structure.
        !            60:  */
        !            61: 
        !            62: struct streams_mem str_mem [1];
        !            63: 
        !            64: 
        !            65: /*
        !            66:  * We need to define information structures for the various locks and
        !            67:  * synchronization variables used in the above.
        !            68:  */
        !            69: 
        !            70: __LOCAL__ lkinfo_t _stream_heap_lkinfo = {
        !            71:        "STREAMS message memory lock", INTERNAL_LOCK
        !            72: };
        !            73: 
        !            74: __LOCAL__ lkinfo_t _stream_seq_lkinfo = {
        !            75:        "STREAMS log sequence-number lock", INTERNAL_LOCK
        !            76: };
        !            77: 
        !            78: __LOCAL__ lkinfo_t _stream_proc_lkinfo = {
        !            79:        "STREAMS qprocsoff () lock", INTERNAL_LOCK
        !            80: };
        !            81: 
        !            82: __LOCAL__ lkinfo_t _stream_dir_lkinfo = {
        !            83:        "STREAM directory read/write lock", INTERNAL_LOCK
        !            84: };
        !            85: 
        !            86: 
        !            87: /*
        !            88:  *-STATUS:
        !            89:  *     DDI/DKI
        !            90:  *
        !            91:  *-NAME:
        !            92:  *     kmem_alloc ()   Allocate space from kernel free memory.
        !            93:  *
        !            94:  *-SYNOPSIS:
        !            95:  *     #include <sys/types.h>
        !            96:  *     #include <sys/kmem.h>
        !            97:  *
        !            98:  *     void * kmem_alloc (size_t size, int flag);
        !            99:  *
        !           100:  *-ARGUMENTS:
        !           101:  *     size            Number of bytes to allocate.
        !           102:  *
        !           103:  *     flag            Specifies whether the caller is willing to sleep
        !           104:  *                     waiting for memory. If "flag" is set to KM_SLEEP, the
        !           105:  *                     caller will sleep if necessary until the specified
        !           106:  *                     amount of memory is available. If "flag" is set to
        !           107:  *                     KM_NOSLEEP, the caller will not sleep, but
        !           108:  *                     kmem_alloc () will return NULL if the specified amount
        !           109:  *                     of memory is not immediately available.
        !           110:  *
        !           111:  *-DESCRIPTION:
        !           112:  *     kmem_alloc () allocates "size" bytes of kernel memory and returns a
        !           113:  *     pointer to the allocated memory.
        !           114:  *
        !           115:  *-RETURN VALUE:
        !           116:  *     Upon successful completion, kmem_alloc () returns a pointer to the
        !           117:  *     allocated memory. If KM_NOSLEEP is specified and sufficient memory is
        !           118:  *     not immediately available, kmem_alloc () returns a NULL pointer. If
        !           119:  *     "size" is set to 0, kmem_alloc () always returns NULL regardless of
        !           120:  *     the value of "flag".
        !           121:  *
        !           122:  *-LEVEL:
        !           123:  *     Base only if "flag" is set to KM_SLEEP. Base or interrupt if "flag" is
        !           124:  *     set to KM_NOSLEEP.
        !           125:  *
        !           126:  *-NOTES:
        !           127:  *     May sleep if "flag" is set to KM_SLEEP.
        !           128:  *
        !           129:  *     Driver-defined basic locks and read/write locks may be held across
        !           130:  *     calls to this function if "flag" is KM_NOSLEEP but may not be held if
        !           131:  *     "flag" is KM_SLEEP.
        !           132:  *
        !           133:  *     Driver-defined sleep locks may be held across calls to this function
        !           134:  *     regardless of the value of "flag".
        !           135:  *
        !           136:  *     Kernel memory is a limited resource and should be used judiciously.
        !           137:  *     Memory allocated using kmem_alloc () should be freed as soon as
        !           138:  *     possible. Drivers should not use local freelists for memory or similar
        !           139:  *     schemes that cause the memory to be held for longer than necessary.
        !           140:  *
        !           141:  *     The address returned by a successful call to kmem_alloc () is word-
        !           142:  *     aligned.
        !           143:  *
        !           144:  *-SEE ALSO:
        !           145:  *     kmem_free (), kmem_zalloc ()
        !           146:  */
        !           147: 
        !           148: #if    __USE_PROTO__
        !           149: _VOID * (kmem_alloc) (size_t size, int flag)
        !           150: #else
        !           151: _VOID *
        !           152: kmem_alloc __ARGS ((size, flag))
        !           153: size_t         size;
        !           154: int            flag;
        !           155: #endif
        !           156: {
        !           157:        _VOID         * mem;
        !           158:        pl_t            prev_pl;
        !           159: 
        !           160:        ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
        !           161: 
        !           162:        ASSERT (ATOMIC_FETCH_UCHAR (str_mem->sm_init) ||
        !           163:                str_mem->sm_other_lock != NULL);
        !           164: 
        !           165:        if (size == 0)
        !           166:                return NULL;
        !           167: 
        !           168:        for (;;) {
        !           169:                /*
        !           170:                 * Lock the basic lock protecting access to the memory pool
        !           171:                 * and attempt to acquire the memory we desire.
        !           172:                 */
        !           173: 
        !           174:                if (str_mem->sm_other_lock != NULL)
        !           175:                        prev_pl = LOCK (str_mem->sm_other_lock, str_other_pl);
        !           176: 
        !           177:                if ((mem = st_alloc (str_mem->sm_other_heap, size)) != NULL ||
        !           178:                    flag == KM_NOSLEEP) {
        !           179:                        OTHER_ALLOCED (size);
        !           180:                        break;
        !           181:                }
        !           182: 
        !           183:                /*
        !           184:                 * Since we cannot acquire the memory, but the caller is
        !           185:                 * willing to wait, we wait on a synchronization variable
        !           186:                 * for sufficient memory to be available. We record the
        !           187:                 * minimum amount that will satisfy any outstanding wait so
        !           188:                 * that kmem_free () need not perform broadcasts in a
        !           189:                 * totally needless fashion.
        !           190:                 *
        !           191:                 * We have arbitrarily chosen a low scheduling priority for
        !           192:                 * SV_WAIT ().
        !           193:                 */
        !           194:                /*
        !           195:                 * RESEARCH NOTE: This policy is a guess, no more. We need to
        !           196:                 * do some profiling to find out what effect other policies
        !           197:                 * might have. In particular, the wakeup heuristic could be
        !           198:                 * altered to broadcast when we can satisfy the largest
        !           199:                 * request.
        !           200:                 */
        !           201: 
        !           202:                if (str_mem->sm_other_needed == 0 ||
        !           203:                    str_mem->sm_other_needed > size)
        !           204:                        str_mem->sm_other_needed = size;
        !           205: 
        !           206:                SV_WAIT (str_mem->sm_other_sv, prilo, str_mem->sm_other_lock);
        !           207:        }
        !           208: 
        !           209:        if (str_mem->sm_other_lock != NULL)
        !           210:                UNLOCK (str_mem->sm_other_lock, prev_pl);
        !           211: 
        !           212:        return mem;
        !           213: }
        !           214: 
        !           215: 
        !           216: 
        !           217: /*
        !           218:  *-STATUS:
        !           219:  *     DDI/DKI
        !           220:  *
        !           221:  *-NAME:
        !           222:  *     kmem_free ()    Free previously allocated kernel memory.
        !           223:  *
        !           224:  *-SYNOPSIS:
        !           225:  *     #include <sys/types.h>
        !           226:  *     #include <sys/kmem.h>
        !           227:  *
        !           228:  *     void kmem_free (void * addr, size_t size);
        !           229:  *
        !           230:  *-ARGUMENTS:
        !           231:  *     addr            Address of the allocated memory to be returned. "addr"
        !           232:  *                     must specify the same address that was returned by the
        !           233:  *                     corresponding call to kmem_alloc () or kmem_zalloc ()
        !           234:  *                     which allocated the memory.
        !           235:  *
        !           236:  *     size            Number of bytes to free. The "size" parameter must
        !           237:  *                     specify the same number of bytes as was allocated by
        !           238:  *                     the corresponding call to kmem_alloc () or\
        !           239:  *                     kmem_zalloc ().
        !           240:  *
        !           241:  *-DESCRIPTION:
        !           242:  *     kmem_free () returns "size" bytes of previously allocated kernel
        !           243:  *     memory to the free pool. The "addr" and "size" arguments must specify
        !           244:  *     exactly one complete area of memory that was allocated by a call to
        !           245:  *     kmem_alloc () or kmem_zalloc () (that is, the memory cannot be freed
        !           246:  *     piecemeal).
        !           247:  *
        !           248:  *-RETURN VALUE:
        !           249:  *     None.
        !           250:  *
        !           251:  *-LEVEL:
        !           252:  *     Base or Interrupt.
        !           253:  *
        !           254:  *-NOTES:
        !           255:  *     Does not sleep.
        !           256:  *
        !           257:  *     Driver-defined basic locks, read/write locks and sleep locks may be
        !           258:  *     held across calls to this function.
        !           259:  *
        !           260:  *-SEE ALSO:
        !           261:  *     kmem_alloc (), kmem_zalloc ()
        !           262:  */
        !           263: 
        !           264: #if    __USE_PROTO__
        !           265: void (kmem_free) (_VOID * addr, size_t size)
        !           266: #else
        !           267: void
        !           268: kmem_free __ARGS ((addr, size))
        !           269: _VOID        * addr;
        !           270: size_t         size;
        !           271: #endif
        !           272: {
        !           273:        pl_t            prev_pl;
        !           274:        int             free_ok;
        !           275: 
        !           276:        ASSERT (addr != NULL);
        !           277:        ASSERT (size > 0);
        !           278: 
        !           279:        ASSERT (ATOMIC_FETCH_UCHAR (str_mem->sm_init) ||
        !           280:                str_mem->sm_other_lock != NULL);
        !           281: 
        !           282:        /*
        !           283:         * Acquire the basic lock protecting access to the memory and free
        !           284:         * the caller's area. If there are processes waiting on memory
        !           285:         * becoming available, wake them up via a synchronization variable
        !           286:         * broadcast.
        !           287:         */
        !           288: 
        !           289:        if (str_mem->sm_other_lock != NULL)
        !           290:                prev_pl = LOCK (str_mem->sm_other_lock, str_other_pl);
        !           291: 
        !           292:        OTHER_FREED (size);
        !           293: 
        !           294:        free_ok = st_free (str_mem->sm_other_heap, addr, size);
        !           295: 
        !           296:        if (str_mem->sm_other_needed > 0 &&
        !           297:            str_mem->sm_other_needed <= st_maxavail (str_mem->sm_other_heap)) {
        !           298:                /*
        !           299:                 * Wake up *all* the waiting processes and clear the marker
        !           300:                 * to indicate that there are no waiting processes.
        !           301:                 */
        !           302: 
        !           303:                SV_BROADCAST (str_mem->sm_other_sv, 0);
        !           304:                str_mem->sm_other_needed = 0;
        !           305:        }
        !           306: 
        !           307:        if (str_mem->sm_other_lock != NULL)
        !           308:                UNLOCK (str_mem->sm_other_lock, prev_pl);
        !           309: 
        !           310:        if (free_ok != 0) {
        !           311:                /*
        !           312:                 * The heap manager has a problem with freeing the block that
        !           313:                 * was passed to it, display a console diagnostic. For
        !           314:                 * simplicity we display addresses as longs.
        !           315:                 */
        !           316: 
        !           317:                cmn_err (CE_WARN,
        !           318:                         "kmem_free : st_free () complained with %d freeing %d bytes at %lx",
        !           319:                         free_ok, size, (long) addr);
        !           320:        }
        !           321: }
        !           322: 
        !           323: 
        !           324: 
        !           325: /*
        !           326:  *-STATUS:
        !           327:  *     DDI/DKI
        !           328:  *
        !           329:  *-NAME:
        !           330:  *     kmem_zalloc ()  Allocate and clear space from kernel free memory.
        !           331:  *
        !           332:  *-SYNOPSIS:
        !           333:  *     #include <sys/types.h>
        !           334:  *     #include <sys/kmem.h>
        !           335:  *
        !           336:  *     void * kmem_zalloc (size_t size, int flag);
        !           337:  *
        !           338:  *-ARGUMENTS:
        !           339:  *     size            Number of bytes to allocate.
        !           340:  *
        !           341:  *     flag            Specifies whether the caller is willing to sleep
        !           342:  *                     waiting for memory. If "flag" is set to KM_SLEEP, the
        !           343:  *                     caller will sleep if necessary until the specified
        !           344:  *                     amount of memory is available. If "flag" is set to
        !           345:  *                     KM_NOSLEEP, the caller will not sleep, but
        !           346:  *                     kmem_zalloc () will return NULL if the specified
        !           347:  *                     amount of memory is not immediately available.
        !           348:  *
        !           349:  *-DESCRIPTION:
        !           350:  *     kmem_zalloc () allocates "size" bytes of kernel memory, clears the
        !           351:  *     memory by filling it with zeros, and returns a pointer to the
        !           352:  *     allocated memory.
        !           353:  *
        !           354:  *-RETURN VALUE:
        !           355:  *     Upon successful completion, kmem_zalloc () returns a pointer to the
        !           356:  *     allocated memory. If KM_NOSLEEP is specified and sufficient memory is
        !           357:  *     not immediately available, kmem_zalloc () returns a NULL pointer. If
        !           358:  *     "size" is set to 0, kmem_zalloc () always returns NULL regardless of
        !           359:  *     the value of "flag".
        !           360:  *
        !           361:  *-LEVEL:
        !           362:  *     Base only if "flag" is set to KM_SLEEP. Base or interrupt if "flag" is
        !           363:  *     set to KM_NOSLEEP.
        !           364:  *
        !           365:  *-NOTES:
        !           366:  *     May sleep if "flag" is set to KM_SLEEP.
        !           367:  *
        !           368:  *     Driver-defined basic locks and read/write locks may be held across
        !           369:  *     calls to this function if "flag" is KM_NOSLEEP but may not be held if
        !           370:  *     "flag" is KM_SLEEP.
        !           371:  *
        !           372:  *     Driver-defined sleep locks may be held across calls to this function
        !           373:  *     regardless of the value of "flag".
        !           374:  *
        !           375:  *     Kernel memory is a limited resource and should be used judiciously.
        !           376:  *     Memory allocated using kmem_zalloc () should be freed as soon as
        !           377:  *     possible. Drivers should not use local freelists for memory or similar
        !           378:  *     schemes that cause the memory to be held for longer than necessary.
        !           379:  *
        !           380:  *     The address returned by a successful call to kmem_zalloc () is word-
        !           381:  *     aligned.
        !           382:  *
        !           383:  *-SEE ALSO:
        !           384:  *     kmem_alloc (), kmem_free ()
        !           385:  */
        !           386: 
        !           387: #if    __USE_PROTO__
        !           388: _VOID * (kmem_zalloc) (size_t size, int flag)
        !           389: #else
        !           390: _VOID *
        !           391: kmem_zalloc __ARGS ((size, flag))
        !           392: size_t         size;
        !           393: int            flag;
        !           394: #endif
        !           395: {
        !           396:        _VOID         * mem;
        !           397: 
        !           398:        if ((mem = kmem_alloc (size, flag)) != NULL)
        !           399:                memset (mem, 0, size);
        !           400:        return mem;
        !           401: }
        !           402: 
        !           403: 
        !           404: /*
        !           405:  *-STATUS:
        !           406:  *     Initialisation
        !           407:  *
        !           408:  *-DESCRIPTION:
        !           409:  *     This function initializes the memory subsystem given a region of
        !           410:  *     kernel virtual memory space to manage.
        !           411:  */
        !           412: 
        !           413: __EXTERN_C__
        !           414: #if    __USE_PROTO__
        !           415: int (KMEM_INIT) (_VOID * addr, size_t size)
        !           416: #else
        !           417: int
        !           418: KMEM_INIT __ARGS ((addr, size))
        !           419: _VOID        * addr;
        !           420: size_t         size;
        !           421: #endif
        !           422: {
        !           423:        int             i;
        !           424: 
        !           425:        /*
        !           426:         * We use a test-and-set lock operation on the streams memory
        !           427:         * structure so that the initialisation process is multiprocessor-
        !           428:         * safe. We don't use a basic lock since we don't know whether basic
        !           429:         * locks exist yet.
        !           430:         */
        !           431: 
        !           432:        if (ATOMIC_TEST_AND_SET_UCHAR (str_mem->sm_init) != 0) {
        !           433:                /*
        !           434:                 * Presumably we are on a separate processor waiting for the
        !           435:                 * initialization to be completed by someone else. To make
        !           436:                 * this processor's call to STRMEM_INIT () behave with the
        !           437:                 * right semantics, we wait for the other instance to complete
        !           438:                 * the setup process.
        !           439:                 */
        !           440: 
        !           441:                while (ATOMIC_FETCH_UCHAR (str_mem->sm_init) != 0) {
        !           442: #ifdef __UNIPROCESSOR__
        !           443:                        cmn_err (CE_PANIC, "Init startup deadlock???");
        !           444: #endif
        !           445:                }
        !           446:                return 0;
        !           447:        }
        !           448: 
        !           449:        if (str_mem->sm_other_lock != NULL) {
        !           450:                /*
        !           451:                 * The init has already been done, thanks!
        !           452:                 */
        !           453: 
        !           454:                ATOMIC_CLEAR_UCHAR (str_mem->sm_init);
        !           455:                return 0;
        !           456:        }
        !           457: 
        !           458: #ifdef SPLIT_STREAMS_MEMORY
        !           459: #endif
        !           460: 
        !           461:        /*
        !           462:         * Now initialize the fast-first-fit heap manager.
        !           463:         *
        !           464:         * For now, we'll just specify 256 segments, but this
        !           465:         * should probably be based on the log of the total
        !           466:         * number of words available.
        !           467:         */
        !           468: 
        !           469:        str_mem->sm_msg_heap = (_ST_HEAP_CONTROL_P) addr;
        !           470: 
        !           471:        addr = (_VOID *) ((char *) addr +
        !           472:                          _ST_HEAP_CONTROL_SIZE (str_segments));
        !           473: 
        !           474:        size -= _ST_HEAP_CONTROL_SIZE (str_segments);
        !           475: 
        !           476:        st_ctor (str_mem->sm_msg_heap, str_segments,
        !           477:                 size / sizeof (_ST_WORD_T), (_ST_ADDR_T) addr);
        !           478: 
        !           479:        str_mem->sm_msg_lock =
        !           480:                        LOCK_ALLOC (stream_heap_hierarchy, str_other_pl,
        !           481:                                    & _stream_heap_lkinfo, KM_NOSLEEP);
        !           482: 
        !           483:        str_mem->sm_msg_sv = SV_ALLOC (KM_NOSLEEP);
        !           484: 
        !           485: 
        !           486:        /*
        !           487:         * If either of the above allocations failed, we have some kind of
        !           488:         * major problem, so we exit without unlocking the initialization flag
        !           489:         * with an error indication.
        !           490:         */
        !           491: 
        !           492:        if (str_mem->sm_msg_lock == NULL || str_mem->sm_msg_sv == NULL) {
        !           493: 
        !           494: init_error:
        !           495:                cmn_err (CE_PANIC, "Could not initialize STREAMS subsystem");
        !           496:                return -1;
        !           497:        }
        !           498: 
        !           499: 
        !           500:        /*
        !           501:         * Now we can calculate the watermarks... start at the
        !           502:         * top and make each lower one some percentage of the
        !           503:         * next higher one (say, 15/16 or 93%, so that it's
        !           504:         * easy to calculate).
        !           505:         */
        !           506: 
        !           507:        for (i = N_PRI_LEVELS ; i -- > 0 ;) {
        !           508: 
        !           509:                str_mem->sm_max [i] = size;
        !           510:                size -= size >> 4;      /* - 1/16 */
        !           511:        }
        !           512: 
        !           513: 
        !           514:        /*
        !           515:         * Do other kinds of initialization for the "str_mem" structure.
        !           516:         */
        !           517: 
        !           518:        for (i = N_PRI_LEVELS ; i -- > 0 ; ) {
        !           519: 
        !           520:                if (SELIST_INIT (& str_mem->sm_bcevents [i],
        !           521:                                 KM_SLEEP) == NULL)
        !           522:                        goto init_error;
        !           523:        }
        !           524: 
        !           525: 
        !           526:        str_mem->sm_seq_lock = LOCK_ALLOC (stream_seq_hierarchy, plstr,
        !           527:                                           & _stream_seq_lkinfo, KM_SLEEP);
        !           528: 
        !           529:        str_mem->sm_head_lock = RW_ALLOC (stream_dir_hierarchy, plstr,
        !           530:                                          & _stream_dir_lkinfo, KM_SLEEP);
        !           531: 
        !           532:        str_mem->sm_proc_lock = LOCK_ALLOC (stream_proc_hierarchy, plstr,
        !           533:                                            & _stream_proc_lkinfo, KM_SLEEP);
        !           534: 
        !           535:        str_mem->sm_proc_sv = SV_ALLOC (KM_SLEEP);
        !           536: 
        !           537:        if (SCHED_INIT (str_mem->sm_sched, KM_SLEEP) == NULL ||
        !           538:            str_mem->sm_seq_lock == NULL || str_mem->sm_head_lock == NULL ||
        !           539:            str_mem->sm_proc_lock == NULL || str_mem->sm_proc_sv == NULL)
        !           540:                goto init_error;
        !           541: 
        !           542:        /*
        !           543:         * All OK, let other CPUs proceed and return success to the caller.
        !           544:         */
        !           545: 
        !           546:        ATOMIC_CLEAR_UCHAR (str_mem->sm_init);
        !           547:        return 0;               /* all OK */
        !           548: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.