Closed ThatRendle closed 9 years ago
One of the problems currently, that is not a problem on mono(or lets say it works on mono), is that the StaticEnd callback during long running applications will get collected
https://github.com/txdv/LibuvSharp/blob/master/LibuvSharp%2FUVFile.cs#L68
int r = uv_fs_close(loop.NativeHandle, fsr.Handle, FileDescriptor, FileSystemRequest.StaticEnd);
I'm using this everywhere. Now this code literally is the same as
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void uv_fs_cb(IntPtr IntPtr); // this is already in the code
int r = uv_fs_close(loop.NativeHandle, fsr.Handle, FileDescriptor, new uv_fs_cb(FileSystemRequest.StaticEnd)); // this is the literal translation
It creates a temporary delegate which gets collected therefore resulting in a faulty pointer therefore a probable AccessViolationException. I tried to create a static delegate which contains this function and is never collected, but then the Test just stop at some point, on mono as well as on the .net framework.
Didn't investigate it further yet, because it is hard to debug.
This is one of the problems which keeps me releasing it on NuGet. A real headache.
It's because you're using an implicitly created delegate for the callback.
I changed CallbackPermaRequest
in my in-project copy:
public static readonly Handle.callback StaticEnd = StaticEndImpl;
private static void StaticEndImpl(IntPtr ptr, int status)
{
var obj = PermaRequest.GetObject<CallbackPermaRequest>(ptr);
if (obj == null) {
throw new Exception("Target is null");
} else {
obj.End(ptr, status);
}
}
Seems to have fixed the problem, for my code at least.
I did exactly the same without the readonly. Did you run the test suite? When I did that it would just stop at some point.
I've encountered a similar issue while writing bindings for evhttp. Try to use GCHandle.Alloc on the delegate like here https://github.com/kekekeks/evhttp-sharp/blob/master/EvHttpSharp/EventHttpListener.cs#L80
I changed the CallbackPermaRequest like this
internal class CallbackPermaRequest : PermaRequest
{
public Handle.callback CallbackDelegate;
public CallbackPermaRequest(int size)
: base(size)
{
CallbackDelegate = new Handle.callback(StaticEnd);
}
public CallbackPermaRequest(RequestType type)
: this(UV.Sizeof(type))
{
CallbackDelegate = new Handle.callback(StaticEnd);
}
public Action<int, CallbackPermaRequest> Callback { get; set; }
protected void End(IntPtr ptr, int status)
{
Callback(status, this);
Dispose();
}
protected void StaticEnd(IntPtr ptr, int status)
{
var obj = PermaRequest.GetObject<CallbackPermaRequest>(ptr);
if (obj == null) {
throw new Exception("Target is null");
} else {
obj.End(ptr, status);
}
}
}
then change the calling from
uv_write_unix(cpr.Handle, NativeHandle, buf, 1, CallbackPermaRequest.StaticEnd);
to
uv_write_unix(cpr.Handle, NativeHandle, buf, 1, cpr.CallbackDelegate);
In my case, it works fine both on Windows and on mono/Linux
Do you mind making a pull request?
@terender suggestion seems reasonable.
On mono these 'on the fly' delegates on static methods are actually saved forever. On the .NET framework they are not. My assumption was that they would stay, but I have fixed it in a commit that I have locally.
I'm working on a version of my Flux web server using LibuvSharp: https://github.com/markrendle/flux/tree/libuv
My test console application works fine until I hit it with around 10,000 requests using
weighttp -n 10000 -t 4 -c 8
, at which point I start getting AccessViolationException thrown all over the place.It also gets thrown sometimes when running the
TcpFixture.Stress
test (using R# test runner).This is on a fairly monster PC, overclocked i7-4770, 32GB RAM, SSDs, etc.
I'm going to do some investigation of my own today, but thought I'd open an issue to get other eyes on the problem.