From 9cc42dea7c4a1482bb1bcaa67b2026d4cfaa2068 Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Thu, 19 Mar 2015 18:07:56 -0700 Subject: [PATCH] Reduce memory allocation and remove channels Signed-off-by: Sachin Joshi --- term/winconsole/console_windows.go | 70 +++++++++++++----------------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/term/winconsole/console_windows.go b/term/winconsole/console_windows.go index 859ee1a..f10b1e0 100644 --- a/term/winconsole/console_windows.go +++ b/term/winconsole/console_windows.go @@ -83,6 +83,7 @@ const ( ANSI_MAX_CMD_LENGTH = 256 + MAX_INPUT_EVENTS = 128 MAX_INPUT_BUFFER = 1024 DEFAULT_WIDTH = 80 DEFAULT_HEIGHT = 24 @@ -195,15 +196,18 @@ type ( type WindowsTerminal struct { outMutex sync.Mutex inMutex sync.Mutex - inputBuffer chan byte + inputBuffer []byte + inputSize int + inputEvents []INPUT_RECORD screenBufferInfo *CONSOLE_SCREEN_BUFFER_INFO inputEscapeSequence []byte } func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) { handler := &WindowsTerminal{ - inputBuffer: make(chan byte, MAX_INPUT_BUFFER), + inputBuffer: make([]byte, MAX_INPUT_BUFFER), inputEscapeSequence: []byte(KEY_ESC_CSI), + inputEvents: make([]INPUT_RECORD, MAX_INPUT_EVENTS), } // Save current screen buffer info @@ -218,6 +222,8 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) { // Set the window size SetWindowSize(uintptr(handle), DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_HEIGHT) + buffer = make([]CHAR_INFO, screenBufferInfo.MaximumWindowSize.X*screenBufferInfo.MaximumWindowSize.Y) + if IsTerminal(os.Stdout.Fd()) { stdOut = &terminalWriter{ wrappedWriter: os.Stdout, @@ -427,6 +433,8 @@ func getNumberOfChars(fromCoord COORD, toCoord COORD, screenSize COORD) uint32 { return 0 } +var buffer []CHAR_INFO + func clearDisplayRect(fileDesc uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (bool, uint32, error) { var writeRegion SMALL_RECT writeRegion.Top = fromCoord.Y @@ -439,14 +447,13 @@ func clearDisplayRect(fileDesc uintptr, fillChar rune, attributes WORD, fromCoor height := toCoord.Y - fromCoord.Y + 1 size := width * height if size > 0 { - buffer := make([]CHAR_INFO, size) - for i := 0; i < len(buffer); i++ { + for i := 0; i < int(size); i++ { buffer[i].UnicodeChar = WCHAR(fillChar) buffer[i].Attributes = attributes } // Write to buffer - r, err := writeConsoleOutput(fileDesc, buffer, windowSize, COORD{X: 0, Y: 0}, &writeRegion) + r, err := writeConsoleOutput(fileDesc, buffer[:size], windowSize, COORD{X: 0, Y: 0}, &writeRegion) if !r { if err != nil { return false, 0, err @@ -914,6 +921,9 @@ func (term *WindowsTerminal) HandleOutputCommand(fd uintptr, command []byte) (n // WriteChars writes the bytes to given writer. func (term *WindowsTerminal) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) { + if len(p) == 0 { + return 0, nil + } return w.Write(p) } @@ -1049,24 +1059,19 @@ func mapKeystokeToTerminalString(keyEvent *KEY_EVENT_RECORD, escapeSequence []by // getAvailableInputEvents polls the console for availble events // The function does not return until at least one input record has been read. -func getAvailableInputEvents(fd uintptr) (inputEvents []INPUT_RECORD, err error) { +func getAvailableInputEvents(fd uintptr, inputEvents []INPUT_RECORD) (n int, err error) { handle := syscall.Handle(fd) if nil != err { - return nil, err + return 0, err } for { // Read number of console events available - tempBuffer := make([]INPUT_RECORD, MAX_INPUT_BUFFER) - nr, err := readConsoleInputKey(uintptr(handle), tempBuffer) + nr, err := readConsoleInputKey(uintptr(handle), inputEvents) if nr == 0 { - return nil, err + return 0, err } if 0 < nr { - retValue := make([]INPUT_RECORD, nr) - for i := 0; i < nr; i++ { - retValue[i] = tempBuffer[i] - } - return retValue, nil + return nr, nil } } } @@ -1086,32 +1091,19 @@ func getTranslatedKeyCodes(inputEvents []INPUT_RECORD, escapeSequence []byte) st } // ReadChars reads the characters from the given reader -func (term *WindowsTerminal) ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error) { - n = 0 - for n < len(p) { - select { - case b := <-term.inputBuffer: - p[n] = b - n++ - default: - // Read at least one byte read - if n > 0 { - return n, nil - } - inputEvents, _ := getAvailableInputEvents(fd) - if inputEvents != nil { - if len(inputEvents) == 0 && nil != err { - return n, err - } - if len(inputEvents) != 0 { - keyCodes := getTranslatedKeyCodes(inputEvents, term.inputEscapeSequence) - for _, b := range []byte(keyCodes) { - term.inputBuffer <- b - } - } - } +func (term *WindowsTerminal) ReadChars(fd uintptr, r io.Reader, p []byte) (n int, err error) { + for term.inputSize == 0 { + nr, err := getAvailableInputEvents(fd, term.inputEvents) + if nr == 0 && nil != err { + return n, err + } + if nr > 0 { + keyCodes := getTranslatedKeyCodes(term.inputEvents[:nr], term.inputEscapeSequence) + term.inputSize = copy(term.inputBuffer, keyCodes) } } + n = copy(p, term.inputBuffer[:term.inputSize]) + term.inputSize -= n return n, nil }