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