OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [fd_windows.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// 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
        "io"
9
        "os"
10
        "runtime"
11
        "sync"
12
        "syscall"
13
        "time"
14
        "unsafe"
15
)
16
 
17
var initErr error
18
 
19
func init() {
20
        var d syscall.WSAData
21
        e := syscall.WSAStartup(uint32(0x202), &d)
22
        if e != nil {
23
                initErr = os.NewSyscallError("WSAStartup", e)
24
        }
25
}
26
 
27
func closesocket(s syscall.Handle) error {
28
        return syscall.Closesocket(s)
29
}
30
 
31
// Interface for all io operations.
32
type anOpIface interface {
33
        Op() *anOp
34
        Name() string
35
        Submit() error
36
}
37
 
38
// IO completion result parameters.
39
type ioResult struct {
40
        qty uint32
41
        err error
42
}
43
 
44
// anOp implements functionality common to all io operations.
45
type anOp struct {
46
        // Used by IOCP interface, it must be first field
47
        // of the struct, as our code rely on it.
48
        o syscall.Overlapped
49
 
50
        resultc chan ioResult
51
        errnoc  chan error
52
        fd      *netFD
53
}
54
 
55
func (o *anOp) Init(fd *netFD, mode int) {
56
        o.fd = fd
57
        var i int
58
        if mode == 'r' {
59
                i = 0
60
        } else {
61
                i = 1
62
        }
63
        if fd.resultc[i] == nil {
64
                fd.resultc[i] = make(chan ioResult, 1)
65
        }
66
        o.resultc = fd.resultc[i]
67
        if fd.errnoc[i] == nil {
68
                fd.errnoc[i] = make(chan error)
69
        }
70
        o.errnoc = fd.errnoc[i]
71
}
72
 
73
func (o *anOp) Op() *anOp {
74
        return o
75
}
76
 
77
// bufOp is used by io operations that read / write
78
// data from / to client buffer.
79
type bufOp struct {
80
        anOp
81
        buf syscall.WSABuf
82
}
83
 
84
func (o *bufOp) Init(fd *netFD, buf []byte, mode int) {
85
        o.anOp.Init(fd, mode)
86
        o.buf.Len = uint32(len(buf))
87
        if len(buf) == 0 {
88
                o.buf.Buf = nil
89
        } else {
90
                o.buf.Buf = (*byte)(unsafe.Pointer(&buf[0]))
91
        }
92
}
93
 
94
// resultSrv will retrieve all io completion results from
95
// iocp and send them to the correspondent waiting client
96
// goroutine via channel supplied in the request.
97
type resultSrv struct {
98
        iocp syscall.Handle
99
}
100
 
101
func (s *resultSrv) Run() {
102
        var o *syscall.Overlapped
103
        var key uint32
104
        var r ioResult
105
        for {
106
                r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE)
107
                switch {
108
                case r.err == nil:
109
                        // Dequeued successfully completed io packet.
110
                case r.err == syscall.Errno(syscall.WAIT_TIMEOUT) && o == nil:
111
                        // Wait has timed out (should not happen now, but might be used in the future).
112
                        panic("GetQueuedCompletionStatus timed out")
113
                case o == nil:
114
                        // Failed to dequeue anything -> report the error.
115
                        panic("GetQueuedCompletionStatus failed " + r.err.Error())
116
                default:
117
                        // Dequeued failed io packet.
118
                }
119
                (*anOp)(unsafe.Pointer(o)).resultc <- r
120
        }
121
}
122
 
123
// ioSrv executes net io requests.
124
type ioSrv struct {
125
        submchan chan anOpIface // submit io requests
126
        canchan  chan anOpIface // cancel io requests
127
}
128
 
129
// ProcessRemoteIO will execute submit io requests on behalf
130
// of other goroutines, all on a single os thread, so it can
131
// cancel them later. Results of all operations will be sent
132
// back to their requesters via channel supplied in request.
133
func (s *ioSrv) ProcessRemoteIO() {
134
        runtime.LockOSThread()
135
        defer runtime.UnlockOSThread()
136
        for {
137
                select {
138
                case o := <-s.submchan:
139
                        o.Op().errnoc <- o.Submit()
140
                case o := <-s.canchan:
141
                        o.Op().errnoc <- syscall.CancelIo(syscall.Handle(o.Op().fd.sysfd))
142
                }
143
        }
144
}
145
 
