github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/net/fd_select.go (about)

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