github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/flipcall/futex_linux.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build linux 16 // +build linux 17 18 package flipcall 19 20 import ( 21 "fmt" 22 "runtime" 23 24 "golang.org/x/sys/unix" 25 "github.com/MerlinKodo/gvisor/pkg/abi/linux" 26 ) 27 28 func (ep *Endpoint) futexSetPeerActive() error { 29 if ep.connState().CompareAndSwap(ep.activeState, ep.inactiveState) { 30 return nil 31 } 32 switch cs := ep.connState().Load(); cs { 33 case csShutdown: 34 return ShutdownError{} 35 default: 36 return fmt.Errorf("unexpected connection state before FUTEX_WAKE: %v", cs) 37 } 38 } 39 40 func (ep *Endpoint) futexWakePeer() error { 41 if err := ep.futexWakeConnState(1); err != nil { 42 return fmt.Errorf("failed to FUTEX_WAKE peer Endpoint: %v", err) 43 } 44 return nil 45 } 46 47 func (ep *Endpoint) futexWaitUntilActive() error { 48 for { 49 switch cs := ep.connState().Load(); cs { 50 case ep.activeState: 51 return nil 52 case ep.inactiveState: 53 if ep.isShutdownLocally() { 54 return ShutdownError{} 55 } 56 if err := ep.futexWaitConnState(ep.inactiveState); err != nil { 57 return fmt.Errorf("failed to FUTEX_WAIT for peer Endpoint: %v", err) 58 } 59 continue 60 case csShutdown: 61 return ShutdownError{} 62 default: 63 return fmt.Errorf("unexpected connection state before FUTEX_WAIT: %v", cs) 64 } 65 } 66 } 67 68 func (ep *Endpoint) futexWakeConnState(numThreads int32) error { 69 if _, _, e := unix.RawSyscall(unix.SYS_FUTEX, ep.packet, linux.FUTEX_WAKE, uintptr(numThreads)); e != 0 { 70 return e 71 } 72 return nil 73 } 74 75 func (ep *Endpoint) futexWaitConnState(curState uint32) error { 76 _, _, e := unix.Syscall6(unix.SYS_FUTEX, ep.packet, linux.FUTEX_WAIT, uintptr(curState), 0, 0, 0) 77 if e != 0 && e != unix.EAGAIN && e != unix.EINTR { 78 return e 79 } 80 return nil 81 } 82 83 func yieldThread() { 84 unix.Syscall(unix.SYS_SCHED_YIELD, 0, 0, 0) 85 // The thread we're trying to yield to may be waiting for a Go runtime P. 86 // runtime.Gosched() will hand off ours if necessary. 87 runtime.Gosched() 88 }