146
// ExecIO executes a single io operation. It either executes it
147
// inline, or, if a deadline is employed, passes the request onto
148
// a special goroutine and waits for completion or cancels request.
149
// deadline is unix nanos.
150
func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (int, error) {
151
        var err error
152
        o := oi.Op()
153
        if deadline != 0 {
154
                // Send request to a special dedicated thread,
155
                // so it can stop the io with CancelIO later.
156
                s.submchan <- oi
157
                err = <-o.errnoc
158
        } else {
159
                err = oi.Submit()
160
        }
161
        switch err {
162
        case nil:
163
                // IO completed immediately, but we need to get our completion message anyway.
164
        case syscall.ERROR_IO_PENDING:
165
                // IO started, and we have to wait for its completion.
166
                err = nil
167
        default:
168
                return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, err}
169
        }
170
        // Wait for our request to complete.
171
        var r ioResult
172
        if deadline != 0 {
173
                dt := deadline - time.Now().UnixNano()
174
                if dt < 1 {
175
                        dt = 1
176
                }
177
                timer := time.NewTimer(time.Duration(dt) * time.Nanosecond)
178
                defer timer.Stop()
179
                select {
180
                case r = <-o.resultc:
181
                case <-timer.C:
182
                        s.canchan <- oi
183
                        <-o.errnoc
184
                        r = <-o.resultc
185
                        if r.err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
186
                                r.err = syscall.EWOULDBLOCK
187
                        }
188
                }
189
        } else {
190
                r = <-o.resultc
191
        }
192
        if r.err != nil {
193
                err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, r.err}
194
        }
195
        return int(r.qty), err
196
}
197
 
198
// Start helper goroutines.
199
var resultsrv *resultSrv
200
var iosrv *ioSrv
201
var onceStartServer sync.Once
202
 
203
func startServer() {
204
        resultsrv = new(resultSrv)
205
        var err error
206
        resultsrv.iocp, err = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
207
        if err != nil {
208
                panic("CreateIoCompletionPort: " + err.Error())
209
        }
210
        go resultsrv.Run()
211
 
212
        iosrv = new(ioSrv)
213
        iosrv.submchan = make(chan anOpIface)
214
        iosrv.canchan = make(chan anOpIface)
215
        go iosrv.ProcessRemoteIO()
216
}
217
 
218
// Network file descriptor.
219
type netFD struct {
220
        // locking/lifetime of sysfd
221
        sysmu   sync.Mutex
222
        sysref  int
223
        closing bool
224
 
225
        // immutable until Close
226
        sysfd       syscall.Handle
227
        family      int
228
        sotype      int
229
        isConnected bool
230
        net         string
231
        laddr       Addr
232
        raddr       Addr
233
        resultc     [2]chan ioResult // read/write completion results
234
        errnoc      [2]chan error    // read/write submit or cancel operation errors
235
 
236
        // owned by client
237
        rdeadline int64
238
        rio       sync.Mutex
239
        wdeadline int64
240
        wio       sync.Mutex
241
}
242
 
243
func allocFD(fd syscall.Handle, family, sotype int, net string) *netFD {
244
        netfd := &netFD{
245
                sysfd:  fd,
246
                family: family,
247
                sotype: sotype,
248
                net:    net,
249
        }
250
        runtime.SetFinalizer(netfd, (*netFD).Close)
251
        return netfd
252
}
253
 
254
func newFD(fd syscall.Handle, family, proto int, net string) (*netFD, error) {
255
        if initErr != nil {
256
                return nil, initErr
257
        }
258
        onceStartServer.Do(startServer)
259
        // Associate our socket with resultsrv.iocp.
260
        if _, err := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); err != nil {
261
                return nil, err
262
        }
263
        return allocFD(fd, family, proto, net), nil
264
}
265
 
266
func (fd *netFD) setAddr(laddr, raddr Addr) {
267
        fd.laddr = laddr
268
        fd.raddr = raddr
269
}
270
 
271
func (fd *netFD) connect(ra syscall.Sockaddr) error {
272
        return syscall.Connect(fd.sysfd, ra)
273
}
274
 
275
// Add a reference to this fd.
276
func (fd *netFD) incref() {
277
        fd.sysmu.Lock()
278
        fd.sysref++
279
        fd.sysmu.Unlock()
280
}
281
 
