Skip to content

Commit

Permalink
Add support for signal handling
Browse files Browse the repository at this point in the history
+ update CHANGELOG.md and add CHANGELOG.native.md (for the changes to the pre-compiled binaries of libvips).
  • Loading branch information
kleisauke committed Apr 11, 2019
1 parent 65629cf commit 3f6430a
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 60 deletions.
24 changes: 12 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# Changelog
All notable changes to this project will be documented in this file.
All notable changes to NetVips will be documented in this file. See [here](CHANGELOG.native.md) for the changes to the [pre-compiled binaries of libvips](https://www.nuget.org/packages/NetVips.Native/).

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.0] - ???
## [1.1.0] - Unreleased
### Added
- Pre-compiled libvips binaries for a few distros ([#21](https://github.com/kleisauke/net-vips/issues/21)):
- [NetVips.Native.linux-x64](https://www.nuget.org/packages/NetVips.Native.linux-x64) - Linux x64 glibc (Ubuntu, Debian, etc).
- [NetVips.Native.linux-musl-x64](https://www.nuget.org/packages/NetVips.Native.linux-musl-x64) - Linux x64 musl (Alpine, Gentoo Linux, etc).
- [NetVips.Native.osx-x64](https://www.nuget.org/packages/NetVips.Native.osx-x64) - macOS x64.
- A new [NetVips.Native](https://www.nuget.org/packages/NetVips.Native/) package containing the pre-compiled libvips binaries for Linux, macOS and Windows ([#21](https://github.com/kleisauke/net-vips/issues/21)).
- Changes to the [NetVips.Native.*](https://www.nuget.org/packages?q=id%3ANetVips.Native) packages will be documented [here](CHANGELOG.native.md).
- Add `Base.GetSuffixes()` to get a list of all the filename suffixes supported by libvips ([libvips/ruby-vips#186](https://github.com/libvips/ruby-vips/issues/186)).
- Add support for progress feedback (`image.SetProgress()`) and signal handling (`image.SignalConnect()`) ([#31](https://github.com/kleisauke/net-vips/issues/31)).
- Add `image.SetKill()` and `image.IsKilled()` ([#31](https://github.com/kleisauke/net-vips/issues/31), [libvips/libvips@91d0e7e](https://github.com/libvips/libvips/commit/91d0e7e3d06fe6293f8e7513f30fd21585ea4305)).

### Changed
- Improve memory management ([#26](https://github.com/kleisauke/net-vips/issues/26)).
- The bundled libvips Windows binaries were split into different NuGet packages:
- [NetVips.Native.win-x64](https://www.nuget.org/packages/NetVips.Native.win-x64) - Windows 64-bit.
- [NetVips.Native.win-x86](https://www.nuget.org/packages/NetVips.Native.win-x86) - Windows 32-bit.
- The bundled libvips Windows binaries were moved to the [NetVips.Native](https://www.nuget.org/packages/NetVips.Native/) package.
- Update the [NetVips.Benchmarks](https://github.com/kleisauke/net-vips/tree/master/tests/NetVips.Benchmarks).
- A statically linked libvips binary is build for Windows. This reduces the number of DLLs from 37 to 3 ([libvips/build-win64#21](https://github.com/libvips/build-win64/issues/21#issuecomment-458112440)).
- The overloadable operators `==` and `!=` have been changed to `Equal` and `NotEqual` to avoid conflicts with `null` checks.
- Some methods are overloaded instead of defining the parameters as `object` type.

### Removed
- The `UseGlobalLibvips` property since the bundled libvips binaries are split into different NuGet packages.
- The `UseGlobalLibvips` property since the bundled libvips binaries were moved to the [NetVips.Native](https://www.nuget.org/packages/NetVips.Native/) package.

## [1.0.7] - 2019-01-18
### Changed
Expand Down Expand Up @@ -85,7 +85,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Added
- First release!

[1.1.0]: https://github.com/kleisauke/net-vips/compare/v1.0.7...v1.1.0
[1.1.0]: https://github.com/kleisauke/net-vips/compare/v1.0.7...1.1.0
[1.0.7]: https://github.com/kleisauke/net-vips/compare/v1.0.6...v1.0.7
[1.0.6]: https://github.com/kleisauke/net-vips/compare/v1.0.5...v1.0.6
[1.0.5]: https://github.com/kleisauke/net-vips/compare/v1.0.4...v1.0.5
Expand Down
33 changes: 33 additions & 0 deletions CHANGELOG.native.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Changelog
All notable changes to the pre-compiled binaries of libvips will be documented in this file. The version number of these NuGet packages is in sync with libvips' version number.
The changes of libvips are documented [here](https://github.com/libvips/libvips/blob/master/ChangeLog).

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [8.8.0] - Unreleased
### Note
If you would like to see a complete list of all the new features, changes and bug fixes, please visit the the release notes of libvips:
https://github.com/libvips/libvips/releases

## [8.7.4] - 2019-04-10
### Added
- A [NetVips.Native](https://www.nuget.org/packages/NetVips.Native/) package which depends on the other [NetVips.Native.*](https://www.nuget.org/packages?q=id%3ANetVips.Native) packages.

### Changed
- The OS X binaries are now distributed with [`jpeg-turbo`](https://github.com/libjpeg-turbo/libjpeg-turbo) instead than [`jpeg`](https://www.ijg.org/) ([lovell/package-libvips-darwin#3](https://github.com/lovell/package-libvips-darwin/pull/3)).

## [8.7.4 beta 1] - 2019-02-25
### Added
- Pre-compiled libvips binaries for a few distros ([#21](https://github.com/kleisauke/net-vips/issues/21)):
- [NetVips.Native.linux-x64](https://www.nuget.org/packages/NetVips.Native.linux-x64) - Linux x64 glibc (Ubuntu, Debian, etc).
- [NetVips.Native.linux-musl-x64](https://www.nuget.org/packages/NetVips.Native.linux-musl-x64) - Linux x64 musl (Alpine, Gentoo Linux, etc).
- [NetVips.Native.osx-x64](https://www.nuget.org/packages/NetVips.Native.osx-x64) - macOS x64.
- [NetVips.Native.win-x64](https://www.nuget.org/packages/NetVips.Native.win-x64) - Windows 64-bit.
- [NetVips.Native.win-x86](https://www.nuget.org/packages/NetVips.Native.win-x86) - Windows 32-bit.

### Changed
- A statically linked libvips binary is build for Windows. This reduces the number of DLLs from 37 to 3 ([libvips/build-win64#21](https://github.com/libvips/build-win64/issues/21#issuecomment-458112440)).

[8.8.0]: https://github.com/kleisauke/libvips-packaging/compare/v8.7.4...HEAD
[8.7.4]: https://github.com/kleisauke/libvips-packaging/compare/v8.7.4-beta1...v8.7.4
[8.7.4 beta 1]: https://github.com/kleisauke/libvips-packaging/releases/tag/v8.7.4-beta1
4 changes: 4 additions & 0 deletions documentation/docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
"files": "CHANGELOG.md",
"src": ".."
},
{
"files": "CHANGELOG.native.md",
"src": ".."
},
{
"files": [
"tutorial/**/*.{md,yml}",
Expand Down
23 changes: 0 additions & 23 deletions src/NetVips/ExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,28 +252,5 @@ internal static string ToReadableBytes(this ulong value)

return $"{dValue:n2} {sizeSuffixes[i]}";
}

/// <summary>
/// Connects a callback function (<see cref="GCallback"/>)
/// to a signal for a particular <see cref="GObject"/>.
/// </summary>
/// <param name="instance">The instance to connect to.</param>
/// <param name="detailedSignal">A string of the form "signal-name::detail".</param>
/// <param name="callback">The <see cref="GCallback"/> to connect.</param>
/// <param name="data">Data to pass to handler calls.</param>
/// <returns>The handler id.</returns>
/// <exception cref="T:System.Exception">If it failed to connect the signal.</exception>
internal static uint Connect(this GObject instance, string detailedSignal, GCallback callback,
IntPtr data = default)
{
var ret = GSignal.ConnectData(instance, detailedSignal, callback, data, null, default);

if (ret == 0)
{
throw new Exception("Failed to connect signal.");
}

return ret;
}
}
}
45 changes: 45 additions & 0 deletions src/NetVips/GObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ namespace NetVips
{
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using NetVips.Internal;

/// <summary>
/// Manage <see cref="Internal.GObject"/> lifetime.
Expand All @@ -10,6 +12,12 @@ public class GObject : SafeHandle
{
// private static Logger logger = LogManager.GetCurrentClassLogger();

/// <summary>
/// We have to record all of the <see cref="SignalConnect"/> delegates to
/// prevent them from being re-located or disposed of by the garbage collector.
/// </summary>
private readonly List<GCHandle> _handles = new List<GCHandle>();

// Handy for debugging
// public static int NObjects;

Expand All @@ -32,6 +40,35 @@ internal GObject(IntPtr pointer)
// logger.Debug($"GObject = {pointer}");
}

/// <summary>
/// Connects a callback function (<paramref name="callback"/>) to a signal on this object.
/// </summary>
/// <remarks>
/// The callback will be triggered every time this signal is issued on this instance.
/// </remarks>
/// <param name="detailedSignal">A string of the form "signal-name::detail".</param>
/// <param name="callback">The callback to connect.</param>
/// <param name="data">Data to pass to handler calls.</param>
/// <returns>The handler id.</returns>
/// <exception cref="T:System.Exception">If it failed to connect the signal.</exception>
public uint SignalConnect(string detailedSignal, Delegate callback, IntPtr data = default)
{
// prevent the delegate from being re-located or disposed of by the garbage collector
var delegateHandle = GCHandle.Alloc(callback);
_handles.Add(delegateHandle);

// get the pointer for the delegate which can be passed to the native code
var callbackPtr = Marshal.GetFunctionPointerForDelegate(callback);
var ret = GSignal.ConnectData(this, detailedSignal, callbackPtr, data, null, default);

if (ret == 0)
{
throw new Exception("Failed to connect signal.");
}

return ret;
}

/// <summary>
/// Decreases the reference count of object.
/// When its reference count drops to 0, the object is finalized (i.e. its memory is freed).
Expand All @@ -44,6 +81,14 @@ protected override bool ReleaseHandle()
if (!IsInvalid)
{
Internal.GObject.Unref(handle);

// release all handles recorded by this object
foreach (var gcHandle in _handles)
{
gcHandle.Free();
}

_handles.Clear();
}
// NObjects--;

Expand Down
27 changes: 9 additions & 18 deletions src/NetVips/Image.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ public sealed partial class Image : VipsObject
/// </summary>
private GCHandle _dataHandle;

/// <summary>
/// Ref for <see cref="SetProgress" />.
/// </summary>
private GCHandle _progressHandle;

/// <inheritdoc cref="VipsObject"/>
internal Image(IntPtr pointer)
: base(pointer)
Expand Down Expand Up @@ -1426,7 +1421,7 @@ public void SetKill(bool kill)
return;
}

VipsImage.SetKill(this, kill ? 1 : 0);
VipsImage.SetKill(this, kill ? 1 : 0);
}

/// <summary>
Expand Down Expand Up @@ -1456,11 +1451,15 @@ public void SetKill(bool kill)
public void SetProgress(IProgress<int> progress, CancellationToken token = default)
{
VipsImage.SetProgress(this, progress == null ? 0 : 1);
if (progress == null)
{
return;
}

var lastPercent = 0;
var isKilled = false;

GCallback evalCallback = (imagePtr, progressPtr, userDataPtr) =>
EvalCallback evalCallback = (imagePtr, progressPtr, userDataPtr) =>
{
// Block evaluation on this image if a cancellation
// has been requested for this token.
Expand All @@ -1483,15 +1482,12 @@ public void SetProgress(IProgress<int> progress, CancellationToken token = defau
var progressStruct = progressPtr.Dereference<VipsProgress.Struct>();
if (progressStruct.Percent != lastPercent)
{
progress?.Report(progressStruct.Percent);
progress.Report(progressStruct.Percent);
lastPercent = progressStruct.Percent;
}
};

// prevent it from being re-located or disposed of by the garbage collector
_progressHandle = GCHandle.Alloc(evalCallback);

this.Connect(Internal.Enums.VipsEvaluation.Eval, evalCallback);
SignalConnect(Internal.Enums.VipsEvaluation.Eval, evalCallback);
}

#endregion
Expand Down Expand Up @@ -1630,17 +1626,12 @@ public override int GetHashCode()
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
// release references to delegates / data objects
// release reference to our secret ref
if (_dataHandle.IsAllocated)
{
_dataHandle.Free();
}

if (_progressHandle.IsAllocated)
{
_progressHandle.Free();
}

// Call our base Dispose method
base.Dispose(disposing);
}
Expand Down
5 changes: 1 addition & 4 deletions src/NetVips/Internal/GObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,16 +163,13 @@ internal struct Struct
[SuppressUnmanagedCodeSecurity, UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void GClosureNotify(IntPtr data, IntPtr closure);

[SuppressUnmanagedCodeSecurity, UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void GCallback(IntPtr gobjectPtr, IntPtr pspecPtr, IntPtr userDataPtr);

internal static class GSignal
{
[SuppressUnmanagedCodeSecurity]
[DllImport(Libraries.GObject, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "g_signal_connect_data")]
internal static extern uint ConnectData(NetVips.GObject instance,
[MarshalAs(UnmanagedType.LPStr)] string detailedSignal, GCallback cHandler, IntPtr data,
[MarshalAs(UnmanagedType.LPStr)] string detailedSignal, IntPtr cHandler, IntPtr data,
GClosureNotify destroyData, Enums.GConnectFlags connectFlags);
}
}
3 changes: 3 additions & 0 deletions src/NetVips/Internal/Vips.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ internal static extern void SetArrayInt(ref GValue.Struct value,
internal static extern void SetArrayImage(ref GValue.Struct value, int n);
}

[SuppressUnmanagedCodeSecurity, UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void EvalCallback(IntPtr imagePtr, IntPtr progressPtr, IntPtr userDataPtr);

internal static class VipsImage
{
[SuppressUnmanagedCodeSecurity]
Expand Down
4 changes: 1 addition & 3 deletions tests/NetVips.Tests/IoFuncsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,13 @@ public void TestSetProgress()

var progress = new Progress<int>(percent =>
{
// Tests whether the actual percentage is higher
// than the last percentage received.
Assert.True(percent > lastPercent);
lastPercent = percent;
});
im.SetProgress(progress);

var buf = im.DzsaveBuffer("image-pyramid");
Assert.True(buf.Length > 0);
Assert.True(lastPercent <= 100);
}

[Fact]
Expand Down

0 comments on commit 3f6430a

Please sign in to comment.