File:  [DragonFly] / src / sys / kern / subr_log.c
Revision 1.6: download - view: text, annotated - select for diffs
Thu May 13 23:49:23 2004 UTC (10 years, 7 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /*
    2:  * Copyright (c) 1982, 1986, 1993
    3:  *	The Regents of the University of California.  All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  * 3. All advertising materials mentioning features or use of this software
   14:  *    must display the following acknowledgement:
   15:  *	This product includes software developed by the University of
   16:  *	California, Berkeley and its contributors.
   17:  * 4. Neither the name of the University nor the names of its contributors
   18:  *    may be used to endorse or promote products derived from this software
   19:  *    without specific prior written permission.
   20:  *
   21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31:  * SUCH DAMAGE.
   32:  *
   33:  *	@(#)subr_log.c	8.1 (Berkeley) 6/10/93
   34:  * $FreeBSD: src/sys/kern/subr_log.c,v 1.39.2.2 2001/06/02 08:11:25 phk Exp $
   35:  * $DragonFly: src/sys/kern/subr_log.c,v 1.6 2004/05/13 23:49:23 dillon Exp $
   36:  */
   37: 
   38: /*
   39:  * Error log buffer for kernel printf's.
   40:  */
   41: 
   42: #include <sys/param.h>
   43: #include <sys/systm.h>
   44: #include <sys/conf.h>
   45: #include <sys/proc.h>
   46: #include <sys/vnode.h>
   47: #include <sys/filio.h>
   48: #include <sys/ttycom.h>
   49: #include <sys/msgbuf.h>
   50: #include <sys/signalvar.h>
   51: #include <sys/kernel.h>
   52: #include <sys/poll.h>
   53: #include <sys/filedesc.h>
   54: #include <sys/sysctl.h>
   55: 
   56: #define LOG_ASYNC	0x04
   57: #define LOG_RDWAIT	0x08
   58: 
   59: static	d_open_t	logopen;
   60: static	d_close_t	logclose;
   61: static	d_read_t	logread;
   62: static	d_ioctl_t	logioctl;
   63: static	d_poll_t	logpoll;
   64: 
   65: static	void logtimeout(void *arg);
   66: 
   67: #define CDEV_MAJOR 7
   68: static struct cdevsw log_cdevsw = {
   69: 	/* name */	"log",
   70: 	/* maj */	CDEV_MAJOR,
   71: 	/* flags */	0,
   72: 	/* port */	NULL,
   73: 	/* clone */	NULL,
   74: 
   75: 	/* open */	logopen,
   76: 	/* close */	logclose,
   77: 	/* read */	logread,
   78: 	/* write */	nowrite,
   79: 	/* ioctl */	logioctl,
   80: 	/* poll */	logpoll,
   81: 	/* mmap */	nommap,
   82: 	/* strategy */	nostrategy,
   83: 	/* dump */	nodump,
   84: 	/* psize */	nopsize
   85: };
   86: 
   87: static struct logsoftc {
   88: 	int	sc_state;		/* see above for possibilities */
   89: 	struct	selinfo sc_selp;	/* process waiting on select call */
   90: 	struct  sigio *sc_sigio;	/* information for async I/O */
   91: 	struct	callout sc_callout;	/* callout to wakeup syslog  */
   92: } logsoftc;
   93: 
   94: int	log_open;			/* also used in log() */
   95: 
   96: /* Times per second to check for a pending syslog wakeup. */
   97: static int	log_wakeups_per_second = 5;
   98: SYSCTL_INT(_kern, OID_AUTO, log_wakeups_per_second, CTLFLAG_RW,
   99:     &log_wakeups_per_second, 0, "");
  100: 
  101: /*ARGSUSED*/
  102: static	int
  103: logopen(dev_t dev, int flags, int mode, struct thread *td)
  104: {
  105: 	struct proc *p = td->td_proc;
  106: 
  107: 	KKASSERT(p != NULL);
  108: 	if (log_open)
  109: 		return (EBUSY);
  110: 	log_open = 1;
  111: 	callout_init(&logsoftc.sc_callout);
  112: 	fsetown(p->p_pid, &logsoftc.sc_sigio);	/* signal process only */
  113: 	callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second,
  114: 	    logtimeout, NULL);
  115: 	return (0);
  116: }
  117: 
  118: /*ARGSUSED*/
  119: static	int
  120: logclose(dev_t dev, int flag, int mode, struct thread *td)
  121: {
  122: 
  123: 	log_open = 0;
  124: 	callout_stop(&logsoftc.sc_callout);
  125: 	logsoftc.sc_state = 0;
  126: 	funsetown(logsoftc.sc_sigio);
  127: 	return (0);
  128: }
  129: 
  130: /*ARGSUSED*/
  131: static	int
  132: logread(dev_t dev, struct uio *uio, int flag)
  133: {
  134: 	struct msgbuf *mbp = msgbufp;
  135: 	long l;
  136: 	int s;
  137: 	int error = 0;
  138: 
  139: 	s = splhigh();
  140: 	while (mbp->msg_bufr == mbp->msg_bufx) {
  141: 		if (flag & IO_NDELAY) {
  142: 			splx(s);
  143: 			return (EWOULDBLOCK);
  144: 		}
  145: 		logsoftc.sc_state |= LOG_RDWAIT;
  146: 		if ((error = tsleep((caddr_t)mbp, PCATCH, "klog", 0))) {
  147: 			splx(s);
  148: 			return (error);
  149: 		}
  150: 	}
  151: 	splx(s);
  152: 	logsoftc.sc_state &= ~LOG_RDWAIT;
  153: 
  154: 	while (uio->uio_resid > 0) {
  155: 		l = mbp->msg_bufx - mbp->msg_bufr;
  156: 		if (l < 0)
  157: 			l = mbp->msg_size - mbp->msg_bufr;
  158: 		l = min(l, uio->uio_resid);
  159: 		if (l == 0)
  160: 			break;
  161: 		error = uiomove((caddr_t)msgbufp->msg_ptr + mbp->msg_bufr,
  162: 		    (int)l, uio);
  163: 		if (error)
  164: 			break;
  165: 		mbp->msg_bufr += l;
  166: 		if (mbp->msg_bufr >= mbp->msg_size)
  167: 			mbp->msg_bufr = 0;
  168: 	}
  169: 	return (error);
  170: }
  171: 
  172: /*ARGSUSED*/
  173: static	int
  174: logpoll(dev_t dev, int events, struct thread *td)
  175: {
  176: 	int s;
  177: 	int revents = 0;
  178: 
  179: 	s = splhigh();
  180: 
  181: 	if (events & (POLLIN | POLLRDNORM)) {
  182: 		if (msgbufp->msg_bufr != msgbufp->msg_bufx)
  183: 			revents |= events & (POLLIN | POLLRDNORM);
  184: 		else
  185: 			selrecord(td, &logsoftc.sc_selp);
  186: 	}
  187: 	splx(s);
  188: 	return (revents);
  189: }
  190: 
  191: static void
  192: logtimeout(void *arg)
  193: {
  194: 
  195: 	if (!log_open)
  196: 		return;
  197: 	if (msgbuftrigger == 0) {
  198: 		callout_reset(&logsoftc.sc_callout,
  199: 		    hz / log_wakeups_per_second, logtimeout, NULL);
  200: 		return;
  201: 	}
  202: 	msgbuftrigger = 0;
  203: 	selwakeup(&logsoftc.sc_selp);
  204: 	if ((logsoftc.sc_state & LOG_ASYNC) && logsoftc.sc_sigio != NULL)
  205: 		pgsigio(logsoftc.sc_sigio, SIGIO, 0);
  206: 	if (logsoftc.sc_state & LOG_RDWAIT) {
  207: 		wakeup((caddr_t)msgbufp);
  208: 		logsoftc.sc_state &= ~LOG_RDWAIT;
  209: 	}
  210: 	callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second,
  211: 	    logtimeout, NULL);
  212: }
  213: 
  214: /*ARGSUSED*/
  215: static	int
  216: logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct thread *td)
  217: {
  218: 	long l;
  219: 	int s;
  220: 
  221: 	switch (com) {
  222: 
  223: 	/* return number of characters immediately available */
  224: 	case FIONREAD:
  225: 		s = splhigh();
  226: 		l = msgbufp->msg_bufx - msgbufp->msg_bufr;
  227: 		splx(s);
  228: 		if (l < 0)
  229: 			l += msgbufp->msg_size;
  230: 		*(int *)data = l;
  231: 		break;
  232: 
  233: 	case FIONBIO:
  234: 		break;
  235: 
  236: 	case FIOASYNC:
  237: 		if (*(int *)data)
  238: 			logsoftc.sc_state |= LOG_ASYNC;
  239: 		else
  240: 			logsoftc.sc_state &= ~LOG_ASYNC;
  241: 		break;
  242: 
  243: 	case FIOSETOWN:
  244: 		return (fsetown(*(int *)data, &logsoftc.sc_sigio));
  245: 
  246: 	case FIOGETOWN:
  247: 		*(int *)data = fgetown(logsoftc.sc_sigio);
  248: 		break;
  249: 
  250: 	/* This is deprecated, FIOSETOWN should be used instead. */
  251: 	case TIOCSPGRP:
  252: 		return (fsetown(-(*(int *)data), &logsoftc.sc_sigio));
  253: 
  254: 	/* This is deprecated, FIOGETOWN should be used instead */
  255: 	case TIOCGPGRP:
  256: 		*(int *)data = -fgetown(logsoftc.sc_sigio);
  257: 		break;
  258: 
  259: 	default:
  260: 		return (ENOTTY);
  261: 	}
  262: 	return (0);
  263: }
  264: 
  265: static void
  266: log_drvinit(void *unused)
  267: {
  268: 
  269: 	make_dev(&log_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "klog");
  270: }
  271: 
  272: SYSINIT(logdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,log_drvinit,NULL)