From 67482a4f8c3a3a7cf17b4edf82e61c28b318ffd9 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Tue, 28 Nov 2017 19:53:14 +0100 Subject: [PATCH] Add WaitReady to VppAdapter - this fixes issue with mocked adapter during AsyncConnect Change-Id: I952025fec865422f9e83cec9383d96f79a639c90 Signed-off-by: Ondrej Fabry --- adapter/adapter.go | 3 ++ adapter/mock/mock_adapter.go | 5 +++ adapter/vppapiclient/empty_adapter.go | 4 ++ adapter/vppapiclient/vppapiclient_adapter.go | 49 ++++++++++++++++++++++ cmd/binapi-generator/generator_test.go | 4 +- core/core.go | 61 ++++------------------------ 6 files changed, 72 insertions(+), 54 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 2843d2c..d8f29c9 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -30,4 +30,7 @@ type VppAdapter interface { // SetMsgCallback sets a callback function that will be called by the adapter whenever a message comes from VPP. SetMsgCallback(func(context uint32, msgId uint16, data []byte)) + + // WaitReady returns func which waits until adapter is ready. + WaitReady() func() error } diff --git a/adapter/mock/mock_adapter.go b/adapter/mock/mock_adapter.go index 8c88030..f85f17d 100644 --- a/adapter/mock/mock_adapter.go +++ b/adapter/mock/mock_adapter.go @@ -294,6 +294,11 @@ func (a *VppAdapter) SetMsgCallback(cb func(context uint32, msgID uint16, data [ a.callback = cb } +// WaitReady mocks waiting for VPP +func (a *VppAdapter) WaitReady() func() error { + return func() error { return nil } +} + // MockReply stores a message to be returned when the next request comes. It is a FIFO queue - multiple replies // can be pushed into it, the first one will be popped when some request comes. // Using of this method automatically switches the mock into th useRepliesQueue mode. diff --git a/adapter/vppapiclient/empty_adapter.go b/adapter/vppapiclient/empty_adapter.go index 14f804d..7249864 100644 --- a/adapter/vppapiclient/empty_adapter.go +++ b/adapter/vppapiclient/empty_adapter.go @@ -50,3 +50,7 @@ func (a *vppAPIClientAdapter) SendMsg(clientID uint32, data []byte) error { func (a *vppAPIClientAdapter) SetMsgCallback(cb func(context uint32, msgID uint16, data []byte)) { // no op } + +func (a *vppAPIClientAdapter) WaitReady() func() error { + return func() error { return nil } +} diff --git a/adapter/vppapiclient/vppapiclient_adapter.go b/adapter/vppapiclient/vppapiclient_adapter.go index 74f0118..dfdd973 100644 --- a/adapter/vppapiclient/vppapiclient_adapter.go +++ b/adapter/vppapiclient/vppapiclient_adapter.go @@ -79,10 +79,21 @@ import "C" import ( "errors" "fmt" + "os" "reflect" "unsafe" "git.fd.io/govpp.git/adapter" + "github.com/fsnotify/fsnotify" +) + +const ( + // watchedFolder is a folder where vpp's shared memory is supposed to be created. + // File system events are monitored in this folder. + watchedFolder = "/dev/shm/" + // watchedFile is a name of the file in the watchedFolder. Once the file is present + // the vpp is ready to accept a new connection. + watchedFile = watchedFolder + "vpe-api" ) // vppAPIClientAdapter is the opaque context of the adapter. @@ -139,6 +150,44 @@ func (a *vppAPIClientAdapter) SetMsgCallback(cb func(context uint32, msgID uint1 a.callback = cb } +// WaitReady returns func which blocks until shared memory +// for sending bin api calls is present on the file system. +func (a *vppAPIClientAdapter) WaitReady() func() error { + return func() error { + watcher, err := fsnotify.NewWatcher() + if err != nil { + return err + } + defer watcher.Close() + + err = watcher.Add(watchedFolder) + if err != nil { + return err + } + + if fileExists(watchedFile) { + return nil + } + + for { + ev := <-watcher.Events + if ev.Name == watchedFile && (ev.Op&fsnotify.Create) == fsnotify.Create { + break + } + } + return nil + } +} + +func fileExists(name string) bool { + if _, err := os.Stat(name); err != nil { + if os.IsNotExist(err) { + return false + } + } + return true +} + //export go_msg_callback func go_msg_callback(msgID C.uint16_t, context C.uint32_t, data unsafe.Pointer, size C.size_t) { // convert unsafe.Pointer to byte slice diff --git a/cmd/binapi-generator/generator_test.go b/cmd/binapi-generator/generator_test.go index c7d89ce..a42e794 100644 --- a/cmd/binapi-generator/generator_test.go +++ b/cmd/binapi-generator/generator_test.go @@ -245,7 +245,7 @@ func TestGenerateMessageFieldTypes(t *testing.T) { for j := 0; j < types.At(i).Len(); j++ { field := types.At(i).At(j) if jsongo.TypeArray == field.GetType() { - err := processMessageField(testCtx, &fields, field, otherMessage) + err := processMessageField(testCtx, &fields, field, false) Expect(err).ShouldNot(HaveOccurred()) Expect(fields[j-1]).To(BeEquivalentTo(expectedTypes[j-1])) } @@ -282,7 +282,7 @@ func TestGenerateMessageFieldMessages(t *testing.T) { specificFieldName == "client_index" || specificFieldName == "context" { continue } - err := processMessageField(testCtx, &fields, field, requestMessage) + err := processMessageField(testCtx, &fields, field, false) Expect(err).ShouldNot(HaveOccurred()) Expect(fields[customIndex]).To(BeEquivalentTo(expectedTypes[customIndex])) customIndex++ diff --git a/core/core.go b/core/core.go index a045e60..c254214 100644 --- a/core/core.go +++ b/core/core.go @@ -28,7 +28,6 @@ import ( "git.fd.io/govpp.git/adapter" "git.fd.io/govpp.git/api" "git.fd.io/govpp.git/core/bin_api/vpe" - "github.com/fsnotify/fsnotify" ) const ( @@ -54,15 +53,6 @@ const ( Disconnected = iota ) -const ( - // watchedFolder is a folder where vpp's shared memory is supposed to be created. - // File system events are monitored in this folder. - watchedFolder = "/dev/shm/" - // watchedFile is a name of the file in the watchedFolder. Once the file is present - // the vpp is ready to accept a new connection. - watchedFile = watchedFolder + "vpe-api" -) - // ConnectionEvent is a notification about change in the VPP connection state. type ConnectionEvent struct { // Timestamp holds the time when the event has been generated. @@ -197,10 +187,13 @@ func newConnection(vppAdapter adapter.VppAdapter) (*Connection, error) { return nil, errors.New("only one connection per process is supported") } - conn = &Connection{vpp: vppAdapter, codec: &MsgCodec{}} - conn.channels = make(map[uint32]*api.Channel) - conn.msgIDs = make(map[string]uint16) - conn.notifSubscriptions = make(map[uint16][]*api.NotifSubscription) + conn = &Connection{ + vpp: vppAdapter, + codec: &MsgCodec{}, + channels: make(map[uint32]*api.Channel), + msgIDs: make(map[string]uint16), + notifSubscriptions: make(map[uint16][]*api.NotifSubscription), + } conn.vpp.SetMsgCallback(msgCallback) return conn, nil @@ -235,50 +228,14 @@ func (c *Connection) disconnectVPP() { } } -func fileExists(name string) bool { - if _, err := os.Stat(name); err != nil { - if os.IsNotExist(err) { - return false - } - } - return true -} - -// waitForVpp blocks until shared memory for sending bin api calls -// is present on the file system. -func waitForVpp() error { - watcher, err := fsnotify.NewWatcher() - if err != nil { - return err - } - defer watcher.Close() - - err = watcher.Add(watchedFolder) - if err != nil { - return err - } - - if fileExists(watchedFile) { - return nil - } - - for { - ev := <-watcher.Events - if ev.Name == watchedFile && (ev.Op&fsnotify.Create) == fsnotify.Create { - break - } - } - return nil -} - // connectLoop attempts to connect to VPP until it succeeds. // Then it continues with healthCheckLoop. func (c *Connection) connectLoop(connChan chan ConnectionEvent) { // loop until connected + waitForVpp := c.vpp.WaitReady() for { waitForVpp() - err := c.connectVPP() - if err == nil { + if err := c.connectVPP(); err == nil { // signal connected event connChan <- ConnectionEvent{Timestamp: time.Now(), State: Connected} break -- 2.16.6