|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.