darwin-xnu/bsd/kern/subr_log.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
  23/*
  24 * Copyright (c) 1982, 1986, 1993
  25 *      The Regents of the University of California.  All rights reserved.
  26 *
  27 * Redistribution and use in source and binary forms, with or without
  28 * modification, are permitted provided that the following conditions
  29 * are met:
  30 * 1. Redistributions of source code must retain the above copyright
  31 *    notice, this list of conditions and the following disclaimer.
  32 * 2. Redistributions in binary form must reproduce the above copyright
  33 *    notice, this list of conditions and the following disclaimer in the
  34 *    documentation and/or other materials provided with the distribution.
  35 * 3. All advertising materials mentioning features or use of this software
  36 *    must display the following acknowledgement:
  37 *      This product includes software developed by the University of
  38 *      California, Berkeley and its contributors.
  39 * 4. Neither the name of the University nor the names of its contributors
  40 *    may be used to endorse or promote products derived from this software
  41 *    without specific prior written permission.
  42 *
  43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  46 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  53 * SUCH DAMAGE.
  54 *
  55 *      @(#)subr_log.c  8.3 (Berkeley) 2/14/95
  56 */
  57
  58/*
  59 * Error log buffer for kernel printf's.
  60 */
  61
  62#include <sys/param.h>
  63#include <sys/systm.h>
  64#include <sys/proc_internal.h>
  65#include <sys/vnode.h>
  66#include <sys/ioctl.h>
  67#include <sys/msgbuf.h>
  68#include <sys/file_internal.h>
  69#include <sys/errno.h>
  70#include <sys/select.h>
  71#include <sys/kernel.h>
  72#include <kern/thread.h>
  73#include <sys/lock.h>
  74
  75#define LOG_RDPRI       (PZERO + 1)
  76
  77#define LOG_NBIO        0x02
  78#define LOG_ASYNC       0x04
  79#define LOG_RDWAIT      0x08
  80
  81struct logsoftc {
  82        int     sc_state;               /* see above for possibilities */
  83        struct  selinfo sc_selp;        /* thread waiting for select */
  84        int     sc_pgid;                /* process/group for async I/O */
  85} logsoftc;
  86
  87int     log_open;                       /* also used in log() */
  88struct msgbuf temp_msgbuf;
  89struct msgbuf *msgbufp;
  90static int _logentrypend = 0;
  91static int log_inited = 0;
  92void bsd_log_lock(void);
  93/* the following two are implemented in osfmk/kern/printf.c  */
  94extern void bsd_log_unlock(void);
  95extern void bsd_log_init(void);
  96
  97/*
  98 * Serialize log access.  Note that the log can be written at interrupt level,
  99 * so any log manipulations that can be done from, or affect, another processor
 100 * at interrupt level must be guarded with a spin lock.
 101 */
 102
 103#define LOG_LOCK() bsd_log_lock()
 104#define LOG_UNLOCK() bsd_log_unlock()
 105
 106
 107/*ARGSUSED*/
 108logopen(dev, flags, mode, p)
 109        dev_t dev;
 110        int flags, mode;
 111        struct proc *p;
 112{
 113        LOG_LOCK();
 114        if (log_open) {
 115                LOG_UNLOCK();
 116                return (EBUSY);
 117        }
 118        log_open = 1;
 119        logsoftc.sc_pgid = p->p_pid;            /* signal process only */
 120        /*
 121         * Potential race here with putchar() but since putchar should be
 122         * called by autoconf, msg_magic should be initialized by the time
 123         * we get here.
 124         */
 125        if (msgbufp->msg_magic != MSG_MAGIC) {
 126                register int i;
 127
 128                msgbufp->msg_magic = MSG_MAGIC;
 129                msgbufp->msg_bufx = msgbufp->msg_bufr = 0;
 130                for (i=0; i < MSG_BSIZE; i++)
 131                        msgbufp->msg_bufc[i] = 0;
 132        }
 133        LOG_UNLOCK();
 134
 135        return (0);
 136}
 137
 138/*ARGSUSED*/
 139int
 140logclose(dev, flag)
 141        dev_t dev;
 142{
 143        int oldpri;
 144        LOG_LOCK();
 145        log_open = 0;
 146        selwakeup(&logsoftc.sc_selp);
 147        selthreadclear(&logsoftc.sc_selp);
 148        LOG_UNLOCK();
 149        return (0);
 150}
 151
 152/*ARGSUSED*/
 153int
 154logread(dev, uio, flag)
 155        dev_t dev;
 156        struct uio *uio;
 157        int flag;
 158{
 159        register long l;
 160        register int s;
 161        int error = 0;
 162        char localbuff[MSG_BSIZE];
 163        int copybytes;
 164
 165        LOG_LOCK();
 166        while (msgbufp->msg_bufr == msgbufp->msg_bufx) {
 167                if (flag & IO_NDELAY) {
 168                        error = EWOULDBLOCK;
 169                        goto out;
 170                }
 171                if (logsoftc.sc_state & LOG_NBIO) {
 172                        error = EWOULDBLOCK;
 173                        goto out;
 174                }
 175                logsoftc.sc_state |= LOG_RDWAIT;
 176                LOG_UNLOCK();
 177                /*
 178                 * If the wakeup is missed the ligtening bolt will wake this up 
 179                 * if there are any new characters. If that doesn't do it
 180                 * then wait for 5 sec and reevaluate 
 181                 */
 182                if (error = tsleep((caddr_t)msgbufp, LOG_RDPRI | PCATCH,
 183                                "klog", 5 * hz)) {
 184                        /* if it times out; ignore */
 185                        if (error != EWOULDBLOCK)
 186                                return (error);
 187                }
 188                LOG_LOCK();
 189        }
 190        logsoftc.sc_state &= ~LOG_RDWAIT;
 191
 192
 193        while (uio_resid(uio) > 0) {
 194                l = msgbufp->msg_bufx - msgbufp->msg_bufr;
 195                if (l < 0)
 196                        l = MSG_BSIZE - msgbufp->msg_bufr;
 197                l = min(l, uio_resid(uio));
 198                if (l == 0)
 199                        break;
 200                bcopy(&msgbufp->msg_bufc[msgbufp->msg_bufr], &localbuff[0], l);
 201                LOG_UNLOCK();
 202                error = uiomove((caddr_t)&localbuff[0],
 203                        (int)l, uio);
 204                LOG_LOCK();
 205                if (error)
 206                        break;
 207                msgbufp->msg_bufr += l;
 208                if (msgbufp->msg_bufr < 0 || msgbufp->msg_bufr >= MSG_BSIZE)
 209                        msgbufp->msg_bufr = 0;
 210        }
 211out:
 212        LOG_UNLOCK();
 213        return (error);
 214}
 215
 216/*ARGSUSED*/
 217int
 218logselect(dev, rw, wql, p)
 219        dev_t dev;
 220        int rw;
 221        void * wql;
 222        struct proc *p;
 223{
 224
 225        switch (rw) {
 226
 227        case FREAD:
 228                LOG_LOCK();     
 229                if (msgbufp->msg_bufr != msgbufp->msg_bufx) {
 230                        LOG_UNLOCK();
 231                        return (1);
 232                }
 233                selrecord(p, &logsoftc.sc_selp, wql);
 234                LOG_UNLOCK();
 235                break;
 236        }
 237        return (0);
 238}
 239
 240void
 241logwakeup()
 242{
 243        struct proc *p;
 244        int pgid;
 245        boolean_t funnel_state;
 246
 247        LOG_LOCK();     
 248        if (!log_open) {
 249                LOG_UNLOCK();
 250                return;
 251        }
 252        selwakeup(&logsoftc.sc_selp);
 253        if (logsoftc.sc_state & LOG_ASYNC) {
 254                pgid = logsoftc.sc_pgid;
 255                LOG_UNLOCK();
 256                if (pgid < 0)
 257                        gsignal(-pgid, SIGIO); 
 258                else if (p = pfind(pgid))
 259                        psignal(p, SIGIO);
 260                LOG_LOCK();
 261        }
 262        if (logsoftc.sc_state & LOG_RDWAIT) {
 263                wakeup((caddr_t)msgbufp);
 264                logsoftc.sc_state &= ~LOG_RDWAIT;
 265        }
 266        LOG_UNLOCK();
 267}
 268
 269void
 270klogwakeup()
 271{
 272
 273        if (_logentrypend) {
 274                _logentrypend = 0;
 275                logwakeup();
 276        }
 277}
 278
 279/*ARGSUSED*/
 280int
 281logioctl(dev, com, data, flag)
 282        caddr_t data;
 283{
 284        long l;
 285        int s;
 286
 287        LOG_LOCK();     
 288        switch (com) {
 289
 290        /* return number of characters immediately available */
 291        case FIONREAD:
 292                l = msgbufp->msg_bufx - msgbufp->msg_bufr;
 293                if (l < 0)
 294                        l += MSG_BSIZE;
 295                *(off_t *)data = l;
 296                break;
 297
 298        case FIONBIO:
 299                if (*(int *)data)
 300                        logsoftc.sc_state |= LOG_NBIO;
 301                else
 302                        logsoftc.sc_state &= ~LOG_NBIO;
 303                break;
 304
 305        case FIOASYNC:
 306                if (*(int *)data)
 307                        logsoftc.sc_state |= LOG_ASYNC;
 308                else
 309                        logsoftc.sc_state &= ~LOG_ASYNC;
 310                break;
 311
 312        case TIOCSPGRP:
 313                logsoftc.sc_pgid = *(int *)data;
 314                break;
 315
 316        case TIOCGPGRP:
 317                *(int *)data = logsoftc.sc_pgid;
 318                break;
 319
 320        default:
 321                LOG_UNLOCK();
 322                return (-1);
 323        }
 324        LOG_UNLOCK();
 325        return (0);
 326}
 327
 328void
 329bsd_log_init()
 330{
 331        if (!log_inited) { 
 332                msgbufp = &temp_msgbuf;
 333                log_inited = 1;
 334        }
 335}
 336
 337void
 338log_putc(char c)
 339{
 340        register struct msgbuf *mbp;
 341
 342        if (!log_inited) {
 343                panic("bsd log is not inited");
 344        }
 345        LOG_LOCK();
 346
 347        mbp = msgbufp; 
 348        if (mbp-> msg_magic != MSG_MAGIC) { 
 349                register int i;
 350
 351                mbp->msg_magic = MSG_MAGIC;
 352                mbp->msg_bufx = mbp->msg_bufr = 0;
 353                for (i=0; i < MSG_BSIZE; i++)
 354                        mbp->msg_bufc[i] = 0;
 355        }
 356        mbp->msg_bufc[mbp->msg_bufx++] = c;
 357        _logentrypend = 1;
 358        if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
 359                mbp->msg_bufx = 0;
 360        LOG_UNLOCK();
 361}
 362
 363
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.