OSDN Git Service

Update to current version of Go library (revision 94d654be2064).
[pf3gnuchains/gcc-fork.git] / libgo / go / net / fd_windows.go
index 9b91eb3..63a8fbc 100644 (file)
@@ -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