Minor flipcall refactoring.

PiperOrigin-RevId: 342768550
This commit is contained in:
Jamie Liu
2020-11-16 19:00:39 -08:00
committed by gVisor bot
parent 267560d159
commit 938aabeecb
3 changed files with 74 additions and 71 deletions
+59 -26
View File
@@ -40,17 +40,41 @@ func (ep *Endpoint) ctrlInit(opts ...EndpointOption) error {
return nil
}
type ctrlHandshakeRequest struct{}
type ctrlHandshakeResponse struct{}
func (ep *Endpoint) ctrlConnect() error {
if err := ep.enterFutexWait(); err != nil {
return err
}
_, err := ep.futexConnect(&ctrlHandshakeRequest{})
ep.exitFutexWait()
return err
defer ep.exitFutexWait()
// Write the connection request.
w := ep.NewWriter()
if err := json.NewEncoder(w).Encode(struct{}{}); err != nil {
return fmt.Errorf("error writing connection request: %v", err)
}
*ep.dataLen() = w.Len()
// Exchange control with the server.
if err := ep.futexSetPeerActive(); err != nil {
return err
}
if err := ep.futexWakePeer(); err != nil {
return err
}
if err := ep.futexWaitUntilActive(); err != nil {
return err
}
// Read the connection response.
var resp struct{}
respLen := atomic.LoadUint32(ep.dataLen())
if respLen > ep.dataCap {
return fmt.Errorf("invalid connection response length %d (maximum %d)", respLen, ep.dataCap)
}
if err := json.NewDecoder(ep.NewReader(respLen)).Decode(&resp); err != nil {
return fmt.Errorf("error reading connection response: %v", err)
}
return nil
}
func (ep *Endpoint) ctrlWaitFirst() error {
@@ -59,52 +83,61 @@ func (ep *Endpoint) ctrlWaitFirst() error {
}
defer ep.exitFutexWait()
// Wait for the handshake request.
if err := ep.futexSwitchFromPeer(); err != nil {
// Wait for the connection request.
if err := ep.futexWaitUntilActive(); err != nil {
return err
}
// Read the handshake request.
// Read the connection request.
reqLen := atomic.LoadUint32(ep.dataLen())
if reqLen > ep.dataCap {
return fmt.Errorf("invalid handshake request length %d (maximum %d)", reqLen, ep.dataCap)
return fmt.Errorf("invalid connection request length %d (maximum %d)", reqLen, ep.dataCap)
}
var req ctrlHandshakeRequest
var req struct{}
if err := json.NewDecoder(ep.NewReader(reqLen)).Decode(&req); err != nil {
return fmt.Errorf("error reading handshake request: %v", err)
return fmt.Errorf("error reading connection request: %v", err)
}
// Write the handshake response.
// Write the connection response.
w := ep.NewWriter()
if err := json.NewEncoder(w).Encode(ctrlHandshakeResponse{}); err != nil {
return fmt.Errorf("error writing handshake response: %v", err)
if err := json.NewEncoder(w).Encode(struct{}{}); err != nil {
return fmt.Errorf("error writing connection response: %v", err)
}
*ep.dataLen() = w.Len()
// Return control to the client.
raceBecomeInactive()
if err := ep.futexSwitchToPeer(); err != nil {
if err := ep.futexSetPeerActive(); err != nil {
return err
}
if err := ep.futexWakePeer(); err != nil {
return err
}
// Wait for the first non-handshake message.
return ep.futexSwitchFromPeer()
// Wait for the first non-connection message.
return ep.futexWaitUntilActive()
}
func (ep *Endpoint) ctrlRoundTrip() error {
if err := ep.futexSwitchToPeer(); err != nil {
return err
}
if err := ep.enterFutexWait(); err != nil {
return err
}
err := ep.futexSwitchFromPeer()
ep.exitFutexWait()
return err
defer ep.exitFutexWait()
if err := ep.futexSetPeerActive(); err != nil {
return err
}
if err := ep.futexWakePeer(); err != nil {
return err
}
return ep.futexWaitUntilActive()
}
func (ep *Endpoint) ctrlWakeLast() error {
return ep.futexSwitchToPeer()
if err := ep.futexSetPeerActive(); err != nil {
return err
}
return ep.futexWakePeer()
}
func (ep *Endpoint) enterFutexWait() error {
+5 -5
View File
@@ -41,11 +41,11 @@ const (
)
func (ep *Endpoint) connState() *uint32 {
return (*uint32)((unsafe.Pointer)(ep.packet))
return (*uint32)(unsafe.Pointer(ep.packet))
}
func (ep *Endpoint) dataLen() *uint32 {
return (*uint32)((unsafe.Pointer)(ep.packet + 4))
return (*uint32)(unsafe.Pointer(ep.packet + 4))
}
// Data returns the datagram part of ep's packet window as a byte slice.
@@ -63,7 +63,7 @@ func (ep *Endpoint) dataLen() *uint32 {
// all.
func (ep *Endpoint) Data() []byte {
var bs []byte
bsReflect := (*reflect.SliceHeader)((unsafe.Pointer)(&bs))
bsReflect := (*reflect.SliceHeader)(unsafe.Pointer(&bs))
bsReflect.Data = ep.packet + PacketHeaderBytes
bsReflect.Len = int(ep.dataCap)
bsReflect.Cap = int(ep.dataCap)
@@ -76,12 +76,12 @@ var ioSync int64
func raceBecomeActive() {
if sync.RaceEnabled {
sync.RaceAcquire((unsafe.Pointer)(&ioSync))
sync.RaceAcquire(unsafe.Pointer(&ioSync))
}
}
func raceBecomeInactive() {
if sync.RaceEnabled {
sync.RaceReleaseMerge((unsafe.Pointer)(&ioSync))
sync.RaceReleaseMerge(unsafe.Pointer(&ioSync))
}
}
+10 -40
View File
@@ -17,7 +17,6 @@
package flipcall
import (
"encoding/json"
"fmt"
"runtime"
"sync/atomic"
@@ -26,55 +25,26 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
)
func (ep *Endpoint) futexConnect(req *ctrlHandshakeRequest) (ctrlHandshakeResponse, error) {
var resp ctrlHandshakeResponse
// Write the handshake request.
w := ep.NewWriter()
if err := json.NewEncoder(w).Encode(req); err != nil {
return resp, fmt.Errorf("error writing handshake request: %v", err)
func (ep *Endpoint) futexSetPeerActive() error {
if atomic.CompareAndSwapUint32(ep.connState(), ep.activeState, ep.inactiveState) {
return nil
}
*ep.dataLen() = w.Len()
// Exchange control with the server.
if err := ep.futexSwitchToPeer(); err != nil {
return resp, err
switch cs := atomic.LoadUint32(ep.connState()); cs {
case csShutdown:
return ShutdownError{}
default:
return fmt.Errorf("unexpected connection state before FUTEX_WAKE: %v", cs)
}
if err := ep.futexSwitchFromPeer(); err != nil {
return resp, err
}
// Read the handshake response.
respLen := atomic.LoadUint32(ep.dataLen())
if respLen > ep.dataCap {
return resp, fmt.Errorf("invalid handshake response length %d (maximum %d)", respLen, ep.dataCap)
}
if err := json.NewDecoder(ep.NewReader(respLen)).Decode(&resp); err != nil {
return resp, fmt.Errorf("error reading handshake response: %v", err)
}
return resp, nil
}
func (ep *Endpoint) futexSwitchToPeer() error {
// Update connection state to indicate that the peer should be active.
if !atomic.CompareAndSwapUint32(ep.connState(), ep.activeState, ep.inactiveState) {
switch cs := atomic.LoadUint32(ep.connState()); cs {
case csShutdown:
return ShutdownError{}
default:
return fmt.Errorf("unexpected connection state before FUTEX_WAKE: %v", cs)
}
}
// Wake the peer's Endpoint.futexSwitchFromPeer().
func (ep *Endpoint) futexWakePeer() error {
if err := ep.futexWakeConnState(1); err != nil {
return fmt.Errorf("failed to FUTEX_WAKE peer Endpoint: %v", err)
}
return nil
}
func (ep *Endpoint) futexSwitchFromPeer() error {
func (ep *Endpoint) futexWaitUntilActive() error {
for {
switch cs := atomic.LoadUint32(ep.connState()); cs {
case ep.activeState: