OSDN Git Service

libgo: Solaris compatibility patches.
[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 != nil {
106                         return -1, 0, os.NewSyscallError("select", e)
107                 }
108                 if n == 0 {
109                         return -1, 0, nil
110                 }
111
112                 p.nReady = n
113                 *p.readyReadFds = tmpReadFds
114                 *p.readyWriteFds = tmpWriteFds
115                 p.lastFd = 0
116         }
117
118         flag := false
119         for i := p.lastFd; i < p.maxFd+1; i++ {
120                 if syscall.FDIsSet(i, p.readyReadFds) {
121                         flag = true
122                         mode = 'r'
123                         syscall.FDClr(i, p.readyReadFds)
124                 } else if syscall.FDIsSet(i, p.readyWriteFds) {
125                         flag = true
126                         mode = 'w'
127                         syscall.FDClr(i, p.readyWriteFds)
128                 }
129                 if flag {
130                         if !syscall.FDIsSet(i, p.repeatFds) {
131                                 p.DelFD(i, mode)
132                         }
133                         p.nReady--
134                         p.lastFd = i
135                         return i, mode, nil
136                 }
137         }
138
139         // Will not reach here.  Just to shut up the compiler.
140         return -1, 0, nil
141 }
142
143 func (p *pollster) Close() error {
144         return nil
145 }