]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/internal/poll/fd_wasip1.go
net: implement wasip1 FileListener and FileConn
[gostls13.git] / src / internal / poll / fd_wasip1.go
index 749fa50220b6903abe15ca91bf8ed693eb0b5d0e..aecd89669b482c450de6bcb438059e29f27a5694 100644 (file)
@@ -11,6 +11,18 @@ import (
 )
 
 type SysFile struct {
+       // RefCountPtr is a pointer to the reference count of Sysfd.
+       //
+       // WASI preview 1 lacks a dup(2) system call. When the os and net packages
+       // need to share a file/socket, instead of duplicating the underlying file
+       // descriptor, we instead provide a way to copy FD instances and manage the
+       // underlying file descriptor with reference counting.
+       RefCountPtr *int32
+
+       // RefCount is the reference count of Sysfd. When a copy of an FD is made,
+       // it points to the reference count of the original FD instance.
+       RefCount int32
+
        // Cache for the file type, lazily initialized when Seek is called.
        Filetype uint32
 
@@ -29,6 +41,47 @@ type SysFile struct {
        // always set instead of being lazily initialized.
 }
 
+func (s *SysFile) init() {
+       if s.RefCountPtr == nil {
+               s.RefCount = 1
+               s.RefCountPtr = &s.RefCount
+       }
+}
+
+func (s *SysFile) ref() SysFile {
+       atomic.AddInt32(s.RefCountPtr, +1)
+       return SysFile{RefCountPtr: s.RefCountPtr}
+}
+
+func (s *SysFile) destroy(fd int) error {
+       if s.RefCountPtr != nil && atomic.AddInt32(s.RefCountPtr, -1) > 0 {
+               return nil
+       }
+
+       // We don't use ignoringEINTR here because POSIX does not define
+       // whether the descriptor is closed if close returns EINTR.
+       // If the descriptor is indeed closed, using a loop would race
+       // with some other goroutine opening a new descriptor.
+       // (The Linux kernel guarantees that it is closed on an EINTR error.)
+       return CloseFunc(fd)
+}
+
+// Copy creates a copy of the FD.
+//
+// The FD instance points to the same underlying file descriptor. The file
+// descriptor isn't closed until all FD instances that refer to it have been
+// closed/destroyed.
+func (fd *FD) Copy() FD {
+       return FD{
+               Sysfd:         fd.Sysfd,
+               SysFile:       fd.SysFile.ref(),
+               IsStream:      fd.IsStream,
+               ZeroReadIsEOF: fd.ZeroReadIsEOF,
+               isBlocking:    fd.isBlocking,
+               isFile:        fd.isFile,
+       }
+}
+
 // dupCloseOnExecOld always errors on wasip1 because there is no mechanism to
 // duplicate file descriptors.
 func dupCloseOnExecOld(fd int) (int, string, error) {