Skip to content

Commit

Permalink
Add runtime.KeepAlive calls to prevent GC finalizers (refs #120)
Browse files Browse the repository at this point in the history
  • Loading branch information
justinfx committed Aug 23, 2017
1 parent 78b7826 commit 3fa86e0
Show file tree
Hide file tree
Showing 12 changed files with 558 additions and 116 deletions.
186 changes: 161 additions & 25 deletions imagick/drawing_wand.go

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion imagick/drawing_wand_exception.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import "C"

import (
"fmt"
"runtime"
"unsafe"
)

Expand All @@ -25,7 +26,9 @@ func (dwe *DrawingWandException) Error() string {

// Clears any exceptions associated with the wand
func (dw *DrawingWand) clearException() bool {
return 1 == C.int(C.DrawClearException(dw.dw))
ret := 1 == C.int(C.DrawClearException(dw.dw))
runtime.KeepAlive(dw)
return ret
}

// Returns the kind, reason and description of any error that occurs when using other methods in this API
Expand All @@ -37,6 +40,7 @@ func (dw *DrawingWand) GetLastError() error {
dw.clearException()
return &DrawingWandException{ExceptionType(C.int(et)), C.GoString(csdescription)}
}
runtime.KeepAlive(dw)
return nil
}

Expand Down
6 changes: 5 additions & 1 deletion imagick/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ package imagick
#include <magick/MagickCore.h>
*/
import "C"
import "runtime"

type Image struct {
img *C.Image
}

func NewMagickImage(info *ImageInfo, width, height uint, background *MagickPixelPacket) *Image {
return &Image{img: C.NewMagickImage(info.info, C.size_t(width), C.size_t(height), background.mpp)}
ret := &Image{img: C.NewMagickImage(info.info, C.size_t(width), C.size_t(height), background.mpp)}
runtime.KeepAlive(info)
runtime.KeepAlive(background)
return ret
}
2 changes: 2 additions & 0 deletions imagick/kernel_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func (ki *KernelInfo) ToArray() [][]float64 {
values = append(values, rowValues)
}

runtime.KeepAlive(ki)
return values
}

