OSDN Git Service

PR go/52583
[pf3gnuchains/gcc-fork.git] / libgo / go / net / fd_select.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 // Waiting for FDs via select(2).
6
7 package net
8
9 import (
10         "os"
11         "syscall"
12 )
13
14 type pollster struct {
15         readFds, writeFds, repeatFds *syscall.FdSet
16         maxFd                        int
17         readyReadFds, readyWriteFds  *syscall.FdSet
18         nReady                       int
19         lastFd                       int
20 }
21
22 func newpollster() (p *pollster, err error) {
23         p = new(pollster)
24         p.readFds = new(syscall.FdSet)
25         p.writeFds = new(syscall.FdSet)
26         p.repeatFds = new(syscall.FdSet)
27         p.readyReadFds = new(syscall.FdSet)
28         p.readyWriteFds = new(syscall.FdSet)
29         p.maxFd = -1
30         p.nReady = 0
31         p.lastFd = 0
32         return p, nil
33 }
34
35 func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
36         // pollServer is locked.
37
38         if mode == 'r' {
39                 syscall.FDSet(fd, p.readFds)
40         } else {
41                 syscall.FDSet(fd, p.writeFds)
42         }
43
44         if repeat {
45                 syscall.FDSet(fd, p.repeatFds)
46         }
47
48         if fd > p.maxFd {
49                 p.maxFd = fd
50         }
51
52         return true, nil
53 }
54
55 func (p *pollster) DelFD(fd int, mode int) {
56         // pollServer is locked.
57
58         if mode == 'r' {
59                 if !syscall.FDIsSet(fd, p.readFds) {
60                         print("Select unexpected fd=", fd, " for read\n")
61                         return
62                 }
63                 syscall.FDClr(fd, p.readFds)
64         } else {
65                 if !syscall.FDIsSet(fd, p.writeFds) {
66                         print("Select unexpected fd=", fd, " for write\n")
67                         return
68                 }
69                 syscall.FDClr(fd, p.writeFds)
70         }
71
72         // Doesn't matter if not already present.
73         syscall.FDClr(fd, p.repeatFds)
74
75         // We don't worry about maxFd here.
76 }
77
78 func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
79         if p.nReady == 0 {
80                 var timeout *syscall.Timeval
81                 var tv syscall.Timeval
82                 timeout = nil
83                 if nsec > 0 {
84                         tv = syscall.NsecToTimeval(nsec)
85                         timeout = &tv
86                 }
87
88                 var n int
89                 var e error
90                 var tmpReadFds, tmpWriteFds syscall.FdSet
91                 for {
92                         // Temporary syscall.FdSet's into which the values are copied
93                         // because select mutates the values.
94                         tmpReadFds = *p.readFds
95                         tmpWriteFds = *p.writeFds
96
97                         s.Unlock()
98                         n, e = syscall.Select(p.maxFd+1, &tmpReadFds, &tmpWriteFds, nil, timeout)
99                         s.Lock()
100
101                         if e != syscall.EINTR {
102                                 break
103                         }
104                 }
105                 if e == syscall.EBADF {
106                         // Some file descriptor has been closed.
107                         tmpReadFds = syscall.FdSet{}
108                         tmpWriteFds = syscall.FdSet{}
109                         n = 0
110                         for i := 0; i < p.maxFd+1; i++ {
111                                 if syscall.FDIsSet(i, p.readFds) {
112                                         var s syscall.Stat_t
113                                         if syscall.Fstat(i, &s) == syscall.EBADF {
114                                                 syscall.FDSet(i, &tmpReadFds)
115                                                 n++
116                                         }
117                                 } else if syscall.FDIsSet(i, p.writeFds) {
118                                         var s syscall.Stat_t
119                                         if syscall.Fstat(i, &s) == syscall.EBADF {
120                                                 syscall.FDSet(i, &tmpWriteFds)
121                                                 n++
122                                         }
123                                 }
124                         }
125                 } else if e != nil {
126                         return -1, 0, os.NewSyscallError("select", e)
127                 }
128                 if n == 0 {
129                         return -1, 0, nil
130                 }
131
132                 p.nReady = n
133                 *p.readyReadFds = tmpReadFds
134                 *p.readyWriteFds = tmpWriteFds
135                 p.lastFd = 0
136         }
137
138         flag := false
139         for i := p.lastFd; i < p.maxFd+1; i++ {
140                 if syscall.FDIsSet(i, p.readyReadFds) {
141                         flag = true
142                         mode = 'r'
143                         syscall.FDClr(i, p.readyReadFds)
144                 } else if syscall.FDIsSet(i, p.readyWriteFds) {
145                         flag = true
146                         mode = 'w'
147                         syscall.FDClr(i, p.readyWriteFds)
148                 }
149                 if flag {
150                         if !syscall.FDIsSet(i, p.repeatFds) {
151                                 p.DelFD(i, mode)
152                         }
153                         p.nReady--
154                         p.lastFd = i
155                         return i, mode, nil
156                 }
157         }
158
159         // Will not reach here.  Just to shut up the compiler.
160         return -1, 0, nil
161 }
162
163 func (p *pollster) Close() error {
164         return nil
165 }