multiple small fixes 46/6746/1
authorRastislav Szabo <raszabo@cisco.com>
Wed, 17 May 2017 14:19:30 +0000 (16:19 +0200)
committerRastislav Szabo <raszabo@cisco.com>
Wed, 17 May 2017 14:19:30 +0000 (16:19 +0200)
Change-Id: I9e822ce7e9b9f44f7d074b0294d6eda37c2a0f12
Signed-off-by: Rastislav Szabo <raszabo@cisco.com>
.gitignore
adapter/mock/mock_adapter.go
api/api.go
binapi_generator/generator.go
core/core.go

index 0d0d750..0f9e2cb 100644 (file)
@@ -1,2 +1,3 @@
+.idea
 binapi_generator/binapi_generator
 examples/examples
index ab49cef..796b96e 100644 (file)
@@ -37,7 +37,7 @@ type VppAdapter struct {
        msgIdsToName *map[uint16]string
        msgIdSeq     uint16
        binApiTypes  map[string]reflect.Type
-       //TODO lock
+       access       sync.RWMutex
 }
 
 // replyHeader represents a common header of each VPP request message.
@@ -104,8 +104,6 @@ func (a *VppAdapter) Disconnect() {
 }
 
 func (a *VppAdapter) GetMsgNameByID(msgId uint16) (string, bool) {
-       a.initMaps()
-
        switch msgId {
        case 100:
                return "control_ping", true
@@ -117,12 +115,17 @@ func (a *VppAdapter) GetMsgNameByID(msgId uint16) (string, bool) {
                return "sw_interface_details", true
        }
 
+       a.access.Lock()
+       defer a.access.Unlock()
+       a.initMaps()
        msgName, found := (*a.msgIdsToName)[msgId]
 
        return msgName, found
 }
 
 func (a *VppAdapter) RegisterBinApiTypes(binApiTypes map[string]reflect.Type) {
+       a.access.Lock()
+       defer a.access.Unlock()
        a.initMaps()
        for _, v := range binApiTypes {
                if msg, ok := reflect.New(v).Interface().(api.Message); ok {
@@ -187,6 +190,8 @@ func (a *VppAdapter) GetMsgID(msgName string, msgCrc string) (uint16, error) {
                return 201, nil
        }
 
+       a.access.Lock()
+       defer a.access.Unlock()
        a.initMaps()
 
        if msgId, found := (*a.msgNameToIds)[msgName]; found {
@@ -219,6 +224,7 @@ func (a *VppAdapter) initMaps() {
 func (a *VppAdapter) SendMsg(clientID uint32, data []byte) error {
        switch mode {
        case useReplyHandlers:
+               a.initMaps()
                for i := len(replyHandlers) - 1; i >= 0; i-- {
                        replyHandler := replyHandlers[i]
 
@@ -226,8 +232,9 @@ func (a *VppAdapter) SendMsg(clientID uint32, data []byte) error {
                        reqHeader := requestHeader{}
                        struc.Unpack(buf, &reqHeader)
 
-                       a.initMaps()
+                       a.access.Lock()
                        reqMsgName, _ := (*a.msgIdsToName)[reqHeader.VlMsgID]
+                       a.access.Unlock()
 
                        reply, msgID, finished := replyHandler(MessageDTO{reqHeader.VlMsgID, reqMsgName,
                                clientID, data})
index 783f97a..f478bf1 100644 (file)
@@ -78,7 +78,8 @@ type MessageIdentifier interface {
 
 // Channel is the main communication interface with govpp core. It contains two Go channels, one for sending the requests
 // to VPP and one for receiving the replies from it. The user can access the Go channels directly, or use the helper
-// methods  provided inside of this package.
+// methods  provided inside of this package. Do not use the same channel from multiple goroutines concurrently,
+// otherwise the responses could mix! Use multiple channels instead.
 type Channel struct {
        ReqChan   chan *VppRequest // channel for sending the requests to VPP, closing this channel releases all resources in the ChannelProvider
        ReplyChan chan *VppReply   // channel where VPP replies are delivered to
@@ -230,7 +231,8 @@ func (ch *Channel) receiveReplyInternal(msg Message) (LastReplyReceived bool, er
                        return false, err
                }
                if vppReply.MessageID != expMsgID {
-                       err = fmt.Errorf("invalid message ID %d, expected %d", vppReply.MessageID, expMsgID)
+                       err = fmt.Errorf("invalid message ID %d, expected %d "+
+                               "(also check if multiple goroutines are not sharing one GoVPP channel)", vppReply.MessageID, expMsgID)
                        return false, err
                }
                // decode the message
index 43f9ede..22fe3e1 100644 (file)
@@ -27,7 +27,6 @@ import (
        "os/exec"
        "path/filepath"
        "strings"
-       "time"
        "unicode"
 
        "github.com/bennyscetbun/jsongo"
@@ -44,7 +43,7 @@ const (
 
 const (
        apiImportPath = "git.fd.io/govpp.git/api" // import path of the govpp API
-       inputFileExt  = ".json"                                               // filename extension of files that should be processed as the input
+       inputFileExt  = ".json"                   // filename extension of files that should be processed as the input
 )
 
 // context is a structure storing details of a particular code generation task
@@ -386,7 +385,7 @@ func processMessageField(ctx *context, fields *[]string, fld *jsongo.JSONNode) e
 // generatePackageHeader generates package header into provider writer
 func generatePackageHeader(ctx *context, w io.Writer, rootNode *jsongo.JSONNode) {
        fmt.Fprintln(w, "// Package "+ctx.packageName+" represents the VPP binary API of the '"+ctx.packageName+"' VPP module.")
-       fmt.Fprintln(w, "// DO NOT EDIT. Generated from '"+ctx.inputFile+"' on "+time.Now().Format(time.RFC1123)+".")
+       fmt.Fprintln(w, "// DO NOT EDIT. Generated from '"+ctx.inputFile+"'")
 
        fmt.Fprintln(w, "package "+ctx.packageName)
 
index 7dc45de..550b6a7 100644 (file)
@@ -207,13 +207,16 @@ func (c *Connection) processRequest(ch *api.Channel, chMeta *channelMetadata, re
                "msg_size": len(data),
        }).Debug("Sending a message to VPP.")
 
-       c.vpp.SendMsg(chMeta.id, data)
-
        if req.Multipart {
-               // multipart request
+               // expect multipart response
                atomic.StoreUint32(&chMeta.multipart, 1)
+       }
 
-               // send a control ping
+       // send the request to VPP
+       c.vpp.SendMsg(chMeta.id, data)
+
+       if req.Multipart {
+               // send a control ping to determine end of the multipart response
                ping := &vpe.ControlPing{}
                pingData, _ := c.codec.EncodeMsg(ping, c.pingReqID)