diff --git a/drivers/libdriver/driver.c b/drivers/libdriver/driver.c index bfd360e62..78c4ebbaa 100644 --- a/drivers/libdriver/driver.c +++ b/drivers/libdriver/driver.c @@ -128,11 +128,13 @@ struct driver *dp; /* Device dependent entry points. */ (*dp->dr_cleanup)(); /* Finally, prepare and send the reply message. */ - mess.m_type = TASK_REPLY; - mess.REP_PROC_NR = proc_nr; - - mess.REP_STATUS = r; /* # of bytes transferred or error code */ - send(device_caller, &mess); /* send reply to caller */ + if (r != EDONTREPLY) { + mess.m_type = TASK_REPLY; + mess.REP_PROC_NR = proc_nr; + /* Status is # of bytes transferred or error code. */ + mess.REP_STATUS = r; + send(device_caller, &mess); + } } } diff --git a/drivers/log/Makefile b/drivers/log/Makefile index d62267d9c..bc6de0779 100644 --- a/drivers/log/Makefile +++ b/drivers/log/Makefile @@ -15,7 +15,7 @@ CFLAGS = -I$i LDFLAGS = -i LIBS = -lsys -lsysutil -OBJ = log.o +OBJ = log.o diag.o kputc.o LIBDRIVER = $d/libdriver/driver.o diff --git a/drivers/log/diag.c b/drivers/log/diag.c new file mode 100644 index 000000000..524a4e79e --- /dev/null +++ b/drivers/log/diag.c @@ -0,0 +1,122 @@ +/* This file handle diagnostic output that is directly sent to the LOG driver. + * This output can either be a kernel message (announced through a SYS_EVENT + * with a SIGKMESS in the signal set) or output from another system process + * (announced through a DIAGNOSTICS message). + * + * Changes: + * 21 July 2005: Created (Jorrit N. Herder) + */ + +#include +#include + +#include "log.h" +#include "../../kernel/const.h" +#include "../../kernel/config.h" +#include "../../kernel/type.h" + + +/*==========================================================================* + * do_new_kmess * + *==========================================================================*/ +PUBLIC int do_new_kmess(m) +message *m; /* notification message */ +{ +/* Notification for a new kernel message. */ + struct kmessages kmess; /* entire kmess structure */ + char print_buf[KMESS_BUF_SIZE]; /* copy new message here */ + static int prev_next = 0; + int size, next; + int bytes; + int i, r; + + /* Try to get a fresh copy of the buffer with kernel messages. */ + if ((r=sys_getkmessages(&kmess)) != OK) { + report("LOG","couldn't get copy of kmessages", r); + return EDONTREPLY; + } + + /* Print only the new part. Determine how many new bytes there are with + * help of the current and previous 'next' index. Note that the kernel + * buffer is circular. This works fine if less then KMESS_BUF_SIZE bytes + * is new data; else we miss % KMESS_BUF_SIZE here. + * Check for size being positive, the buffer might as well be emptied! + */ + if (kmess.km_size > 0) { + bytes = ((kmess.km_next + KMESS_BUF_SIZE) - prev_next) % KMESS_BUF_SIZE; + r=prev_next; /* start at previous old */ + i=0; + while (bytes > 0) { + print_buf[i] = kmess.km_buf[(r%KMESS_BUF_SIZE)]; + log_putc( kmess.km_buf[(r%KMESS_BUF_SIZE)] ); + bytes --; + r ++; + i ++; + } + /* Now terminate the new message and print it. */ + print_buf[i] = 0; + printf(print_buf); + } + + /* Almost done, store 'next' so that we can determine what part of the + * kernel messages buffer to print next time a notification arrives. + */ + prev_next = kmess.km_next; + return EDONTREPLY; +} + + +/*===========================================================================* + * do_diagnostics * + *===========================================================================*/ +PUBLIC int do_diagnostics(message *m) +{ +/* The LOG server handles all diagnostic messages from servers and device + * drivers. It forwards the message to the TTY driver to display it to the + * user. It also saves a copy in a local buffer so that messages can be + * reviewed at a later time. + */ + int result; + int proc_nr; + vir_bytes src; + int count; + char c; + int i = 0; + static char diagbuf[1024]; + + /* Forward the message to the TTY driver. Inform the TTY driver about the + * original sender, so that it knows where the buffer to be printed is. + * The message type, DIAGNOSTICS, remains the same. + */ + if ((proc_nr = m->DIAG_PROC_NR) == SELF) + m->DIAG_PROC_NR = proc_nr = m->m_source; + result = _sendrec(TTY, m); + + /* Now also make a copy for the private buffer at the LOG server, so + * that the messages can be reviewed at a later time. + */ + src = (vir_bytes) m->DIAG_PRINT_BUF; + count = m->DIAG_BUF_COUNT; + while (count > 0) { + if (sys_datacopy(proc_nr, src, SELF, (vir_bytes) &c, 1) != OK) + break; /* stop copying on error */ + log_putc(c); /* accumulate character */ + src ++; + count --; + } + + return result; +} + + +/*===========================================================================* + * log_putc * + *===========================================================================*/ +PUBLIC void log_putc(c) +int c; /* char to be added to diag buffer */ +{ + +} + + + diff --git a/drivers/log/kputc.c b/drivers/log/kputc.c new file mode 100644 index 000000000..527118123 --- /dev/null +++ b/drivers/log/kputc.c @@ -0,0 +1,36 @@ +/* A server must occasionally print some message. It uses a simple version of + * printf() found in the system library that calls putk() to output characters. + * The LOG driver cannot use the regular putk(). Hence, it uses a special + * version of putk() that directly sends to the TTY task. + * + * Changes: + * 21 July 2005: Created (Jorrit N. Herder) + */ + +#include "log.h" + + +/*===========================================================================* + * kputc * + *===========================================================================*/ +void kputc(c) +int c; +{ +/* Accumulate another character. If 0 or buffer full, print it. */ + static int buf_count; /* # characters in the buffer */ + static char print_buf[80]; /* output is buffered here */ + message m; + + if ((c == 0 && buf_count > 0) || buf_count == sizeof(print_buf)) { + m.DIAG_BUF_COUNT = buf_count; + m.DIAG_PRINT_BUF = print_buf; + m.DIAG_PROC_NR = SELF; + m.m_type = DIAGNOSTICS; /* request TTY to output this buffer */ + _sendrec(TTY, &m); /* if it fails, we cannot do better */ + buf_count = 0; /* clear buffer for next batch */ + } + if (c != 0) { + print_buf[buf_count++] = c; + } +} + diff --git a/drivers/log/log.c b/drivers/log/log.c index 54cf75c43..fecf19212 100644 --- a/drivers/log/log.c +++ b/drivers/log/log.c @@ -2,45 +2,26 @@ * /dev/klog - system log device * * Changes: - * 7 july 2005 - Created (Ben Gras) + * 21 July 2005 - Support for diagnostic messages (Jorrit N. Herder) + * 7 July 2005 - Created (Ben Gras) */ -#include "../drivers.h" -#include "../libdriver/driver.h" +#include "log.h" +#include +#include #include "../../kernel/const.h" #include "../../kernel/type.h" -#include -#include - -#define NR_DEVS 1 /* number of minor devices */ -#define KRANDOM_PERIOD 10 /* ticks between krandom calls */ - -#define LOG_DEBUG 0 +#define LOG_DEBUG 0 /* enable/ disable debugging */ +#define NR_DEVS 1 /* number of minor devices */ #define MINOR_KLOG 0 /* /dev/klog */ -#define LOG_SIZE (5*1024) #define LOGINC(n, i) do { (n) = (((n) + (i)) % LOG_SIZE); } while(0) -#define SUSPENDABLE 1 - -PRIVATE struct logdevice { - char log_buffer[LOG_SIZE]; - int log_size, /* no. of bytes in log buffer */ - log_read, /* read mark */ - log_write; /* write mark */ -#if SUSPENDABLE - int log_proc_nr, - log_source, - log_iosize; /* proc that is blocking on read */ - vir_bytes log_user_vir; -#endif - int log_selected, log_select_proc; -} logdevices[NR_DEVS]; - -PRIVATE struct device log_geom[NR_DEVS]; /* base and size of each device */ -PRIVATE int log_device = -1; /* current device */ +PUBLIC struct logdevice logdevices[NR_DEVS]; +PRIVATE struct device log_geom[NR_DEVS]; /* base and size of devices */ +PRIVATE int log_device = -1; /* current device */ FORWARD _PROTOTYPE( char *log_name, (void) ); FORWARD _PROTOTYPE( struct device *log_prepare, (int device) ); @@ -376,15 +357,22 @@ message *m_ptr; * understand. */ switch(m_ptr->m_type) { - case DIAGNOSTICS: - r = subwrite(&logdevices[0], m_ptr->DIAG_BUF_COUNT, - m_ptr->m_source, (vir_bytes) m_ptr->DIAG_PRINT_BUF); - break; - default: - r = EINVAL; - break; + case DIAGNOSTICS: { + r = do_diagnostics(m_ptr); + break; + } + case SYS_EVENT: { + sigset_t sigset = m_ptr->NOTIFY_ARG; + if (sigismember(&sigset, SIGKMESS)) { + do_new_kmess(m_ptr); + } + r = EDONTREPLY; + break; + } + default: + r = EINVAL; + break; } - return r; } diff --git a/drivers/log/log.h b/drivers/log/log.h new file mode 100644 index 000000000..91ab3aee2 --- /dev/null +++ b/drivers/log/log.h @@ -0,0 +1,36 @@ +/* Includes. */ +#include "../drivers.h" +#include "../libdriver/driver.h" +#include +#include +#include +#include +#include + +/* Constants and types. */ + +#define LOG_SIZE (5*1024) +#define SUSPENDABLE 1 + +struct logdevice { + char log_buffer[LOG_SIZE]; + int log_size, /* no. of bytes in log buffer */ + log_read, /* read mark */ + log_write; /* write mark */ +#if SUSPENDABLE + int log_proc_nr, + log_source, + log_iosize; /* proc that is blocking on read */ + vir_bytes log_user_vir; +#endif + int log_selected, log_select_proc; +}; + + +/* Function prototypes. */ +_PROTOTYPE( void kputc, (int c) ); +_PROTOTYPE( int do_new_kmess, (message *m) ); +_PROTOTYPE( int do_diagnostics, (message *m) ); +_PROTOTYPE( void log_putc, (int c) ); + +