mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Merge pull request #39 from achilleasa/enhance-hal-output-log
Enhance hal output log
This commit is contained in:
commit
42e6802323
@ -1,6 +1,9 @@
|
|||||||
package device
|
package device
|
||||||
|
|
||||||
import "gopheros/kernel"
|
import (
|
||||||
|
"gopheros/kernel"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
// Driver is an interface implemented by all drivers.
|
// Driver is an interface implemented by all drivers.
|
||||||
type Driver interface {
|
type Driver interface {
|
||||||
@ -10,8 +13,10 @@ type Driver interface {
|
|||||||
// DriverVersion returns the driver version.
|
// DriverVersion returns the driver version.
|
||||||
DriverVersion() (major uint16, minor uint16, patch uint16)
|
DriverVersion() (major uint16, minor uint16, patch uint16)
|
||||||
|
|
||||||
// DriverInit initializes the device driver.
|
// DriverInit initializes the device driver. If the driver init code
|
||||||
DriverInit() *kernel.Error
|
// needs to log some output, it can use the supplied io.Writer in
|
||||||
|
// conjunction with a call to kfmt.Fprint.
|
||||||
|
DriverInit(io.Writer) *kernel.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProbeFn is a function that scans for the presence of a particular
|
// ProbeFn is a function that scans for the presence of a particular
|
||||||
|
@ -258,7 +258,7 @@ func (t *VT) DriverVersion() (uint16, uint16, uint16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DriverInit initializes this driver.
|
// DriverInit initializes this driver.
|
||||||
func (t *VT) DriverInit() *kernel.Error { return nil }
|
func (t *VT) DriverInit(_ io.Writer) *kernel.Error { return nil }
|
||||||
|
|
||||||
func probeForVT() device.Driver {
|
func probeForVT() device.Driver {
|
||||||
return NewVT(DefaultTabWidth, DefaultScrollback)
|
return NewVT(DefaultTabWidth, DefaultScrollback)
|
||||||
|
@ -324,7 +324,7 @@ func TestVtSetState(t *testing.T) {
|
|||||||
func TestVTDriverInterface(t *testing.T) {
|
func TestVTDriverInterface(t *testing.T) {
|
||||||
var dev device.Driver = NewVT(0, 0)
|
var dev device.Driver = NewVT(0, 0)
|
||||||
|
|
||||||
if err := dev.DriverInit(); err != nil {
|
if err := dev.DriverInit(nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"gopheros/kernel/cpu"
|
"gopheros/kernel/cpu"
|
||||||
"gopheros/kernel/hal/multiboot"
|
"gopheros/kernel/hal/multiboot"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -197,7 +198,7 @@ func (cons *VgaTextConsole) DriverVersion() (uint16, uint16, uint16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DriverInit initializes this driver.
|
// DriverInit initializes this driver.
|
||||||
func (cons *VgaTextConsole) DriverInit() *kernel.Error { return nil }
|
func (cons *VgaTextConsole) DriverInit(_ io.Writer) *kernel.Error { return nil }
|
||||||
|
|
||||||
// probeForVgaTextConsole checks for the presence of a vga text console.
|
// probeForVgaTextConsole checks for the presence of a vga text console.
|
||||||
func probeForVgaTextConsole() device.Driver {
|
func probeForVgaTextConsole() device.Driver {
|
||||||
|
@ -311,7 +311,7 @@ func TestVgaTextSetPaletteColor(t *testing.T) {
|
|||||||
func TestVgaTextDriverInterface(t *testing.T) {
|
func TestVgaTextDriverInterface(t *testing.T) {
|
||||||
var dev device.Driver = NewVgaTextConsole(80, 25, 0)
|
var dev device.Driver = NewVgaTextConsole(80, 25, 0)
|
||||||
|
|
||||||
if err := dev.DriverInit(); err != nil {
|
if err := dev.DriverInit(nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package hal
|
package hal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"gopheros/device"
|
"gopheros/device"
|
||||||
"gopheros/device/tty"
|
"gopheros/device/tty"
|
||||||
"gopheros/device/video/console"
|
"gopheros/device/video/console"
|
||||||
@ -13,7 +14,10 @@ type managedDevices struct {
|
|||||||
activeTTY tty.Device
|
activeTTY tty.Device
|
||||||
}
|
}
|
||||||
|
|
||||||
var devices managedDevices
|
var (
|
||||||
|
devices managedDevices
|
||||||
|
strBuf bytes.Buffer
|
||||||
|
)
|
||||||
|
|
||||||
// ActiveTTY returns the currently active TTY
|
// ActiveTTY returns the currently active TTY
|
||||||
func ActiveTTY() tty.Device {
|
func ActiveTTY() tty.Device {
|
||||||
@ -43,7 +47,10 @@ func DetectHardware() {
|
|||||||
// each detected device. The function returns a list of device drivers that
|
// each detected device. The function returns a list of device drivers that
|
||||||
// were successfully initialized.
|
// were successfully initialized.
|
||||||
func probe(hwProbeFns []device.ProbeFn) []device.Driver {
|
func probe(hwProbeFns []device.ProbeFn) []device.Driver {
|
||||||
var drivers []device.Driver
|
var (
|
||||||
|
drivers []device.Driver
|
||||||
|
w = kfmt.PrefixWriter{Sink: kfmt.GetOutputSink()}
|
||||||
|
)
|
||||||
|
|
||||||
for _, probeFn := range hwProbeFns {
|
for _, probeFn := range hwProbeFns {
|
||||||
drv := probeFn()
|
drv := probeFn()
|
||||||
@ -51,16 +58,18 @@ func probe(hwProbeFns []device.ProbeFn) []device.Driver {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strBuf.Reset()
|
||||||
major, minor, patch := drv.DriverVersion()
|
major, minor, patch := drv.DriverVersion()
|
||||||
|
kfmt.Fprintf(&strBuf, "[hal] %s(%d.%d.%d): ", drv.DriverName(), major, minor, patch)
|
||||||
|
w.Prefix = strBuf.Bytes()
|
||||||
|
|
||||||
kfmt.Printf("[hal] %s(%d.%d.%d): ", drv.DriverName(), major, minor, patch)
|
if err := drv.DriverInit(&w); err != nil {
|
||||||
if err := drv.DriverInit(); err != nil {
|
kfmt.Fprintf(&w, "init failed: %s\n", err.Message)
|
||||||
kfmt.Printf("init failed: %s\n", err.Message)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kfmt.Fprintf(&w, "initialized\n")
|
||||||
drivers = append(drivers, drv)
|
drivers = append(drivers, drv)
|
||||||
kfmt.Printf("initialized\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return drivers
|
return drivers
|
||||||
|
@ -31,6 +31,14 @@ var (
|
|||||||
outputSink io.Writer
|
outputSink io.Writer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetOutputSink returns the default target for calls to Printf.
|
||||||
|
func GetOutputSink() io.Writer {
|
||||||
|
if outputSink == nil {
|
||||||
|
return &earlyPrintBuffer
|
||||||
|
}
|
||||||
|
return outputSink
|
||||||
|
}
|
||||||
|
|
||||||
// SetOutputSink sets the default target for calls to Printf to w and copies
|
// SetOutputSink sets the default target for calls to Printf to w and copies
|
||||||
// any data accumulated in the earlyPrintBuffer to itt .
|
// any data accumulated in the earlyPrintBuffer to itt .
|
||||||
func SetOutputSink(w io.Writer) {
|
func SetOutputSink(w io.Writer) {
|
||||||
|
@ -149,9 +149,17 @@ func TestPrintf(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sink := GetOutputSink(); sink != &earlyPrintBuffer {
|
||||||
|
t.Fatal("expected GetOutputSink() to return the earlyPrintBuffer when no output sink has been set")
|
||||||
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
SetOutputSink(&buf)
|
SetOutputSink(&buf)
|
||||||
|
|
||||||
|
if sink := GetOutputSink(); sink != &buf {
|
||||||
|
t.Fatal("expected GetOutputSink() to return the value passed to SetOutputSink")
|
||||||
|
}
|
||||||
|
|
||||||
for specIndex, spec := range specs {
|
for specIndex, spec := range specs {
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
spec.fn()
|
spec.fn()
|
||||||
|
57
src/gopheros/kernel/kfmt/prefix_writer.go
Normal file
57
src/gopheros/kernel/kfmt/prefix_writer.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package kfmt
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
// PrefixWriter is an io.Writer that wraps another io.Writer and injects a
|
||||||
|
// prefix at the beginning of each line.
|
||||||
|
type PrefixWriter struct {
|
||||||
|
// A writer where all writes get sent to.
|
||||||
|
Sink io.Writer
|
||||||
|
|
||||||
|
// The prefix injected at the beginning of each line.
|
||||||
|
Prefix []byte
|
||||||
|
|
||||||
|
bytesAfterPrefix int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes len(p) bytes from p to the underlying data stream and returns
|
||||||
|
// back the number of bytes written. The PrefixWriter keeps track of the
|
||||||
|
// beginning of new lines and injects the configured prefix at each new line.
|
||||||
|
// The injected prefix is not included in the number of written bytes returned
|
||||||
|
// by this method.
|
||||||
|
func (w *PrefixWriter) Write(p []byte) (int, error) {
|
||||||
|
var (
|
||||||
|
written int
|
||||||
|
startIndex, curIndex int
|
||||||
|
)
|
||||||
|
|
||||||
|
if w.bytesAfterPrefix == 0 && len(p) != 0 {
|
||||||
|
w.Sink.Write(w.Prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; curIndex < len(p); curIndex++ {
|
||||||
|
if p[curIndex] == '\n' {
|
||||||
|
n, err := w.Sink.Write(p[startIndex : curIndex+1])
|
||||||
|
if curIndex+1 != len(p) {
|
||||||
|
w.Sink.Write(w.Prefix)
|
||||||
|
}
|
||||||
|
written += n
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
w.bytesAfterPrefix = 0
|
||||||
|
startIndex = curIndex + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if startIndex < curIndex {
|
||||||
|
n, err := w.Sink.Write(p[startIndex:curIndex])
|
||||||
|
written += n
|
||||||
|
w.bytesAfterPrefix = n
|
||||||
|
if err != nil {
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return written, nil
|
||||||
|
}
|
92
src/gopheros/kernel/kfmt/prefix_writer_test.go
Normal file
92
src/gopheros/kernel/kfmt/prefix_writer_test.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package kfmt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPrefixWriter(t *testing.T) {
|
||||||
|
specs := []struct {
|
||||||
|
input string
|
||||||
|
exp string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"\n",
|
||||||
|
"prefix: \n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"no line break anywhere",
|
||||||
|
"prefix: no line break anywhere",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"line feed at the end\n",
|
||||||
|
"prefix: line feed at the end\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"\nthe big brown\nfog jumped\nover the lazy\ndog",
|
||||||
|
"prefix: \nprefix: the big brown\nprefix: fog jumped\nprefix: over the lazy\nprefix: dog",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
buf bytes.Buffer
|
||||||
|
w = PrefixWriter{
|
||||||
|
Sink: &buf,
|
||||||
|
Prefix: []byte("prefix: "),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
buf.Reset()
|
||||||
|
w.bytesAfterPrefix = 0
|
||||||
|
|
||||||
|
wrote, err := w.Write([]byte(spec.input))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("[spec %d] unexpected error: %v", specIndex, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expLen := len(spec.input); expLen != wrote {
|
||||||
|
t.Errorf("[spec %d] expected writer to write %d bytes; wrote %d", specIndex, expLen, wrote)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := buf.String(); got != spec.exp {
|
||||||
|
t.Errorf("[spec %d] expected output:\n%q\ngot:\n%q", specIndex, spec.exp, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixWriterErrors(t *testing.T) {
|
||||||
|
specs := []string{
|
||||||
|
"no line break anywhere",
|
||||||
|
"\nthe big brown\nfog jumped\nover the lazy\ndog",
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
expErr = errors.New("write failed")
|
||||||
|
w = PrefixWriter{
|
||||||
|
Sink: writerThatAlwaysErrors{expErr},
|
||||||
|
Prefix: []byte("prefix: "),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
w.bytesAfterPrefix = 0
|
||||||
|
_, err := w.Write([]byte(spec))
|
||||||
|
if err != expErr {
|
||||||
|
t.Errorf("[spec %d] expected error: %v; got %v", specIndex, expErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type writerThatAlwaysErrors struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w writerThatAlwaysErrors) Write(_ []byte) (int, error) {
|
||||||
|
return 0, w.err
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user