Fix all possible data races

- Update to go 1.19 for new atomic types
- Use atomic for StitchedImage query counter
- Make sure that we don't copy any tile objects
This commit is contained in:
David Vogel 2022-08-12 11:39:55 +02:00
parent 65f7cb4e60
commit c9d2a37903
5 changed files with 12 additions and 10 deletions

View File

@ -29,7 +29,7 @@ type ImageTile struct {
scaleDivider int // Downscales the coordinates and images on the fly. scaleDivider int // Downscales the coordinates and images on the fly.
image image.Image // Either a rectangle or an RGBA image. The bounds of this image are determined by the filename. image image.Image // Either a rectangle or an RGBA image. The bounds of this image are determined by the filename.
imageMutex *sync.RWMutex // imageMutex *sync.RWMutex
invalidationChan chan struct{} // Used to send invalidation requests to the tile's goroutine. invalidationChan chan struct{} // Used to send invalidation requests to the tile's goroutine.
timeoutChan chan struct{} // Used to determine whether the tile is still being accessed or not. timeoutChan chan struct{} // Used to determine whether the tile is still being accessed or not.

View File

@ -39,7 +39,8 @@ func LoadImageTiles(path string, scaleDivider int) (ImageTiles, error) {
// InvalidateAboveY invalidates all cached images that have no pixel at the given y coordinate or below. // InvalidateAboveY invalidates all cached images that have no pixel at the given y coordinate or below.
func (it ImageTiles) InvalidateAboveY(y int) { func (it ImageTiles) InvalidateAboveY(y int) {
for _, tile := range it { for i := range it {
tile := &it[i] // Need to copy a reference.
if tile.Bounds().Max.Y <= y { if tile.Bounds().Max.Y <= y {
tile.Invalidate() tile.Invalidate()
} }

View File

@ -54,10 +54,10 @@ func (sic *StitchedImageCache) Regenerate() *image.RGBA {
// List of tiles that intersect with the to be generated cache image. // List of tiles that intersect with the to be generated cache image.
intersectingTiles := []*ImageTile{} intersectingTiles := []*ImageTile{}
for i, tile := range si.tiles { for i := range si.tiles {
tile := &si.tiles[i]
if tile.Bounds().Overlaps(sic.rect) { if tile.Bounds().Overlaps(sic.rect) {
tilePtr := &si.tiles[i] intersectingTiles = append(intersectingTiles, tile)
intersectingTiles = append(intersectingTiles, tilePtr)
} }
} }

View File

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"image" "image"
"image/color" "image/color"
"sync/atomic"
) )
// StitchedImageCacheGridSize defines the worker chunk size when the cache image is regenerated. // StitchedImageCacheGridSize defines the worker chunk size when the cache image is regenerated.
@ -37,7 +38,7 @@ type StitchedImage struct {
cacheRowYOffset int // Defines the pixel offset of the first cache row. cacheRowYOffset int // Defines the pixel offset of the first cache row.
oldCacheRowIndex int oldCacheRowIndex int
queryCounter int queryCounter atomic.Int64
} }
// NewStitchedImage creates a new image from several single image tiles. // NewStitchedImage creates a new image from several single image tiles.
@ -98,7 +99,7 @@ func (si *StitchedImage) At(x, y int) color.Color {
// At(Bounds().Max.X-1, Bounds().Max.Y-1) // returns the bottom-right pixel. // At(Bounds().Max.X-1, Bounds().Max.Y-1) // returns the bottom-right pixel.
func (si *StitchedImage) RGBAAt(x, y int) color.RGBA { func (si *StitchedImage) RGBAAt(x, y int) color.RGBA {
// Assume that every pixel is only queried once. // Assume that every pixel is only queried once.
si.queryCounter++ si.queryCounter.Add(1)
// Determine the cache rowIndex index. // Determine the cache rowIndex index.
rowIndex := (y + si.cacheRowYOffset) / si.cacheRowHeight rowIndex := (y + si.cacheRowYOffset) / si.cacheRowHeight
@ -142,5 +143,5 @@ func (si *StitchedImage) Opaque() bool {
func (si *StitchedImage) Progress() (value, max int) { func (si *StitchedImage) Progress() (value, max int) {
size := si.Bounds().Size() size := si.Bounds().Size()
return si.queryCounter, size.X * size.Y return int(si.queryCounter.Load()), size.X * size.Y
} }

2
go.mod
View File

@ -1,6 +1,6 @@
module github.com/Dadido3/noita-mapcap module github.com/Dadido3/noita-mapcap
go 1.18 go 1.19
require ( require (
github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1 github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1