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
 | 
			
		||||
 | 
			
		||||
import "gopheros/kernel"
 | 
			
		||||
import (
 | 
			
		||||
	"gopheros/kernel"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Driver is an interface implemented by all drivers.
 | 
			
		||||
type Driver interface {
 | 
			
		||||
@ -10,8 +13,10 @@ type Driver interface {
 | 
			
		||||
	// DriverVersion returns the driver version.
 | 
			
		||||
	DriverVersion() (major uint16, minor uint16, patch uint16)
 | 
			
		||||
 | 
			
		||||
	// DriverInit initializes the device driver.
 | 
			
		||||
	DriverInit() *kernel.Error
 | 
			
		||||
	// DriverInit initializes the device driver. If the driver init code
 | 
			
		||||
	// 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
 | 
			
		||||
 | 
			
		||||
@ -258,7 +258,7 @@ func (t *VT) DriverVersion() (uint16, uint16, uint16) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 {
 | 
			
		||||
	return NewVT(DefaultTabWidth, DefaultScrollback)
 | 
			
		||||
 | 
			
		||||
@ -324,7 +324,7 @@ func TestVtSetState(t *testing.T) {
 | 
			
		||||
func TestVTDriverInterface(t *testing.T) {
 | 
			
		||||
	var dev device.Driver = NewVT(0, 0)
 | 
			
		||||
 | 
			
		||||
	if err := dev.DriverInit(); err != nil {
 | 
			
		||||
	if err := dev.DriverInit(nil); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ import (
 | 
			
		||||
	"gopheros/kernel/cpu"
 | 
			
		||||
	"gopheros/kernel/hal/multiboot"
 | 
			
		||||
	"image/color"
 | 
			
		||||
	"io"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
@ -197,7 +198,7 @@ func (cons *VgaTextConsole) DriverVersion() (uint16, uint16, uint16) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
func probeForVgaTextConsole() device.Driver {
 | 
			
		||||
 | 
			
		||||
@ -311,7 +311,7 @@ func TestVgaTextSetPaletteColor(t *testing.T) {
 | 
			
		||||
func TestVgaTextDriverInterface(t *testing.T) {
 | 
			
		||||
	var dev device.Driver = NewVgaTextConsole(80, 25, 0)
 | 
			
		||||
 | 
			
		||||
	if err := dev.DriverInit(); err != nil {
 | 
			
		||||
	if err := dev.DriverInit(nil); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package hal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"gopheros/device"
 | 
			
		||||
	"gopheros/device/tty"
 | 
			
		||||
	"gopheros/device/video/console"
 | 
			
		||||
@ -13,7 +14,10 @@ type managedDevices struct {
 | 
			
		||||
	activeTTY     tty.Device
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var devices managedDevices
 | 
			
		||||
var (
 | 
			
		||||
	devices managedDevices
 | 
			
		||||
	strBuf  bytes.Buffer
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ActiveTTY returns the currently active TTY
 | 
			
		||||
func ActiveTTY() tty.Device {
 | 
			
		||||
@ -43,7 +47,10 @@ func DetectHardware() {
 | 
			
		||||
// each detected device. The function returns a list of device drivers that
 | 
			
		||||
// were successfully initialized.
 | 
			
		||||
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 {
 | 
			
		||||
		drv := probeFn()
 | 
			
		||||
@ -51,16 +58,18 @@ func probe(hwProbeFns []device.ProbeFn) []device.Driver {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		strBuf.Reset()
 | 
			
		||||
		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(); err != nil {
 | 
			
		||||
			kfmt.Printf("init failed: %s\n", err.Message)
 | 
			
		||||
		if err := drv.DriverInit(&w); err != nil {
 | 
			
		||||
			kfmt.Fprintf(&w, "init failed: %s\n", err.Message)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		kfmt.Fprintf(&w, "initialized\n")
 | 
			
		||||
		drivers = append(drivers, drv)
 | 
			
		||||
		kfmt.Printf("initialized\n")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return drivers
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,14 @@ var (
 | 
			
		||||
	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
 | 
			
		||||
// any data accumulated in the earlyPrintBuffer to itt .
 | 
			
		||||
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
 | 
			
		||||
	SetOutputSink(&buf)
 | 
			
		||||
 | 
			
		||||
	if sink := GetOutputSink(); sink != &buf {
 | 
			
		||||
		t.Fatal("expected GetOutputSink() to return the value passed to SetOutputSink")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for specIndex, spec := range specs {
 | 
			
		||||
		buf.Reset()
 | 
			
		||||
		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