diff options
Diffstat (limited to 'pkg/flipcall')
-rw-r--r-- | pkg/flipcall/BUILD | 33 | ||||
-rw-r--r-- | pkg/flipcall/flipcall_example_test.go | 113 | ||||
-rw-r--r-- | pkg/flipcall/flipcall_linux_state_autogen.go | 5 | ||||
-rw-r--r-- | pkg/flipcall/flipcall_state_autogen.go | 3 | ||||
-rw-r--r-- | pkg/flipcall/flipcall_test.go | 405 | ||||
-rw-r--r-- | pkg/flipcall/flipcall_unsafe_state_autogen.go | 3 |
6 files changed, 11 insertions, 551 deletions
diff --git a/pkg/flipcall/BUILD b/pkg/flipcall/BUILD deleted file mode 100644 index 9c5ad500b..000000000 --- a/pkg/flipcall/BUILD +++ /dev/null @@ -1,33 +0,0 @@ -load("//tools:defs.bzl", "go_library", "go_test") - -licenses(["notice"]) - -go_library( - name = "flipcall", - srcs = [ - "ctrl_futex.go", - "flipcall.go", - "flipcall_unsafe.go", - "futex_linux.go", - "io.go", - "packet_window_allocator.go", - ], - visibility = ["//visibility:public"], - deps = [ - "//pkg/abi/linux", - "//pkg/log", - "//pkg/memutil", - "//pkg/sync", - ], -) - -go_test( - name = "flipcall_test", - size = "small", - srcs = [ - "flipcall_example_test.go", - "flipcall_test.go", - ], - library = ":flipcall", - deps = ["//pkg/sync"], -) diff --git a/pkg/flipcall/flipcall_example_test.go b/pkg/flipcall/flipcall_example_test.go deleted file mode 100644 index 2e28a149a..000000000 --- a/pkg/flipcall/flipcall_example_test.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2019 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package flipcall - -import ( - "bytes" - "fmt" - - "gvisor.dev/gvisor/pkg/sync" -) - -func Example() { - const ( - reqPrefix = "request " - respPrefix = "response " - count = 3 - maxMessageLen = len(respPrefix) + 1 // 1 digit - ) - - pwa, err := NewPacketWindowAllocator() - if err != nil { - panic(err) - } - defer pwa.Destroy() - pwd, err := pwa.Allocate(PacketWindowLengthForDataCap(uint32(maxMessageLen))) - if err != nil { - panic(err) - } - var clientEP Endpoint - if err := clientEP.Init(ClientSide, pwd); err != nil { - panic(err) - } - defer clientEP.Destroy() - var serverEP Endpoint - if err := serverEP.Init(ServerSide, pwd); err != nil { - panic(err) - } - defer serverEP.Destroy() - - var serverRun sync.WaitGroup - serverRun.Add(1) - go func() { - defer serverRun.Done() - i := 0 - var buf bytes.Buffer - // wait for first request - n, err := serverEP.RecvFirst() - if err != nil { - return - } - for { - // read request - buf.Reset() - buf.Write(serverEP.Data()[:n]) - fmt.Println(buf.String()) - // write response - buf.Reset() - fmt.Fprintf(&buf, "%s%d", respPrefix, i) - copy(serverEP.Data(), buf.Bytes()) - // send response and wait for next request - n, err = serverEP.SendRecv(uint32(buf.Len())) - if err != nil { - return - } - i++ - } - }() - defer func() { - serverEP.Shutdown() - serverRun.Wait() - }() - - // establish connection as client - if err := clientEP.Connect(); err != nil { - panic(err) - } - var buf bytes.Buffer - for i := 0; i < count; i++ { - // write request - buf.Reset() - fmt.Fprintf(&buf, "%s%d", reqPrefix, i) - copy(clientEP.Data(), buf.Bytes()) - // send request and wait for response - n, err := clientEP.SendRecv(uint32(buf.Len())) - if err != nil { - panic(err) - } - // read response - buf.Reset() - buf.Write(clientEP.Data()[:n]) - fmt.Println(buf.String()) - } - - // Output: - // request 0 - // response 0 - // request 1 - // response 1 - // request 2 - // response 2 -} diff --git a/pkg/flipcall/flipcall_linux_state_autogen.go b/pkg/flipcall/flipcall_linux_state_autogen.go new file mode 100644 index 000000000..ce37ac4e1 --- /dev/null +++ b/pkg/flipcall/flipcall_linux_state_autogen.go @@ -0,0 +1,5 @@ +// automatically generated by stateify. + +// +build linux + +package flipcall diff --git a/pkg/flipcall/flipcall_state_autogen.go b/pkg/flipcall/flipcall_state_autogen.go new file mode 100644 index 000000000..0e03c2a65 --- /dev/null +++ b/pkg/flipcall/flipcall_state_autogen.go @@ -0,0 +1,3 @@ +// automatically generated by stateify. + +package flipcall diff --git a/pkg/flipcall/flipcall_test.go b/pkg/flipcall/flipcall_test.go deleted file mode 100644 index 33fd55a44..000000000 --- a/pkg/flipcall/flipcall_test.go +++ /dev/null @@ -1,405 +0,0 @@ -// Copyright 2019 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package flipcall - -import ( - "runtime" - "testing" - "time" - - "gvisor.dev/gvisor/pkg/sync" -) - -var testPacketWindowSize = pageSize - -type testConnection struct { - pwa PacketWindowAllocator - clientEP Endpoint - serverEP Endpoint -} - -func newTestConnectionWithOptions(tb testing.TB, clientOpts, serverOpts []EndpointOption) *testConnection { - c := &testConnection{} - if err := c.pwa.Init(); err != nil { - tb.Fatalf("failed to create PacketWindowAllocator: %v", err) - } - pwd, err := c.pwa.Allocate(testPacketWindowSize) - if err != nil { - c.pwa.Destroy() - tb.Fatalf("PacketWindowAllocator.Allocate() failed: %v", err) - } - if err := c.clientEP.Init(ClientSide, pwd, clientOpts...); err != nil { - c.pwa.Destroy() - tb.Fatalf("failed to create client Endpoint: %v", err) - } - if err := c.serverEP.Init(ServerSide, pwd, serverOpts...); err != nil { - c.pwa.Destroy() - c.clientEP.Destroy() - tb.Fatalf("failed to create server Endpoint: %v", err) - } - return c -} - -func newTestConnection(tb testing.TB) *testConnection { - return newTestConnectionWithOptions(tb, nil, nil) -} - -func (c *testConnection) destroy() { - c.pwa.Destroy() - c.clientEP.Destroy() - c.serverEP.Destroy() -} - -func testSendRecv(t *testing.T, c *testConnection) { - // This shared variable is used to confirm that synchronization between - // flipcall endpoints is visible to the Go race detector. - state := 0 - var serverRun sync.WaitGroup - serverRun.Add(1) - go func() { - defer serverRun.Done() - t.Logf("server Endpoint waiting for packet 1") - if _, err := c.serverEP.RecvFirst(); err != nil { - t.Errorf("server Endpoint.RecvFirst() failed: %v", err) - return - } - state++ - if state != 2 { - t.Errorf("shared state counter: got %d, wanted 2", state) - } - t.Logf("server Endpoint got packet 1, sending packet 2 and waiting for packet 3") - if _, err := c.serverEP.SendRecv(0); err != nil { - t.Errorf("server Endpoint.SendRecv() failed: %v", err) - return - } - state++ - if state != 4 { - t.Errorf("shared state counter: got %d, wanted 4", state) - } - t.Logf("server Endpoint got packet 3") - }() - defer func() { - // Ensure that the server goroutine is cleaned up before - // c.serverEP.Destroy(), even if the test fails. - c.serverEP.Shutdown() - serverRun.Wait() - }() - - t.Logf("client Endpoint establishing connection") - if err := c.clientEP.Connect(); err != nil { - t.Fatalf("client Endpoint.Connect() failed: %v", err) - } - state++ - if state != 1 { - t.Errorf("shared state counter: got %d, wanted 1", state) - } - t.Logf("client Endpoint sending packet 1 and waiting for packet 2") - if _, err := c.clientEP.SendRecv(0); err != nil { - t.Fatalf("client Endpoint.SendRecv() failed: %v", err) - } - state++ - if state != 3 { - t.Errorf("shared state counter: got %d, wanted 3", state) - } - t.Logf("client Endpoint got packet 2, sending packet 3") - if err := c.clientEP.SendLast(0); err != nil { - t.Fatalf("client Endpoint.SendLast() failed: %v", err) - } - t.Logf("waiting for server goroutine to complete") - serverRun.Wait() -} - -func TestSendRecv(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testSendRecv(t, c) -} - -func testShutdownBeforeConnect(t *testing.T, c *testConnection, remoteShutdown bool) { - if remoteShutdown { - c.serverEP.Shutdown() - } else { - c.clientEP.Shutdown() - } - if err := c.clientEP.Connect(); err == nil { - t.Errorf("client Endpoint.Connect() succeeded unexpectedly") - } -} - -func TestShutdownBeforeConnectLocal(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownBeforeConnect(t, c, false) -} - -func TestShutdownBeforeConnectRemote(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownBeforeConnect(t, c, true) -} - -func testShutdownDuringConnect(t *testing.T, c *testConnection, remoteShutdown bool) { - var clientRun sync.WaitGroup - clientRun.Add(1) - go func() { - defer clientRun.Done() - if err := c.clientEP.Connect(); err == nil { - t.Errorf("client Endpoint.Connect() succeeded unexpectedly") - } - }() - time.Sleep(time.Second) // to allow c.clientEP.Connect() to block - if remoteShutdown { - c.serverEP.Shutdown() - } else { - c.clientEP.Shutdown() - } - clientRun.Wait() -} - -func TestShutdownDuringConnectLocal(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringConnect(t, c, false) -} - -func TestShutdownDuringConnectRemote(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringConnect(t, c, true) -} - -func testShutdownBeforeRecvFirst(t *testing.T, c *testConnection, remoteShutdown bool) { - if remoteShutdown { - c.clientEP.Shutdown() - } else { - c.serverEP.Shutdown() - } - if _, err := c.serverEP.RecvFirst(); err == nil { - t.Errorf("server Endpoint.RecvFirst() succeeded unexpectedly") - } -} - -func TestShutdownBeforeRecvFirstLocal(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownBeforeRecvFirst(t, c, false) -} - -func TestShutdownBeforeRecvFirstRemote(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownBeforeRecvFirst(t, c, true) -} - -func testShutdownDuringRecvFirstBeforeConnect(t *testing.T, c *testConnection, remoteShutdown bool) { - var serverRun sync.WaitGroup - serverRun.Add(1) - go func() { - defer serverRun.Done() - if _, err := c.serverEP.RecvFirst(); err == nil { - t.Errorf("server Endpoint.RecvFirst() succeeded unexpectedly") - } - }() - time.Sleep(time.Second) // to allow c.serverEP.RecvFirst() to block - if remoteShutdown { - c.clientEP.Shutdown() - } else { - c.serverEP.Shutdown() - } - serverRun.Wait() -} - -func TestShutdownDuringRecvFirstBeforeConnectLocal(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringRecvFirstBeforeConnect(t, c, false) -} - -func TestShutdownDuringRecvFirstBeforeConnectRemote(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringRecvFirstBeforeConnect(t, c, true) -} - -func testShutdownDuringRecvFirstAfterConnect(t *testing.T, c *testConnection, remoteShutdown bool) { - var serverRun sync.WaitGroup - serverRun.Add(1) - go func() { - defer serverRun.Done() - if _, err := c.serverEP.RecvFirst(); err == nil { - t.Errorf("server Endpoint.RecvFirst() succeeded unexpectedly") - } - }() - defer func() { - // Ensure that the server goroutine is cleaned up before - // c.serverEP.Destroy(), even if the test fails. - c.serverEP.Shutdown() - serverRun.Wait() - }() - if err := c.clientEP.Connect(); err != nil { - t.Fatalf("client Endpoint.Connect() failed: %v", err) - } - if remoteShutdown { - c.clientEP.Shutdown() - } else { - c.serverEP.Shutdown() - } - serverRun.Wait() -} - -func TestShutdownDuringRecvFirstAfterConnectLocal(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringRecvFirstAfterConnect(t, c, false) -} - -func TestShutdownDuringRecvFirstAfterConnectRemote(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringRecvFirstAfterConnect(t, c, true) -} - -func testShutdownDuringClientSendRecv(t *testing.T, c *testConnection, remoteShutdown bool) { - var serverRun sync.WaitGroup - serverRun.Add(1) - go func() { - defer serverRun.Done() - if _, err := c.serverEP.RecvFirst(); err != nil { - t.Errorf("server Endpoint.RecvFirst() failed: %v", err) - } - // At this point, the client must be blocked in c.clientEP.SendRecv(). - if remoteShutdown { - c.serverEP.Shutdown() - } else { - c.clientEP.Shutdown() - } - }() - defer func() { - // Ensure that the server goroutine is cleaned up before - // c.serverEP.Destroy(), even if the test fails. - c.serverEP.Shutdown() - serverRun.Wait() - }() - if err := c.clientEP.Connect(); err != nil { - t.Fatalf("client Endpoint.Connect() failed: %v", err) - } - if _, err := c.clientEP.SendRecv(0); err == nil { - t.Errorf("client Endpoint.SendRecv() succeeded unexpectedly") - } -} - -func TestShutdownDuringClientSendRecvLocal(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringClientSendRecv(t, c, false) -} - -func TestShutdownDuringClientSendRecvRemote(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringClientSendRecv(t, c, true) -} - -func testShutdownDuringServerSendRecv(t *testing.T, c *testConnection, remoteShutdown bool) { - var serverRun sync.WaitGroup - serverRun.Add(1) - go func() { - defer serverRun.Done() - if _, err := c.serverEP.RecvFirst(); err != nil { - t.Errorf("server Endpoint.RecvFirst() failed: %v", err) - return - } - if _, err := c.serverEP.SendRecv(0); err == nil { - t.Errorf("server Endpoint.SendRecv() succeeded unexpectedly") - } - }() - defer func() { - // Ensure that the server goroutine is cleaned up before - // c.serverEP.Destroy(), even if the test fails. - c.serverEP.Shutdown() - serverRun.Wait() - }() - if err := c.clientEP.Connect(); err != nil { - t.Fatalf("client Endpoint.Connect() failed: %v", err) - } - if _, err := c.clientEP.SendRecv(0); err != nil { - t.Fatalf("client Endpoint.SendRecv() failed: %v", err) - } - time.Sleep(time.Second) // to allow serverEP.SendRecv() to block - if remoteShutdown { - c.clientEP.Shutdown() - } else { - c.serverEP.Shutdown() - } - serverRun.Wait() -} - -func TestShutdownDuringServerSendRecvLocal(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringServerSendRecv(t, c, false) -} - -func TestShutdownDuringServerSendRecvRemote(t *testing.T) { - c := newTestConnection(t) - defer c.destroy() - testShutdownDuringServerSendRecv(t, c, true) -} - -func benchmarkSendRecv(b *testing.B, c *testConnection) { - var serverRun sync.WaitGroup - serverRun.Add(1) - go func() { - defer serverRun.Done() - if b.N == 0 { - return - } - if _, err := c.serverEP.RecvFirst(); err != nil { - b.Errorf("server Endpoint.RecvFirst() failed: %v", err) - return - } - for i := 1; i < b.N; i++ { - if _, err := c.serverEP.SendRecv(0); err != nil { - b.Errorf("server Endpoint.SendRecv() failed: %v", err) - return - } - } - if err := c.serverEP.SendLast(0); err != nil { - b.Errorf("server Endpoint.SendLast() failed: %v", err) - } - }() - defer func() { - c.serverEP.Shutdown() - serverRun.Wait() - }() - - if err := c.clientEP.Connect(); err != nil { - b.Fatalf("client Endpoint.Connect() failed: %v", err) - } - runtime.GC() - b.ResetTimer() - for i := 0; i < b.N; i++ { - if _, err := c.clientEP.SendRecv(0); err != nil { - b.Fatalf("client Endpoint.SendRecv() failed: %v", err) - } - } - b.StopTimer() -} - -func BenchmarkSendRecv(b *testing.B) { - c := newTestConnection(b) - defer c.destroy() - benchmarkSendRecv(b, c) -} diff --git a/pkg/flipcall/flipcall_unsafe_state_autogen.go b/pkg/flipcall/flipcall_unsafe_state_autogen.go new file mode 100644 index 000000000..0e03c2a65 --- /dev/null +++ b/pkg/flipcall/flipcall_unsafe_state_autogen.go @@ -0,0 +1,3 @@ +// automatically generated by stateify. + +package flipcall |