github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/internal/poll/fd_io_plan9.go (about)

     1  // Copyright 2016 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  package poll
     6  
     7  import (
     8  	"github.com/hxx258456/ccgo/internal/itoa"
     9  	"runtime"
    10  	"sync"
    11  	"syscall"
    12  )
    13  
    14  // asyncIO implements asynchronous cancelable I/O.
    15  // An asyncIO represents a single asynchronous Read or Write
    16  // operation. The result is returned on the result channel.
    17  // The undergoing I/O system call can either complete or be
    18  // interrupted by a note.
    19  type asyncIO struct {
    20  	res chan result
    21  
    22  	// mu guards the pid field.
    23  	mu sync.Mutex
    24  
    25  	// pid holds the process id of
    26  	// the process running the IO operation.
    27  	pid int
    28  }
    29  
    30  // result is the return value of a Read or Write operation.
    31  type result struct {
    32  	n   int
    33  	err error
    34  }
    35  
    36  // newAsyncIO returns a new asyncIO that performs an I/O
    37  // operation by calling fn, which must do one and only one
    38  // interruptible system call.
    39  func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO {
    40  	aio := &asyncIO{
    41  		res: make(chan result, 0),
    42  	}
    43  	aio.mu.Lock()
    44  	go func() {
    45  		// Lock the current goroutine to its process
    46  		// and store the pid in io so that Cancel can
    47  		// interrupt it. We ignore the "hangup" signal,
    48  		// so the signal does not take down the entire
    49  		// Go runtime.
    50  		runtime.LockOSThread()
    51  		runtime_ignoreHangup()
    52  		aio.pid = syscall.Getpid()
    53  		aio.mu.Unlock()
    54  
    55  		n, err := fn(b)
    56  
    57  		aio.mu.Lock()
    58  		aio.pid = -1
    59  		runtime_unignoreHangup()
    60  		aio.mu.Unlock()
    61  
    62  		aio.res <- result{n, err}
    63  	}()
    64  	return aio
    65  }
    66  
    67  // Cancel interrupts the I/O operation, causing
    68  // the Wait function to return.
    69  func (aio *asyncIO) Cancel() {
    70  	aio.mu.Lock()
    71  	defer aio.mu.Unlock()
    72  	if aio.pid == -1 {
    73  		return
    74  	}
    75  	f, e := syscall.Open("/proc/"+itoa.Itoa(aio.pid)+"/note", syscall.O_WRONLY)
    76  	if e != nil {
    77  		return
    78  	}
    79  	syscall.Write(f, []byte("hangup"))
    80  	syscall.Close(f)
    81  }
    82  
    83  // Wait for the I/O operation to complete.
    84  func (aio *asyncIO) Wait() (int, error) {
    85  	res := <-aio.res
    86  	return res.n, res.err
    87  }
    88  
    89  // The following functions, provided by the runtime, are used to
    90  // ignore and unignore the "hangup" signal received by the process.
    91  func runtime_ignoreHangup()
    92  func runtime_unignoreHangup()