Go

Go on z/OS

Go on z/OS

This group is a space for open discussions and sharing technical information, and also provides a connection to the wider Go open source community for anyone who is interested in Go on z/OS

 View Only
  • 1.  Possible Go z/OS runtime issue.

    Posted Sun June 02, 2024 03:16 PM
    Edited by Frank Swarbrick Sun June 02, 2024 03:17 PM

    So I am adding z/OS support to package github.com/creack/pty.  I've got it working pretty well (see attached pty_zos.go), but it is not passing one of the tests:

    --- FAIL: TestReadClose (0.00s)
        io_test.go:80: Unexpected read error: read /dev/ptmx: EDC5112I Resource temporarily unavailable..
    panic: Fail in goroutine after TestReadClose has completed
    
    goroutine 20 [running]:
    testing.(*common).Fail(0xc0004956c0)
            /u/dvfjs/.local/usr/go/src/testing/testing.go:952 +0x134
    testing.(*common).Errorf(0xc0004956c0, {0x10850424, 0x19}, {0xc0004e2fc8, 0x1, 0x1})
            /u/dvfjs/.local/usr/go/src/testing/testing.go:1075 +0x9e
    github.com/creack/pty/v2.TestReadClose.func1()
            /u/dvfjs/diffm/pty/io_test.go:72 +0xf0
    created by github.com/creack/pty/v2.TestReadClose in goroutine 17
            /u/dvfjs/diffm/pty/io_test.go:69 +0x192
    FAIL    github.com/creack/pty/v2        0.829s
    FAIL

    The code in question is this:

    func TestReadClose(t *testing.T) {
            ptmx, success := prepare(t)
            if err := syscall.SetNonblock(int(ptmx.Fd()), true); err != nil {
                    t.Fatalf("Error: set non block: %s", err)
            }
    
            go func() {
                    time.Sleep(timeout / 10)
                    if err := ptmx.Close(); err != nil {
                            t.Errorf("Failed to close ptmx: %s.", err)
                    }
            }()
    
            buf := make([]byte, 1)
            n, err := ptmx.Read(buf)
            success()
            if err != nil && !errors.Is(err, os.ErrClosed) {
                    t.Fatalf("Unexpected read error: %s.", err)
            }
    
            if n != 0 && buf[0] != errMarker {
                    t.Errorf("Received unexpected data from pmtx (%d bytes): 0x%X; err=%v.", n, buf, err)
            }
    }
    

    Line 80 is the t.Fatal with "Unexpected read error".  The read should be returning os.ErrClosed, because the earlier go routine has closed the psuedo-terminal asynchronously.  I've stepped through the code in Linux and z/OS and have found a difference in behavior.

    In go/src/internal/poll/fd_mutex.go we have method rwlock:

    func (mu *fdMutex) rwlock(read bool) bool { 
     var mutexBit, mutexWait, mutexMask uint64  
     var mutexSema *uint32                      
     if read {                                  
      mutexBit = mutexRLock                     
      mutexWait = mutexRWait                    
      mutexMask = mutexRMask                    
      mutexSema = &mu.rsema                     
     } else {                                   
      mutexBit = mutexWLock                     
      mutexWait = mutexWWait                    
      mutexMask = mutexWMask                    
      mutexSema = &mu.wsema                     
     }                                          
     for {                                      
      old := atomic.LoadUint64(&mu.state)       
      if old&mutexClosed != 0 {                 
       return false                             
      }                                         
      [...]

    On Linux, when the method is entered, mu.state == 0x0, but by the time it gets to the first line of rwlock, the state has been updated to 0x1 (asynchronously, I assume). So when it checks old&mutextClosed, that returns 0x1 and causes the method to return false. The causes readLock (below) to return errClosing(fd.isFile).

    func (fd *FD) readLock() error {
     if !fd.fdmu.rwlock(true) {     
      return errClosing(fd.isFile)  
     }                              
     return nil                     
    }                               

    Then of course this error gets passed back through the read.

    With z/OS the state is not changing from 0x0 to 0x1, so the errClosing return never executes.

    Thoughts?

    (Edit: My attachment didn't upload.  I will include it in a reply to this post.)

    ------------------------------
    Frank Swarbrick
    ------------------------------



  • 2.  RE: Possible Go z/OS runtime issue.

    Posted Sun June 02, 2024 03:19 PM
    //go:build zos
    // +build zos
    
    package pty
    
    import (
    	"os"
    	"syscall"
    
    	"golang.org/x/sys/unix"
    )
    
    func open() (pty, tty *os.File, err error) {
    	ptmxfd, err := unix.Posix_openpt(os.O_RDWR | syscall.O_NOCTTY)
    	if err != nil {
    		return nil, nil, err
    	}
    
    	// Needed for z/OS so that the characters are not garbled if ptyp* is untagged
    	cvtreq := unix.F_cnvrt{Cvtcmd: unix.SETCVTON, Pccsid: 0, Fccsid: 1047}
    	if _, err = unix.FcntlFcnvrt(uintptr(ptmxfd), unix.F_CONTROL_CVT, &cvtreq); err != nil {
    		return nil, nil, err
    	}
    
    	p := os.NewFile(uintptr(ptmxfd), "/dev/ptmx")
    	if p == nil {
    		return nil, nil, err
    	}
    
    	// In case of error after this point, make sure we close the ptmx fd.
    	defer func() {
    		if err != nil {
    			_ = p.Close() // Best effort.
    		}
    	}()
    
    	sname, err := unix.Ptsname(ptmxfd)
    	if err != nil {
    		return nil, nil, err
    	}
    
    	_, err = unix.Grantpt(ptmxfd)
    	if err != nil {
    		return nil, nil, err
    	}
    
    	if _, err = unix.Unlockpt(ptmxfd); err != nil {
    		return nil, nil, err
    	}
    
    	ptsfd, err := syscall.Open(sname, os.O_RDWR|syscall.O_NOCTTY, 0)
    	if err != nil {
    		return nil, nil, err
    	}
    
    	if _, err = unix.FcntlFcnvrt(uintptr(ptsfd), unix.F_CONTROL_CVT, &cvtreq); err != nil {
    		return nil, nil, err
    	}
    
    	t := os.NewFile(uintptr(ptsfd), sname)
    	if err != nil {
    		return nil, nil, err
    	}
    
    	return p, t, nil
    }
    


    ------------------------------
    Frank Swarbrick
    ------------------------------



  • 3.  RE: Possible Go z/OS runtime issue.

    Posted Thu June 06, 2024 07:40 PM

    Is there a better place to report possible issues?



    ------------------------------
    Frank Swarbrick
    ------------------------------



  • 4.  RE: Possible Go z/OS runtime issue.

    Posted Mon June 10, 2024 03:37 PM

    hi Frank,

    Yes ,this is the right forum and I understand you are already in contact with someone on the Go team on this topic.

    thanks



    ------------------------------
    Linda Chui
    Compilation Technology & Enterprise Products
    IBM Canada
    ------------------------------



  • 5.  RE: Possible Go z/OS runtime issue.

    Posted Thu November 28, 2024 02:41 PM

    Is this bug by chance on anyone's list?  If not, can it be addressed?



    ------------------------------
    Frank Swarbrick
    ------------------------------



  • 6.  RE: Possible Go z/OS runtime issue.
    Best Answer

    Posted Thu November 28, 2024 03:08 PM

    Hello Frank,

    This bug has been fixed as of this PR
    add z/OS support by MacMalainey · Pull Request #201 · creack/pty

    According to the repo this change has already been tagged and is included in the latest release of the pty module.



    ------------------------------
    Mackenzie Malainey
    ------------------------------



  • 7.  RE: Possible Go z/OS runtime issue.

    Posted Thu November 28, 2024 06:17 PM

    Interesting.  Well cool.  If he's here, thank you very much!  There is one change that still needs to be made, but I think I can handle it. 



    ------------------------------
    Frank Swarbrick
    ------------------------------