github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/eventfd/eventfd.go (about)

     1  // Copyright 2021 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package eventfd wraps Linux's eventfd(2) syscall.
    16  package eventfd
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  
    22  	"golang.org/x/sys/unix"
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/hostarch"
    24  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/link/rawfile"
    25  )
    26  
    27  const sizeofUint64 = 8
    28  
    29  // Eventfd represents a Linux eventfd object.
    30  type Eventfd struct {
    31  	fd int
    32  }
    33  
    34  // Create returns an initialized eventfd.
    35  func Create() (Eventfd, error) {
    36  	fd, _, err := unix.RawSyscall(unix.SYS_EVENTFD2, 0, 0, 0)
    37  	if err != 0 {
    38  		return Eventfd{}, fmt.Errorf("failed to create eventfd: %v", error(err))
    39  	}
    40  	if err := unix.SetNonblock(int(fd), true); err != nil {
    41  		unix.Close(int(fd))
    42  		return Eventfd{}, err
    43  	}
    44  	return Eventfd{int(fd)}, nil
    45  }
    46  
    47  // Wrap returns an initialized Eventfd using the provided fd.
    48  func Wrap(fd int) Eventfd {
    49  	return Eventfd{fd}
    50  }
    51  
    52  // Close closes the eventfd, after which it should not be used.
    53  func (ev Eventfd) Close() error {
    54  	return unix.Close(ev.fd)
    55  }
    56  
    57  // Dup copies the eventfd, calling dup(2) on the underlying file descriptor.
    58  func (ev Eventfd) Dup() (Eventfd, error) {
    59  	other, err := unix.Dup(ev.fd)
    60  	if err != nil {
    61  		return Eventfd{}, fmt.Errorf("failed to dup: %v", other)
    62  	}
    63  	return Eventfd{other}, nil
    64  }
    65  
    66  // Notify alerts other users of the eventfd. Users can receive alerts by
    67  // calling Wait or Read.
    68  func (ev Eventfd) Notify() error {
    69  	return ev.Write(1)
    70  }
    71  
    72  // Write writes a specific value to the eventfd.
    73  func (ev Eventfd) Write(val uint64) error {
    74  	var buf [sizeofUint64]byte
    75  	hostarch.ByteOrder.PutUint64(buf[:], val)
    76  	for {
    77  		n, err := nonBlockingWrite(ev.fd, buf[:])
    78  		if err == unix.EINTR {
    79  			continue
    80  		}
    81  		if err != nil || n != sizeofUint64 {
    82  			panic(fmt.Sprintf("bad write to eventfd: got %d bytes, wanted %d with error %v", n, sizeofUint64, err))
    83  		}
    84  		return err
    85  	}
    86  }
    87  
    88  // Wait blocks until eventfd is non-zero (i.e. someone calls Notify or Write).
    89  func (ev Eventfd) Wait() error {
    90  	_, err := ev.Read()
    91  	return err
    92  }
    93  
    94  // Read blocks until eventfd is non-zero (i.e. someone calls Notify or Write)
    95  // and returns the value read.
    96  func (ev Eventfd) Read() (uint64, error) {
    97  	var tmp [sizeofUint64]byte
    98  	n, err := rawfile.BlockingReadUntranslated(ev.fd, tmp[:])
    99  	if err != 0 {
   100  		return 0, err
   101  	}
   102  	if n == 0 {
   103  		return 0, io.EOF
   104  	}
   105  	if n != sizeofUint64 {
   106  		panic(fmt.Sprintf("short read from eventfd: got %d bytes, wanted %d", n, sizeofUint64))
   107  	}
   108  	return hostarch.ByteOrder.Uint64(tmp[:]), nil
   109  }
   110  
   111  // FD returns the underlying file descriptor. Use with care, as this breaks the
   112  // Eventfd abstraction.
   113  func (ev Eventfd) FD() int {
   114  	return ev.fd
   115  }