[Darwin] Fix kqueue/kevent bindings to actually work. (#1871)
* [Darwin] Fix kqueue/kevent bindings to actually work. Fix kqueue/kevent bindings to actually work. The P/Invoke signatures were badly broken (missing an argument), so there's no way this could ever have worked. Additionally obsoletes kevent signatures that return bool (they're ignoring vital information: how many events were actually returned from kevent), and add overloads that do the right thing. * [Darwin] Improve input validation and add more tests.
This commit is contained in:
Родитель
78052430ab
Коммит
2380389278
|
@ -45,7 +45,11 @@ namespace XamCore.Darwin {
|
||||||
public IntPtr /* uintptr_tr */ Ident;
|
public IntPtr /* uintptr_tr */ Ident;
|
||||||
public EventFilter /* int16_t */ Filter;
|
public EventFilter /* int16_t */ Filter;
|
||||||
public EventFlags /* uint16_t */ Flags;
|
public EventFlags /* uint16_t */ Flags;
|
||||||
public uint /* uint16_t */ FilterFlags;
|
#if XAMCORE_4_0
|
||||||
|
public FilterFlags /* uint32_t */ FilterFlags;
|
||||||
|
#else
|
||||||
|
public uint /* uint32_t */ FilterFlags;
|
||||||
|
#endif
|
||||||
public IntPtr /* uintptr_t */ Data;
|
public IntPtr /* uintptr_t */ Data;
|
||||||
public IntPtr /* void */ UserData;
|
public IntPtr /* void */ UserData;
|
||||||
}
|
}
|
||||||
|
@ -175,11 +179,74 @@ namespace XamCore.Darwin {
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport (Constants.SystemLibrary)]
|
[DllImport (Constants.SystemLibrary)]
|
||||||
unsafe extern static int /* int */ kevent (KernelEvent *changeList, int /* int */ nChanges, KernelEvent *eventList, int /* int */ nEvents, IntPtr timeout);
|
unsafe extern static int /* int */ kevent (int kq, KernelEvent *changeList, int /* int */ nChanges, KernelEvent *eventList, int /* int */ nEvents, IntPtr timeout);
|
||||||
|
|
||||||
[DllImport (Constants.SystemLibrary)]
|
[DllImport (Constants.SystemLibrary)]
|
||||||
unsafe extern static int /* int */ kevent (KernelEvent *changeList, int /* int */ nChanges, KernelEvent *eventList, int /* int */ nEvents, ref TimeSpec timeout);
|
unsafe extern static int /* int */ kevent (int kq, KernelEvent *changeList, int /* int */ nChanges, KernelEvent *eventList, int /* int */ nEvents, ref TimeSpec timeout);
|
||||||
|
|
||||||
|
public int KEvent (KernelEvent[] changeList, KernelEvent[] eventList, TimeSpan? timeout = null)
|
||||||
|
{
|
||||||
|
if (changeList == null)
|
||||||
|
throw new ArgumentNullException (nameof (changeList));
|
||||||
|
|
||||||
|
if (eventList == null)
|
||||||
|
throw new ArgumentNullException (nameof (eventList));
|
||||||
|
|
||||||
|
if (changeList.Length < 1)
|
||||||
|
throw new ArgumentOutOfRangeException ("eventList must contain at least one element", nameof (eventList));
|
||||||
|
|
||||||
|
if (eventList.Length < 1)
|
||||||
|
throw new ArgumentOutOfRangeException ("changeList must contain at least one element", nameof (changeList));
|
||||||
|
|
||||||
|
return KEvent (changeList, changeList.Length, eventList, eventList.Length, ToTimespec (timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe int KEvent (KernelEvent[] changeList, int nChanges, KernelEvent[] eventList, int nEvents, TimeSpec? timeout = null)
|
||||||
|
{
|
||||||
|
if (changeList == null)
|
||||||
|
throw new ArgumentNullException (nameof (changeList));
|
||||||
|
|
||||||
|
if (eventList == null)
|
||||||
|
throw new ArgumentNullException (nameof (eventList));
|
||||||
|
|
||||||
|
if (changeList.Length < 1)
|
||||||
|
throw new ArgumentOutOfRangeException ("eventList must contain at least one element", nameof (eventList));
|
||||||
|
|
||||||
|
if (eventList.Length < 1)
|
||||||
|
throw new ArgumentOutOfRangeException ("changeList must contain at least one element", nameof (changeList));
|
||||||
|
|
||||||
|
if (changeList.Length < nChanges)
|
||||||
|
throw new ArgumentOutOfRangeException ("nChanges is larger than the number of elements in changeList", nameof (nChanges));
|
||||||
|
|
||||||
|
if (eventList.Length < nEvents)
|
||||||
|
throw new ArgumentOutOfRangeException ("nEvents is larger than the number of elements in eventList", nameof (nEvents));
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
fixed (KernelEvent *cp = &changeList [0])
|
||||||
|
fixed (KernelEvent *ep = &eventList [0]) {
|
||||||
|
if (timeout == null) {
|
||||||
|
return kevent (handle, cp, nChanges, ep, nEvents, IntPtr.Zero);
|
||||||
|
} else {
|
||||||
|
TimeSpec ts = timeout.Value;
|
||||||
|
return kevent (handle, cp, nChanges, ep, nEvents, ref ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static TimeSpec? ToTimespec (TimeSpan? ts)
|
||||||
|
{
|
||||||
|
if (ts == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var rv = new TimeSpec ();
|
||||||
|
rv.Seconds = (nint) ts.Value.TotalSeconds;
|
||||||
|
rv.NanoSeconds = (nint) (ts.Value.Milliseconds * 1000000L);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !XAMCORE_4_0
|
||||||
|
[Obsolete ("Use any of the overloads that return an int to get how many events were returned from kevent.")]
|
||||||
public bool KEvent (KernelEvent [] changeList, int nChanges, KernelEvent [] eventList, int nEvents, ref TimeSpec timeOut)
|
public bool KEvent (KernelEvent [] changeList, int nChanges, KernelEvent [] eventList, int nEvents, ref TimeSpec timeOut)
|
||||||
{
|
{
|
||||||
if (changeList != null && changeList.Length < nChanges)
|
if (changeList != null && changeList.Length < nChanges)
|
||||||
|
@ -191,10 +258,11 @@ namespace XamCore.Darwin {
|
||||||
unsafe {
|
unsafe {
|
||||||
fixed (KernelEvent *cp = &changeList [0])
|
fixed (KernelEvent *cp = &changeList [0])
|
||||||
fixed (KernelEvent *ep = &eventList [0])
|
fixed (KernelEvent *ep = &eventList [0])
|
||||||
return kevent (cp, nChanges, ep, nEvents, ref timeOut) != -1;
|
return kevent (handle, cp, nChanges, ep, nEvents, ref timeOut) != -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete ("Use any of the overloads that return an int to get how many events were returned from kevent.")]
|
||||||
public bool KEvent (KernelEvent [] changeList, int nChanges, KernelEvent [] eventList, int nEvents)
|
public bool KEvent (KernelEvent [] changeList, int nChanges, KernelEvent [] eventList, int nEvents)
|
||||||
{
|
{
|
||||||
if (changeList != null && changeList.Length < nChanges)
|
if (changeList != null && changeList.Length < nChanges)
|
||||||
|
@ -206,25 +274,36 @@ namespace XamCore.Darwin {
|
||||||
unsafe {
|
unsafe {
|
||||||
fixed (KernelEvent *cp = &changeList [0])
|
fixed (KernelEvent *cp = &changeList [0])
|
||||||
fixed (KernelEvent *ep = &eventList [0])
|
fixed (KernelEvent *ep = &eventList [0])
|
||||||
return kevent (cp, nChanges, ep, nEvents, IntPtr.Zero) != -1;
|
return kevent (handle, cp, nChanges, ep, nEvents, IntPtr.Zero) != -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete ("Use any of the overloads that return an int to get how many events were returned from kevent.")]
|
||||||
public bool KEvent (KernelEvent [] changeList, KernelEvent [] eventList, ref TimeSpec timeOut)
|
public bool KEvent (KernelEvent [] changeList, KernelEvent [] eventList, ref TimeSpec timeOut)
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
fixed (KernelEvent *cp = &changeList [0])
|
fixed (KernelEvent *cp = &changeList [0])
|
||||||
fixed (KernelEvent *ep = &eventList [0])
|
fixed (KernelEvent *ep = &eventList [0])
|
||||||
return kevent (cp, changeList != null ? changeList.Length : 0, ep, eventList != null ? eventList.Length : 0, ref timeOut) != -1;
|
return kevent (handle, cp, changeList != null ? changeList.Length : 0, ep, eventList != null ? eventList.Length : 0, ref timeOut) != -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if XAMCORE_4_0
|
||||||
|
public int KEvent (KernelEvent [] changeList, KernelEvent [] eventList)
|
||||||
|
#else
|
||||||
|
[Obsolete ("Use any of the overloads that return an int to get how many events were returned from kevent.")]
|
||||||
public bool KEvent (KernelEvent [] changeList, KernelEvent [] eventList)
|
public bool KEvent (KernelEvent [] changeList, KernelEvent [] eventList)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
fixed (KernelEvent *cp = &changeList [0])
|
fixed (KernelEvent *cp = &changeList [0])
|
||||||
fixed (KernelEvent *ep = &eventList [0])
|
fixed (KernelEvent *ep = &eventList [0])
|
||||||
return kevent (cp, changeList != null ? changeList.Length : 0, ep, eventList != null ? eventList.Length : 0, IntPtr.Zero) != -1;
|
#if XAMCORE_4_0
|
||||||
|
return kevent (handle, cp, changeList != null ? changeList.Length : 0, ep, eventList != null ? eventList.Length : 0, IntPtr.Zero);
|
||||||
|
#else
|
||||||
|
return kevent (handle, cp, changeList != null ? changeList.Length : 0, ep, eventList != null ? eventList.Length : 0, IntPtr.Zero) != -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@
|
||||||
<Compile Include="src\CoreAnimation\CALayer.cs" />
|
<Compile Include="src\CoreAnimation\CALayer.cs" />
|
||||||
<Compile Include="src\CoreAnimation\CAOpenGLLayer.cs" />
|
<Compile Include="src\CoreAnimation\CAOpenGLLayer.cs" />
|
||||||
<Compile Include="src\CoreImage\CIFilter.cs" />
|
<Compile Include="src\CoreImage\CIFilter.cs" />
|
||||||
|
<Compile Include="src\Darwin\KernelNotificationTest.cs" />
|
||||||
<Compile Include="src\DelegateAndDataSourceTest.cs" />
|
<Compile Include="src\DelegateAndDataSourceTest.cs" />
|
||||||
<Compile Include="src\DerivedEventTest.cs" />
|
<Compile Include="src\DerivedEventTest.cs" />
|
||||||
<Compile Include="src\EveryFrameworkSmokeTest.cs" />
|
<Compile Include="src\EveryFrameworkSmokeTest.cs" />
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
#if XAMCORE_2_0
|
||||||
|
using Darwin;
|
||||||
|
#else
|
||||||
|
using MonoMac.Darwin;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace apitest
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class KernelNotificationTest
|
||||||
|
{
|
||||||
|
KernelEvent [] CreateEvents (Process process)
|
||||||
|
{
|
||||||
|
return new KernelEvent [] {
|
||||||
|
new KernelEvent {
|
||||||
|
Ident = (IntPtr) process.Id,
|
||||||
|
Filter = EventFilter.Proc,
|
||||||
|
Flags = EventFlags.Add,
|
||||||
|
FilterFlags = (uint) (FilterFlags.ProcExit),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void KEvent ()
|
||||||
|
{
|
||||||
|
// (KernelEvent[], KernelEvent[])
|
||||||
|
using (var sleep = Process.Start ("/bin/sleep", "0.5")) {
|
||||||
|
using (var kqueue = new KernelQueue ()) {
|
||||||
|
var events = CreateEvents (sleep);
|
||||||
|
Assert.IsTrue (kqueue.KEvent (events, events), "kevent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (KernelEvent[], KernelEvent[], TimeSpan?)
|
||||||
|
using (var sleep = Process.Start ("/bin/sleep", "0.5")) {
|
||||||
|
using (var kqueue = new KernelQueue ()) {
|
||||||
|
var events = CreateEvents (sleep);
|
||||||
|
Assert.AreEqual (1, kqueue.KEvent (events, events, TimeSpan.FromSeconds (5)), "kevent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (KernelEvent[], KernelEvent[], TimeSpan?)
|
||||||
|
using (var sleep = Process.Start ("/bin/sleep", "0.5")) {
|
||||||
|
using (var kqueue = new KernelQueue ()) {
|
||||||
|
var events = CreateEvents (sleep);
|
||||||
|
Assert.AreEqual (1, kqueue.KEvent (events, events, null), "kevent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (KernelEvent[], int, KernelEvent[], int, TimeSpec?)
|
||||||
|
using (var sleep = Process.Start ("/bin/sleep", "0.5")) {
|
||||||
|
using (var kqueue = new KernelQueue ()) {
|
||||||
|
var events = CreateEvents (sleep);
|
||||||
|
TimeSpec ts = new TimeSpec
|
||||||
|
{
|
||||||
|
Seconds = 5,
|
||||||
|
};
|
||||||
|
Assert.AreEqual (1, kqueue.KEvent (events, events.Length, events, events.Length, ts), "kevent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (KernelEvent[], int, KernelEvent[], int, TimeSpec?)
|
||||||
|
using (var sleep = Process.Start ("/bin/sleep", "0.5")) {
|
||||||
|
using (var kqueue = new KernelQueue ()) {
|
||||||
|
var events = CreateEvents (sleep);
|
||||||
|
Assert.AreEqual (1, kqueue.KEvent (events, events.Length, events, events.Length, null), "kevent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (KernelEvent[], int, KernelEvent[], int, ref TimeSpec)
|
||||||
|
using (var sleep = Process.Start ("/bin/sleep", "0.5")) {
|
||||||
|
using (var kqueue = new KernelQueue ()) {
|
||||||
|
var events = CreateEvents (sleep);
|
||||||
|
TimeSpec ts = new TimeSpec
|
||||||
|
{
|
||||||
|
Seconds = 5,
|
||||||
|
};
|
||||||
|
Assert.IsTrue (kqueue.KEvent (events, events.Length, events, events.Length, ref ts), "kevent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (KernelEvent[], KernelEvent[], ref TimeSpec)
|
||||||
|
using (var sleep = Process.Start ("/bin/sleep", "0.5")) {
|
||||||
|
using (var kqueue = new KernelQueue ()) {
|
||||||
|
var events = CreateEvents (sleep);
|
||||||
|
TimeSpec ts = new TimeSpec
|
||||||
|
{
|
||||||
|
Seconds = 5,
|
||||||
|
};
|
||||||
|
Assert.IsTrue (kqueue.KEvent (events, events, ref ts), "kevent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (KernelEvent[], int, KernelEvent[], int)
|
||||||
|
using (var sleep = Process.Start ("/bin/sleep", "0.5")) {
|
||||||
|
using (var kqueue = new KernelQueue ()) {
|
||||||
|
var events = CreateEvents (sleep);
|
||||||
|
Assert.IsTrue (kqueue.KEvent (events, events.Length, events, events.Length), "kevent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void KEventExceptions ()
|
||||||
|
{
|
||||||
|
using (var sleep = Process.Start ("/bin/sleep", "0")) {
|
||||||
|
using (var kqueue = new KernelQueue ()) {
|
||||||
|
var events = CreateEvents (sleep);
|
||||||
|
var empty = new KernelEvent [0];
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentNullException> (() => kqueue.KEvent (null, events, null), "a1");
|
||||||
|
Assert.Throws<ArgumentNullException> (() => kqueue.KEvent (events, null, null), "a2");
|
||||||
|
Assert.Throws<ArgumentNullException> (() => kqueue.KEvent (null, null, null), "a3");
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException> (() => kqueue.KEvent (events, empty, null), "a4");
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException> (() => kqueue.KEvent (empty, events, null), "a5");
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentNullException> (() => kqueue.KEvent (null, 1, events, 1, null), "b1");
|
||||||
|
Assert.Throws<ArgumentNullException> (() => kqueue.KEvent (events, 1, null, 1, null), "b2");
|
||||||
|
Assert.Throws<ArgumentNullException> (() => kqueue.KEvent (null, 1, null, 1, null), "b3");
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException> (() => kqueue.KEvent (events, 1, empty, 1, null), "b4");
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException> (() => kqueue.KEvent (empty, 1, events, 1, null), "b5");
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException> (() => kqueue.KEvent (events, 1, events, 2, null), "b6");
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException> (() => kqueue.KEvent (events, 2, events, 1, null), "b7");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче