From owner-freebsd-hackers Mon Dec 4 03:03:48 1995 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.6.12/8.6.6) id DAA19399 for hackers-outgoing; Mon, 4 Dec 1995 03:03:48 -0800 Received: from godzilla.zeta.org.au (godzilla.zeta.org.au [203.2.228.19]) by freefall.freebsd.org (8.6.12/8.6.6) with ESMTP id DAA19386 for ; Mon, 4 Dec 1995 03:03:33 -0800 Received: (from bde@localhost) by godzilla.zeta.org.au (8.6.9/8.6.9) id VAA03902; Mon, 4 Dec 1995 21:58:03 +1100 Date: Mon, 4 Dec 1995 21:58:03 +1100 From: Bruce Evans Message-Id: <199512041058.VAA03902@godzilla.zeta.org.au> To: bde@zeta.org.au, witr@rwwa.com Subject: Re: Proper way to determine non-blocking status... Cc: freebsd-hackers@freebsd.org Sender: owner-hackers@freebsd.org Precedence: bulk >Do you mind if I pepper you with some more questions? Perhaps these should be added to the NFAQ :-). >1) Is there any guidance on what priority pass to tsleep? It doesn't matter much. Normally use something between PZERO and PUSER, and OR in PCATCH for interruptible sleeps. >2) Would I be correct in assuming that IPL will be the >same *after* tsleep returns as it was *before*. (I'm >already pretty sure of that, reading the code. It makes >sense anyway.) Yes. >3) Is there anyway short of using timeout() to hook >into the clock interrupt (like xxpoll() in SYSV)? No. Restart the timeout when the timeout handler gets called (or when it returns). >4) I'm porting a streams driver to FreeBSD. It isn't >a network style device, so I need to use the character >dev model. The backend (and parts of the frontend) >construct and enqueue messages to pass to the user >when he eventually does a read. I need to alloc >memory for each of these messages (which have random >sizes, from dozens of bytes up to 1024 bytes). I'm curently >using malloc(size,M_DEVBUF,waitflag). Is there better >way to do this? Not unless you can use mbufs. Don't depend on mallocing more than a page or two (1024 bytes is OK). Don't call malloc() from interrupt handlers except for network drivers. Be careful about using the M_WAITOK flag - it allows malloc() to sleep, so you probably wouldn't want to use it while spl'ed. Don't manage a large pool of free buffers yourself. One or two might be good. >5) Are there any ipl restrictions on calling wakeup()? No. >6) Where does device ipl come from? I don't see it in the >config file? How do I know what ipl my device interrupts >at? It is tty_imask for ttys etc, where ttys are the things specified by the keyword `tty' in the config file and the mask is the OR of the hardware masks for each tty device together with a few software masks. This will change. >7) xxintr(int unit). Which unit? How computed? I'm used >to xxintr(int vec). unit = intr_unit[vec]. intr_unit[] is initialized by register_intr(), normally to the unit numbers specified in the config file. This will change to xxintr(void *cookie) where cookie is normally (void *)&xxdriverstuff[unit]. >8) I see that people often avoid having xxread/xxwrite routines >for this situation. I did the opposite: I have xxread/xxwrite >routines and require the stuff sent to be protocol packets. >Is there any major drawback to this besides the possiblity >of having some butthead do ``cat /etc/passwd /dev/mcc''? No. >Actual routine is: >int mccread(dev_t dev, struct uio *uio, int ioflag) >{ > mcc_t *mcc = MCC_DEV(dev); /* Private data for this channel */ > mcc_mblk_t *mp; > int oldspl; > /* Send first accumulated message, or wait if possible */ > again: > oldspl = SPLINT(); /* Lock */ > mp = l_remove_head(&mcc->mcc_done); /* Get anything there */ > if (mp) { /* Return it */ > mc_primitives_union_t *mcp = MCC_MBLK_DATA(mp); > if (mcp->header.mc_length > uio->uio_resid) { > /* > We refuse to copy less than a complete message, > so we requeue this one! > */ > l_add_head(&mcc->mcc_done,mp); /* Return it to head of list */ > splx(oldspl); /* Unlock */ > return EINVAL; > } else { > splx(oldspl); /* Unlock */ > uiomove(mcp, mcp->header.mc_length, uio); ^^^^^^^ check the return code - it can be EFAULT... > free(mp,M_DEVBUF); > return 0; > } > } else if (ioflag & IO_NDELAY) { /* Can't block, sorry */ > splx(oldspl); /* Unlock */ > return EWOULDBLOCK; > } else { /* Otherwise try again */ > int error; > mcc->mcc_blocked = 1; /* Mark ourselves blocked */ > error = tsleep(&mcc->mcc_done, PZERO | PCATCH, "mccin", 0); > mcc->mcc_blocked = 0; /* Mark ourselves unblocked */ > splx(oldspl); /* Unlock */ > if (error && (error != ERESTART)) return error; > goto again; > } >}