Patchwork [gccgo] Use select on RTEMS

login
register
mail settings
Submitter Ian Taylor
Date July 2, 2010, 4:42 p.m.
Message ID <mcr630xltru.fsf@google.com>
Download mbox | patch
Permalink /patch/57675/
State New
Headers show

Comments

Ian Taylor - July 2, 2010, 4:42 p.m.
RTEMS does not support epoll or kqueue.  This patch from Vinu
Rajashekhar changes libgo to use select when running on RTEMS.
Committed to gccgo branch.

Ian

Patch

diff -r bc4beadc0c0c libgo/Makefile.am
--- a/libgo/Makefile.am	Fri Jul 02 07:53:16 2010 -0700
+++ b/libgo/Makefile.am	Fri Jul 02 09:36:35 2010 -0700
@@ -535,12 +535,21 @@ 
 go_mime_files = \
 	go/mime/type.go
 
+if LIBGO_IS_RTEMS
+go_net_fd_os_file = go/net/fd_rtems.go
+go_net_newpollserver_file = go/net/newpollserver_rtems.go
+else
+go_net_fd_os_file = go/net/fd_linux.go
+go_net_newpollserver_file = go/net/newpollserver.go
+endif
+
 go_net_files = \
 	go/net/dnsclient.go \
 	go/net/dnsconfig.go \
 	go/net/dnsmsg.go \
+	$(go_net_newpollserver_file) \
 	go/net/fd.go \
-	go/net/fd_linux.go \
+	$(go_net_fd_os_file) \
 	go/net/hosts.go \
 	go/net/ip.go \
 	go/net/iprawsock.go \
diff -r bc4beadc0c0c libgo/go/net/fd.go
--- a/libgo/go/net/fd.go	Fri Jul 02 07:53:16 2010 -0700
+++ b/libgo/go/net/fd.go	Fri Jul 02 09:36:35 2010 -0700
@@ -93,37 +93,6 @@ 
 	deadline int64     // next deadline (nsec since 1970)
 }
 
