LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // +build darwin freebsd linux netbsd openbsd | 5 // +build darwin freebsd linux netbsd openbsd |
6 | 6 |
7 package net | 7 package net |
8 | 8 |
9 import ( | 9 import ( |
10 "io" | 10 "io" |
11 "os" | 11 "os" |
12 "runtime" | 12 "runtime" |
13 "sync" | 13 "sync" |
| 14 "sync/atomic" |
14 "syscall" | 15 "syscall" |
15 "time" | 16 "time" |
16 ) | 17 ) |
17 | 18 |
18 // Network file descriptor. | 19 // Network file descriptor. |
19 type netFD struct { | 20 type netFD struct { |
20 // locking/lifetime of sysfd | 21 // locking/lifetime of sysfd |
21 sysmu sync.Mutex | 22 sysmu sync.Mutex |
22 sysref int | 23 sysref int |
23 | 24 |
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 | 399 |
399 if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil { | 400 if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil { |
400 closesocket(s) | 401 closesocket(s) |
401 return nil, err | 402 return nil, err |
402 } | 403 } |
403 lsa, _ := syscall.Getsockname(netfd.sysfd) | 404 lsa, _ := syscall.Getsockname(netfd.sysfd) |
404 netfd.setAddr(toAddr(lsa), toAddr(rsa)) | 405 netfd.setAddr(toAddr(lsa), toAddr(rsa)) |
405 return netfd, nil | 406 return netfd, nil |
406 } | 407 } |
407 | 408 |
408 // dupCloseOnExec is a variable so it can be modified in fd_linux.go. | 409 // tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used. |
409 var dupCloseOnExec = dupCloseOnExecUnix | 410 // If the kernel doesn't support it, this is set to 0. |
410 | 411 var tryDupCloexec = int32(1) |
411 // dupCloseOnExecUnix is the traditional way to dup an fd and set | 412 |
412 // its O_CLOEXEC bit, using two system calls. | 413 func dupCloseOnExec(fd int) (newfd int, err error) { |
413 func dupCloseOnExecUnix(fd int) (newfd int, err error) { | 414 » if atomic.LoadInt32(&tryDupCloexec) == 1 { |
| 415 » » r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), sys
call.F_DUPFD_CLOEXEC, 0) |
| 416 » » switch e1 { |
| 417 » » case 0: |
| 418 » » » return int(r0), nil |
| 419 » » case syscall.EINVAL: |
| 420 » » » // Old kernel. Fall back to the portable way |
| 421 » » » // from now on. |
| 422 » » » atomic.StoreInt32(&tryDupCloexec, 0) |
| 423 » » default: |
| 424 » » » return -1, e1 |
| 425 » » } |
| 426 » } |
| 427 » return dupCloseOnExecOld(fd) |
| 428 } |
| 429 |
| 430 // dupCloseOnExecUnixOld is the traditional way to dup an fd and |
| 431 // set its O_CLOEXEC bit, using two system calls. |
| 432 func dupCloseOnExecOld(fd int) (newfd int, err error) { |
414 syscall.ForkLock.RLock() | 433 syscall.ForkLock.RLock() |
415 defer syscall.ForkLock.RUnlock() | 434 defer syscall.ForkLock.RUnlock() |
416 » ns, err := syscall.Dup(fd) | 435 » newfd, err = syscall.Dup(fd) |
417 if err != nil { | 436 if err != nil { |
418 » » return | 437 » » return -1, err |
419 » } | 438 » } |
420 » syscall.CloseOnExec(ns) | 439 » syscall.CloseOnExec(newfd) |
421 » return ns, nil | 440 » return |
422 } | 441 } |
423 | 442 |
424 func (fd *netFD) dup() (f *os.File, err error) { | 443 func (fd *netFD) dup() (f *os.File, err error) { |
425 ns, err := dupCloseOnExec(fd.sysfd) | 444 ns, err := dupCloseOnExec(fd.sysfd) |
426 if err != nil { | 445 if err != nil { |
427 syscall.ForkLock.RUnlock() | 446 syscall.ForkLock.RUnlock() |
428 return nil, &OpError{"dup", fd.net, fd.laddr, err} | 447 return nil, &OpError{"dup", fd.net, fd.laddr, err} |
429 } | 448 } |
430 | 449 |
431 // We want blocking mode for the new fd, hence the double negative. | 450 // We want blocking mode for the new fd, hence the double negative. |
432 // This also puts the old fd into blocking mode, meaning that | 451 // This also puts the old fd into blocking mode, meaning that |
433 // I/O will block the thread instead of letting us use the epoll server. | 452 // I/O will block the thread instead of letting us use the epoll server. |
434 // Everything will still work, just with more threads. | 453 // Everything will still work, just with more threads. |
435 if err = syscall.SetNonblock(ns, false); err != nil { | 454 if err = syscall.SetNonblock(ns, false); err != nil { |
436 return nil, &OpError{"setnonblock", fd.net, fd.laddr, err} | 455 return nil, &OpError{"setnonblock", fd.net, fd.laddr, err} |
437 } | 456 } |
438 | 457 |
439 return os.NewFile(uintptr(ns), fd.name()), nil | 458 return os.NewFile(uintptr(ns), fd.name()), nil |
440 } | 459 } |
441 | 460 |
442 func closesocket(s int) error { | 461 func closesocket(s int) error { |
443 return syscall.Close(s) | 462 return syscall.Close(s) |
444 } | 463 } |
LEFT | RIGHT |