|
|
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: * This local function gathers some of the aspects of streams message memory ! 89: * allocation into a single place (message blocks are allocated in allocb (), ! 90: * dupb (), and esballoc ()). We leave the initialization of the newly ! 91: * allocated memory up to the caller. ! 92: */ ! 93: ! 94: #if __USE_PROTO__ ! 95: mblk_t * (STRMEM_ALLOC) (size_t size, int pri, int flag) ! 96: #else ! 97: mblk_t * ! 98: STRMEM_ALLOC __ARGS ((size, pri, flag)) ! 99: size_t size; ! 100: int pri; ! 101: int flag; ! 102: #endif ! 103: { ! 104: pl_t prev_pl; ! 105: mblk_t * mblkp; ! 106: ! 107: ASSERT (size > 0); ! 108: ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP); ! 109: ! 110: /* ! 111: * Note that if the size is one such that it cannot possibly ever be ! 112: * satisfied given the allocation watermarks we have set, then we just ! 113: * return failure now. ! 114: */ ! 115: ! 116: pri = MAP_PRI_LEVEL (pri); ! 117: ! 118: if (size > str_mem->sm_max [pri]) ! 119: return NULL; ! 120: ! 121: ! 122: for (;;) { ! 123: /* ! 124: * Lock the basic lock protecting access to the memory pool ! 125: * and attempt to acquire the memory we desire. ! 126: */ ! 127: ! 128: prev_pl = LOCK (str_mem->sm_msg_lock, str_msg_pl); ! 129: ! 130: ! 131: /* ! 132: * Before allocating any memory, we check to see that it makes ! 133: * sense to give out that memory to the given priority level. ! 134: */ ! 135: ! 136: if (str_mem->sm_used + size <= str_mem->sm_max [pri]) { ! 137: /* ! 138: * Try to get the memory, and if we do update the ! 139: * priority bookkeeping information to record the ! 140: * amount of memory that we have allowed out. ! 141: */ ! 142: ! 143: mblkp = (mblk_t *) st_alloc (str_mem->sm_msg_heap, ! 144: size); ! 145: ! 146: if (mblkp != NULL) { ! 147: ! 148: str_mem->sm_used += size; ! 149: break; ! 150: } ! 151: } ! 152: ! 153: ! 154: /* ! 155: * Depending on the caller, we may sleep waiting for memory ! 156: * to become available. ! 157: */ ! 158: ! 159: if (flag == KM_NOSLEEP) { ! 160: ! 161: mblkp = NULL; ! 162: break; ! 163: } ! 164: ! 165: ! 166: /* ! 167: * RESEARCH NOTE: This policy is a guess, no more. We need to ! 168: * do some profiling to find out what effect other policies ! 169: * might have. In particular, the wakeup heuristic could be ! 170: * altered to broadcast when we can satisfy the largest ! 171: * request. ! 172: */ ! 173: ! 174: if (str_mem->sm_msg_needed == 0 || ! 175: str_mem->sm_msg_needed > size) ! 176: str_mem->sm_msg_needed = size; ! 177: ! 178: SV_WAIT (str_mem->sm_msg_sv, prilo, str_mem->sm_msg_lock); ! 179: } ! 180: ! 181: UNLOCK (str_mem->sm_msg_lock, prev_pl); ! 182: ! 183: return mblkp; ! 184: } ! 185: ! 186: ! 187: /* ! 188: * This simple function factors out some common code from different calls to ! 189: * st_free () inside freeb (). This just reduces some of the cost of all the ! 190: * error checking that is my custom, and consolidates the interface to the ! 191: * bookkeeping for callback events and so forth. ! 192: * ! 193: * The streams heap must be locked on entry to this function. ! 194: */ ! 195: ! 196: #if __USE_PROTO__ ! 197: void (STRMEM_FREE) (mblk_t * bp, size_t size) ! 198: #else ! 199: void ! 200: STRMEM_FREE __ARGS ((bp, size)) ! 201: mblk_t * bp; ! 202: size_t size; ! 203: #endif ! 204: { ! 205: int free_ok; ! 206: ! 207: ASSERT (TRYLOCK (str_mem->sm_msg_lock, str_msg_pl) == invpl); ! 208: ! 209: free_ok = st_free (str_mem->sm_msg_heap, bp, size); ! 210: ! 211: if (free_ok != 0) { ! 212: /* ! 213: * The heap manager has a problem with freeing the block that ! 214: * was passed to it, display a console diagnostic. For ! 215: * simplicity we display addresses as longs. ! 216: */ ! 217: ! 218: cmn_err (CE_WARN, ! 219: "MSGB_FREE : st_free () complained with %d freeing %d bytes at %lx", ! 220: free_ok, size, (long) bp); ! 221: } else { ! 222: /* ! 223: * Update the allocation bookkeeping, and request that the ! 224: * routine that processes bufcall () events be run. This other ! 225: * procedure also has responsibility for waking up message and ! 226: * possibly "other" allocations if there is sufficient memory ! 227: * available. ! 228: */ ! 229: ! 230: str_mem->sm_used -= size; ! 231: ! 232: SCHEDULE_BUFCALLS (); ! 233: } ! 234: } ! 235: ! 236: ! 237: /* ! 238: *-STATUS: ! 239: * DDI/DKI ! 240: * ! 241: *-NAME: ! 242: * kmem_alloc () Allocate space from kernel free memory. ! 243: * ! 244: *-SYNOPSIS: ! 245: * #include <sys/types.h> ! 246: * #include <sys/kmem.h> ! 247: * ! 248: * void * kmem_alloc (size_t size, int flag); ! 249: * ! 250: *-ARGUMENTS: ! 251: * size Number of bytes to allocate. ! 252: * ! 253: * flag Specifies whether the caller is willing to sleep ! 254: * waiting for memory. If "flag" is set to KM_SLEEP, the ! 255: * caller will sleep if necessary until the specified ! 256: * amount of memory is available. If "flag" is set to ! 257: * KM_NOSLEEP, the caller will not sleep, but ! 258: * kmem_alloc () will return NULL if the specified amount ! 259: * of memory is not immediately available. ! 260: * ! 261: *-DESCRIPTION: ! 262: * kmem_alloc () allocates "size" bytes of kernel memory and returns a ! 263: * pointer to the allocated memory. ! 264: * ! 265: *-RETURN VALUE: ! 266: * Upon successful completion, kmem_alloc () returns a pointer to the ! 267: * allocated memory. If KM_NOSLEEP is specified and sufficient memory is ! 268: * not immediately available, kmem_alloc () returns a NULL pointer. If ! 269: * "size" is set to 0, kmem_alloc () always returns NULL regardless of ! 270: * the value of "flag". ! 271: * ! 272: *-LEVEL: ! 273: * Base only if "flag" is set to KM_SLEEP. Base or interrupt if "flag" is ! 274: * set to KM_NOSLEEP. ! 275: * ! 276: *-NOTES: ! 277: * May sleep if "flag" is set to KM_SLEEP. ! 278: * ! 279: * Driver-defined basic locks and read/write locks may be held across ! 280: * calls to this function if "flag" is KM_NOSLEEP but may not be held if ! 281: * "flag" is KM_SLEEP. ! 282: * ! 283: * Driver-defined sleep locks may be held across calls to this function ! 284: * regardless of the value of "flag". ! 285: * ! 286: * Kernel memory is a limited resource and should be used judiciously. ! 287: * Memory allocated using kmem_alloc () should be freed as soon as ! 288: * possible. Drivers should not use local freelists for memory or similar ! 289: * schemes that cause the memory to be held for longer than necessary. ! 290: * ! 291: * The address returned by a successful call to kmem_alloc () is word- ! 292: * aligned. ! 293: * ! 294: *-SEE ALSO: ! 295: * kmem_free (), kmem_zalloc () ! 296: */ ! 297: ! 298: #if __USE_PROTO__ ! 299: _VOID * (kmem_alloc) (size_t size, int flag) ! 300: #else ! 301: _VOID * ! 302: kmem_alloc __ARGS ((size, flag)) ! 303: size_t size; ! 304: int flag; ! 305: #endif ! 306: { ! 307: _VOID * mem; ! 308: pl_t prev_pl; ! 309: ! 310: ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP); ! 311: ! 312: ASSERT (ATOMIC_FETCH_UCHAR (str_mem->sm_init) || ! 313: str_mem->sm_other_lock != NULL); ! 314: ! 315: if (size == 0) ! 316: return NULL; ! 317: ! 318: for (;;) { ! 319: /* ! 320: * Lock the basic lock protecting access to the memory pool ! 321: * and attempt to acquire the memory we desire. ! 322: */ ! 323: ! 324: if (str_mem->sm_other_lock != NULL) ! 325: prev_pl = LOCK (str_mem->sm_other_lock, str_other_pl); ! 326: ! 327: if ((mem = st_alloc (str_mem->sm_other_heap, size)) != NULL || ! 328: flag == KM_NOSLEEP) { ! 329: OTHER_ALLOCED (size); ! 330: break; ! 331: } ! 332: ! 333: /* ! 334: * Since we cannot acquire the memory, but the caller is ! 335: * willing to wait, we wait on a synchronization variable ! 336: * for sufficient memory to be available. We record the ! 337: * minimum amount that will satisfy any outstanding wait so ! 338: * that kmem_free () need not perform broadcasts in a ! 339: * totally needless fashion. ! 340: * ! 341: * We have arbitrarily chosen a low scheduling priority for ! 342: * SV_WAIT (). ! 343: */ ! 344: /* ! 345: * RESEARCH NOTE: This policy is a guess, no more. We need to ! 346: * do some profiling to find out what effect other policies ! 347: * might have. In particular, the wakeup heuristic could be ! 348: * altered to broadcast when we can satisfy the largest ! 349: * request. ! 350: */ ! 351: ! 352: if (str_mem->sm_other_needed == 0 || ! 353: str_mem->sm_other_needed > size) ! 354: str_mem->sm_other_needed = size; ! 355: ! 356: SV_WAIT (str_mem->sm_other_sv, prilo, str_mem->sm_other_lock); ! 357: } ! 358: ! 359: if (str_mem->sm_other_lock != NULL) ! 360: UNLOCK (str_mem->sm_other_lock, prev_pl); ! 361: ! 362: return mem; ! 363: } ! 364: ! 365: ! 366: ! 367: /* ! 368: *-STATUS: ! 369: * DDI/DKI ! 370: * ! 371: *-NAME: ! 372: * kmem_free () Free previously allocated kernel memory. ! 373: * ! 374: *-SYNOPSIS: ! 375: * #include <sys/types.h> ! 376: * #include <sys/kmem.h> ! 377: * ! 378: * void kmem_free (void * addr, size_t size); ! 379: * ! 380: *-ARGUMENTS: ! 381: * addr Address of the allocated memory to be returned. "addr" ! 382: * must specify the same address that was returned by the ! 383: * corresponding call to kmem_alloc () or kmem_zalloc () ! 384: * which allocated the memory. ! 385: * ! 386: * size Number of bytes to free. The "size" parameter must ! 387: * specify the same number of bytes as was allocated by ! 388: * the corresponding call to kmem_alloc () or\ ! 389: * kmem_zalloc (). ! 390: * ! 391: *-DESCRIPTION: ! 392: * kmem_free () returns "size" bytes of previously allocated kernel ! 393: * memory to the free pool. The "addr" and "size" arguments must specify ! 394: * exactly one complete area of memory that was allocated by a call to ! 395: * kmem_alloc () or kmem_zalloc () (that is, the memory cannot be freed ! 396: * piecemeal). ! 397: * ! 398: *-RETURN VALUE: ! 399: * None. ! 400: * ! 401: *-LEVEL: ! 402: * Base or Interrupt. ! 403: * ! 404: *-NOTES: ! 405: * Does not sleep. ! 406: * ! 407: * Driver-defined basic locks, read/write locks and sleep locks may be ! 408: * held across calls to this function. ! 409: * ! 410: *-SEE ALSO: ! 411: * kmem_alloc (), kmem_zalloc () ! 412: */ ! 413: ! 414: #if __USE_PROTO__ ! 415: void (kmem_free) (_VOID * addr, size_t size) ! 416: #else ! 417: void ! 418: kmem_free __ARGS ((addr, size)) ! 419: _VOID * addr; ! 420: size_t size; ! 421: #endif ! 422: { ! 423: pl_t prev_pl; ! 424: int free_ok; ! 425: ! 426: ASSERT (addr != NULL); ! 427: ASSERT (size > 0); ! 428: ! 429: ASSERT (ATOMIC_FETCH_UCHAR (str_mem->sm_init) || ! 430: str_mem->sm_other_lock != NULL); ! 431: ! 432: /* ! 433: * Acquire the basic lock protecting access to the memory and free ! 434: * the caller's area. If there are processes waiting on memory ! 435: * becoming available, wake them up via a synchronization variable ! 436: * broadcast. ! 437: */ ! 438: ! 439: if (str_mem->sm_other_lock != NULL) ! 440: prev_pl = LOCK (str_mem->sm_other_lock, str_other_pl); ! 441: ! 442: OTHER_FREED (size); ! 443: ! 444: free_ok = st_free (str_mem->sm_other_heap, addr, size); ! 445: ! 446: if (str_mem->sm_other_needed > 0 && ! 447: str_mem->sm_other_needed <= st_maxavail (str_mem->sm_other_heap)) { ! 448: /* ! 449: * Wake up *all* the waiting processes and clear the marker ! 450: * to indicate that there are no waiting processes. ! 451: */ ! 452: ! 453: SV_BROADCAST (str_mem->sm_other_sv, 0); ! 454: str_mem->sm_other_needed = 0; ! 455: } ! 456: ! 457: if (str_mem->sm_other_lock != NULL) ! 458: UNLOCK (str_mem->sm_other_lock, prev_pl); ! 459: ! 460: if (free_ok != 0) { ! 461: /* ! 462: * The heap manager has a problem with freeing the block that ! 463: * was passed to it, display a console diagnostic. For ! 464: * simplicity we display addresses as longs. ! 465: */ ! 466: ! 467: cmn_err (CE_WARN, ! 468: "kmem_free : st_free () complained with %d freeing %d bytes at %lx", ! 469: free_ok, size, (long) addr); ! 470: } ! 471: } ! 472: ! 473: ! 474: ! 475: /* ! 476: *-STATUS: ! 477: * DDI/DKI ! 478: * ! 479: *-NAME: ! 480: * kmem_zalloc () Allocate and clear space from kernel free memory. ! 481: * ! 482: *-SYNOPSIS: ! 483: * #include <sys/types.h> ! 484: * #include <sys/kmem.h> ! 485: * ! 486: * void * kmem_zalloc (size_t size, int flag); ! 487: * ! 488: *-ARGUMENTS: ! 489: * size Number of bytes to allocate. ! 490: * ! 491: * flag Specifies whether the caller is willing to sleep ! 492: * waiting for memory. If "flag" is set to KM_SLEEP, the ! 493: * caller will sleep if necessary until the specified ! 494: * amount of memory is available. If "flag" is set to ! 495: * KM_NOSLEEP, the caller will not sleep, but ! 496: * kmem_zalloc () will return NULL if the specified ! 497: * amount of memory is not immediately available. ! 498: * ! 499: *-DESCRIPTION: ! 500: * kmem_zalloc () allocates "size" bytes of kernel memory, clears the ! 501: * memory by filling it with zeros, and returns a pointer to the ! 502: * allocated memory. ! 503: * ! 504: *-RETURN VALUE: ! 505: * Upon successful completion, kmem_zalloc () returns a pointer to the ! 506: * allocated memory. If KM_NOSLEEP is specified and sufficient memory is ! 507: * not immediately available, kmem_zalloc () returns a NULL pointer. If ! 508: * "size" is set to 0, kmem_zalloc () always returns NULL regardless of ! 509: * the value of "flag". ! 510: * ! 511: *-LEVEL: ! 512: * Base only if "flag" is set to KM_SLEEP. Base or interrupt if "flag" is ! 513: * set to KM_NOSLEEP. ! 514: * ! 515: *-NOTES: ! 516: * May sleep if "flag" is set to KM_SLEEP. ! 517: * ! 518: * Driver-defined basic locks and read/write locks may be held across ! 519: * calls to this function if "flag" is KM_NOSLEEP but may not be held if ! 520: * "flag" is KM_SLEEP. ! 521: * ! 522: * Driver-defined sleep locks may be held across calls to this function ! 523: * regardless of the value of "flag". ! 524: * ! 525: * Kernel memory is a limited resource and should be used judiciously. ! 526: * Memory allocated using kmem_zalloc () should be freed as soon as ! 527: * possible. Drivers should not use local freelists for memory or similar ! 528: * schemes that cause the memory to be held for longer than necessary. ! 529: * ! 530: * The address returned by a successful call to kmem_zalloc () is word- ! 531: * aligned. ! 532: * ! 533: *-SEE ALSO: ! 534: * kmem_alloc (), kmem_free () ! 535: */ ! 536: ! 537: #if __USE_PROTO__ ! 538: _VOID * (kmem_zalloc) (size_t size, int flag) ! 539: #else ! 540: _VOID * ! 541: kmem_zalloc __ARGS ((size, flag)) ! 542: size_t size; ! 543: int flag; ! 544: #endif ! 545: { ! 546: _VOID * mem; ! 547: ! 548: if ((mem = kmem_alloc (size, flag)) != NULL) ! 549: memset (mem, 0, size); ! 550: return mem; ! 551: } ! 552: ! 553: ! 554: /* ! 555: *-STATUS: ! 556: * Initialisation ! 557: * ! 558: *-DESCRIPTION: ! 559: * This function initializes the memory subsystem given a region of ! 560: * kernel virtual memory space to manage. ! 561: */ ! 562: ! 563: __EXTERN_C__ ! 564: #if __USE_PROTO__ ! 565: int (STRMEM_INIT) (_VOID * addr, size_t size) ! 566: #else ! 567: int ! 568: STRMEM_INIT __ARGS ((addr, size)) ! 569: _VOID * addr; ! 570: size_t size; ! 571: #endif ! 572: { ! 573: int i; ! 574: ! 575: /* ! 576: * We use a test-and-set lock operation on the streams memory ! 577: * structure so that the initialisation process is multiprocessor- ! 578: * safe. We don't use a basic lock since we don't know whether basic ! 579: * locks exist yet. ! 580: */ ! 581: ! 582: if (ATOMIC_TEST_AND_SET_UCHAR (str_mem->sm_init) != 0) { ! 583: /* ! 584: * Presumably we are on a separate processor waiting for the ! 585: * initialization to be completed by someone else. To make ! 586: * this processor's call to STRMEM_INIT () behave with the ! 587: * right semantics, we wait for the other instance to complete ! 588: * the setup process. ! 589: */ ! 590: ! 591: while (ATOMIC_FETCH_UCHAR (str_mem->sm_init) != 0) { ! 592: #ifdef __UNIPROCESSOR__ ! 593: cmn_err (CE_PANIC, "Init startup deadlock???"); ! 594: #endif ! 595: } ! 596: return 0; ! 597: } ! 598: ! 599: if (str_mem->sm_other_lock != NULL) { ! 600: /* ! 601: * The init has already been done, thanks! ! 602: */ ! 603: ! 604: ATOMIC_CLEAR_UCHAR (str_mem->sm_init); ! 605: return 0; ! 606: } ! 607: ! 608: #ifdef SPLIT_STREAMS_MEMORY ! 609: #endif ! 610: ! 611: /* ! 612: * Now initialize the fast-first-fit heap manager. ! 613: * ! 614: * For now, we'll just specify 256 segments, but this ! 615: * should probably be based on the log of the total ! 616: * number of words available. ! 617: */ ! 618: ! 619: str_mem->sm_msg_heap = (_ST_HEAP_CONTROL_P) addr; ! 620: ! 621: addr = (_VOID *) ((char *) addr + ! 622: _ST_HEAP_CONTROL_SIZE (str_segments)); ! 623: ! 624: size -= _ST_HEAP_CONTROL_SIZE (str_segments); ! 625: ! 626: st_ctor (str_mem->sm_msg_heap, str_segments, ! 627: size / sizeof (_ST_WORD_T), (_ST_ADDR_T) addr); ! 628: ! 629: str_mem->sm_msg_lock = ! 630: LOCK_ALLOC (stream_heap_hierarchy, str_other_pl, ! 631: & _stream_heap_lkinfo, KM_NOSLEEP); ! 632: ! 633: str_mem->sm_msg_sv = SV_ALLOC (KM_NOSLEEP); ! 634: ! 635: ! 636: /* ! 637: * If either of the above allocations failed, we have some kind of ! 638: * major problem, so we exit without unlocking the initialization flag ! 639: * with an error indication. ! 640: */ ! 641: ! 642: if (str_mem->sm_msg_lock == NULL || str_mem->sm_msg_sv == NULL) { ! 643: ! 644: init_error: ! 645: cmn_err (CE_PANIC, "Could not initialize STREAMS subsystem"); ! 646: return -1; ! 647: } ! 648: ! 649: ! 650: /* ! 651: * Now we can calculate the watermarks... start at the ! 652: * top and make each lower one some percentage of the ! 653: * next higher one (say, 15/16 or 93%, so that it's ! 654: * easy to calculate). ! 655: */ ! 656: ! 657: for (i = N_PRI_LEVELS ; i -- > 0 ;) { ! 658: ! 659: str_mem->sm_max [i] = size; ! 660: ! 661: size -= size >> 4; /* - 1/16 */ ! 662: } ! 663: ! 664: ! 665: /* ! 666: * Do other kinds of initialization for the "str_mem" structure. ! 667: */ ! 668: ! 669: for (i = N_PRI_LEVELS ; i -- > 0 ; ) { ! 670: ! 671: if (SELIST_INIT (& str_mem->sm_bcevents [i], ! 672: KM_SLEEP) == NULL) ! 673: ! 674: goto init_error; ! 675: } ! 676: ! 677: ! 678: str_mem->sm_seq_lock = LOCK_ALLOC (stream_seq_hierarchy, plstr, ! 679: & _stream_seq_lkinfo, KM_SLEEP); ! 680: ! 681: str_mem->sm_head_lock = RW_ALLOC (stream_dir_hierarchy, plstr, ! 682: & _stream_dir_lkinfo, KM_SLEEP); ! 683: ! 684: str_mem->sm_proc_lock = LOCK_ALLOC (stream_proc_hierarchy, plstr, ! 685: & _stream_proc_lkinfo, KM_SLEEP); ! 686: ! 687: str_mem->sm_proc_sv = SV_ALLOC (KM_SLEEP); ! 688: ! 689: if (SCHED_INIT (str_mem->sm_sched, KM_SLEEP) == NULL || ! 690: str_mem->sm_seq_lock == NULL || str_mem->sm_head_lock == NULL || ! 691: str_mem->sm_proc_lock == NULL || str_mem->sm_proc_sv == NULL) ! 692: goto init_error; ! 693: ! 694: /* ! 695: * All OK, let other CPUs proceed and return success to the caller. ! 696: */ ! 697: ! 698: ATOMIC_CLEAR_UCHAR (str_mem->sm_init); ! 699: ! 700: return 0; /* all OK */ ! 701: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.