| // Copyright 2016 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package poll | 
 |  | 
 | import ( | 
 | 	"internal/itoa" | 
 | 	"runtime" | 
 | 	"sync" | 
 | 	"syscall" | 
 | ) | 
 |  | 
 | // asyncIO implements asynchronous cancelable I/O. | 
 | // An asyncIO represents a single asynchronous Read or Write | 
 | // operation. The result is returned on the result channel. | 
 | // The undergoing I/O system call can either complete or be | 
 | // interrupted by a note. | 
 | type asyncIO struct { | 
 | 	res chan result | 
 |  | 
 | 	// mu guards the pid field. | 
 | 	mu sync.Mutex | 
 |  | 
 | 	// pid holds the process id of | 
 | 	// the process running the IO operation. | 
 | 	pid int | 
 | } | 
 |  | 
 | // result is the return value of a Read or Write operation. | 
 | type result struct { | 
 | 	n   int | 
 | 	err error | 
 | } | 
 |  | 
 | // newAsyncIO returns a new asyncIO that performs an I/O | 
 | // operation by calling fn, which must do one and only one | 
 | // interruptible system call. | 
 | func newAsyncIO(fn func([]byte) (int, error), b []byte) *asyncIO { | 
 | 	aio := &asyncIO{ | 
 | 		res: make(chan result, 0), | 
 | 	} | 
 | 	aio.mu.Lock() | 
 | 	go func() { | 
 | 		// Lock the current goroutine to its process | 
 | 		// and store the pid in io so that Cancel can | 
 | 		// interrupt it. We ignore the "hangup" signal, | 
 | 		// so the signal does not take down the entire | 
 | 		// Go runtime. | 
 | 		runtime.LockOSThread() | 
 | 		runtime_ignoreHangup() | 
 | 		aio.pid = syscall.Getpid() | 
 | 		aio.mu.Unlock() | 
 |  | 
 | 		n, err := fn(b) | 
 |  | 
 | 		aio.mu.Lock() | 
 | 		aio.pid = -1 | 
 | 		runtime_unignoreHangup() | 
 | 		aio.mu.Unlock() | 
 |  | 
 | 		aio.res <- result{n, err} | 
 | 	}() | 
 | 	return aio | 
 | } | 
 |  | 
 | // Cancel interrupts the I/O operation, causing | 
 | // the Wait function to return. | 
 | func (aio *asyncIO) Cancel() { | 
 | 	aio.mu.Lock() | 
 | 	defer aio.mu.Unlock() | 
 | 	if aio.pid == -1 { | 
 | 		return | 
 | 	} | 
 | 	f, e := syscall.Open("/proc/"+itoa.Itoa(aio.pid)+"/note", syscall.O_WRONLY) | 
 | 	if e != nil { | 
 | 		return | 
 | 	} | 
 | 	syscall.Write(f, []byte("hangup")) | 
 | 	syscall.Close(f) | 
 | } | 
 |  | 
 | // Wait for the I/O operation to complete. | 
 | func (aio *asyncIO) Wait() (int, error) { | 
 | 	res := <-aio.res | 
 | 	return res.n, res.err | 
 | } | 
 |  | 
 | // The following functions, provided by the runtime, are used to | 
 | // ignore and unignore the "hangup" signal received by the process. | 
 | func runtime_ignoreHangup() | 
 | func runtime_unignoreHangup() |