From 224b41e8b1f574f03b89e30931df60925291a2c1 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Sun, 28 Jun 2020 11:00:40 -0700 Subject: [PATCH] Fix a threading segfault when filling zones The shape cache gets reset by the zone fill algorithm. This needs to be cleaned before multiple threads are created and cannot be modified when threading. Fixes https://gitlab.com/kicad/code/kicad/issues/4723 --- pcbnew/class_pad.cpp | 8 ++++---- pcbnew/class_pad.h | 9 +++++++-- pcbnew/zone_filler.cpp | 24 ++++++++++++++++-------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index 5782868e3a..ab2c67eff7 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -193,7 +193,7 @@ void D_PAD::SetChamferRectRatio( double aChamferScale ) const std::vector>& D_PAD::GetEffectiveShapes() const { if( m_shapesDirty ) - buildEffectiveShapes(); + BuildEffectiveShapes(); return m_effectiveShapes; } @@ -202,7 +202,7 @@ const std::vector>& D_PAD::GetEffectiveShapes() const const std::shared_ptr& D_PAD::GetEffectiveHoleShape() const { if( m_shapesDirty ) - buildEffectiveShapes(); + BuildEffectiveShapes(); return m_effectiveHoleShape; } @@ -211,13 +211,13 @@ const std::shared_ptr& D_PAD::GetEffectiveHoleShape() const int D_PAD::GetBoundingRadius() const { if( m_shapesDirty ) - buildEffectiveShapes(); + BuildEffectiveShapes(); return m_effectiveBoundingRadius; } -void D_PAD::buildEffectiveShapes() const +void D_PAD::BuildEffectiveShapes() const { m_effectiveShapes.clear(); m_effectiveHoleShape = nullptr; diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index c16c9901c2..7793dad838 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -317,6 +317,8 @@ public: void SetDrillShape( PAD_DRILL_SHAPE_T aShape ) { m_drillShape = aShape; m_shapesDirty = true; } PAD_DRILL_SHAPE_T GetDrillShape() const { return m_drillShape; } + bool IsDirty() const { return m_shapesDirty; } + /** * JEY TODO: temporary until Tom is done with DRC stuff.... */ @@ -575,6 +577,11 @@ public: */ bool PadShouldBeNPTH() const; + /** + * Rebuilds the shape cache for the pad and clears the dirty bit + */ + void BuildEffectiveShapes() const; + virtual void ViewGetLayers( int aLayers[], int& aCount ) const override; virtual unsigned int ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override; @@ -597,8 +604,6 @@ private: void addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const; - void buildEffectiveShapes() const; - private: wxString m_name; ///< pad name (pin number in schematic) wxString m_pinFunction; ///< pin function in schematic diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 9eed130f56..337e80fa70 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -119,6 +119,16 @@ bool ZONE_FILLER::Fill( const std::vector& aZones, bool aCheck m_boardOutline.RemoveAllContours(); m_brdOutlinesValid = m_board->GetBoardPolygonOutlines( m_boardOutline ); + // Update the bounding box shape caches in the pads to prevent multi-threaded rebuilds + for( auto module : m_board->Modules() ) + { + for( auto pad : module->Pads() ) + { + if( pad->IsDirty() ) + pad->BuildEffectiveShapes(); + } + } + for( auto zone : aZones ) { // Keepout zones are not filled @@ -949,16 +959,14 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE_CONTAINER* aZone, PCB_LAYER_ID // // We use the bounding-box to lay out the spokes, but for this to work the // bounding box has to be built at the same rotation as the spokes. - + // We have to use a dummy pad to avoid dirtying the cached shapes wxPoint shapePos = pad->ShapePos(); - wxPoint padPos = pad->GetPosition(); - double padAngle = pad->GetOrientation(); - pad->SetOrientation( 0.0 ); - pad->SetPosition( { 0, 0 } ); - BOX2I reliefBB = pad->GetBoundingBox(); - pad->SetPosition( padPos ); - pad->SetOrientation( padAngle ); + double padAngle = pad->GetOrientation(); + D_PAD dummy_pad( *pad ); + dummy_pad.SetOrientation( 0.0 ); + dummy_pad.SetPosition( { 0, 0 } ); + BOX2I reliefBB = dummy_pad.GetBoundingBox(); reliefBB.Inflate( thermalReliefGap + epsilon ); // For circle pads, the thermal spoke orientation is 45 deg