282
// Remove a reference to this FD and close if we've been asked to do so (and
283
// there are no references left.
284
func (fd *netFD) decref() {
285
        fd.sysmu.Lock()
286
        fd.sysref--
287
        if fd.closing && fd.sysref == 0 && fd.sysfd != syscall.InvalidHandle {
288
                // In case the user has set linger, switch to blocking mode so
289
                // the close blocks.  As long as this doesn't happen often, we
290
                // can handle the extra OS processes.  Otherwise we'll need to
291
                // use the resultsrv for Close too.  Sigh.
292
                syscall.SetNonblock(fd.sysfd, false)
293
                closesocket(fd.sysfd)
294
                fd.sysfd = syscall.InvalidHandle
295
                // no need for a finalizer anymore
296
                runtime.SetFinalizer(fd, nil)
297
        }
298
        fd.sysmu.Unlock()
299
}
300
 
301
func (fd *netFD) Close() error {
302
        if fd == nil || fd.sysfd == syscall.InvalidHandle {
303
                return os.EINVAL
304
        }
305
 
306
        fd.incref()
307
        syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
308
        fd.closing = true
309
        fd.decref()
310
        return nil
311
}
312
 
313
func (fd *netFD) shutdown(how int) error {
314
        if fd == nil || fd.sysfd == syscall.InvalidHandle {
315
                return os.EINVAL
316
        }
317
        err := syscall.Shutdown(fd.sysfd, how)
318
        if err != nil {
319
                return &OpError{"shutdown", fd.net, fd.laddr, err}
320
        }
321
        return nil
322
}
323
 
324
func (fd *netFD) CloseRead() error {
325
        return fd.shutdown(syscall.SHUT_RD)
326
}
327
 
328
func (fd *netFD) CloseWrite() error {
329
        return fd.shutdown(syscall.SHUT_WR)
330
}
331
 
332
// Read from network.
333
 
334
type readOp struct {
335
        bufOp
336
}
337
 
338
func (o *readOp) Submit() error {
339
        var d, f uint32
340
        return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
341
}
342
 
343
func (o *readOp) Name() string {
344
        return "WSARecv"
345
}
346
 
347
func (fd *netFD) Read(buf []byte) (int, error) {
348
        if fd == nil {
349
                return 0, os.EINVAL
350
        }
351
        fd.rio.Lock()
352
        defer fd.rio.Unlock()
353
        fd.incref()
354
        defer fd.decref()
355
        if fd.sysfd == syscall.InvalidHandle {
356
                return 0, os.EINVAL
357
        }
358
        var o readOp
359
        o.Init(fd, buf, 'r')
360
        n, err := iosrv.ExecIO(&o, fd.rdeadline)
361
        if err == nil && n == 0 {
362
                err = io.EOF
363
        }
364
        return n, err
365
}
366
 
367
// ReadFrom from network.
368
 
369
type readFromOp struct {
370
        bufOp
371
        rsa  syscall.RawSockaddrAny
372
        rsan int32
373
}
374
 
375
func (o *readFromOp) Submit() error {
376
        var d, f uint32
377
        return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
378
}
379
 
380
func (o *readFromOp) Name() string {
381
        return "WSARecvFrom"
382
}
383
 
384
func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
385
        if fd == nil {
386
                return 0, nil, os.EINVAL
387
        }
388
        if len(buf) == 0 {
389
                return 0, nil, nil
390
        }
391
        fd.rio.Lock()
392
        defer fd.rio.Unlock()
393
        fd.incref()
394
        defer fd.decref()
395
        if fd.sysfd == syscall.InvalidHandle {
396
                return 0, nil, os.EINVAL
397
        }
398
        var o readFromOp
399
        o.Init(fd, buf, 'r')
400
        o.rsan = int32(unsafe.Sizeof(o.rsa))
401
        n, err = iosrv.ExecIO(&o, fd.rdeadline)
402
        if err != nil {
403
                return 0, nil, err
404
        }
405
        sa, _ = o.rsa.Sockaddr()
406
        return
407
}
408
 
409
// Write to network.
410
 
411
type writeOp struct {
412
        bufOp
413
}
414
 
415
func (o *writeOp) Submit() error {
416
        var d uint32
417
        return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
418
}
419
 
420
func (o *writeOp) Name() string {
421
        return "WSASend"
422
}
423
 
