From 87009ab40a905b6f7d267f71434fda2a32725c57 Mon Sep 17 00:00:00 2001
From: 6543 <6543@obermui.de>
Date: Wed, 3 Feb 2021 22:36:38 +0100
Subject: [PATCH] Reduce data races (#14549)

* Add race conditions into test

* Fix Race in GetManager()

* DataAsync() use error chan

* just log no chan

* finish
---
 modules/git/blob_nogogit.go     | 10 ++++++----
 modules/process/manager.go      |  5 +++--
 modules/process/manager_test.go |  9 +++++++++
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/modules/git/blob_nogogit.go b/modules/git/blob_nogogit.go
index 401b172860..731f7d06e8 100644
--- a/modules/git/blob_nogogit.go
+++ b/modules/git/blob_nogogit.go
@@ -11,6 +11,8 @@ import (
 	"io"
 	"strconv"
 	"strings"
+
+	gitea_log "code.gitea.io/gitea/modules/log"
 )
 
 // Blob represents a Git object.
@@ -27,13 +29,13 @@ type Blob struct {
 // Calling the Close function on the result will discard all unread output.
 func (b *Blob) DataAsync() (io.ReadCloser, error) {
 	stdoutReader, stdoutWriter := io.Pipe()
-	var err error
 
 	go func() {
 		stderr := &strings.Builder{}
-		err = NewCommand("cat-file", "--batch").RunInDirFullPipeline(b.repoPath, stdoutWriter, stderr, strings.NewReader(b.ID.String()+"\n"))
+		err := NewCommand("cat-file", "--batch").RunInDirFullPipeline(b.repoPath, stdoutWriter, stderr, strings.NewReader(b.ID.String()+"\n"))
 		if err != nil {
 			err = ConcatenateError(err, stderr.String())
+			gitea_log.Error("Blob.DataAsync Error: %v", err)
 			_ = stdoutWriter.CloseWithError(err)
 		} else {
 			_ = stdoutWriter.Close()
@@ -50,8 +52,8 @@ func (b *Blob) DataAsync() (io.ReadCloser, error) {
 	return &LimitedReaderCloser{
 		R: bufReader,
 		C: stdoutReader,
-		N: int64(size),
-	}, err
+		N: size,
+	}, nil
 }
 
 // Size returns the uncompressed size of the blob
diff --git a/modules/process/manager.go b/modules/process/manager.go
index 27ed1d4964..9d57f4eb7b 100644
--- a/modules/process/manager.go
+++ b/modules/process/manager.go
@@ -25,6 +25,7 @@ var (
 	// ErrExecTimeout represent a timeout error
 	ErrExecTimeout = errors.New("Process execution timeout")
 	manager        *Manager
+	managerInit    sync.Once
 
 	// DefaultContext is the default context to run processing commands in
 	DefaultContext = context.Background()
@@ -48,11 +49,11 @@ type Manager struct {
 
 // GetManager returns a Manager and initializes one as singleton if there's none yet
 func GetManager() *Manager {
-	if manager == nil {
+	managerInit.Do(func() {
 		manager = &Manager{
 			processes: make(map[int64]*Process),
 		}
-	}
+	})
 	return manager
 }
 
diff --git a/modules/process/manager_test.go b/modules/process/manager_test.go
index 42f4b0c04b..a515fc32cd 100644
--- a/modules/process/manager_test.go
+++ b/modules/process/manager_test.go
@@ -12,6 +12,15 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+func TestGetManager(t *testing.T) {
+	go func() {
+		// test race protection
+		_ = GetManager()
+	}()
+	pm := GetManager()
+	assert.NotNil(t, pm)
+}
+
 func TestManager_Add(t *testing.T) {
 	pm := Manager{processes: make(map[int64]*Process)}