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