github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/net/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 net
     6  
     7  import (
     8  	"os"
     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 = os.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  var hangupNote os.Signal = syscall.Note("hangup")
    68  
    69  // Cancel interrupts the I/O operation, causing
    70  // the Wait function to return.
    71  func (aio *asyncIO) Cancel() {
    72  	aio.mu.Lock()
    73  	defer aio.mu.Unlock()
    74  	if aio.pid == -1 {
    75  		return
    76  	}
    77  	proc, err := os.FindProcess(aio.pid)
    78  	if err != nil {
    79  		return
    80  	}
    81  	proc.Signal(hangupNote)
    82  }
    83  
    84  // Wait for the I/O operation to complete.
    85  func (aio *asyncIO) Wait() (int, error) {
    86  	res := <-aio.res
    87  	return res.n, res.err
    88  }
    89  
    90  // The following functions, provided by the runtime, are used to
    91  // ignore and unignore the "hangup" signal received by the process.
    92  func runtime_ignoreHangup()
    93  func runtime_unignoreHangup()