github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/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()