Skip to content

Commit a07ada6

Browse files
authored
RSDK-10204 - Camera API server GetImage data race (viamrobotics#4843)
1 parent 49d9218 commit a07ada6

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

components/camera/server.go

+16-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"image"
7+
"sync"
78

89
"github.com/pkg/errors"
910
"go.opencensus.io/trace"
@@ -22,9 +23,11 @@ import (
2223
// serviceServer implements the CameraService from camera.proto.
2324
type serviceServer struct {
2425
pb.UnimplementedCameraServiceServer
25-
coll resource.APIResourceCollection[Camera]
26-
imgTypes map[string]ImageType
27-
logger logging.Logger
26+
coll resource.APIResourceCollection[Camera]
27+
28+
imgTypesMu sync.RWMutex
29+
imgTypes map[string]ImageType
30+
logger logging.Logger
2831
}
2932

3033
// NewRPCServiceServer constructs an camera gRPC service server.
@@ -54,16 +57,22 @@ func (s *serviceServer) GetImage(
5457

5558
// Determine the mimeType we should try to use based on camera properties
5659
if req.MimeType == "" {
57-
if _, ok := s.imgTypes[req.Name]; !ok {
60+
s.imgTypesMu.RLock()
61+
imgType, ok := s.imgTypes[req.Name]
62+
s.imgTypesMu.RUnlock()
63+
if !ok {
5864
props, err := cam.Properties(ctx)
5965
if err != nil {
6066
s.logger.CWarnf(ctx, "camera properties not found for %s, assuming color images: %v", req.Name, err)
61-
s.imgTypes[req.Name] = ColorStream
67+
imgType = ColorStream
6268
} else {
63-
s.imgTypes[req.Name] = props.ImageType
69+
imgType = props.ImageType
6470
}
71+
s.imgTypesMu.Lock()
72+
s.imgTypes[req.Name] = imgType
73+
s.imgTypesMu.Unlock()
6574
}
66-
switch s.imgTypes[req.Name] {
75+
switch imgType {
6776
case ColorStream, UnspecifiedStream:
6877
req.MimeType = utils.MimeTypeJPEG
6978
case DepthStream:

components/camera/server_test.go

+23
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"image"
88
"image/jpeg"
99
"image/png"
10+
"sync"
1011
"testing"
1112
"time"
1213

@@ -478,3 +479,25 @@ func TestServer(t *testing.T) {
478479
test.That(t, err.Error(), test.ShouldContainSubstring, errGetImageFailed.Error())
479480
})
480481
}
482+
483+
func TestGetImageRace(t *testing.T) {
484+
cameraServer, injectCamera, _, _, err := newServer()
485+
test.That(t, err, test.ShouldBeNil)
486+
487+
injectCamera.PropertiesFunc = func(ctx context.Context) (camera.Properties, error) { return camera.Properties{}, nil }
488+
injectCamera.ImageFunc = func(ctx context.Context, mimeType string, extra map[string]interface{}) ([]byte, camera.ImageMetadata, error) {
489+
return []byte{1, 2}, camera.ImageMetadata{}, nil
490+
}
491+
var wg sync.WaitGroup
492+
493+
getImg := func() {
494+
defer wg.Done()
495+
_, retErr := cameraServer.GetImage(context.Background(), &pb.GetImageRequest{Name: testCameraName})
496+
test.That(t, retErr, test.ShouldBeNil)
497+
}
498+
for range 2 {
499+
wg.Add(1)
500+
go getImg()
501+
}
502+
wg.Wait()
503+
}

0 commit comments

Comments
 (0)