summaryrefslogtreecommitdiff
path: root/libgo/go/net/fd_windows.go
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-03-16 23:05:44 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-03-16 23:05:44 +0000
commit31c6ec422702226aabab7d082da16663e6c3e72c (patch)
tree44176975832a3faf1626836e70c97d5edd674122 /libgo/go/net/fd_windows.go
parentb3145af52cfb7c84d62a8e4ceeb165a7369718da (diff)
downloadgcc-31c6ec422702226aabab7d082da16663e6c3e72c.tar.gz
Update to current version of Go library (revision 94d654be2064).
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@171076 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/net/fd_windows.go')
-rw-r--r--libgo/go/net/fd_windows.go655
1 files changed, 308 insertions, 347 deletions
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
index 9b91eb398cb..63a8fbc4489 100644
--- a/libgo/go/net/fd_windows.go
+++ b/libgo/go/net/fd_windows.go
@@ -13,147 +13,241 @@ import (
"unsafe"
)
+type InvalidConnError struct{}
+
+func (e *InvalidConnError) String() string { return "invalid net.Conn" }
+func (e *InvalidConnError) Temporary() bool { return false }
+func (e *InvalidConnError) Timeout() bool { return false }
+
+var initErr os.Error
+
+func init() {
+ var d syscall.WSAData
+ e := syscall.WSAStartup(uint32(0x101), &d)
+ if e != 0 {
+ initErr = os.NewSyscallError("WSAStartup", e)
+ }
+}
+
+func closesocket(s int) (errno int) {
+ return syscall.Closesocket(int32(s))
+}
+
+// Interface for all io operations.
+type anOpIface interface {
+ Op() *anOp
+ Name() string
+ Submit() (errno int)
+}
+
// IO completion result parameters.
type ioResult struct {
- key uint32
- qty uint32
- errno int
+ qty uint32
+ err int
}
-// Network file descriptor.
-type netFD struct {
- // locking/lifetime of sysfd
- sysmu sync.Mutex
- sysref int
- closing bool
+// anOp implements functionality common to all io operations.
+type anOp struct {
+ // Used by IOCP interface, it must be first field
+ // of the struct, as our code rely on it.
+ o syscall.Overlapped
- // immutable until Close
- sysfd int
- family int
- proto int
- cr chan *ioResult
- cw chan *ioResult
- net string
- laddr Addr
- raddr Addr
+ resultc chan ioResult // io completion results
+ errnoc chan int // io submit / cancel operation errors
+ fd *netFD
+}
- // owned by client
- rdeadline_delta int64
- rdeadline int64
- rio sync.Mutex
- wdeadline_delta int64
- wdeadline int64
- wio sync.Mutex
+func (o *anOp) Init(fd *netFD) {
+ o.fd = fd
+ o.resultc = make(chan ioResult, 1)
+ o.errnoc = make(chan int)
}
-type InvalidConnError struct{}
+func (o *anOp) Op() *anOp {
+ return o
+}
-func (e *InvalidConnError) String() string { return "invalid net.Conn" }
-func (e *InvalidConnError) Temporary() bool { return false }
-func (e *InvalidConnError) Timeout() bool { return false }
+// bufOp is used by io operations that read / write
+// data from / to client buffer.
+type bufOp struct {
+ anOp
+ buf syscall.WSABuf
+}
-// pollServer will run around waiting for io completion request
-// to arrive. Every request received will contain channel to signal
-// io owner about the completion.
+func (o *bufOp) Init(fd *netFD, buf []byte) {
+ o.anOp.Init(fd)
+ o.buf.Len = uint32(len(buf))
+ if len(buf) == 0 {
+ o.buf.Buf = nil
+ } else {
+ o.buf.Buf = (*byte)(unsafe.Pointer(&buf[0]))
+ }
+}
-type pollServer struct {
+// resultSrv will retreive all io completion results from
+// iocp and send them to the correspondent waiting client
+// goroutine via channel supplied in the request.
+type resultSrv struct {
iocp int32
}
-func newPollServer() (s *pollServer, err os.Error) {
- s = new(pollServer)
- var e int
- if s.iocp, e = syscall.CreateIoCompletionPort(-1, 0, 0, 1); e != 0 {
- return nil, os.NewSyscallError("CreateIoCompletionPort", e)
+func (s *resultSrv) Run() {
+ var o *syscall.Overlapped
+ var key uint32
+ var r ioResult
+ for {
+ r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE)
+ switch {
+ case r.err == 0:
+ // Dequeued successfully completed io packet.
+ case r.err == syscall.WAIT_TIMEOUT && o == nil:
+ // Wait has timed out (should not happen now, but might be used in the future).
+ panic("GetQueuedCompletionStatus timed out")
+ case o == nil:
+ // Failed to dequeue anything -> report the error.
+ panic("GetQueuedCompletionStatus failed " + syscall.Errstr(r.err))
+ default:
+ // Dequeued failed io packet.
+ }
+ (*anOp)(unsafe.Pointer(o)).resultc <- r
}
- go s.Run()
- return s, nil
}
-type ioPacket struct {
- // Used by IOCP interface,
- // it must be first field of the struct,
- // as our code rely on it.
- o syscall.Overlapped
- // Link to the io owner.
- c chan *ioResult
-
- w *syscall.WSABuf
+// ioSrv executes net io requests.
+type ioSrv struct {
+ submchan chan anOpIface // submit io requests
+ canchan chan anOpIface // cancel io requests
}
-func (s *pollServer) getCompletedIO() (ov *syscall.Overlapped, result *ioResult, err os.Error) {
- var r ioResult
- var o *syscall.Overlapped
- _, e := syscall.GetQueuedCompletionStatus(s.iocp, &r.qty, &r.key, &o, syscall.INFINITE)
- switch {
- case e == 0:
- // Dequeued successfully completed io packet.
- return o, &r, nil
- case e == syscall.WAIT_TIMEOUT && o == nil:
- // Wait has timed out (should not happen now, but might be used in the future).
- return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
- case o == nil:
- // Failed to dequeue anything -> report the error.
- return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
- default:
- // Dequeued failed io packet.
- r.errno = e
- return o, &r, nil
+// ProcessRemoteIO will execute submit io requests on behalf
+// of other goroutines, all on a single os thread, so it can
+// cancel them later. Results of all operations will be sent
+// back to their requesters via channel supplied in request.
+func (s *ioSrv) ProcessRemoteIO() {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ for {
+ select {
+ case o := <-s.submchan:
+ o.Op().errnoc <- o.Submit()
+ case o := <-s.canchan:
+ o.Op().errnoc <- syscall.CancelIo(uint32(o.Op().fd.sysfd))
+ }
}
- return
}
-func (s *pollServer) Run() {
- for {
- o, r, err := s.getCompletedIO()
- if err != nil {
- panic("Run pollServer: " + err.String() + "\n")
+// ExecIO executes a single io operation. It either executes it
+// inline, or, if timeouts are employed, passes the request onto
+// a special goroutine and waits for completion or cancels request.
+func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error) {
+ var e int
+ o := oi.Op()
+ if deadline_delta > 0 {
+ // Send request to a special dedicated thread,
+ // so it can stop the io with CancelIO later.
+ s.submchan <- oi
+ e = <-o.errnoc
+ } else {
+ e = oi.Submit()
+ }
+ switch e {
+ case 0:
+ // IO completed immediately, but we need to get our completion message anyway.
+ case syscall.ERROR_IO_PENDING:
+ // IO started, and we have to wait for it's completion.
+ default:
+ return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)}
+ }
+ // Wait for our request to complete.
+ var r ioResult
+ if deadline_delta > 0 {
+ select {
+ case r = <-o.resultc:
+ case <-time.After(deadline_delta):
+ s.canchan <- oi
+ <-o.errnoc
+ r = <-o.resultc
+ if r.err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
+ r.err = syscall.EWOULDBLOCK
+ }
}
- p := (*ioPacket)(unsafe.Pointer(o))
- p.c <- r
+ } else {
+ r = <-o.resultc
}
+ if r.err != 0 {
+ err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(r.err)}
+ }
+ return int(r.qty), err
}
-// Network FD methods.
-// All the network FDs use a single pollServer.
-
-var pollserver *pollServer
+// Start helper goroutines.
+var resultsrv *resultSrv
+var iosrv *ioSrv
var onceStartServer sync.Once
func startServer() {
- p, err := newPollServer()
- if err != nil {
- panic("Start pollServer: " + err.String() + "\n")
- }
- pollserver = p
-
- go timeoutIO()
+ resultsrv = new(resultSrv)
+ var errno int
+ resultsrv.iocp, errno = syscall.CreateIoCompletionPort(-1, 0, 0, 1)
+ if errno != 0 {
+ panic("CreateIoCompletionPort failed " + syscall.Errstr(errno))
+ }
+ go resultsrv.Run()
+
+ iosrv = new(ioSrv)
+ iosrv.submchan = make(chan anOpIface)
+ iosrv.canchan = make(chan anOpIface)
+ go iosrv.ProcessRemoteIO()
}
-var initErr os.Error
+// Network file descriptor.
+type netFD struct {
+ // locking/lifetime of sysfd
+ sysmu sync.Mutex
+ sysref int
+ closing bool
-func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
- if initErr != nil {
- return nil, initErr
- }
- onceStartServer.Do(startServer)
- // Associate our socket with pollserver.iocp.
- if _, e := syscall.CreateIoCompletionPort(int32(fd), pollserver.iocp, 0, 0); e != 0 {
- return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)}
- }
+ // immutable until Close
+ sysfd int
+ family int
+ proto int
+ net string
+ laddr Addr
+ raddr Addr
+
+ // owned by client
+ rdeadline_delta int64
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline_delta int64
+ wdeadline int64
+ wio sync.Mutex
+}
+
+func allocFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD) {
f = &netFD{
sysfd: fd,
family: family,
proto: proto,
- cr: make(chan *ioResult, 1),
- cw: make(chan *ioResult, 1),
net: net,
laddr: laddr,
raddr: raddr,
}
runtime.SetFinalizer(f, (*netFD).Close)
- return f, nil
+ return f
+}
+
+func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
+ if initErr != nil {
+ return nil, initErr
+ }
+ onceStartServer.Do(startServer)
+ // Associate our socket with resultsrv.iocp.
+ if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 {
+ return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)}
+ }
+ return allocFD(fd, family, proto, net, laddr, raddr), nil
}
// Add a reference to this fd.
@@ -172,7 +266,7 @@ func (fd *netFD) decref() {
// 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.
+ // use the resultsrv for Close too. Sigh.
syscall.SetNonblock(fd.sysfd, false)
closesocket(fd.sysfd)
fd.sysfd = -1
@@ -194,89 +288,22 @@ func (fd *netFD) Close() os.Error {
return nil
}
-func newWSABuf(p []byte) *syscall.WSABuf {
- var p0 *byte
- if len(p) > 0 {
- p0 = (*byte)(unsafe.Pointer(&p[0]))
- }
- return &syscall.WSABuf{uint32(len(p)), p0}
-}
-
-func waitPacket(fd *netFD, pckt *ioPacket, mode int) (r *ioResult) {
- var delta int64
- if mode == 'r' {
- delta = fd.rdeadline_delta
- }
- if mode == 'w' {
- delta = fd.wdeadline_delta
- }
- if delta <= 0 {
- return <-pckt.c
- }
+// Read from network.
- select {
- case r = <-pckt.c:
- case <-time.After(delta):
- a := &arg{f: cancel, fd: fd, pckt: pckt, c: make(chan int)}
- ioChan <- a
- <-a.c
- r = <-pckt.c
- if r.errno == 995 { // IO Canceled
- r.errno = syscall.EWOULDBLOCK
- }
- }
- return r
+type readOp struct {
+ bufOp
}
-const (
- read = iota
- readfrom
- write
- writeto
- cancel
-)
+func (o *readOp) Submit() (errno int) {
+ var d, f uint32
+ return syscall.WSARecv(uint32(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
+}
-type arg struct {
- f int
- fd *netFD
- pckt *ioPacket
- done *uint32
- flags *uint32
- rsa *syscall.RawSockaddrAny
- size *int32
- sa *syscall.Sockaddr
- c chan int
-}
-
-var ioChan chan *arg = make(chan *arg)
-
-func timeoutIO() {
- // CancelIO only cancels all pending input and output (I/O) operations that are
- // issued by the calling thread for the specified file, does not cancel I/O
- // operations that other threads issue for a file handle. So we need do all timeout
- // I/O in single OS thread.
- runtime.LockOSThread()
- defer runtime.UnlockOSThread()
- for {
- o := <-ioChan
- var e int
- switch o.f {
- case read:
- e = syscall.WSARecv(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, &o.pckt.o, nil)
- case readfrom:
- e = syscall.WSARecvFrom(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, o.rsa, o.size, &o.pckt.o, nil)
- case write:
- e = syscall.WSASend(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, uint32(0), &o.pckt.o, nil)
- case writeto:
- e = syscall.WSASendto(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, 0, *o.sa, &o.pckt.o, nil)
- case cancel:
- _, e = syscall.CancelIo(uint32(o.fd.sysfd))
- }
- o.c <- e
- }
+func (o *readOp) Name() string {
+ return "WSARecv"
}
-func (fd *netFD) Read(p []byte) (n int, err os.Error) {
+func (fd *netFD) Read(buf []byte) (n int, err os.Error) {
if fd == nil {
return 0, os.EINVAL
}
@@ -287,45 +314,37 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) {
if fd.sysfd == -1 {
return 0, os.EINVAL
}
- // Submit receive request.
- var pckt ioPacket
- pckt.c = fd.cr
- pckt.w = newWSABuf(p)
- var done uint32
- flags := uint32(0)
- var e int
- if fd.rdeadline_delta > 0 {
- a := &arg{f: read, fd: fd, pckt: &pckt, done: &done, flags: &flags, c: make(chan int)}
- ioChan <- a
- e = <-a.c
- } else {
- e = syscall.WSARecv(uint32(fd.sysfd), pckt.w, 1, &done, &flags, &pckt.o, nil)
- }
- switch e {
- case 0:
- // IO completed immediately, but we need to get our completion message anyway.
- case syscall.ERROR_IO_PENDING:
- // IO started, and we have to wait for it's completion.
- default:
- return 0, &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(e)}
- }
- // Wait for our request to complete.
- r := waitPacket(fd, &pckt, 'r')
- if r.errno != 0 {
- err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)}
- }
- n = int(r.qty)
+ var o readOp
+ o.Init(fd, buf)
+ n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
if err == nil && n == 0 {
err = os.EOF
}
return
}
-func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
+// ReadFrom from network.
+
+type readFromOp struct {
+ bufOp
+ rsa syscall.RawSockaddrAny
+}
+
+func (o *readFromOp) Submit() (errno int) {
+ var d, f uint32
+ l := int32(unsafe.Sizeof(o.rsa))
+ return syscall.WSARecvFrom(uint32(o.fd.sysfd), &o.buf, 1, &d, &f, &o.rsa, &l, &o.o, nil)
+}
+
+func (o *readFromOp) Name() string {
+ return "WSARecvFrom"
+}
+
+func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error) {
if fd == nil {
return 0, nil, os.EINVAL
}
- if len(p) == 0 {
+ if len(buf) == 0 {
return 0, nil, nil
}
fd.rio.Lock()
@@ -335,41 +354,29 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
if fd.sysfd == -1 {
return 0, nil, os.EINVAL
}
- // Submit receive request.
- var pckt ioPacket
- pckt.c = fd.cr
- pckt.w = newWSABuf(p)
- var done uint32
- flags := uint32(0)
- var rsa syscall.RawSockaddrAny
- l := int32(unsafe.Sizeof(rsa))
- var e int
- if fd.rdeadline_delta > 0 {
- a := &arg{f: readfrom, fd: fd, pckt: &pckt, done: &done, flags: &flags, rsa: &rsa, size: &l, c: make(chan int)}
- ioChan <- a
- e = <-a.c
- } else {
- e = syscall.WSARecvFrom(uint32(fd.sysfd), pckt.w, 1, &done, &flags, &rsa, &l, &pckt.o, nil)
- }
- switch e {
- case 0:
- // IO completed immediately, but we need to get our completion message anyway.
- case syscall.ERROR_IO_PENDING:
- // IO started, and we have to wait for it's completion.
- default:
- return 0, nil, &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(e)}
- }
- // Wait for our request to complete.
- r := waitPacket(fd, &pckt, 'r')
- if r.errno != 0 {
- err = &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(r.errno)}
- }
- n = int(r.qty)
- sa, _ = rsa.Sockaddr()
+ var o readFromOp
+ o.Init(fd, buf)
+ n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+ sa, _ = o.rsa.Sockaddr()
return
}
-func (fd *netFD) Write(p []byte) (n int, err os.Error) {
+// Write to network.
+
+type writeOp struct {
+ bufOp
+}
+
+func (o *writeOp) Submit() (errno int) {
+ var d uint32
+ return syscall.WSASend(uint32(o.fd.sysfd), &o.buf, 1, &d, 0, &o.o, nil)
+}
+
+func (o *writeOp) Name() string {
+ return "WSASend"
+}
+
+func (fd *netFD) Write(buf []byte) (n int, err os.Error) {
if fd == nil {
return 0, os.EINVAL
}
@@ -380,41 +387,32 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) {
if fd.sysfd == -1 {
return 0, os.EINVAL
}
- // Submit send request.
- var pckt ioPacket
- pckt.c = fd.cw
- pckt.w = newWSABuf(p)
- var done uint32
- var e int
- if fd.wdeadline_delta > 0 {
- a := &arg{f: write, fd: fd, pckt: &pckt, done: &done, c: make(chan int)}
- ioChan <- a
- e = <-a.c
- } else {
- e = syscall.WSASend(uint32(fd.sysfd), pckt.w, 1, &done, uint32(0), &pckt.o, nil)
- }
- switch e {
- case 0:
- // IO completed immediately, but we need to get our completion message anyway.
- case syscall.ERROR_IO_PENDING:
- // IO started, and we have to wait for it's completion.
- default:
- return 0, &OpError{"WSASend", fd.net, fd.laddr, os.Errno(e)}
- }
- // Wait for our request to complete.
- r := waitPacket(fd, &pckt, 'w')
- if r.errno != 0 {
- err = &OpError{"WSASend", fd.net, fd.laddr, os.Errno(r.errno)}
- }
- n = int(r.qty)
- return
+ var o writeOp
+ o.Init(fd, buf)
+ return iosrv.ExecIO(&o, fd.wdeadline_delta)
+}
+
+// WriteTo to network.
+
+type writeToOp struct {
+ bufOp
+ sa syscall.Sockaddr
+}
+
+func (o *writeToOp) Submit() (errno int) {
+ var d uint32
+ return syscall.WSASendto(uint32(o.fd.sysfd), &o.buf, 1, &d, 0, o.sa, &o.o, nil)
+}
+
+func (o *writeToOp) Name() string {
+ return "WSASendto"
}
-func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
+func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error) {
if fd == nil {
return 0, os.EINVAL
}
- if len(p) == 0 {
+ if len(buf) == 0 {
return 0, nil
}
fd.wio.Lock()
@@ -424,34 +422,29 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
if fd.sysfd == -1 {
return 0, os.EINVAL
}
- // Submit send request.
- var pckt ioPacket
- pckt.c = fd.cw
- pckt.w = newWSABuf(p)
- var done uint32
- var e int
- if fd.wdeadline_delta > 0 {
- a := &arg{f: writeto, fd: fd, pckt: &pckt, done: &done, sa: &sa, c: make(chan int)}
- ioChan <- a
- e = <-a.c
- } else {
- e = syscall.WSASendto(uint32(fd.sysfd), pckt.w, 1, &done, 0, sa, &pckt.o, nil)
- }
- switch e {
- case 0:
- // IO completed immediately, but we need to get our completion message anyway.
- case syscall.ERROR_IO_PENDING:
- // IO started, and we have to wait for it's completion.
- default:
- return 0, &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(e)}
- }
- // Wait for our request to complete.
- r := waitPacket(fd, &pckt, 'w')
- if r.errno != 0 {
- err = &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(r.errno)}
- }
- n = int(r.qty)
- return
+ var o writeToOp
+ o.Init(fd, buf)
+ o.sa = sa
+ return iosrv.ExecIO(&o, fd.wdeadline_delta)
+}
+
+// Accept new network connections.
+
+type acceptOp struct {
+ anOp
+ newsock int
+ attrs [2]syscall.RawSockaddrAny // space for local and remote address only
+}
+
+func (o *acceptOp) Submit() (errno int) {
+ var d uint32
+ l := uint32(unsafe.Sizeof(o.attrs[0]))
+ return syscall.AcceptEx(uint32(o.fd.sysfd), uint32(o.newsock),
+ (*byte)(unsafe.Pointer(&o.attrs[0])), 0, l, l, &d, &o.o)
+}
+
+func (o *acceptOp) Name() string {
+ return "AcceptEx"
}
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
@@ -474,72 +467,40 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
// Associate our new socket with IOCP.
onceStartServer.Do(startServer)
- if _, e = syscall.CreateIoCompletionPort(int32(s), pollserver.iocp, 0, 0); e != 0 {
+ if _, e = syscall.CreateIoCompletionPort(int32(s), resultsrv.iocp, 0, 0); e != 0 {
return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
}
// Submit accept request.
- // Will use new unique channel here, because, unlike Read or Write,
- // Accept is expected to be executed by many goroutines simultaniously.
- var pckt ioPacket
- pckt.c = make(chan *ioResult)
- attrs, e := syscall.AcceptIOCP(fd.sysfd, s, &pckt.o)
- switch e {
- case 0:
- // IO completed immediately, but we need to get our completion message anyway.
- case syscall.ERROR_IO_PENDING:
- // IO started, and we have to wait for it's completion.
- default:
- closesocket(s)
- return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(e)}
- }
-
- // Wait for peer connection.
- r := <-pckt.c
- if r.errno != 0 {
+ var o acceptOp
+ o.Init(fd)
+ o.newsock = s
+ _, err = iosrv.ExecIO(&o, 0)
+ if err != nil {
closesocket(s)
- return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(r.errno)}
+ return nil, err
}
// Inherit properties of the listening socket.
e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd)
if e != 0 {
closesocket(s)
- return nil, &OpError{"Setsockopt", fd.net, fd.laddr, os.Errno(r.errno)}
+ return nil, err
}
// Get local and peer addr out of AcceptEx buffer.
- lsa, rsa := syscall.GetAcceptIOCPSockaddrs(attrs)
-
- // Create our netFD and return it for further use.
- laddr := toAddr(lsa)
- raddr := toAddr(rsa)
-
- f := &netFD{
- sysfd: s,
- family: fd.family,
- proto: fd.proto,
- cr: make(chan *ioResult, 1),
- cw: make(chan *ioResult, 1),
- net: fd.net,
- laddr: laddr,
- raddr: raddr,
- }
- runtime.SetFinalizer(f, (*netFD).Close)
- return f, nil
-}
-
-func closesocket(s int) (errno int) {
- return syscall.Closesocket(int32(s))
+ var lrsa, rrsa *syscall.RawSockaddrAny
+ var llen, rlen int32
+ l := uint32(unsafe.Sizeof(*lrsa))
+ syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&o.attrs[0])),
+ 0, l, l, &lrsa, &llen, &rrsa, &rlen)
+ lsa, _ := lrsa.Sockaddr()
+ rsa, _ := rrsa.Sockaddr()
+
+ return allocFD(s, fd.family, fd.proto, fd.net, toAddr(lsa), toAddr(rsa)), nil
}
-func init() {
- var d syscall.WSAData
- e := syscall.WSAStartup(uint32(0x101), &d)
- if e != 0 {
- initErr = os.NewSyscallError("WSAStartup", e)
- }
-}
+// Not implemeted functions.
func (fd *netFD) dup() (f *os.File, err os.Error) {
// TODO: Implement this