|
|
1.1 root 1: /*
2: * primitives dealing in stream blocks
3: */
4:
5: #include "sys/param.h"
6: #include "sys/stream.h"
7: #include "sys/mtpr.h"
8: #include "sys/buf.h"
9:
10: #define M_HIPRI 127 /* for use by putbq */
11:
12: extern struct block cblock[];
13: extern struct buf *cblkbuf[];
14: extern struct queue queue[];
15: extern int blkcnt, blkbcnt, queuecnt;
16: struct queue *qhead; /* head of queues to run */
17: struct queue *qtail; /* last queue */
18:
19: /*
20: * blocks are kept in handful of free lists,
21: * each containing blocks of a particular size.
22: * there are MAXLEVEL sizes, each SPLITSIZE times bigger than the last.
23: * the system starts out with blkbcnt blocks of the largest size
24: * (which are in fact buffers from bio)
25: * and blkcnt-blkbcnt blocks of the smallest size.
26: * if there are no blocks of the requested size,
27: * larger ones are split to make some.
28: * the smallest blocks (level 0) are a special case:
29: * the data lives in the block header,
30: * and there's no point splitting larger blocks to make more
31: * because there are no headers to use after splitting.
32: */
33:
34: #define MAXLEVEL 6
35: #define SPLITSIZE 4
36:
37: int rbsize[MAXLEVEL] = { 4, 16, 64, 256, 1024, 4096 }; /* real block sizes */
38: int bsize[MAXLEVEL] = { 4, 16, 64, 256, 256, 256 }; /* size for q limits */
39: struct block *qfreelist[MAXLEVEL];
40: short blkfree[MAXLEVEL];
41: short blkall[MAXLEVEL];
42: short blkmax[MAXLEVEL];
43:
44: /*
45: * hooks for debugging
46: * turn this on only if you need it;
47: * it's quite slow
48: */
49: #if STDEBUG
50:
51: static int qiniting;
52: #define BADBP(bp) ((bp)!=&cblock[(bp)-cblock])
53:
54: static
55: badfreelist(lev)
56: register lev;
57: {
58: register i = 0;
59: register struct block *bp;
60:
61: /* look for block that is already on the free list */
62: for(bp=qfreelist[lev];bp!=0;bp=bp->next)
63: i++;
64: if(i!=blkfree[lev]){
65: printf("blkfree[%d]==%d i==%d\n", lev, blkfree[lev], i);
66: panic("bad free list 1");
67: }
68: }
69:
70: static
71: duplicateblock(lev, bp)
72: register lev;
73: register struct block *bp;
74: {
75: register i = 0;
76: register struct block *nbp;
77:
78: /* look for block that is already on the free list */
79: for(nbp=qfreelist[lev];nbp!=0;nbp=nbp->next) {
80: if(nbp==bp)
81: panic("duplicate free");
82: i++;
83: }
84: if(i!=blkfree[lev]){
85: printf("blkfree[%d]==%d i==%d\n", lev, blkfree[lev], i);
86: panic("bad free list 2");
87: }
88: }
89: #endif
90:
91: /*
92: * more debugging: trace the owner of a block
93: * not so slow, but very VAX-dependent.
94: */
95: #if BLKOWNER
96: #define MAXOWNER 2000 /* this many blocks will be traced */
97: #define CALLER(x) *(&x+5) /* x is an int, and is first auto in function */
98: int blkowner[MAXOWNER];
99: #endif
100:
101: qinit()
102: {
103: register i;
104: register struct buf *bp;
105:
106: #if STDEBUG
107: qiniting=1;
108: #endif
109: for (i = 0; i<blkbcnt; i++) {
110: if ((bp = geteblk()) == NULL)
111: break; /* probably not best */
112: cblock[i].class = MAXLEVEL-1;
113: cblock[i].base = (u_char *)&bp->b_un.b_addr[0];
114: cblock[i].lim = (u_char *)&bp->b_un.b_addr[bp->b_bcount];
115: cblock[i].rbufix = i;
116: cblkbuf[i] = bp;
117: freeb(&cblock[i]);
118: }
119: blkall[MAXLEVEL-1] = 0;
120: for ( ; i<blkcnt; i++) {
121: cblock[i].class = 0;
122: cblock[i].base = &cblock[i].data[0];
123: cblock[i].lim = &cblock[i].data[sizeof(cblock[0].data)];
124: cblock[i].rbufix = NOBUFIX;
125: freeb(&cblock[i]);
126: }
127: blkall[0] = 0;
128: #if STDEBUG
129: qiniting=0;
130: #endif
131: }
132:
133: static bsplit();
134:
135: struct block *
136: allocb(size)
137: {
138: #if BLKOWNER
139: int x;
140: #endif
141: register struct block *bp;
142: register lev;
143: register s;
144:
145: for (lev = 0; lev < MAXLEVEL; lev++) {
146: if (size <= rbsize[lev])
147: break;
148: }
149: if (lev >= MAXLEVEL)
150: panic("allocb bad size");
151: s = spl6();
152: #if STDEBUG
153: badfreelist(lev);
154: #endif
155:
156: /* check for free block of right size */
157: if ((bp = qfreelist[lev]) == NULL) {
158: bsplit(lev+1); /* else try to split larger block */
159: if ((bp = qfreelist[lev]) == NULL) {
160: if (size != QBSIZE) {
161: splx(s);
162: return (allocb(QBSIZE)); /* last chance */
163: }
164: panic("allocb no block");
165: }
166: }
167: qfreelist[lev] = bp->next;
168: blkall[lev]++;
169: if (blkall[lev] > blkmax[lev])
170: blkmax[lev] = blkall[lev];
171: blkfree[lev]--;
172: #if BLKOWNER
173: if ((x = bp-cblock) < MAXOWNER)
174: blkowner[x] = CALLER(x);
175: #endif
176: splx(s);
177: bp->type = M_DATA;
178: bp->next = NULL;
179: bp->rptr = bp->base;
180: bp->wptr = bp->base;
181: bp->bufix = bp->rbufix;
182: bp->class &= ~S_DELIM;
183: #if STDEBUG
184: if (BADBP(bp))
185: panic("allocb");
186: #endif
187: return(bp);
188: }
189:
190: static
191: bsplit(lev)
192: register lev;
193: {
194: register struct block *bp, *bp1;
195: register i, size;
196:
197: if (lev>=MAXLEVEL)
198: return;
199: if ((bp = qfreelist[lev]) == NULL) {
200: bsplit(lev+1);
201: if ((bp = qfreelist[lev]) == NULL)
202: return;
203: }
204: qfreelist[lev] = bp->next;
205: blkfree[lev]--;
206: size = (bp->lim - bp->base)/SPLITSIZE;
207: lev--; /* the blocks we're creating */
208: for (i=1; i<SPLITSIZE; i++) {
209: if ((bp1 = qfreelist[0]) == NULL)
210: return;
211: qfreelist[0] = bp1->next;
212: blkfree[0]--;
213: bp1->base = bp->base;
214: bp->base += size;
215: bp1->lim = bp1->base+size;
216: bp1->class = lev;
217: bp1->rbufix = bp->rbufix;
218: bp1->next = qfreelist[lev];
219: qfreelist[lev] = bp1;
220: blkfree[lev]++;
221: }
222: bp->class = lev;
223: bp->next = qfreelist[lev];
224: qfreelist[lev] = bp;
225: blkfree[lev]++;
226: }
227:
228: /*
229: * if this is a large block and its data can be squeezed
230: * into a smaller block, do it.
231: */
232: struct block *
233: cramb(bp)
234: register struct block *bp;
235: {
236: register struct block *nbp;
237: register int n;
238:
239: n = bp->wptr - bp->rptr;
240: if((bp->class&CL_MASK) < 3 || n > rbsize[(bp->class&CL_MASK)-1])
241: return bp;
242: nbp = allocb(n);
243: if(nbp==NULL)
244: return bp;
245: if(nbp->lim-nbp->wptr < n) {
246: freeb(nbp);
247: return bp;
248: }
249: bcopy(bp->rptr, nbp->wptr, n);
250: nbp->wptr += n;
251: nbp->type = bp->type;
252: if (bp->class & S_DELIM)
253: nbp->class |= S_DELIM;
254: freeb(bp);
255: return nbp;
256: }
257:
258: /*
259: * make a block that points to the same data
260: * as some existing block
261: */
262: struct block *
263: dupb(bp)
264: register struct block *bp;
265: {
266: #if BLKOWNER
267: int x;
268: #endif
269: register struct block *nbp;
270:
271: if ((nbp = allocb(0)) == NULL)
272: return (NULL);
273: nbp->type = bp->type;
274: nbp->rptr = bp->rptr;
275: nbp->wptr = bp->wptr;
276: nbp->bufix = bp->bufix;
277: nbp->class |= bp->class&S_DELIM;
278: #if BLKOWNER
279: if ((x = nbp-cblock) < MAXOWNER)
280: blkowner[x] = CALLER(x);
281: #endif
282: return (nbp);
283: }
284:
285: freeb(bp)
286: register struct block *bp;
287: {
288: register s = spl6();
289: register lev;
290:
291: lev = bp->class&CL_MASK;
292: #if STDEBUG
293: if (BADBP(bp))
294: panic("freeb");
295: duplicateblock(lev, bp);
296: if (blkall[lev] <= 0 && !qiniting)
297: panic("freeb excess free");
298: #endif
299: bp->next = qfreelist[lev];
300: qfreelist[lev] = bp;
301: blkall[lev]--;
302: blkfree[lev]++;
303: splx(s);
304: }
305:
306: struct block *
307: getq(q)
308: register struct queue *q;
309: {
310: #if BLKOWNER
311: int x;
312: #endif
313: register struct block *bp;
314: register s = spl6();
315:
316: if ((bp = q->first) == NULL) {
317: if ((q->flag&QENAB) == 0)
318: q->flag |= QWANTR;
319: } else {
320: if ((q->first = bp->next) == NULL)
321: q->last = NULL;
322: q->count -= bsize[bp->class&CL_MASK];
323: if (q->count < q->qinfo->limit)
324: q->flag &= ~QFULL;
325: q->flag &= ~QWANTR;
326: #if BLKOWNER
327: if ((x = bp-cblock) < MAXOWNER)
328: blkowner[x] = CALLER(x);
329: #endif
330: }
331: if (q->count<=q->qinfo->lolimit && q->flag&QWANTW && OTHERQ(q)->next) {
332: register struct queue *bq = backq(q);
333: if (bq->qinfo->srvp)
334: qenable(bq);
335: q->flag &= ~QWANTW;
336: }
337: splx(s);
338: #if STDEBUG
339: if(bp && BADBP(bp))
340: panic("getq");
341: #endif
342: return(bp);
343: }
344:
345: putq(q, bp)
346: register struct queue *q;
347: register struct block *bp;
348: {
349: int s;
350:
351: #if STDEBUG
352: if (BADBP(bp))
353: panic("putq");
354: #endif
355: if (bp->type==M_FLUSH)
356: flushq(q, 0);
357: s = spl6();
358: if (q->first==NULL) { /* empty, just tack on */
359: q->first = bp;
360: q->last = bp;
361: bp->next = NULL;
362: } else if (bp->type<QPCTL || q->last->type>=QPCTL) { /* put at end */
363: register struct block *lastp = q->last;
364: register n = bp->wptr - bp->rptr;
365: if (bp->type==M_DATA && lastp->type==M_DATA
366: && (lastp->class&S_DELIM)==0
367: && n <= lastp->lim-lastp->wptr && lastp->wptr>=lastp->base) {
368: bcopy(bp->rptr, lastp->wptr, n);
369: lastp->wptr += n;
370: if (bp->class&S_DELIM)
371: lastp->class |= S_DELIM;
372: freeb(bp);
373: bp = NULL;
374: } else {
375: lastp->next = bp;
376: q->last = bp;
377: bp->next = NULL;
378: }
379: } else { /* pri, put after any others */
380: register struct block *nbp = q->first;
381: if (nbp->type < QPCTL) {
382: bp->next = q->first;
383: q->first = bp;
384: } else {
385: while (nbp->next->type>=QPCTL)
386: nbp = nbp->next;
387: bp->next = nbp->next;
388: nbp->next = bp;
389: }
390: }
391: if (bp) {
392: q->count += bsize[bp->class&CL_MASK];
393: if (bp->type >= QPCTL && bp->type!= M_HIPRI)
394: q->flag |= QWANTR;
395: }
396: if (q->count >= q->qinfo->limit)
397: q->flag |= QFULL|QWANTW;
398: if ((q->flag & (QWANTR|QENAB|QNOENB)) == QWANTR && q->qinfo->srvp)
399: qenable(q);
400: splx(s);
401: }
402:
403: /*
404: * Put stuff back at beginning of Q
405: * (but after any priority msgs)
406: */
407: putbq(q, bp)
408: register struct queue *q;
409: register struct block *bp;
410: {
411: register savetype = bp->type;
412: register s = spl6();
413:
414: bp->type = M_HIPRI; /* fake priority, to force to start */
415: putq(q, bp);
416: bp->type = savetype;
417: splx(s);
418: }
419:
420: /*
421: * empty a queue. Leave any non-data messages, unless flag is 1.
422: */
423: flushq(q, flag)
424: register struct queue *q;
425: {
426: register struct block *bp, *nbp;
427: register s = spl6();
428:
429: bp = q->first;
430: q->first = NULL;
431: if (q->last)
432: q->last->next = NULL;
433: q->last = NULL;
434: q->count = 0;
435: q->flag &= ~QFULL;
436: while (bp) {
437: nbp = bp->next;
438: if (bp->type != M_DATA && bp->type != M_DELIM
439: && bp->type != M_CTL && bp->type != M_DELAY
440: && bp->type != M_FLUSH && !flag)
441: putq(q, bp);
442: else {
443: if (bp->type == M_PASS)
444: printf("flushing PASS %x\n",*(int *)(bp->rptr));
445: freeb(bp);
446: }
447: bp = nbp;
448: }
449: if (q->flag&QWANTW && OTHERQ(q)->next) {
450: q->flag &= ~QWANTW;
451: qenable(backq(q));
452: }
453: splx(s);
454: }
455:
456: /*
457: * allocate a pair of queues
458: */
459: struct queue *
460: allocq()
461: {
462: register struct queue *qp;
463: static struct queue zeroR =
464: { NULL,NULL,NULL,NULL,NULL,NULL,0,QUSE|QREADR};
465: static struct queue zeroW =
466: { NULL,NULL,NULL,NULL,NULL,NULL,0,QUSE};
467:
468: for (qp = queue; qp < &queue[queuecnt]; qp += 2) {
469: if ((qp->flag & QUSE) == 0) {
470: *qp = zeroR;
471: *WR(qp) = zeroW;
472: return(qp);
473: }
474: }
475: return(NULL);
476: }
477:
478: /*
479: * put routine that shouldn't be called
480: */
481: noput(q, c)
482: struct queue *q;
483: {
484: panic("noput");
485: }
486:
487: /*
488: * Put one data char on a queue, using f
489: */
490: putd(f, q, c)
491: int (*f)();
492: register struct queue *q;
493: {
494: register struct block *bp;
495: register s = spl6();
496:
497: if (f==putq && (bp = q->last) && bp->type==M_DATA && bp->wptr<bp->lim
498: && (bp->class&S_DELIM)==0) {
499: *bp->wptr++ = c;
500: splx(s);
501: } else {
502: splx(s);
503: if ((bp = allocb(16)) == NULL)
504: return(0);
505: *bp->wptr++ = c;
506: (*f)(q, bp);
507: }
508: return(1);
509: }
510:
511: /*
512: * Put a block of type c on queue
513: */
514: putctl(q, c)
515: struct queue *q;
516: {
517: register struct block *bp;
518:
519: if ((bp = allocb(0)) == NULL)
520: return(0);
521: bp->type = c;
522: (*q->qinfo->putp)(q, bp);
523: return(1);
524: }
525:
526: /*
527: * Put a block of type c, delimited, on queue
528: */
529: putctld(q, c)
530: struct queue *q;
531: {
532: register struct block *bp;
533:
534: if ((bp = allocb(0)) == NULL)
535: return(0);
536: bp->type = c;
537: bp->class |= S_DELIM;
538: (*q->qinfo->putp)(q, bp);
539: return(1);
540: }
541:
542: /*
543: * Block of type c, with one byte of data
544: */
545: putctl1(q, c, p)
546: struct queue *q;
547: {
548: register struct block *bp;
549:
550: if ((bp = allocb(1)) == NULL)
551: return(0);
552: bp->type = c;
553: *bp->wptr++ = p;
554: (*q->qinfo->putp)(q, bp);
555: return(1);
556: }
557:
558: /*
559: * Block of type c, delimited, with one byte of data
560: */
561: putctl1d(q, c, p)
562: struct queue *q;
563: {
564: register struct block *bp;
565:
566: if ((bp = allocb(1)) == NULL)
567: return(0);
568: bp->type = c;
569: bp->class |= S_DELIM;
570: *bp->wptr++ = p;
571: (*q->qinfo->putp)(q, bp);
572: return(1);
573: }
574:
575: /*
576: * block with two parameters
577: */
578: putctl2(q, c, p1, p2)
579: struct queue *q;
580: {
581: register struct block *bp;
582:
583: if ((bp = allocb(2)) == NULL)
584: return(0);
585: bp->type = c;
586: *bp->wptr++ = p1;
587: *bp->wptr++ = p2;
588: (*q->qinfo->putp)(q, bp);
589: return(1);
590: }
591:
592: /*
593: * put control record, using putq instead of queue's putp
594: */
595: qpctl(q, d)
596: register struct queue *q;
597: {
598: register struct block *bp = allocb(1);
599:
600: if (bp) {
601: bp->type = d;
602: putq(q, bp);
603: }
604: }
605:
606: qpctl1(q, c, d)
607: register struct queue *q;
608: {
609: register struct block *bp = allocb(1);
610:
611: if (bp) {
612: bp->type = c;
613: *bp->wptr++ = d;
614: putq(q, bp);
615: }
616: }
617:
618: qpctld(q, d)
619: register struct queue *q;
620: {
621: register struct block *bp = allocb(1);
622:
623: if (bp) {
624: bp->type = d;
625: bp->class |= S_DELIM;
626: putq(q, bp);
627: }
628: }
629:
630: /*
631: * Copy a literal record onto queue
632: */
633: putcpy(q, cp, n)
634: register struct queue *q;
635: register char *cp;
636: {
637: register struct block *bp;
638: register nm;
639:
640: while (n) {
641: if ((bp = allocb(n)) == NULL) /* sorry */
642: return;
643: bp->type = M_DATA;
644: nm = bp->lim - bp->wptr;
645: if (nm > n)
646: nm = n;
647: bcopy(cp, bp->wptr, nm);
648: cp += nm;
649: bp->wptr += nm;
650: n -= nm;
651: (*q->qinfo->putp)(q, bp);
652: }
653: }
654:
655: /*
656: * return the queue upstream from this one
657: */
658: struct queue *
659: backq(q)
660: register struct queue *q;
661: {
662: q = OTHERQ(q);
663: if (q->next) {
664: q = q->next;
665: return(OTHERQ(q));
666: }
667: q = OTHERQ(q);
668: printf("backq called with no back (Q %x)\n", q);
669: panic("backq");
670: return(NULL);
671: }
672:
673: /*
674: * Send a block back up the queue in reverse from this
675: * one (e.g. to respond to ioctls)
676: */
677: qreply(q, bp)
678: register struct queue *q;
679: struct block *bp;
680: {
681: q = OTHERQ(q);
682: (*q->next->qinfo->putp)(q->next, bp);
683: }
684:
685: /*
686: * Enable a queue: put it on list of those whose srvp's are
687: * ready to run.
688: */
689: qenable(q)
690: register struct queue *q;
691: {
692: register s;
693:
694: s = spl6();
695: if (q->flag & QENAB) {
696: splx(s);
697: return;
698: }
699: if (q->qinfo->srvp==NULL) {
700: splx(s);
701: return;
702: }
703: q->flag |= QENAB;
704: q->link = NULL;
705: if (qhead==NULL)
706: qhead = q;
707: else
708: qtail->link = q;
709: qtail = q;
710: setqsched();
711: splx(s);
712: }
713:
714: /*
715: * Run the srvp's of each enabled queue
716: * -- Should not be reentered
717: */
718: queuerun()
719: {
720: register struct queue *q;
721: register s;
722: extern int queueflag;
723: extern char *panicstr;
724:
725: if (panicstr)
726: return; /* to minimize destruction */
727: s = spl6();
728: queueflag++;
729: while (q = qhead) {
730: if ((qhead = q->link) == NULL)
731: qtail = NULL;
732: q->flag &= ~QENAB;
733: splx(s);
734: if (q->qinfo->srvp != NULL)
735: (*q->qinfo->srvp)(q);
736: else
737: printf("Q %x run with no srvp\n", q);
738: spl6();
739: }
740: queueflag--;
741: splx(s);
742: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.