Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/exp/shiny/driver/x11driver: runtime error on centos-7 #15100

Open
sbinet opened this issue Apr 4, 2016 · 13 comments
Open

x/exp/shiny/driver/x11driver: runtime error on centos-7 #15100

sbinet opened this issue Apr 4, 2016 · 13 comments
Labels
help wanted NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@sbinet
Copy link
Member

sbinet commented Apr 4, 2016

Please answer these questions before submitting your issue. Thanks!

  1. What version of Go are you using (go version)?
$> go version
go version go1.6 linux/amd64
  1. What operating system and processor architecture are you using (go env)?
$> go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GO15VENDOREXPERIMENT="1"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"
  1. What did you do?
$> go get -t -u golang.org/x/exp/shiny/...
$> cd $GOPATH/src/golang/x/exp/shiny/example/basic
$> go build main.go
$> ./main
  1. What did you expect to see?
    a window with 3 rounded squares.
  2. What did you see instead?

an empty window (with whatever was displayed behind that window, captured into that window but not refreshed) and the following error:

$> ./main
2016/04/04 13:47:06 x11driver: xproto.WaitForEvent: BadAccess {NiceName: Access, Sequence: 17, BadValue: 92274692, MinorOpcode: 1, MajorOpcode: 130}
2016/04/04 13:47:06 x11driver: xproto.WaitForEvent: BadBadSeg {NiceName: BadSeg, Sequence: 21, BadValue: 92274691, MinorOpcode: 3, MajorOpcode: 130}

The "interesting" thing is that the pointer-painting example from xgbutil works correctly.
So it presumably is some configuration issue on the x11driver end.
(I tried replacing xgb.NewConn() with xgbutil.NewConn() and adapt a bit, to no avail)

@sbinet
Copy link
Member Author

sbinet commented Apr 7, 2016

FYI, it's also present when using a docker container (centos:7).

$> xhost +
$> docker run -ti --rm \
      -e DISPLAY=$DISPLAY \
      -v /tmp/.X11-unix:/tmp/.X11-unix \
      centos:7 bash

docker> yum install -y git gcc && \
 curl -O -L https://storage.googleapis.com/golang/go1.6.linux-amd64.tar.gz && \
 tar -C /usr/local -xzf go1.6.linux-amd64.tar.gz

docker> export PATH=/usr/local/go/bin:$PATH
docker> export GOPATH=/go
docker> go get -t -u golang.org/x/exp/shiny/driver/x11driver
docker> cd $GOPATH/src/golang.org/x/exp/shiny/example/basic
docker> go run main.go
XGB: conn.go:47: Could not get authority info: open /root/.Xauthority: no such file or directory
XGB: conn.go:48: Trying connection without authority info...
2016/04/07 12:33:07 x11driver: xproto.WaitForEvent: BadAccess {NiceName: Access, Sequence: 17, BadValue: 83886084, MinorOpcode: 1, MajorOpcode: 130}
2016/04/07 12:33:07 x11driver: xproto.WaitForEvent: BadBadSeg {NiceName: BadSeg, Sequence: 21, BadValue: 83886083, MinorOpcode: 3, MajorOpcode: 130}

@nigeltao any idea?

@bradfitz bradfitz added this to the Unreleased milestone Apr 7, 2016
@nigeltao
Copy link
Contributor

nigeltao commented Apr 8, 2016

