[gccgo] Use select on RTEMS
diff mbox

Message ID mcr630xltru.fsf@google.com
State New
Headers show

Commit Message

Ian Taylor July 2, 2010, 4:42 p.m. UTC
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 mbox

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
+}