Annotation of coherent/b/STREAMS/conf/streams/src/kmem.c, revision 1.1.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.