|
|
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.