Expand Down Expand Up @@ -169,6 +170,7 @@ func NewKernelInfoBuiltIn(typ KernelInfoType, kernel string) *KernelInfo {
// KERNEL_NORMALIZE_PERCENT
func (ki *KernelInfo) Scale(scale float64, normalizeType KernelNormalizeType) {
C.ScaleKernelInfo(ki.info, C.double(scale), C.GeometryFlags(normalizeType))
runtime.KeepAlive(ki)
}

// cleanGeometryInfo peforms some tidy up of the geometry info for the kernel.
Expand Down
25 changes: 21 additions & 4 deletions imagick/magick_wand.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,22 @@ func NewMagickWand() *MagickWand {

// Returns a wand with an image
func NewMagickWandFromImage(img *Image) *MagickWand {
return newMagickWand(C.NewMagickWandFromImage(img.img))
ret := newMagickWand(C.NewMagickWandFromImage(img.img))
runtime.KeepAlive(img)
return ret
}

// Clear resources associated with the wand, leaving the wand blank, and ready to be used for a new set of images.
func (mw *MagickWand) Clear() {
C.ClearMagickWand(mw.mw)
runtime.KeepAlive(mw)
}

// Makes an exact copy of the MagickWand object
func (mw *MagickWand) Clone() *MagickWand {
return newMagickWand(C.CloneMagickWand(mw.mw))
ret := newMagickWand(C.CloneMagickWand(mw.mw))
runtime.KeepAlive(mw)
return ret
}

// Deallocates memory associated with an MagickWand
Expand All @@ -71,6 +76,7 @@ func (mw *MagickWand) IsVerified() bool {
if mw.mw != nil {
return 1 == C.int(C.IsMagickWand(mw.mw))
}
runtime.KeepAlive(mw)
return false
}

Expand All @@ -88,7 +94,9 @@ func (mw *MagickWand) DecreaseCount() {

// Returns the position of the iterator in the image list
func (mw *MagickWand) GetIteratorIndex() uint {
return uint(C.MagickGetIteratorIndex(mw.mw))
ret := uint(C.MagickGetIteratorIndex(mw.mw))
runtime.KeepAlive(mw)
return ret
}

// Returns the value associated with the specified configure option
Expand Down Expand Up @@ -120,6 +128,8 @@ func (mw *MagickWand) QueryFontMetrics(dw *DrawingWand, textLine string) *FontMe
cstext := C.CString(textLine)
defer C.free(unsafe.Pointer(cstext))
cdoubles := C.MagickQueryFontMetrics(mw.mw, dw.dw, cstext)
runtime.KeepAlive(mw)
runtime.KeepAlive(dw)
defer relinquishMemory(unsafe.Pointer(cdoubles))
doubles := sizedDoubleArrayToFloat64Slice(cdoubles, 13)
return NewFontMetricsFromArray(doubles)
Expand All @@ -130,6 +140,8 @@ func (mw *MagickWand) QueryMultilineFontMetrics(dw *DrawingWand, textParagraph s
cstext := C.CString(textParagraph)
defer C.free(unsafe.Pointer(cstext))
cdoubles := C.MagickQueryMultilineFontMetrics(mw.mw, dw.dw, cstext)
runtime.KeepAlive(mw)
runtime.KeepAlive(dw)
defer relinquishMemory(unsafe.Pointer(cdoubles))
doubles := sizedDoubleArrayToFloat64Slice(cdoubles, 13)
return NewFontMetricsFromArray(doubles)
Expand Down Expand Up @@ -164,6 +176,7 @@ func (mw *MagickWand) QueryFormats(pattern string) (formats []string) {
// Using this before AddImages() or ReadImages() will cause new images to be inserted between the first and second image.
func (mw *MagickWand) ResetIterator() {
C.MagickResetIterator(mw.mw)
runtime.KeepAlive(mw)
}

// This method sets the wand iterator to the first image.
Expand All @@ -173,6 +186,7 @@ func (mw *MagickWand) ResetIterator() {
// This operation is similar to ResetIterator() but differs in how AddImage(), ReadImage(), and NextImage() behaves afterward.
func (mw *MagickWand) SetFirstIterator() {
C.MagickSetFirstIterator(mw.mw)
runtime.KeepAlive(mw)
}

// This method set the iterator to the given position in the image list specified with the index parameter.
Expand All @@ -184,7 +198,9 @@ func (mw *MagickWand) SetFirstIterator() {
// regardless of if a zero (first image in list) or negative index (from end) is used.
// Jumping to index 0 is similar to ResetIterator() but differs in how NextImage() behaves afterward.
func (mw *MagickWand) SetIteratorIndex(index int) bool {
return 1 == C.int(C.MagickSetIteratorIndex(mw.mw, C.ssize_t(index)))
ret := 1 == C.int(C.MagickSetIteratorIndex(mw.mw, C.ssize_t(index)))
runtime.KeepAlive(mw)
return ret
}

// SetLastIterator() sets the wand iterator to the last image.
Expand All @@ -193,4 +209,5 @@ func (mw *MagickWand) SetIteratorIndex(index int) bool {
// Typically this function is used before AddImage(), ReadImage() functions to ensure new images are appended to the very end of wand's image list.
func (mw *MagickWand) SetLastIterator() {
C.MagickSetLastIterator(mw.mw)
runtime.KeepAlive(mw)
}
2 changes: 2 additions & 0 deletions imagick/magick_wand_exception.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import "C"

import (
"fmt"
"runtime"
"unsafe"
)

Expand All @@ -37,6 +38,7 @@ func (mw *MagickWand) GetLastError() error {
mw.clearException()
return &MagickWandException{ExceptionType(C.int(et)), C.GoString(csdescription)}
}
runtime.KeepAlive(mw)
return nil
}

Expand Down
Loading

0 comments on commit 3fa86e0

Please sign in to comment.