2008-09-29 14:37:00 -06:00
|
|
|
// Copyright 2009 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.
|
|
|
|
|
|
|
|
// TODO(rsc): All the prints in this file should go to standard error.
|
|
|
|
|
|
|
|
package net
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net";
|
|
|
|
"once";
|
|
|
|
"os";
|
|
|
|
"syscall";
|
|
|
|
)
|
|
|
|
|
|
|
|
// Network file descriptor. Only intended to be used internally,
|
|
|
|
// but have to export to make it available in other files implementing package net.
|
|
|
|
export type FD struct {
|
|
|
|
// immutable until Close
|
|
|
|
fd int64;
|
|
|
|
osfd *os.FD;
|
|
|
|
cr *chan *FD;
|
|
|
|
cw *chan *FD;
|
|
|
|
|
|
|
|
// owned by fd wait server
|
|
|
|
ncr, ncw int;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make reads and writes on fd return EAGAIN instead of blocking.
|
|
|
|
func SetNonblock(fd int64) *os.Error {
|
2008-10-07 13:31:31 -06:00
|
|
|
flags, e := syscall.fcntl(fd, syscall.F_GETFL, 0);
|
2008-09-29 14:37:00 -06:00
|
|
|
if e != 0 {
|
|
|
|
return os.ErrnoToError(e)
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
flags, e = syscall.fcntl(fd, syscall.F_SETFL, flags | syscall.O_NONBLOCK);
|
2008-09-29 14:37:00 -06:00
|
|
|
if e != 0 {
|
|
|
|
return os.ErrnoToError(e)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// A PollServer helps FDs determine when to retry a non-blocking
|
|
|
|
// read or write after they get EAGAIN. When an FD needs to wait,
|
|
|
|
// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
|
|
|
|
// request to the poll server. Then receive on fd.cr/fd.cw.
|
|
|
|
// When the PollServer finds that i/o on FD should be possible
|
|
|
|
// again, it will send fd on fd.cr/fd.cw to wake any waiting processes.
|
|
|
|
// This protocol is implemented as s.WaitRead() and s.WaitWrite().
|
|
|
|
//
|
|
|
|
// There is one subtlety: when sending on s.cr/s.cw, the
|
|
|
|
// poll server is probably in a system call, waiting for an fd
|
|
|
|
// to become ready. It's not looking at the request channels.
|
|
|
|
// To resolve this, the poll server waits not just on the FDs it has
|
|
|
|
// been given but also its own pipe. After sending on the
|
|
|
|
// buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a
|
|
|
|
// byte to the pipe, causing the PollServer's poll system call to
|
|
|
|
// return. In response to the pipe being readable, the PollServer
|
|
|
|
// re-polls its request channels.
|
|
|
|
//
|
|
|
|
// Note that the ordering is "send request" and then "wake up server".
|
|
|
|
// If the operations were reversed, there would be a race: the poll
|
|
|
|
// server might wake up and look at the request channel, see that it
|
|
|
|
// was empty, and go back to sleep, all before the requester managed
|
|
|
|
// to send the request. Because the send must complete before the wakeup,
|
|
|
|
// the request channel must be buffered. A buffer of size 1 is sufficient
|
|
|
|
// for any request load. If many processes are trying to submit requests,
|
|
|
|
// one will succeed, the PollServer will read the request, and then the
|
|
|
|
// channel will be empty for the next process's request. A larger buffer
|
|
|
|
// might help batch requests.
|
|
|
|
|
|
|
|
type PollServer struct {
|
|
|
|
cr, cw *chan *FD; // buffered >= 1
|
|
|
|
pr, pw *os.FD;
|
|
|
|
pending *map[int64] *FD;
|
|
|
|
poll *Pollster; // low-level OS hooks
|
|
|
|
}
|
|
|
|
func (s *PollServer) Run();
|
|
|
|
|
|
|
|
func NewPollServer() (s *PollServer, err *os.Error) {
|
|
|
|
s = new(PollServer);
|
|
|
|
s.cr = new(chan *FD, 1);
|
|
|
|
s.cw = new(chan *FD, 1);
|
|
|
|
if s.pr, s.pw, err = os.Pipe(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err = SetNonblock(s.pr.fd); err != nil {
|
|
|
|
Error:
|
|
|
|
s.pr.Close();
|
2008-10-07 13:31:31 -06:00
|
|
|
s.pw.Close();
|
2008-09-29 14:37:00 -06:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err = SetNonblock(s.pw.fd); err != nil {
|
|
|
|
goto Error
|
|
|
|
}
|
|
|
|
if s.poll, err = NewPollster(); err != nil {
|
|
|
|
goto Error
|
|
|
|
}
|
|
|
|
if err = s.poll.AddFD(s.pr.fd, 'r', true); err != nil {
|
2008-10-07 13:31:31 -06:00
|
|
|
s.poll.Close();
|
2008-09-29 14:37:00 -06:00
|
|
|
goto Error
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
s.pending = new(map[int64] *FD);
|
|
|
|
go s.Run();
|
2008-09-29 14:37:00 -06:00
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PollServer) AddFD(fd *FD, mode int) {
|
|
|
|
if err := s.poll.AddFD(fd.fd, mode, false); err != nil {
|
2008-10-07 13:31:31 -06:00
|
|
|
print("PollServer AddFD: ", err.String(), "\n");
|
2008-09-29 14:37:00 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2008-10-07 13:31:31 -06:00
|
|
|
key := fd.fd << 1;
|
2008-09-29 14:37:00 -06:00
|
|
|
if mode == 'r' {
|
2008-10-07 13:31:31 -06:00
|
|
|
fd.ncr++;
|
2008-09-29 14:37:00 -06:00
|
|
|
} else {
|
2008-10-07 13:31:31 -06:00
|
|
|
fd.ncw++;
|
|
|
|
key++;
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
s.pending[key] = fd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PollServer) LookupFD(fd int64, mode int) *FD {
|
2008-10-07 13:31:31 -06:00
|
|
|
key := fd << 1;
|
2008-09-29 14:37:00 -06:00
|
|
|
if mode == 'w' {
|
2008-10-07 13:31:31 -06:00
|
|
|
key++;
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
netfd, ok := s.pending[key];
|
2008-09-29 14:37:00 -06:00
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
s.pending[key] = nil, false;
|
2008-09-29 14:37:00 -06:00
|
|
|
return netfd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PollServer) Run() {
|
|
|
|
var scratch [100]byte;
|
|
|
|
for {
|
|
|
|
fd, mode, err := s.poll.WaitFD();
|
|
|
|
if err != nil {
|
2008-10-07 13:31:31 -06:00
|
|
|
print("PollServer WaitFD: ", err.String(), "\n");
|
2008-09-29 14:37:00 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if fd == s.pr.fd {
|
|
|
|
// Drain our wakeup pipe.
|
2008-12-18 23:37:22 -07:00
|
|
|
for nn, e := s.pr.Read(scratch); nn > 0; {
|
|
|
|
nn, e = s.pr.Read(scratch)
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read from channels
|
|
|
|
for fd, ok := <-s.cr; ok; fd, ok = <-s.cr {
|
|
|
|
s.AddFD(fd, 'r')
|
|
|
|
}
|
|
|
|
for fd, ok := <-s.cw; ok; fd, ok = <-s.cw {
|
|
|
|
s.AddFD(fd, 'w')
|
|
|
|
}
|
|
|
|
} else {
|
2008-10-07 13:31:31 -06:00
|
|
|
netfd := s.LookupFD(fd, mode);
|
2008-09-29 14:37:00 -06:00
|
|
|
if netfd == nil {
|
2008-10-07 13:31:31 -06:00
|
|
|
print("PollServer: unexpected wakeup for fd=", netfd, " mode=", string(mode), "\n");
|
2008-09-29 14:37:00 -06:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
if mode == 'r' {
|
|
|
|
for netfd.ncr > 0 {
|
2008-10-07 13:31:31 -06:00
|
|
|
netfd.ncr--;
|
2008-09-29 14:37:00 -06:00
|
|
|
netfd.cr <- netfd
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for netfd.ncw > 0 {
|
2008-10-07 13:31:31 -06:00
|
|
|
netfd.ncw--;
|
2008-09-29 14:37:00 -06:00
|
|
|
netfd.cw <- netfd
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PollServer) Wakeup() {
|
|
|
|
var b [1]byte;
|
2008-12-18 23:37:22 -07:00
|
|
|
s.pw.Write(b)
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PollServer) WaitRead(fd *FD) {
|
|
|
|
s.cr <- fd;
|
|
|
|
s.Wakeup();
|
|
|
|
<-fd.cr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PollServer) WaitWrite(fd *FD) {
|
|
|
|
s.cr <- fd;
|
|
|
|
s.Wakeup();
|
|
|
|
<-fd.cr
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Network FD methods.
|
|
|
|
// All the network FDs use a single PollServer.
|
|
|
|
|
|
|
|
var pollserver *PollServer
|
|
|
|
|
|
|
|
func StartServer() {
|
2008-10-07 13:31:31 -06:00
|
|
|
p, err := NewPollServer();
|
2008-09-29 14:37:00 -06:00
|
|
|
if err != nil {
|
|
|
|
print("Start PollServer: ", err.String(), "\n")
|
|
|
|
}
|
|
|
|
pollserver = p
|
|
|
|
}
|
|
|
|
|
|
|
|
export func NewFD(fd int64) (f *FD, err *os.Error) {
|
|
|
|
if pollserver == nil {
|
|
|
|
once.Do(&StartServer);
|
|
|
|
}
|
|
|
|
if err = SetNonblock(fd); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
f = new(FD);
|
|
|
|
f.fd = fd;
|
|
|
|
f.osfd = os.NewFD(fd);
|
|
|
|
f.cr = new(chan *FD, 1);
|
|
|
|
f.cw = new(chan *FD, 1);
|
|
|
|
return f, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fd *FD) Close() *os.Error {
|
|
|
|
if fd == nil || fd.osfd == nil {
|
|
|
|
return os.EINVAL
|
|
|
|
}
|
|
|
|
e := fd.osfd.Close();
|
|
|
|
fd.osfd = nil;
|
2008-10-07 13:31:31 -06:00
|
|
|
fd.fd = -1;
|
2008-09-29 14:37:00 -06:00
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
2008-12-18 23:37:22 -07:00
|
|
|
func (fd *FD) Read(p []byte) (n int, err *os.Error) {
|
2008-09-29 14:37:00 -06:00
|
|
|
if fd == nil || fd.osfd == nil {
|
|
|
|
return -1, os.EINVAL
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
n, err = fd.osfd.Read(p);
|
2008-09-29 14:37:00 -06:00
|
|
|
for err == os.EAGAIN {
|
|
|
|
pollserver.WaitRead(fd);
|
|
|
|
n, err = fd.osfd.Read(p)
|
|
|
|
}
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
2008-12-18 23:37:22 -07:00
|
|
|
func (fd *FD) Write(p []byte) (n int, err *os.Error) {
|
2008-09-29 14:37:00 -06:00
|
|
|
if fd == nil || fd.osfd == nil {
|
|
|
|
return -1, os.EINVAL
|
|
|
|
}
|
2008-11-25 17:48:10 -07:00
|
|
|
// TODO(rsc): Lock fd while writing to avoid interlacing writes.
|
2008-09-29 14:37:00 -06:00
|
|
|
err = nil;
|
2008-10-07 13:31:31 -06:00
|
|
|
nn := 0;
|
2008-09-29 14:37:00 -06:00
|
|
|
for nn < len(p) && err == nil {
|
2008-11-25 17:48:10 -07:00
|
|
|
// TODO(rsc): If os.FD.Write loops, have to use syscall instead.
|
2008-09-29 14:37:00 -06:00
|
|
|
n, err = fd.osfd.Write(p[nn:len(p)]);
|
|
|
|
for err == os.EAGAIN {
|
|
|
|
pollserver.WaitWrite(fd);
|
|
|
|
n, err = fd.osfd.Write(p[nn:len(p)])
|
|
|
|
}
|
|
|
|
if n > 0 {
|
|
|
|
nn += n
|
|
|
|
}
|
|
|
|
if n == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nn, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fd *FD) Accept(sa *syscall.Sockaddr) (nfd *FD, err *os.Error) {
|
|
|
|
if fd == nil || fd.osfd == nil {
|
|
|
|
return nil, os.EINVAL
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
s, e := syscall.accept(fd.fd, sa);
|
2008-09-29 14:37:00 -06:00
|
|
|
for e == syscall.EAGAIN {
|
|
|
|
pollserver.WaitRead(fd);
|
|
|
|
s, e = syscall.accept(fd.fd, sa)
|
|
|
|
}
|
|
|
|
if e != 0 {
|
|
|
|
return nil, os.ErrnoToError(e)
|
|
|
|
}
|
|
|
|
if nfd, err = NewFD(s); err != nil {
|
2008-10-07 13:31:31 -06:00
|
|
|
syscall.close(s);
|
2008-09-29 14:37:00 -06:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return nfd, nil
|
|
|
|
}
|
|
|
|
|