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 (
|
|
|
|
"once";
|
|
|
|
"os";
|
2009-03-06 18:51:31 -07:00
|
|
|
"sync";
|
2008-09-29 14:37:00 -06:00
|
|
|
"syscall";
|
|
|
|
)
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
// Network file descriptor.
|
|
|
|
type netFD struct {
|
2008-09-29 14:37:00 -06:00
|
|
|
// immutable until Close
|
2009-06-01 23:14:39 -06:00
|
|
|
fd int;
|
2009-03-11 13:51:10 -06:00
|
|
|
file *os.File;
|
2009-02-15 15:18:39 -07:00
|
|
|
cr chan *netFD;
|
|
|
|
cw chan *netFD;
|
|
|
|
net string;
|
|
|
|
laddr string;
|
|
|
|
raddr string;
|
2008-09-29 14:37:00 -06:00
|
|
|
|
2009-03-06 18:51:31 -07:00
|
|
|
// owned by client
|
|
|
|
rdeadline_delta int64;
|
|
|
|
rdeadline int64;
|
|
|
|
rio sync.Mutex;
|
|
|
|
wdeadline_delta int64;
|
|
|
|
wdeadline int64;
|
|
|
|
wio sync.Mutex;
|
|
|
|
|
2008-09-29 14:37:00 -06:00
|
|
|
// owned by fd wait server
|
|
|
|
ncr, ncw int;
|
|
|
|
}
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
// A pollServer helps FDs determine when to retry a non-blocking
|
2008-09-29 14:37:00 -06:00
|
|
|
// 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.
|
2009-02-15 15:18:39 -07:00
|
|
|
// When the pollServer finds that i/o on FD should be possible
|
2008-09-29 14:37:00 -06:00
|
|
|
// 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
|
2009-02-15 15:18:39 -07:00
|
|
|
// byte to the pipe, causing the pollServer's poll system call to
|
|
|
|
// return. In response to the pipe being readable, the pollServer
|
2008-09-29 14:37:00 -06:00
|
|
|
// 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,
|
2009-02-15 15:18:39 -07:00
|
|
|
// one will succeed, the pollServer will read the request, and then the
|
2008-09-29 14:37:00 -06:00
|
|
|
// channel will be empty for the next process's request. A larger buffer
|
|
|
|
// might help batch requests.
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
type pollServer struct {
|
|
|
|
cr, cw chan *netFD; // buffered >= 1
|
2009-03-11 13:51:10 -06:00
|
|
|
pr, pw *os.File;
|
2009-06-01 23:14:39 -06:00
|
|
|
pending map[int] *netFD;
|
2009-03-05 16:48:12 -07:00
|
|
|
poll *pollster; // low-level OS hooks
|
2009-03-06 18:51:31 -07:00
|
|
|
deadline int64; // next deadline (nsec since 1970)
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func newPollServer() (s *pollServer, err os.Error) {
|
2009-02-15 15:18:39 -07:00
|
|
|
s = new(pollServer);
|
|
|
|
s.cr = make(chan *netFD, 1);
|
|
|
|
s.cw = make(chan *netFD, 1);
|
2008-09-29 14:37:00 -06:00
|
|
|
if s.pr, s.pw, err = os.Pipe(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
var e int;
|
|
|
|
if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
|
|
|
|
Errno:
|
2009-06-25 21:24:55 -06:00
|
|
|
err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)};
|
2008-09-29 14:37:00 -06:00
|
|
|
Error:
|
|
|
|
s.pr.Close();
|
2008-10-07 13:31:31 -06:00
|
|
|
s.pw.Close();
|
2009-06-01 23:14:39 -06:00
|
|
|
return nil, err;
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
|
|
|
|
goto Errno;
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2009-03-05 16:48:12 -07:00
|
|
|
if s.poll, err = newpollster(); err != nil {
|
2009-06-01 23:14:39 -06:00
|
|
|
goto Error;
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2009-02-06 18:54:26 -07:00
|
|
|
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
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
s.pending = make(map[int] *netFD);
|
2008-10-07 13:31:31 -06:00
|
|
|
go s.Run();
|
2008-09-29 14:37:00 -06:00
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
func (s *pollServer) AddFD(fd *netFD, mode int) {
|
2009-04-15 20:01:48 -06:00
|
|
|
// TODO(rsc): This check handles a race between
|
|
|
|
// one goroutine reading and another one closing,
|
|
|
|
// but it doesn't solve the race completely:
|
|
|
|
// it still could happen that one goroutine closes
|
|
|
|
// but we read fd.fd before it does, and then
|
|
|
|
// another goroutine creates a new open file with
|
|
|
|
// that fd, which we'd now be referring to.
|
|
|
|
// The fix is probably to send the Close call
|
|
|
|
// through the poll server too, except that
|
|
|
|
// not all Reads and Writes go through the poll
|
|
|
|
// server even now.
|
|
|
|
intfd := fd.fd;
|
|
|
|
if intfd < 0 {
|
|
|
|
// fd closed underfoot
|
|
|
|
if mode == 'r' {
|
|
|
|
fd.cr <- fd
|
|
|
|
} else {
|
|
|
|
fd.cw <- fd
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if err := s.poll.AddFD(intfd, mode, false); err != nil {
|
|
|
|
panicln("pollServer AddFD ", intfd, ": ", err.String(), "\n");
|
2008-09-29 14:37:00 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2009-03-06 18:51:31 -07:00
|
|
|
var t int64;
|
2009-04-15 20:01:48 -06:00
|
|
|
key := intfd << 1;
|
2008-09-29 14:37:00 -06:00
|
|
|
if mode == 'r' {
|
2008-10-07 13:31:31 -06:00
|
|
|
fd.ncr++;
|
2009-03-06 18:51:31 -07:00
|
|
|
t = fd.rdeadline;
|
2008-09-29 14:37:00 -06:00
|
|
|
} else {
|
2008-10-07 13:31:31 -06:00
|
|
|
fd.ncw++;
|
|
|
|
key++;
|
2009-03-06 18:51:31 -07:00
|
|
|
t = fd.wdeadline;
|
|
|
|
}
|
|
|
|
s.pending[key] = fd;
|
|
|
|
if t > 0 && (s.deadline == 0 || t < s.deadline) {
|
|
|
|
s.deadline = t;
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
func (s *pollServer) LookupFD(fd int, mode int) *netFD {
|
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
|
|
|
|
}
|
|
|
|
|
2009-03-06 18:51:31 -07:00
|
|
|
func (s *pollServer) WakeFD(fd *netFD, mode int) {
|
|
|
|
if mode == 'r' {
|
|
|
|
for fd.ncr > 0 {
|
|
|
|
fd.ncr--;
|
|
|
|
fd.cr <- fd
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for fd.ncw > 0 {
|
|
|
|
fd.ncw--;
|
|
|
|
fd.cw <- fd
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *pollServer) Now() int64 {
|
|
|
|
sec, nsec, err := os.Time();
|
|
|
|
if err != nil {
|
|
|
|
panic("net: os.Time: ", err.String());
|
|
|
|
}
|
|
|
|
nsec += sec * 1e9;
|
|
|
|
return nsec;
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *pollServer) CheckDeadlines() {
|
|
|
|
now := s.Now();
|
|
|
|
// TODO(rsc): This will need to be handled more efficiently,
|
|
|
|
// probably with a heap indexed by wakeup time.
|
|
|
|
|
|
|
|
var next_deadline int64;
|
|
|
|
for key, fd := range s.pending {
|
|
|
|
var t int64;
|
|
|
|
var mode int;
|
|
|
|
if key&1 == 0 {
|
|
|
|
mode = 'r';
|
|
|
|
} else {
|
|
|
|
mode = 'w';
|
|
|
|
}
|
|
|
|
if mode == 'r' {
|
|
|
|
t = fd.rdeadline;
|
|
|
|
} else {
|
|
|
|
t = fd.wdeadline;
|
|
|
|
}
|
|
|
|
if t > 0 {
|
|
|
|
if t <= now {
|
|
|
|
s.pending[key] = nil, false;
|
|
|
|
if mode == 'r' {
|
|
|
|
s.poll.DelFD(fd.fd, mode);
|
|
|
|
fd.rdeadline = -1;
|
|
|
|
} else {
|
|
|
|
s.poll.DelFD(fd.fd, mode);
|
|
|
|
fd.wdeadline = -1;
|
|
|
|
}
|
|
|
|
s.WakeFD(fd, mode);
|
|
|
|
} else if next_deadline == 0 || t < next_deadline {
|
|
|
|
next_deadline = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s.deadline = next_deadline;
|
|
|
|
}
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
func (s *pollServer) Run() {
|
2008-09-29 14:37:00 -06:00
|
|
|
var scratch [100]byte;
|
|
|
|
for {
|
2009-03-06 18:51:31 -07:00
|
|
|
var t = s.deadline;
|
|
|
|
if t > 0 {
|
|
|
|
t = t - s.Now();
|
|
|
|
if t < 0 {
|
|
|
|
s.CheckDeadlines();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fd, mode, err := s.poll.WaitFD(t);
|
2008-09-29 14:37:00 -06:00
|
|
|
if err != nil {
|
2009-02-15 15:18:39 -07:00
|
|
|
print("pollServer WaitFD: ", err.String(), "\n");
|
2008-09-29 14:37:00 -06:00
|
|
|
return
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
if fd < 0 {
|
|
|
|
// Timeout happened.
|
|
|
|
s.CheckDeadlines();
|
|
|
|
continue;
|
|
|
|
}
|
2009-02-06 18:54:26 -07:00
|
|
|
if fd == s.pr.Fd() {
|
2008-09-29 14:37:00 -06:00
|
|
|
// Drain our wakeup pipe.
|
2009-09-15 10:41:59 -06:00
|
|
|
for nn, _ := s.pr.Read(&scratch); nn > 0; {
|
|
|
|
nn, _ = 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 {
|
2009-02-15 15:18:39 -07:00
|
|
|
print("pollServer: unexpected wakeup for fd=", netfd, " mode=", string(mode), "\n");
|
2008-09-29 14:37:00 -06:00
|
|
|
continue
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
s.WakeFD(netfd, mode);
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-15 21:27:45 -06:00
|
|
|
var wakeupbuf [1]byte;
|
2009-02-15 15:18:39 -07:00
|
|
|
func (s *pollServer) Wakeup() {
|
2009-04-15 21:27:45 -06:00
|
|
|
s.pw.Write(&wakeupbuf)
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
func (s *pollServer) WaitRead(fd *netFD) {
|
2008-09-29 14:37:00 -06:00
|
|
|
s.cr <- fd;
|
|
|
|
s.Wakeup();
|
|
|
|
<-fd.cr
|
|
|
|
}
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
func (s *pollServer) WaitWrite(fd *netFD) {
|
2009-04-29 18:36:37 -06:00
|
|
|
s.cw <- fd;
|
2008-09-29 14:37:00 -06:00
|
|
|
s.Wakeup();
|
2009-04-29 18:36:37 -06:00
|
|
|
<-fd.cw
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Network FD methods.
|
2009-02-15 15:18:39 -07:00
|
|
|
// All the network FDs use a single pollServer.
|
2008-09-29 14:37:00 -06:00
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
var pollserver *pollServer
|
2008-09-29 14:37:00 -06:00
|
|
|
|
2009-01-16 12:04:44 -07:00
|
|
|
func _StartServer() {
|
2009-02-15 15:18:39 -07:00
|
|
|
p, err := newPollServer();
|
2008-09-29 14:37:00 -06:00
|
|
|
if err != nil {
|
2009-02-15 15:18:39 -07:00
|
|
|
print("Start pollServer: ", err.String(), "\n")
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
pollserver = p
|
|
|
|
}
|
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
func newFD(fd int, net, laddr, raddr string) (f *netFD, err os.Error) {
|
2008-09-29 14:37:00 -06:00
|
|
|
if pollserver == nil {
|
2009-01-30 15:39:31 -07:00
|
|
|
once.Do(_StartServer);
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
if e := syscall.SetNonblock(fd, true); e != 0 {
|
2009-06-25 21:24:55 -06:00
|
|
|
return nil, &os.PathError{"setnonblock", laddr, os.Errno(e)};
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2009-02-15 15:18:39 -07:00
|
|
|
f = new(netFD);
|
2008-09-29 14:37:00 -06:00
|
|
|
f.fd = fd;
|
2009-02-15 15:18:39 -07:00
|
|
|
f.net = net;
|
|
|
|
f.laddr = laddr;
|
|
|
|
f.raddr = raddr;
|
2009-06-25 21:24:55 -06:00
|
|
|
f.file = os.NewFile(fd, net + "!" + laddr + "->" + raddr);
|
2009-02-15 15:18:39 -07:00
|
|
|
f.cr = make(chan *netFD, 1);
|
|
|
|
f.cw = make(chan *netFD, 1);
|
2008-09-29 14:37:00 -06:00
|
|
|
return f, nil
|
|
|
|
}
|
|
|
|
|
2009-06-25 21:24:55 -06:00
|
|
|
func isEAGAIN(e os.Error) bool {
|
|
|
|
if e1, ok := e.(*os.PathError); ok {
|
|
|
|
return e1.Error == os.EAGAIN;
|
|
|
|
}
|
|
|
|
return e == os.EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fd *netFD) addr() string {
|
|
|
|
sa, e := syscall.Getsockname(fd.fd);
|
|
|
|
if e != 0 {
|
|
|
|
return "";
|
|
|
|
}
|
2009-09-15 10:41:59 -06:00
|
|
|
addr, _ := sockaddrToString(sa);
|
2009-06-25 21:24:55 -06:00
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fd *netFD) remoteAddr() string {
|
|
|
|
sa, e := syscall.Getpeername(fd.fd);
|
|
|
|
if e != 0 {
|
|
|
|
return "";
|
|
|
|
}
|
2009-09-15 10:41:59 -06:00
|
|
|
addr, _ := sockaddrToString(sa);
|
2009-06-25 21:24:55 -06:00
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (fd *netFD) Close() os.Error {
|
2009-03-11 13:51:10 -06:00
|
|
|
if fd == nil || fd.file == nil {
|
2008-09-29 14:37:00 -06:00
|
|
|
return os.EINVAL
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
|
|
|
|
// In case the user has set linger,
|
|
|
|
// switch to blocking mode so the close blocks.
|
|
|
|
// As long as this doesn't happen often,
|
|
|
|
// we can handle the extra OS processes.
|
|
|
|
// Otherwise we'll need to use the pollserver
|
|
|
|
// for Close too. Sigh.
|
2009-06-01 23:14:39 -06:00
|
|
|
syscall.SetNonblock(fd.file.Fd(), false);
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
e := fd.file.Close();
|
|
|
|
fd.file = nil;
|
2008-10-07 13:31:31 -06:00
|
|
|
fd.fd = -1;
|
2008-09-29 14:37:00 -06:00
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (fd *netFD) Read(p []byte) (n int, err os.Error) {
|
2009-03-11 13:51:10 -06:00
|
|
|
if fd == nil || fd.file == nil {
|
2009-06-25 21:24:55 -06:00
|
|
|
return 0, os.EINVAL
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
fd.rio.Lock();
|
|
|
|
defer fd.rio.Unlock();
|
|
|
|
if fd.rdeadline_delta > 0 {
|
|
|
|
fd.rdeadline = pollserver.Now() + fd.rdeadline_delta;
|
|
|
|
} else {
|
|
|
|
fd.rdeadline = 0;
|
|
|
|
}
|
2009-06-25 21:24:55 -06:00
|
|
|
for {
|
|
|
|
n, err = fd.file.Read(p);
|
|
|
|
if isEAGAIN(err) && fd.rdeadline >= 0 {
|
|
|
|
pollserver.WaitRead(fd);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2009-06-25 21:24:55 -06:00
|
|
|
return;
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (fd *netFD) Write(p []byte) (n int, err os.Error) {
|
2009-03-11 13:51:10 -06:00
|
|
|
if fd == nil || fd.file == nil {
|
2009-06-25 21:24:55 -06:00
|
|
|
return 0, os.EINVAL
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
fd.wio.Lock();
|
|
|
|
defer fd.wio.Unlock();
|
|
|
|
if fd.wdeadline_delta > 0 {
|
|
|
|
fd.wdeadline = pollserver.Now() + fd.wdeadline_delta;
|
|
|
|
} else {
|
|
|
|
fd.wdeadline = 0;
|
|
|
|
}
|
2008-09-29 14:37:00 -06:00
|
|
|
err = nil;
|
2008-10-07 13:31:31 -06:00
|
|
|
nn := 0;
|
2009-03-06 18:51:31 -07:00
|
|
|
for nn < len(p) {
|
2009-03-11 13:51:10 -06:00
|
|
|
n, err = fd.file.Write(p[nn:len(p)]);
|
2008-09-29 14:37:00 -06:00
|
|
|
if n > 0 {
|
|
|
|
nn += n
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
if nn == len(p) {
|
|
|
|
break;
|
|
|
|
}
|
2009-06-25 21:24:55 -06:00
|
|
|
if isEAGAIN(err) && fd.wdeadline >= 0 {
|
2009-03-06 18:51:31 -07:00
|
|
|
pollserver.WaitWrite(fd);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if n == 0 || err != nil {
|
|
|
|
break;
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nn, err
|
|
|
|
}
|
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
func (fd *netFD) accept() (nfd *netFD, err os.Error) {
|
2009-03-11 13:51:10 -06:00
|
|
|
if fd == nil || fd.file == nil {
|
2008-09-29 14:37:00 -06:00
|
|
|
return nil, os.EINVAL
|
|
|
|
}
|
2009-02-15 15:18:39 -07:00
|
|
|
|
2009-02-15 20:35:52 -07:00
|
|
|
// See ../syscall/exec.go for description of ForkLock.
|
|
|
|
// It is okay to hold the lock across syscall.Accept
|
|
|
|
// because we have put fd.fd into non-blocking mode.
|
|
|
|
syscall.ForkLock.RLock();
|
2009-06-01 23:14:39 -06:00
|
|
|
var s, e int;
|
|
|
|
var sa syscall.Sockaddr;
|
2009-02-15 15:18:39 -07:00
|
|
|
for {
|
2009-06-01 23:14:39 -06:00
|
|
|
s, sa, e = syscall.Accept(fd.fd);
|
2009-02-15 15:18:39 -07:00
|
|
|
if e != syscall.EAGAIN {
|
|
|
|
break;
|
|
|
|
}
|
2009-02-15 20:35:52 -07:00
|
|
|
syscall.ForkLock.RUnlock();
|
2008-09-29 14:37:00 -06:00
|
|
|
pollserver.WaitRead(fd);
|
2009-02-15 20:35:52 -07:00
|
|
|
syscall.ForkLock.RLock();
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
|
|
|
if e != 0 {
|
2009-02-15 20:35:52 -07:00
|
|
|
syscall.ForkLock.RUnlock();
|
2009-06-25 21:24:55 -06:00
|
|
|
return nil, &os.PathError{"accept", fd.addr(), os.Errno(e)}
|
2008-09-29 14:37:00 -06:00
|
|
|
}
|
2009-02-15 20:35:52 -07:00
|
|
|
syscall.CloseOnExec(s);
|
|
|
|
syscall.ForkLock.RUnlock();
|
2009-02-15 15:18:39 -07:00
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
raddr, err1 := sockaddrToString(sa);
|
2009-02-15 15:18:39 -07:00
|
|
|
if err1 != nil {
|
|
|
|
raddr = "invalid-address";
|
|
|
|
}
|
|
|
|
if nfd, err = newFD(s, fd.net, fd.laddr, raddr); err != nil {
|
2009-01-16 12:36:44 -07:00
|
|
|
syscall.Close(s);
|
2008-09-29 14:37:00 -06:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return nfd, nil
|
|
|
|
}
|