Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 1 | // Copyright 2009 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 | // TODO(rsc): All the prints in this file should go to standard error. |
| 6 | |
| 7 | package net |
| 8 | |
| 9 | import ( |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 10 | "once"; |
| 11 | "os"; |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 12 | "sync"; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 13 | "syscall"; |
| 14 | ) |
| 15 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 16 | // Network file descriptor. |
| 17 | type netFD struct { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 18 | // locking/lifetime of sysfd |
| 19 | sysmu sync.Mutex; |
| 20 | sysref int; |
| 21 | closing bool; |
| 22 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 23 | // immutable until Close |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 24 | sysfd int; |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 25 | family int; |
| 26 | proto int; |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 27 | sysfile *os.File; |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 28 | cr chan *netFD; |
| 29 | cw chan *netFD; |
| 30 | net string; |
| 31 | laddr Addr; |
| 32 | raddr Addr; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 33 | |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 34 | // owned by client |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 35 | rdeadline_delta int64; |
| 36 | rdeadline int64; |
| 37 | rio sync.Mutex; |
| 38 | wdeadline_delta int64; |
| 39 | wdeadline int64; |
| 40 | wio sync.Mutex; |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 41 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 42 | // owned by fd wait server |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 43 | ncr, ncw int; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 44 | } |
| 45 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 46 | // A pollServer helps FDs determine when to retry a non-blocking |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 47 | // read or write after they get EAGAIN. When an FD needs to wait, |
| 48 | // send the fd on s.cr (for a read) or s.cw (for a write) to pass the |
| 49 | // request to the poll server. Then receive on fd.cr/fd.cw. |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 50 | // When the pollServer finds that i/o on FD should be possible |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 51 | // again, it will send fd on fd.cr/fd.cw to wake any waiting processes. |
| 52 | // This protocol is implemented as s.WaitRead() and s.WaitWrite(). |
| 53 | // |
| 54 | // There is one subtlety: when sending on s.cr/s.cw, the |
| 55 | // poll server is probably in a system call, waiting for an fd |
| 56 | // to become ready. It's not looking at the request channels. |
| 57 | // To resolve this, the poll server waits not just on the FDs it has |
| 58 | // been given but also its own pipe. After sending on the |
| 59 | // buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 60 | // byte to the pipe, causing the pollServer's poll system call to |
| 61 | // return. In response to the pipe being readable, the pollServer |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 62 | // re-polls its request channels. |
| 63 | // |
| 64 | // Note that the ordering is "send request" and then "wake up server". |
| 65 | // If the operations were reversed, there would be a race: the poll |
| 66 | // server might wake up and look at the request channel, see that it |
| 67 | // was empty, and go back to sleep, all before the requester managed |
| 68 | // to send the request. Because the send must complete before the wakeup, |
| 69 | // the request channel must be buffered. A buffer of size 1 is sufficient |
| 70 | // for any request load. If many processes are trying to submit requests, |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 71 | // one will succeed, the pollServer will read the request, and then the |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 72 | // channel will be empty for the next process's request. A larger buffer |
| 73 | // might help batch requests. |
Adam Langley | ef8f483 | 2009-11-18 13:18:34 -0800 | [diff] [blame] | 74 | // |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 75 | // To avoid races in closing, all fd operations are locked and |
| 76 | // refcounted. when netFD.Close() is called, it calls syscall.Shutdown |
| 77 | // and sets a closing flag. Only when the last reference is removed |
| 78 | // will the fd be closed. |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 79 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 80 | type pollServer struct { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 81 | cr, cw chan *netFD; // buffered >= 1 |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 82 | pr, pw *os.File; |
| 83 | pending map[int]*netFD; |
| 84 | poll *pollster; // low-level OS hooks |
| 85 | deadline int64; // next deadline (nsec since 1970) |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 86 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 87 | |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 88 | func newPollServer() (s *pollServer, err os.Error) { |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 89 | s = new(pollServer); |
| 90 | s.cr = make(chan *netFD, 1); |
| 91 | s.cw = make(chan *netFD, 1); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 92 | if s.pr, s.pw, err = os.Pipe(); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 93 | return nil, err |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 94 | } |
Russ Cox | 9e0fec9 | 2009-06-01 22:14:39 -0700 | [diff] [blame] | 95 | var e int; |
| 96 | if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 { |
| 97 | Errno: |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 98 | err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 99 | Error: |
| 100 | s.pr.Close(); |
Russ Cox | 983f06b | 2008-10-07 12:31:31 -0700 | [diff] [blame] | 101 | s.pw.Close(); |
Russ Cox | 9e0fec9 | 2009-06-01 22:14:39 -0700 | [diff] [blame] | 102 | return nil, err; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 103 | } |
Russ Cox | 9e0fec9 | 2009-06-01 22:14:39 -0700 | [diff] [blame] | 104 | if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 105 | goto Errno |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 106 | } |
Russ Cox | c93da7c7 | 2009-03-05 15:48:12 -0800 | [diff] [blame] | 107 | if s.poll, err = newpollster(); err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 108 | goto Error |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 109 | } |
Rob Pike | 704bc9d | 2009-02-06 17:54:26 -0800 | [diff] [blame] | 110 | if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil { |
Russ Cox | 983f06b | 2008-10-07 12:31:31 -0700 | [diff] [blame] | 111 | s.poll.Close(); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 112 | goto Error; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 113 | } |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 114 | s.pending = make(map[int]*netFD); |
Russ Cox | 983f06b | 2008-10-07 12:31:31 -0700 | [diff] [blame] | 115 | go s.Run(); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 116 | return s, nil; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 117 | } |
| 118 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 119 | func (s *pollServer) AddFD(fd *netFD, mode int) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 120 | intfd := fd.sysfd; |
Russ Cox | 37a5374 | 2009-04-15 19:01:48 -0700 | [diff] [blame] | 121 | if intfd < 0 { |
| 122 | // fd closed underfoot |
| 123 | if mode == 'r' { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 124 | fd.cr <- fd |
Russ Cox | 37a5374 | 2009-04-15 19:01:48 -0700 | [diff] [blame] | 125 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 126 | fd.cw <- fd |
Russ Cox | 37a5374 | 2009-04-15 19:01:48 -0700 | [diff] [blame] | 127 | } |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 128 | return; |
Russ Cox | 37a5374 | 2009-04-15 19:01:48 -0700 | [diff] [blame] | 129 | } |
| 130 | if err := s.poll.AddFD(intfd, mode, false); err != nil { |
| 131 | panicln("pollServer AddFD ", intfd, ": ", err.String(), "\n"); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 132 | return; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 133 | } |
| 134 | |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 135 | var t int64; |
Robert Griesemer | 3bb0032 | 2009-11-09 21:23:52 -0800 | [diff] [blame] | 136 | key := intfd << 1; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 137 | if mode == 'r' { |
Russ Cox | 983f06b | 2008-10-07 12:31:31 -0700 | [diff] [blame] | 138 | fd.ncr++; |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 139 | t = fd.rdeadline; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 140 | } else { |
Russ Cox | 983f06b | 2008-10-07 12:31:31 -0700 | [diff] [blame] | 141 | fd.ncw++; |
| 142 | key++; |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 143 | t = fd.wdeadline; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 144 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 145 | s.pending[key] = fd; |
| 146 | if t > 0 && (s.deadline == 0 || t < s.deadline) { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 147 | s.deadline = t |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 148 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 149 | } |
| 150 | |
Russ Cox | 9e0fec9 | 2009-06-01 22:14:39 -0700 | [diff] [blame] | 151 | func (s *pollServer) LookupFD(fd int, mode int) *netFD { |
Robert Griesemer | 3bb0032 | 2009-11-09 21:23:52 -0800 | [diff] [blame] | 152 | key := fd << 1; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 153 | if mode == 'w' { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 154 | key++ |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 155 | } |
Russ Cox | 983f06b | 2008-10-07 12:31:31 -0700 | [diff] [blame] | 156 | netfd, ok := s.pending[key]; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 157 | if !ok { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 158 | return nil |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 159 | } |
Russ Cox | 983f06b | 2008-10-07 12:31:31 -0700 | [diff] [blame] | 160 | s.pending[key] = nil, false; |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 161 | return netfd; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 162 | } |
| 163 | |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 164 | func (s *pollServer) WakeFD(fd *netFD, mode int) { |
| 165 | if mode == 'r' { |
| 166 | for fd.ncr > 0 { |
| 167 | fd.ncr--; |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 168 | fd.cr <- fd; |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 169 | } |
| 170 | } else { |
| 171 | for fd.ncw > 0 { |
| 172 | fd.ncw--; |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 173 | fd.cw <- fd; |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 174 | } |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | func (s *pollServer) Now() int64 { |
| 179 | sec, nsec, err := os.Time(); |
| 180 | if err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 181 | panic("net: os.Time: ", err.String()) |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 182 | } |
Robert Griesemer | 3bb0032 | 2009-11-09 21:23:52 -0800 | [diff] [blame] | 183 | nsec += sec * 1e9; |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 184 | return nsec; |
| 185 | } |
| 186 | |
| 187 | func (s *pollServer) CheckDeadlines() { |
| 188 | now := s.Now(); |
| 189 | // TODO(rsc): This will need to be handled more efficiently, |
| 190 | // probably with a heap indexed by wakeup time. |
| 191 | |
| 192 | var next_deadline int64; |
| 193 | for key, fd := range s.pending { |
| 194 | var t int64; |
| 195 | var mode int; |
| 196 | if key&1 == 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 197 | mode = 'r' |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 198 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 199 | mode = 'w' |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 200 | } |
| 201 | if mode == 'r' { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 202 | t = fd.rdeadline |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 203 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 204 | t = fd.wdeadline |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 205 | } |
| 206 | if t > 0 { |
| 207 | if t <= now { |
| 208 | s.pending[key] = nil, false; |
| 209 | if mode == 'r' { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 210 | s.poll.DelFD(fd.sysfd, mode); |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 211 | fd.rdeadline = -1; |
| 212 | } else { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 213 | s.poll.DelFD(fd.sysfd, mode); |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 214 | fd.wdeadline = -1; |
| 215 | } |
| 216 | s.WakeFD(fd, mode); |
| 217 | } else if next_deadline == 0 || t < next_deadline { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 218 | next_deadline = t |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 219 | } |
| 220 | } |
| 221 | } |
| 222 | s.deadline = next_deadline; |
| 223 | } |
| 224 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 225 | func (s *pollServer) Run() { |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 226 | var scratch [100]byte; |
| 227 | for { |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 228 | var t = s.deadline; |
| 229 | if t > 0 { |
| 230 | t = t - s.Now(); |
| 231 | if t < 0 { |
| 232 | s.CheckDeadlines(); |
| 233 | continue; |
| 234 | } |
| 235 | } |
| 236 | fd, mode, err := s.poll.WaitFD(t); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 237 | if err != nil { |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 238 | print("pollServer WaitFD: ", err.String(), "\n"); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 239 | return; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 240 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 241 | if fd < 0 { |
| 242 | // Timeout happened. |
| 243 | s.CheckDeadlines(); |
| 244 | continue; |
| 245 | } |
Rob Pike | 704bc9d | 2009-02-06 17:54:26 -0800 | [diff] [blame] | 246 | if fd == s.pr.Fd() { |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 247 | // Drain our wakeup pipe. |
Russ Cox | ca6a0fe | 2009-09-15 09:41:59 -0700 | [diff] [blame] | 248 | for nn, _ := s.pr.Read(&scratch); nn > 0; { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 249 | nn, _ = s.pr.Read(&scratch) |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 250 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 251 | // Read from channels |
| 252 | for fd, ok := <-s.cr; ok; fd, ok = <-s.cr { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 253 | s.AddFD(fd, 'r') |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 254 | } |
| 255 | for fd, ok := <-s.cw; ok; fd, ok = <-s.cw { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 256 | s.AddFD(fd, 'w') |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 257 | } |
| 258 | } else { |
Russ Cox | 983f06b | 2008-10-07 12:31:31 -0700 | [diff] [blame] | 259 | netfd := s.LookupFD(fd, mode); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 260 | if netfd == nil { |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 261 | print("pollServer: unexpected wakeup for fd=", netfd, " mode=", string(mode), "\n"); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 262 | continue; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 263 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 264 | s.WakeFD(netfd, mode); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 265 | } |
| 266 | } |
| 267 | } |
| 268 | |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 269 | var wakeupbuf [1]byte |
| 270 | |
Robert Griesemer | 368f8cb | 2009-11-06 14:24:38 -0800 | [diff] [blame] | 271 | func (s *pollServer) Wakeup() { s.pw.Write(&wakeupbuf) } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 272 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 273 | func (s *pollServer) WaitRead(fd *netFD) { |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 274 | s.cr <- fd; |
| 275 | s.Wakeup(); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 276 | <-fd.cr; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 277 | } |
| 278 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 279 | func (s *pollServer) WaitWrite(fd *netFD) { |
Brendan O'Dea | 7326a38 | 2009-04-29 17:36:37 -0700 | [diff] [blame] | 280 | s.cw <- fd; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 281 | s.Wakeup(); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 282 | <-fd.cw; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 283 | } |
| 284 | |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 285 | // Network FD methods. |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 286 | // All the network FDs use a single pollServer. |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 287 | |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 288 | var pollserver *pollServer |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 289 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 290 | func startServer() { |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 291 | p, err := newPollServer(); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 292 | if err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 293 | print("Start pollServer: ", err.String(), "\n") |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 294 | } |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 295 | pollserver = p; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 296 | } |
| 297 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 298 | func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) { |
| 299 | once.Do(startServer); |
Russ Cox | 9e0fec9 | 2009-06-01 22:14:39 -0700 | [diff] [blame] | 300 | if e := syscall.SetNonblock(fd, true); e != 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 301 | return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)} |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 302 | } |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 303 | f = &netFD{ |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 304 | sysfd: fd, |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 305 | family: family, |
| 306 | proto: proto, |
| 307 | net: net, |
| 308 | laddr: laddr, |
| 309 | raddr: raddr, |
| 310 | }; |
| 311 | var ls, rs string; |
| 312 | if laddr != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 313 | ls = laddr.String() |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 314 | } |
| 315 | if raddr != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 316 | rs = raddr.String() |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 317 | } |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 318 | f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs); |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 319 | f.cr = make(chan *netFD, 1); |
| 320 | f.cw = make(chan *netFD, 1); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 321 | return f, nil; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 322 | } |
| 323 | |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 324 | // Add a reference to this fd. |
| 325 | func (fd *netFD) incref() { |
| 326 | fd.sysmu.Lock(); |
| 327 | fd.sysref++; |
| 328 | fd.sysmu.Unlock(); |
| 329 | } |
| 330 | |
| 331 | // Remove a reference to this FD and close if we've been asked to do so (and |
| 332 | // there are no references left. |
| 333 | func (fd *netFD) decref() { |
| 334 | fd.sysmu.Lock(); |
| 335 | fd.sysref--; |
| 336 | if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 { |
| 337 | // In case the user has set linger, switch to blocking mode so |
| 338 | // the close blocks. As long as this doesn't happen often, we |
| 339 | // can handle the extra OS processes. Otherwise we'll need to |
| 340 | // use the pollserver for Close too. Sigh. |
| 341 | syscall.SetNonblock(fd.sysfd, false); |
| 342 | fd.sysfile.Close(); |
| 343 | fd.sysfile = nil; |
| 344 | fd.sysfd = -1; |
| 345 | } |
| 346 | fd.sysmu.Unlock(); |
| 347 | } |
| 348 | |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 349 | func isEAGAIN(e os.Error) bool { |
| 350 | if e1, ok := e.(*os.PathError); ok { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 351 | return e1.Error == os.EAGAIN |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 352 | } |
| 353 | return e == os.EAGAIN; |
| 354 | } |
| 355 | |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 356 | func (fd *netFD) Close() os.Error { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 357 | if fd == nil || fd.sysfile == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 358 | return os.EINVAL |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 359 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 360 | |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 361 | fd.incref(); |
| 362 | syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR); |
| 363 | fd.closing = true; |
| 364 | fd.decref(); |
| 365 | return nil; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 366 | } |
| 367 | |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 368 | func (fd *netFD) Read(p []byte) (n int, err os.Error) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 369 | if fd == nil || fd.sysfile == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 370 | return 0, os.EINVAL |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 371 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 372 | fd.rio.Lock(); |
| 373 | defer fd.rio.Unlock(); |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 374 | fd.incref(); |
| 375 | defer fd.decref(); |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 376 | if fd.rdeadline_delta > 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 377 | fd.rdeadline = pollserver.Now() + fd.rdeadline_delta |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 378 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 379 | fd.rdeadline = 0 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 380 | } |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 381 | for { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 382 | n, err = fd.sysfile.Read(p); |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 383 | if isEAGAIN(err) && fd.rdeadline >= 0 { |
| 384 | pollserver.WaitRead(fd); |
| 385 | continue; |
| 386 | } |
| 387 | break; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 388 | } |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 389 | return; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 390 | } |
| 391 | |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 392 | func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 393 | if fd == nil || fd.sysfile == nil { |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 394 | return 0, nil, os.EINVAL |
| 395 | } |
| 396 | fd.rio.Lock(); |
| 397 | defer fd.rio.Unlock(); |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 398 | fd.incref(); |
| 399 | defer fd.decref(); |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 400 | if fd.rdeadline_delta > 0 { |
| 401 | fd.rdeadline = pollserver.Now() + fd.rdeadline_delta |
| 402 | } else { |
| 403 | fd.rdeadline = 0 |
| 404 | } |
| 405 | for { |
| 406 | var errno int; |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 407 | n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0); |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 408 | if errno == syscall.EAGAIN && fd.rdeadline >= 0 { |
| 409 | pollserver.WaitRead(fd); |
| 410 | continue; |
| 411 | } |
| 412 | if errno != 0 { |
| 413 | n = 0; |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 414 | err = &os.PathError{"recvfrom", fd.sysfile.Name(), os.Errno(errno)}; |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 415 | } |
| 416 | break; |
| 417 | } |
| 418 | return; |
| 419 | } |
| 420 | |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 421 | func (fd *netFD) Write(p []byte) (n int, err os.Error) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 422 | if fd == nil || fd.sysfile == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 423 | return 0, os.EINVAL |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 424 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 425 | fd.wio.Lock(); |
| 426 | defer fd.wio.Unlock(); |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 427 | fd.incref(); |
| 428 | defer fd.decref(); |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 429 | if fd.wdeadline_delta > 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 430 | fd.wdeadline = pollserver.Now() + fd.wdeadline_delta |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 431 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 432 | fd.wdeadline = 0 |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 433 | } |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 434 | err = nil; |
Russ Cox | 983f06b | 2008-10-07 12:31:31 -0700 | [diff] [blame] | 435 | nn := 0; |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 436 | for nn < len(p) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 437 | n, err = fd.sysfile.Write(p[nn:]); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 438 | if n > 0 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 439 | nn += n |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 440 | } |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 441 | if nn == len(p) { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 442 | break |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 443 | } |
Russ Cox | a0bcaf4 | 2009-06-25 20:24:55 -0700 | [diff] [blame] | 444 | if isEAGAIN(err) && fd.wdeadline >= 0 { |
Russ Cox | 1e37e8a | 2009-03-06 17:51:31 -0800 | [diff] [blame] | 445 | pollserver.WaitWrite(fd); |
| 446 | continue; |
| 447 | } |
| 448 | if n == 0 || err != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 449 | break |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 450 | } |
| 451 | } |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 452 | return nn, err; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 453 | } |
| 454 | |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 455 | func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 456 | if fd == nil || fd.sysfile == nil { |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 457 | return 0, os.EINVAL |
| 458 | } |
| 459 | fd.wio.Lock(); |
| 460 | defer fd.wio.Unlock(); |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 461 | fd.incref(); |
| 462 | defer fd.decref(); |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 463 | if fd.wdeadline_delta > 0 { |
| 464 | fd.wdeadline = pollserver.Now() + fd.wdeadline_delta |
| 465 | } else { |
| 466 | fd.wdeadline = 0 |
| 467 | } |
| 468 | err = nil; |
| 469 | for { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 470 | errno := syscall.Sendto(fd.sysfd, p, 0, sa); |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 471 | if errno == syscall.EAGAIN && fd.wdeadline >= 0 { |
| 472 | pollserver.WaitWrite(fd); |
| 473 | continue; |
| 474 | } |
| 475 | if errno != 0 { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 476 | err = &os.PathError{"sendto", fd.sysfile.Name(), os.Errno(errno)} |
Russ Cox | 6e788e0 | 2009-11-17 08:39:17 -0800 | [diff] [blame] | 477 | } |
| 478 | break; |
| 479 | } |
| 480 | if err == nil { |
| 481 | n = len(p) |
| 482 | } |
| 483 | return; |
| 484 | } |
| 485 | |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 486 | func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 487 | if fd == nil || fd.sysfile == nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 488 | return nil, os.EINVAL |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 489 | } |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 490 | |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 491 | fd.incref(); |
| 492 | defer fd.decref(); |
| 493 | |
Russ Cox | 91ceda5 | 2009-02-15 19:35:52 -0800 | [diff] [blame] | 494 | // See ../syscall/exec.go for description of ForkLock. |
| 495 | // It is okay to hold the lock across syscall.Accept |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 496 | // because we have put fd.sysfd into non-blocking mode. |
Russ Cox | 91ceda5 | 2009-02-15 19:35:52 -0800 | [diff] [blame] | 497 | syscall.ForkLock.RLock(); |
Russ Cox | 9e0fec9 | 2009-06-01 22:14:39 -0700 | [diff] [blame] | 498 | var s, e int; |
| 499 | var sa syscall.Sockaddr; |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 500 | for { |
Devon H. O'Dell | eb16346 | 2009-12-01 23:28:57 -0800 | [diff] [blame] | 501 | s, sa, e = syscall.Accept(fd.sysfd); |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 502 | if e != syscall.EAGAIN { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 503 | break |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 504 | } |
Russ Cox | 91ceda5 | 2009-02-15 19:35:52 -0800 | [diff] [blame] | 505 | syscall.ForkLock.RUnlock(); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 506 | pollserver.WaitRead(fd); |
Russ Cox | 91ceda5 | 2009-02-15 19:35:52 -0800 | [diff] [blame] | 507 | syscall.ForkLock.RLock(); |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 508 | } |
| 509 | if e != 0 { |
Russ Cox | 91ceda5 | 2009-02-15 19:35:52 -0800 | [diff] [blame] | 510 | syscall.ForkLock.RUnlock(); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 511 | return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)}; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 512 | } |
Russ Cox | 91ceda5 | 2009-02-15 19:35:52 -0800 | [diff] [blame] | 513 | syscall.CloseOnExec(s); |
| 514 | syscall.ForkLock.RUnlock(); |
Russ Cox | d8921c5 | 2009-02-15 14:18:39 -0800 | [diff] [blame] | 515 | |
Russ Cox | c83b838 | 2009-11-02 18:37:30 -0800 | [diff] [blame] | 516 | if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil { |
Rob Pike | 1a91b9a | 2009-01-16 11:36:44 -0800 | [diff] [blame] | 517 | syscall.Close(s); |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 518 | return nil, err; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 519 | } |
Robert Griesemer | 5d37705 | 2009-11-04 23:16:46 -0800 | [diff] [blame] | 520 | return nfd, nil; |
Russ Cox | e4a61c6 | 2008-09-29 13:37:00 -0700 | [diff] [blame] | 521 | } |