What is $HOME and $XAUTHORITY for both cases? For docker, it looks like $HOME is "/home", which looks weird. Are you running as root? (Sorry, I'm not very familiar with docker).

On centos, could you strace both the xgb- and xgbutil-based programs and see what files they open, whose names look vaguely like "Xauthority"?

@nigeltao
Copy link
Contributor

nigeltao commented Apr 8, 2016

Ah, never mind about the strace. I just read the first post again, and if you can get a window up, then xgb should have auth'd correctly, even if the window isn't painting properly. Hmm...

@sbinet
Copy link
Member Author

sbinet commented Apr 15, 2016

just a small update.
the following program works on centos-7:

package main

import (
    "fmt"
    "image"
    "image/color"
    "image/draw"
    "time"

    "github.com/BurntSushi/xgbutil"
    "github.com/BurntSushi/xgbutil/xevent"
    "github.com/BurntSushi/xgbutil/xgraphics"
)

func main() {
    const (
        w = 150
        h = 150
    )
    img := image.NewRGBA(image.Rect(0, 0, int(w), int(h)))

    X, err := xgbutil.NewConn()
    fatal(err)

    ximg := xgraphics.New(X, img.Bounds())

    wid := ximg.XShowExtra("foo", true)
    go func() {
        xevent.Main(X)
    }()

    ximg.XDraw()
    ximg.XPaint(wid.Id)
    fmt.Printf("window id: %v\n", wid.Id)

    time.Sleep(2 * time.Second)
    fmt.Printf("drawing white...\n")
    draw.Draw(ximg, ximg.Bounds(), image.NewUniform(color.White), image.Point{0, 0}, draw.Src)
    ximg.XDraw()
    ximg.XPaint(wid.Id)

    time.Sleep(5 * time.Second)
}

func fatal(err error) {
    if err != nil {
        panic(err)
    }
}

@nigeltao
Copy link
Contributor

I'd still like to know what $HOME and $XAUTHORITY are, and whether you're running as root.

@sbinet
Copy link
Member Author

sbinet commented Apr 15, 2016

inside the docker container, I get these:

[binet@32e78b70bb07 basic]$ whoami
binet
[binet@32e78b70bb07 basic]$ echo $HOME
/home/binet
[binet@32e78b70bb07 basic]$ echo "auth=[$XAUTHORITY]"
auth=[]

inside a proper centos-7 VM, I am indeed running as root:

[root@themachine ~]# whoami
root
[root@themachine ~]# echo $HOME
/root
[root@themachine ~]# echo "auth=[$XAUTHORITY]"
auth=[]

@sbinet
Copy link
Member Author

sbinet commented Apr 15, 2016

and, on another Centos-7 machine I have access to, as a regular user:

13:37 binet@lxplus0099 shiny/example/basic% ./main 
2016/04/15 13:37:40 x11driver: xproto.WaitForEvent: BadAccess {NiceName: Access, Sequence: 17, BadValue: 106954756, MinorOpcode: 1, MajorOpcode: 130}
2016/04/15 13:37:40 x11driver: xproto.WaitForEvent: BadBadSeg {NiceName: BadSeg, Sequence: 21, BadValue: 106954755, MinorOpcode: 3, MajorOpcode: 130}
^C
zsh: interrupt  ./main
13:37 binet@lxplus0099 shiny/example/basic% echo $HOME
/afs/cern.ch/user/b/binet
13:37 binet@lxplus0099 shiny/example/basic% whoami
binet
13:37 binet@lxplus0099 shiny/example/basic% echo $XAUTHORITY

13:38 binet@lxplus0099 shiny/example/basic% cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core) 

@sbinet
Copy link
Member Author

sbinet commented Apr 15, 2016

did a bit of print-foo debugging.
here are the print-outs:

$ ./main
-- render.Init --
--- case 1: err=<nil> seq=1
----> cookies... (seq=1 err=<nil>)
-- shm.Init --
--- case 1: err=<nil> seq=2
----> cookies... (seq=2 err=<nil>)
-- newScreenImpl --
xsi...
initAtoms...
--- case 1: err=<nil> seq=3
----> cookies... (seq=3 err=<nil>)
--- case 1: err=<nil> seq=4
----> cookies... (seq=4 err=<nil>)
--- case 1: err=<nil> seq=5
----> cookies... (seq=5 err=<nil>)
initKeyboardMapping...
--- case 1: err=<nil> seq=6
----> cookies... (seq=6 err=<nil>)
initPictformats...
--- case 1: err=<nil> seq=7
----> cookies... (seq=7 err=<nil>)
initWindow32...
--- case 1: err=<nil> seq=9
----> cookies... (seq=9 err=<nil>)
s.xsi.Root-Depth = 24 (24)
--- case 1: err=<nil> seq=11
----> cookies... (seq=11 err=<nil>)
--- case 1: err=<nil> seq=13
----> cookies... (seq=13 err=<nil>)
go run()...
... wait for event...
--- case 1: err=<nil> seq=15
----> cookies... (seq=15 err=<nil>)
--- case 1: err=<nil> seq=17
----> cookies... (seq=17 err=<nil>)
--- case 1: err=<nil> seq=19
----> cookies... (seq=19 err=<nil>)
--- case 1: err=<nil> seq=21
----> cookies... (seq=21 err=<nil>)
--- case 1: err=<nil> seq=23
----> cookies... (seq=23 err=<nil>)
--- case default: err=<nil> evtnum=21
--- case 0: err=BadAccess {NiceName: Access, Sequence: 24, BadValue: 111149060, MinorOpcode: 1, MajorOpcode: 130} seq=24
buf=[0 10 24 0 4 0 160 6 1 0 130 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
----> cookies... (seq=24 err=BadAccess {NiceName: Access, Sequence: 24, BadValue: 111149060, MinorOpcode: 1, MajorOpcode: 130})
****cookie err: BadAccess {NiceName: Access, Sequence: 24, BadValue: 111149060, MinorOpcode: 1, MajorOpcode: 130}
... wait for event...
2016/04/15 12:33:55 x11driver: xproto.WaitForEvent: BadAccess {NiceName: Access, Sequence: 24, BadValue: 111149060, MinorOpcode: 1, MajorOpcode: 130}
... wait for event...
--- case default: err=<nil> evtnum=22
... wait for event...
--- case 1: err=<nil> seq=26
----> cookies... (seq=26 err=<nil>)
--- case 1: err=<nil> seq=28
----> cookies... (seq=28 err=<nil>)
--- case default: err=<nil> evtnum=22
... wait for event...
--- case 1: err=<nil> seq=30
----> cookies... (seq=30 err=<nil>)
--- case 0: err=BadBadSeg {NiceName: BadSeg, Sequence: 31, BadValue: 111149059, MinorOpcode: 3, MajorOpcode: 130} seq=31
buf=[0 128 31 0 3 0 160 6 3 0 130 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
----> cookies... (seq=31 err=BadBadSeg {NiceName: BadSeg, Sequence: 31, BadValue: 111149059, MinorOpcode: 3, MajorOpcode: 130})
****cookie err: BadBadSeg {NiceName: BadSeg, Sequence: 31, BadValue: 111149059, MinorOpcode: 3, MajorOpcode: 130}
2016/04/15 12:33:55 x11driver: xproto.WaitForEvent: BadBadSeg {NiceName: BadSeg, Sequence: 31, BadValue: 111149059, MinorOpcode: 3, MajorOpcode: 130}

which correspond to:
https://github.com/golang/exp/blob/master/shiny/vendor/github.com/BurntSushi/xgb/xgb.go#L400

        buf := make([]byte, 32)
        err, seq = nil, 0
        if _, err := io.ReadFull(c.conn, buf); err != nil {
            Logger.Printf("A read error is unrecoverable: %s", err)
            fmt.Printf("**** read error: %v\n", err)
            c.eventChan <- err
            c.Close()
            continue
        }
        switch buf[0] {
        case 0: // This is an error
            // Use the constructor function for this error (that is auto
            // generated) by looking it up by the error number.
            newErrFun, ok := NewErrorFuncs[int(buf[1])]
            if !ok {
                Logger.Printf("BUG: Could not find error constructor function "+
                    "for error with number %d.", buf[1])
                continue
            }
            err = newErrFun(buf)
            seq = err.SequenceId()
            fmt.Printf("--- case 0: err=%v seq=%v\nbuf=%v\n", err, seq, buf)
            // This error is either sent to the event channel or a specific
            // cookie's error channel below.
        case 1: // This is a reply
            seq = Get16(buf[2:])

            // check to see if this reply has more bytes to be read
            size := Get32(buf[4:])
            if size > 0 {
                byteCount := 32 + size*4
                biggerBuf := make([]byte, byteCount)
                copy(biggerBuf[:32], buf)
                if _, err := io.ReadFull(c.conn, biggerBuf[32:]); err != nil {
                    Logger.Printf("A read error is unrecoverable: %s", err)
                    fmt.Printf("**** read-error: %v\n", err)
                    c.eventChan <- err
                    c.Close()
                    continue
                }
                replyBytes = biggerBuf
            } else {
                replyBytes = buf
            }
            fmt.Printf("--- case 1: err=%v seq=%v\n", err, seq)

            // This reply is sent to its corresponding cookie below.
        default: // This is an event
            // Use the constructor function for this event (like for errors,
            // and is also auto generated) by looking it up by the event number.
            // Note that we AND the event number with 127 so that we ignore
            // the most significant bit (which is set when it was sent from
            // a SendEvent request).
            evNum := int(buf[0] & 127)
            newEventFun, ok := NewEventFuncs[evNum]
            if !ok {
                Logger.Printf("BUG: Could not find event construct function "+
                    "for event with number %d.", evNum)
                fmt.Printf("*** could not find event construct[%d]\n", evNum)
                continue
            }
            fmt.Printf("--- case default: err=%v evtnum=%v\n", err, evNum)
            c.eventChan <- newEventFun(buf)
            continue
        }

        fmt.Printf("----> cookies... (seq=%v err=%v)\n", seq, err)
        // At this point, we have a sequence number and we're either
        // processing an error or a reply, which are both responses to
        // requests. So all we have to do is find the cookie corresponding
        // to this error/reply, and send the appropriate data to it.
        // In doing so, we make sure that any cookies that came before it
        // are marked as successful if they are void and checked.
        // If there's a cookie that requires a reply that is before this
        // reply, then something is wrong.
        for cookie := range c.cookieChan {
            // This is the cookie we're looking for. Process and break.
            if cookie.Sequence == seq {
                if err != nil { // this is an error to a request
                    // synchronous processing
                    if cookie.errorChan != nil {
                        fmt.Printf("**** sync-cookie error: %v\n", err)
                        cookie.errorChan <- err
                    } else { // asynchronous processing
                        fmt.Printf("****cookie err: %v\n", err)
                        c.eventChan <- err
                        // if this is an unchecked reply, ping the cookie too
                        if cookie.pingChan != nil {
                            cookie.pingChan <- true
                        }
                    }
                } else { // this is a reply
                    if cookie.replyChan == nil {
                        Logger.Printf("Reply with sequence id %d does not "+
                            "have a cookie with a valid reply channel.", seq)
                        continue
                    } else {
                        cookie.replyChan <- replyBytes
                    }
                }
                break
            }

hth,
-s

@aarzilli
Copy link
Contributor

@sbinet: are you trying to use shiny with a remote display server? The 'afs' in your home path makes me think you are.

@sbinet
Copy link
Member Author

sbinet commented Apr 21, 2016

@aarzilli dunno. with X11, remote, server and client have (to me) unclear semantics.
in the specific case of the afs test:

  • from my localhost (an archlinux64b machine where shiny is working correctly) I ssh -YC to lxplus.cern.ch which is a CentOS-7 machine (and where xlogo and xclock are working correctly)
  • there, I try to run the basic shiny example, with the unfortunate outcome.

hth

@sbinet
Copy link
Member Author

sbinet commented Apr 21, 2016

for all the variations of (centos-7) machines to which I ssh, the BurntSushi/xgb examples are working.
the shiny ones do not.

@aarzilli
Copy link
Contributor

with X11, server and client have (to me) unclear semantics.

I can sympathize with this.

So, the display server (ie the thing that puts stuff on the screen) you are trying to use is running on your local archlinux64b machine, the shiny program is running on a CentOS-7 machine you are ssh'ing into. This makes the display server "remote" wrt the shiny program.

AFAIK this won't work, x11driver uses MIT-SHM to upload the image and MIT-SHM doesn't work without, you know, actual "shared memory" between the client and the display server.

xgbutil and xgb examples work because they are using server side pixmaps (or whatever they are called, I'm not an expert). I guess it wouldn't be too much work to add PutImage as a fallback for uploading but remember that we're all getting waylanded soon and once we are in wayland-land there's no way remote display servers work.

@dmitshur dmitshur changed the title shiny/driver/x11driver: runtime error on centos-7 x/exp/shiny/driver/x11driver: runtime error on centos-7 Mar 10, 2018
@andybons andybons added help wanted NeedsFix The path to resolution is known, but the work has not been done. labels Mar 11, 2018
@gopherbot
Copy link

Change https://golang.org/cl/213199 mentions this issue: shiny/driver/x11driver: failback to regular pixmaps if SHM is unavaiable

gopherbot pushed a commit to golang/exp that referenced this issue Jan 19, 2020
This PR implement the **TODO** in buffer.go:
```
// TODO: detect if the X11 server or connection cannot support SHM pixmaps,
// and fall back to regular pixmaps.
```
It fixes the issues:
[golang/go#15100](golang/go#15100)
[aarzilli/gdlv#26](aarzilli/gdlv#26)
[aarzilli/gdlv#5](aarzilli/gdlv#5)
[oakmound#8](oakmound#8)

@sbinet
@aarzilli
@200sc

Change-Id: I7f157c95928ca5fde015935ea5fe1d1f8b03ea43
GitHub-Last-Rev: 0a5d514
GitHub-Pull-Request: #9
Reviewed-on: https://go-review.googlesource.com/c/exp/+/213199
Reviewed-by: Nigel Tao <nigeltao@golang.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

6 participants