424
func (fd *netFD) Write(buf []byte) (int, error) {
425
        if fd == nil {
426
                return 0, os.EINVAL
427
        }
428
        fd.wio.Lock()
429
        defer fd.wio.Unlock()
430
        fd.incref()
431
        defer fd.decref()
432
        if fd.sysfd == syscall.InvalidHandle {
433
                return 0, os.EINVAL
434
        }
435
        var o writeOp
436
        o.Init(fd, buf, 'w')
437
        return iosrv.ExecIO(&o, fd.wdeadline)
438
}
439
 
440
// WriteTo to network.
441
 
442
type writeToOp struct {
443
        bufOp
444
        sa syscall.Sockaddr
445
}
446
 
447
func (o *writeToOp) Submit() error {
448
        var d uint32
449
        return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
450
}
451
 
452
func (o *writeToOp) Name() string {
453
        return "WSASendto"
454
}
455
 
456
func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
457
        if fd == nil {
458
                return 0, os.EINVAL
459
        }
460
        if len(buf) == 0 {
461
                return 0, nil
462
        }
463
        fd.wio.Lock()
464
        defer fd.wio.Unlock()
465
        fd.incref()
466
        defer fd.decref()
467
        if fd.sysfd == syscall.InvalidHandle {
468
                return 0, os.EINVAL
469
        }
470
        var o writeToOp
471
        o.Init(fd, buf, 'w')
472
        o.sa = sa
473
        return iosrv.ExecIO(&o, fd.wdeadline)
474
}
475
 
476
// Accept new network connections.
477
 
478
type acceptOp struct {
479
        anOp
480
        newsock syscall.Handle
481
        attrs   [2]syscall.RawSockaddrAny // space for local and remote address only
482
}
483
 
484
func (o *acceptOp) Submit() error {
485
        var d uint32
486
        l := uint32(unsafe.Sizeof(o.attrs[0]))
487
        return syscall.AcceptEx(o.fd.sysfd, o.newsock,
488
                (*byte)(unsafe.Pointer(&o.attrs[0])), 0, l, l, &d, &o.o)
489
}
490
 
491
func (o *acceptOp) Name() string {
492
        return "AcceptEx"
493
}
494
 
495
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
496
        if fd == nil || fd.sysfd == syscall.InvalidHandle {
497
                return nil, os.EINVAL
498
        }
499
        fd.incref()
500
        defer fd.decref()
501
 
502
        // Get new socket.
503
        // See ../syscall/exec.go for description of ForkLock.
504
        syscall.ForkLock.RLock()
505
        s, err := syscall.Socket(fd.family, fd.sotype, 0)
506
        if err != nil {
507
                syscall.ForkLock.RUnlock()
508
                return nil, err
509
        }
510
        syscall.CloseOnExec(s)
511
        syscall.ForkLock.RUnlock()
512
 
513
        // Associate our new socket with IOCP.
514
        onceStartServer.Do(startServer)
515
        if _, err := syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); err != nil {
516
                return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, err}
517
        }
518
 
519
        // Submit accept request.
520
        var o acceptOp
521
        o.Init(fd, 'r')
522
        o.newsock = s
523
        _, err = iosrv.ExecIO(&o, 0)
524
        if err != nil {
525
                closesocket(s)
526
                return nil, err
527
        }
528
 
529
        // Inherit properties of the listening socket.
530
        err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
531
        if err != nil {
532
                closesocket(s)
533
                return nil, err
534
        }
535
 
536
        // Get local and peer addr out of AcceptEx buffer.
537
        var lrsa, rrsa *syscall.RawSockaddrAny
538
        var llen, rlen int32
539
        l := uint32(unsafe.Sizeof(*lrsa))
540
        syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&o.attrs[0])),
541
                0, l, l, &lrsa, &llen, &rrsa, &rlen)
542
        lsa, _ := lrsa.Sockaddr()
543
        rsa, _ := rrsa.Sockaddr()
544
 
545
        netfd := allocFD(s, fd.family, fd.sotype, fd.net)
546
        netfd.setAddr(toAddr(lsa), toAddr(rsa))
547
        return netfd, nil
548
}
549
 
550
// Unimplemented functions.
551
 
552
func (fd *netFD) dup() (*os.File, error) {
553
        // TODO: Implement this
554
        return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
555
}
556
 
557
func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
558
        return 0, 0, 0, nil, os.EAFNOSUPPORT
559
}
560
 
561
func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
562
        return 0, 0, os.EAFNOSUPPORT
563
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.