]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/go/net/fd_windows.go
Add Go frontend, libgo library, and Go testsuite.
[thirdparty/gcc.git] / libgo / go / net / fd_windows.go
1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package net
6
7 import (
8 "os"
9 "sync"
10 "syscall"
11 "unsafe"
12 )
13
14 // BUG(brainman): The Windows implementation does not implement SetTimeout.
15
16 // IO completion result parameters.
17 type ioResult struct {
18 key uint32
19 qty uint32
20 errno int
21 }
22
23 // Network file descriptor.
24 type netFD struct {
25 // locking/lifetime of sysfd
26 sysmu sync.Mutex
27 sysref int
28 closing bool
29
30 // immutable until Close
31 sysfd int
32 family int
33 proto int
34 sysfile *os.File
35 cr chan *ioResult
36 cw chan *ioResult
37 net string
38 laddr Addr
39 raddr Addr
40
41 // owned by client
42 rdeadline_delta int64
43 rdeadline int64
44 rio sync.Mutex
45 wdeadline_delta int64
46 wdeadline int64
47 wio sync.Mutex
48 }
49
50 type InvalidConnError struct{}
51
52 func (e *InvalidConnError) String() string { return "invalid net.Conn" }
53 func (e *InvalidConnError) Temporary() bool { return false }
54 func (e *InvalidConnError) Timeout() bool { return false }
55
56 // pollServer will run around waiting for io completion request
57 // to arrive. Every request received will contain channel to signal
58 // io owner about the completion.
59
60 type pollServer struct {
61 iocp int32
62 }
63
64 func newPollServer() (s *pollServer, err os.Error) {
65 s = new(pollServer)
66 var e int
67 if s.iocp, e = syscall.CreateIoCompletionPort(-1, 0, 0, 1); e != 0 {
68 return nil, os.NewSyscallError("CreateIoCompletionPort", e)
69 }
70 go s.Run()
71 return s, nil
72 }
73
74 type ioPacket struct {
75 // Used by IOCP interface,
76 // it must be first field of the struct,
77 // as our code rely on it.
78 o syscall.Overlapped
79
80 // Link to the io owner.
81 c chan *ioResult
82 }
83
84 func (s *pollServer) getCompletedIO() (ov *syscall.Overlapped, result *ioResult, err os.Error) {
85 var r ioResult
86 var o *syscall.Overlapped
87 _, e := syscall.GetQueuedCompletionStatus(s.iocp, &r.qty, &r.key, &o, syscall.INFINITE)
88 switch {
89 case e == 0:
90 // Dequeued successfully completed io packet.
91 return o, &r, nil
92 case e == syscall.WAIT_TIMEOUT && o == nil:
93 // Wait has timed out (should not happen now, but might be used in the future).
94 return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
95 case o == nil:
96 // Failed to dequeue anything -> report the error.
97 return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
98 default:
99 // Dequeued failed io packet.
100 r.errno = e
101 return o, &r, nil
102 }
103 return
104 }
105
106 func (s *pollServer) Run() {
107 for {
108 o, r, err := s.getCompletedIO()
109 if err != nil {
110 panic("Run pollServer: " + err.String() + "\n")
111 }
112 p := (*ioPacket)(unsafe.Pointer(o))
113 p.c <- r
114 }
115 }
116
117 // Network FD methods.
118 // All the network FDs use a single pollServer.
119
120 var pollserver *pollServer
121 var onceStartServer sync.Once
122
123 func startServer() {
124 p, err := newPollServer()
125 if err != nil {
126 panic("Start pollServer: " + err.String() + "\n")
127 }
128 pollserver = p
129 }
130
131 var initErr os.Error
132
133 func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
134 if initErr != nil {
135 return nil, initErr
136 }
137 onceStartServer.Do(startServer)
138 // Associate our socket with pollserver.iocp.
139 if _, e := syscall.CreateIoCompletionPort(int32(fd), pollserver.iocp, 0, 0); e != 0 {
140 return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)}
141 }
142 f = &netFD{
143 sysfd: fd,
144 family: family,
145 proto: proto,
146 cr: make(chan *ioResult),
147 cw: make(chan *ioResult),
148 net: net,
149 laddr: laddr,
150 raddr: raddr,
151 }
152 var ls, rs string
153 if laddr != nil {
154 ls = laddr.String()
155 }
156 if raddr != nil {
157 rs = raddr.String()
158 }
159 f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs)
160 return f, nil
161 }
162
163 // Add a reference to this fd.
164 func (fd *netFD) incref() {
165 fd.sysmu.Lock()
166 fd.sysref++
167 fd.sysmu.Unlock()
168 }
169
170 // Remove a reference to this FD and close if we've been asked to do so (and
171 // there are no references left.
172 func (fd *netFD) decref() {
173 fd.sysmu.Lock()
174 fd.sysref--
175 if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
176 // In case the user has set linger, switch to blocking mode so
177 // the close blocks. As long as this doesn't happen often, we
178 // can handle the extra OS processes. Otherwise we'll need to
179 // use the pollserver for Close too. Sigh.
180 syscall.SetNonblock(fd.sysfd, false)
181 fd.sysfile.Close()
182 fd.sysfile = nil
183 fd.sysfd = -1
184 }
185 fd.sysmu.Unlock()
186 }
187
188 func (fd *netFD) Close() os.Error {
189 if fd == nil || fd.sysfile == nil {
190 return os.EINVAL
191 }
192
193 fd.incref()
194 syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
195 fd.closing = true
196 fd.decref()
197 return nil
198 }
199
200 func newWSABuf(p []byte) *syscall.WSABuf {
201 var p0 *byte
202 if len(p) > 0 {
203 p0 = (*byte)(unsafe.Pointer(&p[0]))
204 }
205 return &syscall.WSABuf{uint32(len(p)), p0}
206 }
207
208 func (fd *netFD) Read(p []byte) (n int, err os.Error) {
209 if fd == nil {
210 return 0, os.EINVAL
211 }
212 fd.rio.Lock()
213 defer fd.rio.Unlock()
214 fd.incref()
215 defer fd.decref()
216 if fd.sysfile == nil {
217 return 0, os.EINVAL
218 }
219 // Submit receive request.
220 var pckt ioPacket
221 pckt.c = fd.cr
222 var done uint32
223 flags := uint32(0)
224 e := syscall.WSARecv(uint32(fd.sysfd), newWSABuf(p), 1, &done, &flags, &pckt.o, nil)
225 switch e {
226 case 0:
227 // IO completed immediately, but we need to get our completion message anyway.
228 case syscall.ERROR_IO_PENDING:
229 // IO started, and we have to wait for it's completion.
230 default:
231 return 0, &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(e)}
232 }
233 // Wait for our request to complete.
234 r := <-pckt.c
235 if r.errno != 0 {
236 err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)}
237 }
238 n = int(r.qty)
239 if err == nil && n == 0 {
240 err = os.EOF
241 }
242 return
243 }
244
245 func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
246 var r syscall.Sockaddr
247 return 0, r, nil
248 }
249
250 func (fd *netFD) Write(p []byte) (n int, err os.Error) {
251 if fd == nil {
252 return 0, os.EINVAL
253 }
254 fd.wio.Lock()
255 defer fd.wio.Unlock()
256 fd.incref()
257 defer fd.decref()
258 if fd.sysfile == nil {
259 return 0, os.EINVAL
260 }
261 // Submit send request.
262 var pckt ioPacket
263 pckt.c = fd.cw
264 var done uint32
265 e := syscall.WSASend(uint32(fd.sysfd), newWSABuf(p), 1, &done, uint32(0), &pckt.o, nil)
266 switch e {
267 case 0:
268 // IO completed immediately, but we need to get our completion message anyway.
269 case syscall.ERROR_IO_PENDING:
270 // IO started, and we have to wait for it's completion.
271 default:
272 return 0, &OpError{"WSASend", fd.net, fd.laddr, os.Errno(e)}
273 }
274 // Wait for our request to complete.
275 r := <-pckt.c
276 if r.errno != 0 {
277 err = &OpError{"WSASend", fd.net, fd.laddr, os.Errno(r.errno)}
278 }
279 n = int(r.qty)
280 return
281 }
282
283 func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
284 return 0, nil
285 }
286
287 func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
288 if fd == nil || fd.sysfile == nil {
289 return nil, os.EINVAL
290 }
291 fd.incref()
292 defer fd.decref()
293
294 // Get new socket.
295 // See ../syscall/exec.go for description of ForkLock.
296 syscall.ForkLock.RLock()
297 s, e := syscall.Socket(fd.family, fd.proto, 0)
298 if e != 0 {
299 syscall.ForkLock.RUnlock()
300 return nil, os.Errno(e)
301 }
302 syscall.CloseOnExec(s)
303 syscall.ForkLock.RUnlock()
304
305 // Associate our new socket with IOCP.
306 onceStartServer.Do(startServer)
307 if _, e = syscall.CreateIoCompletionPort(int32(s), pollserver.iocp, 0, 0); e != 0 {
308 return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
309 }
310
311 // Submit accept request.
312 // Will use new unique channel here, because, unlike Read or Write,
313 // Accept is expected to be executed by many goroutines simultaniously.
314 var pckt ioPacket
315 pckt.c = make(chan *ioResult)
316 attrs, e := syscall.AcceptIOCP(fd.sysfd, s, &pckt.o)
317 switch e {
318 case 0:
319 // IO completed immediately, but we need to get our completion message anyway.
320 case syscall.ERROR_IO_PENDING:
321 // IO started, and we have to wait for it's completion.
322 default:
323 syscall.Close(s)
324 return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(e)}
325 }
326
327 // Wait for peer connection.
328 r := <-pckt.c
329 if r.errno != 0 {
330 syscall.Close(s)
331 return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(r.errno)}
332 }
333
334 // Inherit properties of the listening socket.
335 e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd)
336 if e != 0 {
337 syscall.Close(s)
338 return nil, &OpError{"Setsockopt", fd.net, fd.laddr, os.Errno(r.errno)}
339 }
340
341 // Get local and peer addr out of AcceptEx buffer.
342 lsa, rsa := syscall.GetAcceptIOCPSockaddrs(attrs)
343
344 // Create our netFD and return it for further use.
345 laddr := toAddr(lsa)
346 raddr := toAddr(rsa)
347
348 f := &netFD{
349 sysfd: s,
350 family: fd.family,
351 proto: fd.proto,
352 cr: make(chan *ioResult),
353 cw: make(chan *ioResult),
354 net: fd.net,
355 laddr: laddr,
356 raddr: raddr,
357 }
358 var ls, rs string
359 if laddr != nil {
360 ls = laddr.String()
361 }
362 if raddr != nil {
363 rs = raddr.String()
364 }
365 f.sysfile = os.NewFile(s, fd.net+":"+ls+"->"+rs)
366 return f, nil
367 }
368
369 func init() {
370 var d syscall.WSAData
371 e := syscall.WSAStartup(uint32(0x101), &d)
372 if e != 0 {
373 initErr = os.NewSyscallError("WSAStartup", e)
374 }
375 }
376
377 func (fd *netFD) dup() (f *os.File, err os.Error) {
378 // TODO: Implement this
379 return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
380 }