-func newPollServer() (s *pollServer, err os.Error) {
-	s = new(pollServer)
-	s.cr = make(chan *netFD, 1)
-	s.cw = make(chan *netFD, 1)
-	if s.pr, s.pw, err = os.Pipe(); err != nil {
-		return nil, err
-	}
-	var e int
-	if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
-	Errno:
-		err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
-	Error:
-		s.pr.Close()
-		s.pw.Close()
-		return nil, err
-	}
-	if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
-		goto Errno
-	}
-	if s.poll, err = newpollster(); err != nil {
-		goto Error
-	}
-	if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
-		s.poll.Close()
-		goto Error
-	}
-	s.pending = make(map[int]*netFD)
-	go s.Run()
-	return s, nil
-}
-
 func (s *pollServer) AddFD(fd *netFD, mode int) {
 	intfd := fd.sysfd
 	if intfd < 0 {
diff -r bc4beadc0c0c libgo/go/net/fd_rtems.go
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/go/net/fd_rtems.go	Fri Jul 02 09:36:35 2010 -0700
@@ -0,0 +1,138 @@ 
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via select(2).
+
+package net
+
+import (
+	"os"
+	"syscall"
+	//"fmt"
+)
+
+type pollster struct {
+	readFds, writeFds, repeatFds *syscall.FdSet_t
+	maxFd int
+	readyReadFds, readyWriteFds *syscall.FdSet_t
+	nReady int
+	lastFd int
+}
+
+func newpollster() (p *pollster, err os.Error) {
+	p = new(pollster)
+	p.readFds = new(syscall.FdSet_t)
+	p.writeFds = new(syscall.FdSet_t)
+	p.repeatFds = new(syscall.FdSet_t)
+	p.readyReadFds = new(syscall.FdSet_t)
+	p.readyWriteFds = new(syscall.FdSet_t)
+	p.maxFd = -1
+	p.nReady = 0
+	p.lastFd = 0
+	return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
+	if mode == 'r' {
+		syscall.FDSet(fd, p.readFds)
+	} else {
+		syscall.FDSet(fd, p.writeFds)
+	}
+
+	if repeat {
+		syscall.FDSet(fd, p.repeatFds)
+	}
+
+	if fd > p.maxFd {
+		p.maxFd = fd
+	}
+
+	return nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+	if mode == 'r' {
+		if !syscall.FDIsSet(fd, p.readFds) {
+			print("Select unexpected fd=", fd, " for read\n")
+			return
+		}
+		syscall.FDClr(fd, p.readFds)
+	} else {
+		if !syscall.FDIsSet(fd, p.writeFds) {
+			print("Select unexpected fd=", fd, " for write\n")
+			return
+		}
+		syscall.FDClr(fd, p.writeFds)
+	}
+
+	// Doesn't matter if not already present.
+	syscall.FDClr(fd, p.repeatFds)
+
+	// We don't worry about maxFd here.
+}
+
+func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
+	if p.nReady == 0 {
+		var timeout *syscall.Timeval
+		var tv syscall.Timeval
+		timeout = nil
+		if nsec > 0 {
+			tv = syscall.NsecToTimeval(nsec)
+			timeout = &tv
+		}
+
+		var n, e int
+		var tmpReadFds, tmpWriteFds syscall.FdSet_t
+		for {
+			// Temporary syscall.FdSet_ts into which the values are copied
+			// because select mutates the values.
+			tmpReadFds = *p.readFds
+			tmpWriteFds = *p.writeFds
+
+			n, e = syscall.Select(p.maxFd + 1, &tmpReadFds, &tmpWriteFds, nil, timeout)
+			if e != syscall.EINTR {
+				break
+			}
+		}
+		if e != 0 {
+			return -1, 0, os.NewSyscallError("select", e)
+		}
+		if n == 0 {
+			return -1, 0, nil
+		}
+
+		p.nReady = n
+		*p.readyReadFds = tmpReadFds
+		*p.readyWriteFds = tmpWriteFds
+		p.lastFd = 0
+	}
+
+	flag := false
+	for i := p.lastFd; i < p.maxFd + 1; i++ {
+		if syscall.FDIsSet(i, p.readyReadFds) {
+			flag = true
+			mode := 'r'
+			syscall.FDClr(i, p.readyReadFds)
+		} else if syscall.FDIsSet(i, p.readyWriteFds) {
+			flag = true
+			mode := 'w'
+			syscall.FDClr(i, p.readyWriteFds)
+		}
+		if flag {
+			if !syscall.FDIsSet(i, p.repeatFds) {
+				p.DelFD(i, mode)
+			}
+			p.nReady--
+			p.lastFd = i
+			return i, mode, nil
+		}
+	}
+
+	// Will not reach here.  Just to shut up the compiler.
+	return -1, 0, nil
+}
+
+func (p *pollster) Close() os.Error {
+	return nil
+}
diff -r bc4beadc0c0c libgo/go/net/newpollserver.go
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/go/net/newpollserver.go	Fri Jul 02 09:36:35 2010 -0700
@@ -0,0 +1,41 @@ 
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+	"os"
+	"syscall"
+)
+
+func newPollServer() (s *pollServer, err os.Error) {
+	s = new(pollServer)
+	s.cr = make(chan *netFD, 1)
+	s.cw = make(chan *netFD, 1)
+	if s.pr, s.pw, err = os.Pipe(); err != nil {
+		return nil, err
+	}
+	var e int
+	if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
+	Errno:
+		err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+	Error:
+		s.pr.Close()
+		s.pw.Close()
+		return nil, err
+	}
+	if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
+		goto Errno
+	}
+	if s.poll, err = newpollster(); err != nil {
+		goto Error
+	}
+	if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
+		s.poll.Close()
+		goto Error
+	}
+	s.pending = make(map[int]*netFD)
+	go s.Run()
+	return s, nil
+}
diff -r bc4beadc0c0c libgo/go/net/newpollserver_rtems.go
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/go/net/newpollserver_rtems.go	Fri Jul 02 09:36:35 2010 -0700
@@ -0,0 +1,78 @@ 
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+	"os"
+	"syscall"
+)
+
+func selfConnectedTCPSocket() (pr, pw *os.File, err os.Error) {
+	// See ../syscall/exec.go for description of ForkLock.
+	syscall.ForkLock.RLock()
+	sockfd, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0)
+	if e != 0 {
+		syscall.ForkLock.RUnlock()
+		return nil, nil, os.Errno(e)
+	}
+	syscall.CloseOnExec(sockfd)
+	syscall.ForkLock.RUnlock()
+
+	// Allow reuse of recently-used addresses.
+	syscall.SetsockoptInt(sockfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+
+	var laTCP *TCPAddr
+	var la syscall.Sockaddr
+	if laTCP, err = ResolveTCPAddr("127.0.0.1:0"); err != nil {
+	Error:
+		return nil, nil, err
+	}
+	if la, err = laTCP.sockaddr(syscall.AF_INET); err != nil {
+		goto Error
+	}
+	e = syscall.Bind(sockfd, la)
+	if e != 0 {
+	Errno:
+		syscall.Close(sockfd)
+		return nil, nil, os.Errno(e)
+	}
+
+	laddr, _ := syscall.Getsockname(sockfd)
+	e = syscall.Connect(sockfd, laddr)
+	if e != 0 {
+		goto Errno
+	}
+
+	fd := os.NewFile(sockfd, "wakeupSocket")
+	return fd, fd, nil
+}
+
+func newPollServer() (s *pollServer, err os.Error) {
+	s = new(pollServer)
+	s.cr = make(chan *netFD, 1)
+	s.cw = make(chan *netFD, 1)
+	// s.pr and s.pw are indistinguishable.
+	if s.pr, s.pw, err = selfConnectedTCPSocket(); err != nil {
+		return nil, err
+	}
+	var e int
+	if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
+	Errno:
+		err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+	Error:
+		s.pr.Close()
+		return nil, err
+	}
+	if s.poll, err = newpollster(); err != nil {
+		goto Error
+	}
+	if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
+		s.poll.Close()
+		goto Error
+	}
+	s.pending = make(map[int]*netFD)
+	go s.Run()
+	return s, nil
+}