github.com/JimmyHuang454/JLS-go@v0.0.0-20230831150107-90d536585ba0/internal/poll/fd_unix.go (about)

     1  // Copyright 2017 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  //go:build unix || (js && wasm)
     6  
     7  package poll
     8  
     9  import (
    10  	"internal/syscall/unix"
    11  	"io"
    12  	"sync/atomic"
    13  	"syscall"
    14  )
    15  
    16  // FD is a file descriptor. The net and os packages use this type as a
    17  // field of a larger type representing a network connection or OS file.
    18  type FD struct {
    19  	// Lock sysfd and serialize access to Read and Write methods.
    20  	fdmu fdMutex
    21  
    22  	// System file descriptor. Immutable until Close.
    23  	Sysfd int
    24  
    25  	// I/O poller.
    26  	pd pollDesc
    27  
    28  	// Writev cache.
    29  	iovecs *[]syscall.Iovec
    30  
    31  	// Semaphore signaled when file is closed.
    32  	csema uint32
    33  
    34  	// Non-zero if this file has been set to blocking mode.
    35  	isBlocking uint32
    36  
    37  	// Whether this is a streaming descriptor, as opposed to a
    38  	// packet-based descriptor like a UDP socket. Immutable.
    39  	IsStream bool
    40  
    41  	// Whether a zero byte read indicates EOF. This is false for a
    42  	// message based socket connection.
    43  	ZeroReadIsEOF bool
    44  
    45  	// Whether this is a file rather than a network socket.
    46  	isFile bool
    47  }
    48  
    49  // Init initializes the FD. The Sysfd field should already be set.
    50  // This can be called multiple times on a single FD.
    51  // The net argument is a network name from the net package (e.g., "tcp"),
    52  // or "file".
    53  // Set pollable to true if fd should be managed by runtime netpoll.
    54  func (fd *FD) Init(net string, pollable bool) error {
    55  	// We don't actually care about the various network types.
    56  	if net == "file" {
    57  		fd.isFile = true
    58  	}
    59  	if !pollable {
    60  		fd.isBlocking = 1
    61  		return nil
    62  	}
    63  	err := fd.pd.init(fd)
    64  	if err != nil {
    65  		// If we could not initialize the runtime poller,
    66  		// assume we are using blocking mode.
    67  		fd.isBlocking = 1
    68  	}
    69  	return err
    70  }
    71  
    72  // Destroy closes the file descriptor. This is called when there are
    73  // no remaining references.
    74  func (fd *FD) destroy() error {
    75  	// Poller may want to unregister fd in readiness notification mechanism,
    76  	// so this must be executed before CloseFunc.
    77  	fd.pd.close()
    78  
    79  	// We don't use ignoringEINTR here because POSIX does not define
    80  	// whether the descriptor is closed if close returns EINTR.
    81  	// If the descriptor is indeed closed, using a loop would race
    82  	// with some other goroutine opening a new descriptor.
    83  	// (The Linux kernel guarantees that it is closed on an EINTR error.)
    84  	err := CloseFunc(fd.Sysfd)
    85  
    86  	fd.Sysfd = -1
    87  	runtime_Semrelease(&fd.csema)
    88  	return err
    89  }
    90  
    91  // Close closes the FD. The underlying file descriptor is closed by the
    92  // destroy method when there are no remaining references.
    93  func (fd *FD) Close() error {
    94  	if !fd.fdmu.increfAndClose() {
    95  		return errClosing(fd.isFile)
    96  	}
    97  
    98  	// Unblock any I/O.  Once it all unblocks and returns,
    99  	// so that it cannot be referring to fd.sysfd anymore,
   100  	// the final decref will close fd.sysfd. This should happen
   101  	// fairly quickly, since all the I/O is non-blocking, and any
   102  	// attempts to block in the pollDesc will return errClosing(fd.isFile).
   103  	fd.pd.evict()
   104  
   105  	// The call to decref will call destroy if there are no other
   106  	// references.
   107  	err := fd.decref()
   108  
   109  	// Wait until the descriptor is closed. If this was the only
   110  	// reference, it is already closed. Only wait if the file has
   111  	// not been set to blocking mode, as otherwise any current I/O
   112  	// may be blocking, and that would block the Close.
   113  	// No need for an atomic read of isBlocking, increfAndClose means
   114  	// we have exclusive access to fd.
   115  	if fd.isBlocking == 0 {
   116  		runtime_Semacquire(&fd.csema)
   117  	}
   118  
   119  	return err
   120  }
   121  
   122  // SetBlocking puts the file into blocking mode.
   123  func (fd *FD) SetBlocking() error {
   124  	if err := fd.incref(); err != nil {
   125  		return err
   126  	}
   127  	defer fd.decref()
   128  	// Atomic store so that concurrent calls to SetBlocking
   129  	// do not cause a race condition. isBlocking only ever goes
   130  	// from 0 to 1 so there is no real race here.
   131  	atomic.StoreUint32(&fd.isBlocking, 1)
   132  	return syscall.SetNonblock(fd.Sysfd, false)
   133  }
   134  
   135  // Darwin and FreeBSD can't read or write 2GB+ files at a time,
   136  // even on 64-bit systems.
   137  // The same is true of socket implementations on many systems.
   138  // See golang.org/issue/7812 and golang.org/issue/16266.
   139  // Use 1GB instead of, say, 2GB-1, to keep subsequent reads aligned.
   140  const maxRW = 1 << 30
   141  
   142  // Read implements io.Reader.
   143  func (fd *FD) Read(p []byte) (int, error) {
   144  	if err := fd.readLock(); err != nil {
   145  		return 0, err
   146  	}
   147  	defer fd.readUnlock()
   148  	if len(p) == 0 {
   149  		// If the caller wanted a zero byte read, return immediately
   150  		// without trying (but after acquiring the readLock).
   151  		// Otherwise syscall.Read returns 0, nil which looks like
   152  		// io.EOF.
   153  		// TODO(bradfitz): make it wait for readability? (Issue 15735)
   154  		return 0, nil
   155  	}
   156  	if err := fd.pd.prepareRead(fd.isFile); err != nil {
   157  		return 0, err
   158  	}
   159  	if fd.IsStream && len(p) > maxRW {
   160  		p = p[:maxRW]
   161  	}
   162  	for {
   163  		n, err := ignoringEINTRIO(syscall.Read, fd.Sysfd, p)
   164  		if err != nil {
   165  			n = 0
   166  			if err == syscall.EAGAIN && fd.pd.pollable() {
   167  				if err = fd.pd.waitRead(fd.isFile); err == nil {
   168  					continue
   169  				}
   170  			}
   171  		}
   172  		err = fd.eofError(n, err)
   173  		return n, err
   174  	}
   175  }
   176  
   177  // Pread wraps the pread system call.
   178  func (fd *FD) Pread(p []byte, off int64) (int, error) {
   179  	// Call incref, not readLock, because since pread specifies the
   180  	// offset it is independent from other reads.
   181  	// Similarly, using the poller doesn't make sense for pread.
   182  	if err := fd.incref(); err != nil {
   183  		return 0, err
   184  	}
   185  	if fd.IsStream && len(p) > maxRW {
   186  		p = p[:maxRW]
   187  	}
   188  	var (
   189  		n   int
   190  		err error
   191  	)
   192  	for {
   193  		n, err = syscall.Pread(fd.Sysfd, p, off)
   194  		if err != syscall.EINTR {
   195  			break
   196  		}
   197  	}
   198  	if err != nil {
   199  		n = 0
   200  	}
   201  	fd.decref()
   202  	err = fd.eofError(n, err)
   203  	return n, err
   204  }
   205  
   206  // ReadFrom wraps the recvfrom network call.
   207  func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) {
   208  	if err := fd.readLock(); err != nil {
   209  		return 0, nil, err
   210  	}
   211  	defer fd.readUnlock()
   212  	if err := fd.pd.prepareRead(fd.isFile); err != nil {
   213  		return 0, nil, err
   214  	}
   215  	for {
   216  		n, sa, err := syscall.Recvfrom(fd.Sysfd, p, 0)
   217  		if err != nil {
   218  			if err == syscall.EINTR {
   219  				continue
   220  			}
   221  			n = 0
   222  			if err == syscall.EAGAIN && fd.pd.pollable() {
   223  				if err = fd.pd.waitRead(fd.isFile); err == nil {
   224  					continue
   225  				}
   226  			}
   227  		}
   228  		err = fd.eofError(n, err)
   229  		return n, sa, err
   230  	}
   231  }
   232  
   233  // ReadFromInet4 wraps the recvfrom network call for IPv4.
   234  func (fd *FD) ReadFromInet4(p []byte, from *syscall.SockaddrInet4) (int, error) {
   235  	if err := fd.readLock(); err != nil {
   236  		return 0, err
   237  	}
   238  	defer fd.readUnlock()
   239  	if err := fd.pd.prepareRead(fd.isFile); err != nil {
   240  		return 0, err
   241  	}
   242  	for {
   243  		n, err := unix.RecvfromInet4(fd.Sysfd, p, 0, from)
   244  		if err != nil {
   245  			if err == syscall.EINTR {
   246  				continue
   247  			}
   248  			n = 0
   249  			if err == syscall.EAGAIN && fd.pd.pollable() {
   250  				if err = fd.pd.waitRead(fd.isFile); err == nil {
   251  					continue
   252  				}
   253  			}
   254  		}
   255  		err = fd.eofError(n, err)
   256  		return n, err
   257  	}
   258  }
   259  
   260  // ReadFromInet6 wraps the recvfrom network call for IPv6.
   261  func (fd *FD) ReadFromInet6(p []byte, from *syscall.SockaddrInet6) (int, error) {
   262  	if err := fd.readLock(); err != nil {
   263  		return 0, err
   264  	}
   265  	defer fd.readUnlock()
   266  	if err := fd.pd.prepareRead(fd.isFile); err != nil {
   267  		return 0, err
   268  	}
   269  	for {
   270  		n, err := unix.RecvfromInet6(fd.Sysfd, p, 0, from)
   271  		if err != nil {
   272  			if err == syscall.EINTR {
   273  				continue
   274  			}
   275  			n = 0
   276  			if err == syscall.EAGAIN && fd.pd.pollable() {
   277  				if err = fd.pd.waitRead(fd.isFile); err == nil {
   278  					continue
   279  				}
   280  			}
   281  		}
   282  		err = fd.eofError(n, err)
   283  		return n, err
   284  	}
   285  }
   286  
   287  // ReadMsg wraps the recvmsg network call.
   288  func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.Sockaddr, error) {
   289  	if err := fd.readLock(); err != nil {
   290  		return 0, 0, 0, nil, err
   291  	}
   292  	defer fd.readUnlock()
   293  	if err := fd.pd.prepareRead(fd.isFile); err != nil {
   294  		return 0, 0, 0, nil, err
   295  	}
   296  	for {
   297  		n, oobn, sysflags, sa, err := syscall.Recvmsg(fd.Sysfd, p, oob, flags)
   298  		if err != nil {
   299  			if err == syscall.EINTR {
   300  				continue
   301  			}
   302  			// TODO(dfc) should n and oobn be set to 0
   303  			if err == syscall.EAGAIN && fd.pd.pollable() {
   304  				if err = fd.pd.waitRead(fd.isFile); err == nil {
   305  					continue
   306  				}
   307  			}
   308  		}
   309  		err = fd.eofError(n, err)
   310  		return n, oobn, sysflags, sa, err
   311  	}
   312  }
   313  
   314  // ReadMsgInet4 is ReadMsg, but specialized for syscall.SockaddrInet4.
   315  func (fd *FD) ReadMsgInet4(p []byte, oob []byte, flags int, sa4 *syscall.SockaddrInet4) (int, int, int, error) {
   316  	if err := fd.readLock(); err != nil {
   317  		return 0, 0, 0, err
   318  	}
   319  	defer fd.readUnlock()
   320  	if err := fd.pd.prepareRead(fd.isFile); err != nil {
   321  		return 0, 0, 0, err
   322  	}
   323  	for {
   324  		n, oobn, sysflags, err := unix.RecvmsgInet4(fd.Sysfd, p, oob, flags, sa4)
   325  		if err != nil {
   326  			if err == syscall.EINTR {
   327  				continue
   328  			}
   329  			// TODO(dfc) should n and oobn be set to 0
   330  			if err == syscall.EAGAIN && fd.pd.pollable() {
   331  				if err = fd.pd.waitRead(fd.isFile); err == nil {
   332  					continue
   333  				}
   334  			}
   335  		}
   336  		err = fd.eofError(n, err)
   337  		return n, oobn, sysflags, err
   338  	}
   339  }
   340  
   341  // ReadMsgInet6 is ReadMsg, but specialized for syscall.SockaddrInet6.
   342  func (fd *FD) ReadMsgInet6(p []byte, oob []byte, flags int, sa6 *syscall.SockaddrInet6) (int, int, int, error) {
   343  	if err := fd.readLock(); err != nil {
   344  		return 0, 0, 0, err
   345  	}
   346  	defer fd.readUnlock()
   347  	if err := fd.pd.prepareRead(fd.isFile); err != nil {
   348  		return 0, 0, 0, err
   349  	}
   350  	for {
   351  		n, oobn, sysflags, err := unix.RecvmsgInet6(fd.Sysfd, p, oob, flags, sa6)
   352  		if err != nil {
   353  			if err == syscall.EINTR {
   354  				continue
   355  			}
   356  			// TODO(dfc) should n and oobn be set to 0
   357  			if err == syscall.EAGAIN && fd.pd.pollable() {
   358  				if err = fd.pd.waitRead(fd.isFile); err == nil {
   359  					continue
   360  				}
   361  			}
   362  		}
   363  		err = fd.eofError(n, err)
   364  		return n, oobn, sysflags, err
   365  	}
   366  }
   367  
   368  // Write implements io.Writer.
   369  func (fd *FD) Write(p []byte) (int, error) {
   370  	if err := fd.writeLock(); err != nil {
   371  		return 0, err
   372  	}
   373  	defer fd.writeUnlock()
   374  	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
   375  		return 0, err
   376  	}
   377  	var nn int
   378  	for {
   379  		max := len(p)
   380  		if fd.IsStream && max-nn > maxRW {
   381  			max = nn + maxRW
   382  		}
   383  		n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max])
   384  		if n > 0 {
   385  			nn += n
   386  		}
   387  		if nn == len(p) {
   388  			return nn, err
   389  		}
   390  		if err == syscall.EAGAIN && fd.pd.pollable() {
   391  			if err = fd.pd.waitWrite(fd.isFile); err == nil {
   392  				continue
   393  			}
   394  		}
   395  		if err != nil {
   396  			return nn, err
   397  		}
   398  		if n == 0 {
   399  			return nn, io.ErrUnexpectedEOF
   400  		}
   401  	}
   402  }
   403  
   404  // Pwrite wraps the pwrite system call.
   405  func (fd *FD) Pwrite(p []byte, off int64) (int, error) {
   406  	// Call incref, not writeLock, because since pwrite specifies the
   407  	// offset it is independent from other writes.
   408  	// Similarly, using the poller doesn't make sense for pwrite.
   409  	if err := fd.incref(); err != nil {
   410  		return 0, err
   411  	}
   412  	defer fd.decref()
   413  	var nn int
   414  	for {
   415  		max := len(p)
   416  		if fd.IsStream && max-nn > maxRW {
   417  			max = nn + maxRW
   418  		}
   419  		n, err := syscall.Pwrite(fd.Sysfd, p[nn:max], off+int64(nn))
   420  		if err == syscall.EINTR {
   421  			continue
   422  		}
   423  		if n > 0 {
   424  			nn += n
   425  		}
   426  		if nn == len(p) {
   427  			return nn, err
   428  		}
   429  		if err != nil {
   430  			return nn, err
   431  		}
   432  		if n == 0 {
   433  			return nn, io.ErrUnexpectedEOF
   434  		}
   435  	}
   436  }
   437  
   438  // WriteToInet4 wraps the sendto network call for IPv4 addresses.
   439  func (fd *FD) WriteToInet4(p []byte, sa *syscall.SockaddrInet4) (int, error) {
   440  	if err := fd.writeLock(); err != nil {
   441  		return 0, err
   442  	}
   443  	defer fd.writeUnlock()
   444  	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
   445  		return 0, err
   446  	}
   447  	for {
   448  		err := unix.SendtoInet4(fd.Sysfd, p, 0, sa)
   449  		if err == syscall.EINTR {
   450  			continue
   451  		}
   452  		if err == syscall.EAGAIN && fd.pd.pollable() {
   453  			if err = fd.pd.waitWrite(fd.isFile); err == nil {
   454  				continue
   455  			}
   456  		}
   457  		if err != nil {
   458  			return 0, err
   459  		}
   460  		return len(p), nil
   461  	}
   462  }
   463  
   464  // WriteToInet6 wraps the sendto network call for IPv6 addresses.
   465  func (fd *FD) WriteToInet6(p []byte, sa *syscall.SockaddrInet6) (int, error) {
   466  	if err := fd.writeLock(); err != nil {
   467  		return 0, err
   468  	}
   469  	defer fd.writeUnlock()
   470  	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
   471  		return 0, err
   472  	}
   473  	for {
   474  		err := unix.SendtoInet6(fd.Sysfd, p, 0, sa)
   475  		if err == syscall.EINTR {
   476  			continue
   477  		}
   478  		if err == syscall.EAGAIN && fd.pd.pollable() {
   479  			if err = fd.pd.waitWrite(fd.isFile); err == nil {
   480  				continue
   481  			}
   482  		}
   483  		if err != nil {
   484  			return 0, err
   485  		}
   486  		return len(p), nil
   487  	}
   488  }
   489  
   490  // WriteTo wraps the sendto network call.
   491  func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (int, error) {
   492  	if err := fd.writeLock(); err != nil {
   493  		return 0, err
   494  	}
   495  	defer fd.writeUnlock()
   496  	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
   497  		return 0, err
   498  	}
   499  	for {
   500  		err := syscall.Sendto(fd.Sysfd, p, 0, sa)
   501  		if err == syscall.EINTR {
   502  			continue
   503  		}
   504  		if err == syscall.EAGAIN && fd.pd.pollable() {
   505  			if err = fd.pd.waitWrite(fd.isFile); err == nil {
   506  				continue
   507  			}
   508  		}
   509  		if err != nil {
   510  			return 0, err
   511  		}
   512  		return len(p), nil
   513  	}
   514  }
   515  
   516  // WriteMsg wraps the sendmsg network call.
   517  func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) {
   518  	if err := fd.writeLock(); err != nil {
   519  		return 0, 0, err
   520  	}
   521  	defer fd.writeUnlock()
   522  	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
   523  		return 0, 0, err
   524  	}
   525  	for {
   526  		n, err := syscall.SendmsgN(fd.Sysfd, p, oob, sa, 0)
   527  		if err == syscall.EINTR {
   528  			continue
   529  		}
   530  		if err == syscall.EAGAIN && fd.pd.pollable() {
   531  			if err = fd.pd.waitWrite(fd.isFile); err == nil {
   532  				continue
   533  			}
   534  		}
   535  		if err != nil {
   536  			return n, 0, err
   537  		}
   538  		return n, len(oob), err
   539  	}
   540  }
   541  
   542  // WriteMsgInet4 is WriteMsg specialized for syscall.SockaddrInet4.
   543  func (fd *FD) WriteMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (int, int, error) {
   544  	if err := fd.writeLock(); err != nil {
   545  		return 0, 0, err
   546  	}
   547  	defer fd.writeUnlock()
   548  	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
   549  		return 0, 0, err
   550  	}
   551  	for {
   552  		n, err := unix.SendmsgNInet4(fd.Sysfd, p, oob, sa, 0)
   553  		if err == syscall.EINTR {
   554  			continue
   555  		}
   556  		if err == syscall.EAGAIN && fd.pd.pollable() {
   557  			if err = fd.pd.waitWrite(fd.isFile); err == nil {
   558  				continue
   559  			}
   560  		}
   561  		if err != nil {
   562  			return n, 0, err
   563  		}
   564  		return n, len(oob), err
   565  	}
   566  }
   567  
   568  // WriteMsgInet6 is WriteMsg specialized for syscall.SockaddrInet6.
   569  func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (int, int, error) {
   570  	if err := fd.writeLock(); err != nil {
   571  		return 0, 0, err
   572  	}
   573  	defer fd.writeUnlock()
   574  	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
   575  		return 0, 0, err
   576  	}
   577  	for {
   578  		n, err := unix.SendmsgNInet6(fd.Sysfd, p, oob, sa, 0)
   579  		if err == syscall.EINTR {
   580  			continue
   581  		}
   582  		if err == syscall.EAGAIN && fd.pd.pollable() {
   583  			if err = fd.pd.waitWrite(fd.isFile); err == nil {
   584  				continue
   585  			}
   586  		}
   587  		if err != nil {
   588  			return n, 0, err
   589  		}
   590  		return n, len(oob), err
   591  	}
   592  }
   593  
   594  // Accept wraps the accept network call.
   595  func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
   596  	if err := fd.readLock(); err != nil {
   597  		return -1, nil, "", err
   598  	}
   599  	defer fd.readUnlock()
   600  
   601  	if err := fd.pd.prepareRead(fd.isFile); err != nil {
   602  		return -1, nil, "", err
   603  	}
   604  	for {
   605  		s, rsa, errcall, err := accept(fd.Sysfd)
   606  		if err == nil {
   607  			return s, rsa, "", err
   608  		}
   609  		switch err {
   610  		case syscall.EINTR:
   611  			continue
   612  		case syscall.EAGAIN:
   613  			if fd.pd.pollable() {
   614  				if err = fd.pd.waitRead(fd.isFile); err == nil {
   615  					continue
   616  				}
   617  			}
   618  		case syscall.ECONNABORTED:
   619  			// This means that a socket on the listen
   620  			// queue was closed before we Accept()ed it;
   621  			// it's a silly error, so try again.
   622  			continue
   623  		}
   624  		return -1, nil, errcall, err
   625  	}
   626  }
   627  
   628  // Seek wraps syscall.Seek.
   629  func (fd *FD) Seek(offset int64, whence int) (int64, error) {
   630  	if err := fd.incref(); err != nil {
   631  		return 0, err
   632  	}
   633  	defer fd.decref()
   634  	return syscall.Seek(fd.Sysfd, offset, whence)
   635  }
   636  
   637  // ReadDirent wraps syscall.ReadDirent.
   638  // We treat this like an ordinary system call rather than a call
   639  // that tries to fill the buffer.
   640  func (fd *FD) ReadDirent(buf []byte) (int, error) {
   641  	if err := fd.incref(); err != nil {
   642  		return 0, err
   643  	}
   644  	defer fd.decref()
   645  	for {
   646  		n, err := ignoringEINTRIO(syscall.ReadDirent, fd.Sysfd, buf)
   647  		if err != nil {
   648  			n = 0
   649  			if err == syscall.EAGAIN && fd.pd.pollable() {
   650  				if err = fd.pd.waitRead(fd.isFile); err == nil {
   651  					continue
   652  				}
   653  			}
   654  		}
   655  		// Do not call eofError; caller does not expect to see io.EOF.
   656  		return n, err
   657  	}
   658  }
   659  
   660  // Fchmod wraps syscall.Fchmod.
   661  func (fd *FD) Fchmod(mode uint32) error {
   662  	if err := fd.incref(); err != nil {
   663  		return err
   664  	}
   665  	defer fd.decref()
   666  	return ignoringEINTR(func() error {
   667  		return syscall.Fchmod(fd.Sysfd, mode)
   668  	})
   669  }
   670  
   671  // Fchdir wraps syscall.Fchdir.
   672  func (fd *FD) Fchdir() error {
   673  	if err := fd.incref(); err != nil {
   674  		return err
   675  	}
   676  	defer fd.decref()
   677  	return syscall.Fchdir(fd.Sysfd)
   678  }
   679  
   680  // Fstat wraps syscall.Fstat
   681  func (fd *FD) Fstat(s *syscall.Stat_t) error {
   682  	if err := fd.incref(); err != nil {
   683  		return err
   684  	}
   685  	defer fd.decref()
   686  	return ignoringEINTR(func() error {
   687  		return syscall.Fstat(fd.Sysfd, s)
   688  	})
   689  }
   690  
   691  // tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
   692  // If the kernel doesn't support it, this is set to 0.
   693  var tryDupCloexec = int32(1)
   694  
   695  // DupCloseOnExec dups fd and marks it close-on-exec.
   696  func DupCloseOnExec(fd int) (int, string, error) {
   697  	if syscall.F_DUPFD_CLOEXEC != 0 && atomic.LoadInt32(&tryDupCloexec) == 1 {
   698  		r0, e1 := fcntl(fd, syscall.F_DUPFD_CLOEXEC, 0)
   699  		if e1 == nil {
   700  			return r0, "", nil
   701  		}
   702  		switch e1.(syscall.Errno) {
   703  		case syscall.EINVAL, syscall.ENOSYS:
   704  			// Old kernel, or js/wasm (which returns
   705  			// ENOSYS). Fall back to the portable way from
   706  			// now on.
   707  			atomic.StoreInt32(&tryDupCloexec, 0)
   708  		default:
   709  			return -1, "fcntl", e1
   710  		}
   711  	}
   712  	return dupCloseOnExecOld(fd)
   713  }
   714  
   715  // dupCloseOnExecOld is the traditional way to dup an fd and
   716  // set its O_CLOEXEC bit, using two system calls.
   717  func dupCloseOnExecOld(fd int) (int, string, error) {
   718  	syscall.ForkLock.RLock()
   719  	defer syscall.ForkLock.RUnlock()
   720  	newfd, err := syscall.Dup(fd)
   721  	if err != nil {
   722  		return -1, "dup", err
   723  	}
   724  	syscall.CloseOnExec(newfd)
   725  	return newfd, "", nil
   726  }
   727  
   728  // Dup duplicates the file descriptor.
   729  func (fd *FD) Dup() (int, string, error) {
   730  	if err := fd.incref(); err != nil {
   731  		return -1, "", err
   732  	}
   733  	defer fd.decref()
   734  	return DupCloseOnExec(fd.Sysfd)
   735  }
   736  
   737  // On Unix variants only, expose the IO event for the net code.
   738  
   739  // WaitWrite waits until data can be read from fd.
   740  func (fd *FD) WaitWrite() error {
   741  	return fd.pd.waitWrite(fd.isFile)
   742  }
   743  
   744  // WriteOnce is for testing only. It makes a single write call.
   745  func (fd *FD) WriteOnce(p []byte) (int, error) {
   746  	if err := fd.writeLock(); err != nil {
   747  		return 0, err
   748  	}
   749  	defer fd.writeUnlock()
   750  	return ignoringEINTRIO(syscall.Write, fd.Sysfd, p)
   751  }
   752  
   753  // RawRead invokes the user-defined function f for a read operation.
   754  func (fd *FD) RawRead(f func(uintptr) bool) error {
   755  	if err := fd.readLock(); err != nil {
   756  		return err
   757  	}
   758  	defer fd.readUnlock()
   759  	if err := fd.pd.prepareRead(fd.isFile); err != nil {
   760  		return err
   761  	}
   762  	for {
   763  		if f(uintptr(fd.Sysfd)) {
   764  			return nil
   765  		}
   766  		if err := fd.pd.waitRead(fd.isFile); err != nil {
   767  			return err
   768  		}
   769  	}
   770  }
   771  
   772  // RawWrite invokes the user-defined function f for a write operation.
   773  func (fd *FD) RawWrite(f func(uintptr) bool) error {
   774  	if err := fd.writeLock(); err != nil {
   775  		return err
   776  	}
   777  	defer fd.writeUnlock()
   778  	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
   779  		return err
   780  	}
   781  	for {
   782  		if f(uintptr(fd.Sysfd)) {
   783  			return nil
   784  		}
   785  		if err := fd.pd.waitWrite(fd.isFile); err != nil {
   786  			return err
   787  		}
   788  	}
   789  }
   790  
   791  // ignoringEINTRIO is like ignoringEINTR, but just for IO calls.
   792  func ignoringEINTRIO(fn func(fd int, p []byte) (int, error), fd int, p []byte) (int, error) {
   793  	for {
   794  		n, err := fn(fd, p)
   795  		if err != syscall.EINTR {
   796  			return n, err
   797  		}
   798  	}
   799  }