/* $Id$ * * Project: Swicli.Library - Two Way Interface for .NET and MONO to SWI-Prolog * Author: Douglas R. Miles * E-mail: logicmoo@gmail.com * WWW: http://www.logicmoo.com * Copyright (C): 2010-2012 LogicMOO Developement * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *********************************************************/ using System; using System.Collections.Generic; using System.Reflection; using System.Threading; using SbsSW.SwiPlCs; namespace Swicli.Library { public partial class PrologCLR { /// /// Create a Event Handler with a ResetEvent /// /// /// /// /// [PrologVisible] public static bool cliNewEventWaiter(PlTerm clazzOrInstance, PlTerm memberSpec, PlTerm blockOn) { object getInstance; Type c; if (!GetInstanceAndType(clazzOrInstance, out getInstance, out c)) return false; Type[] paramz = null; if (!CheckBound(memberSpec)) return false; EventInfo fi = findEventInfo(memberSpec, c, ref paramz, BindingFlagsALL); if (fi == null) { return Embedded.Error("Cant find event {0} on {1}", memberSpec, (object) c ?? clazzOrInstance); } WaitUntilDelegateList list = new WaitUntilDelegateList(); list.WaitOns.Add(new WaitUntilDelegate(list, fi, getInstance)); return blockOn.FromObject(list); } /// /// Add another event to be waited on /// /// /// /// /// [PrologVisible] public static bool cliAddEventWaiter(PlTerm blockOn, PlTerm clazzOrInstance, PlTerm memberSpec, PlTerm newBlockOn) { WaitUntilDelegateList list = null; object getInstance1 = GetInstance(blockOn); var wud = getInstance1 as WaitUntilDelegate; if (wud == null) { if (!(getInstance1 is WaitUntilDelegateList)) return Embedded.Error("Not an instance of WaitUntilDelegate: " + blockOn); list = getInstance1 as WaitUntilDelegateList; } else { list = wud.parent; } object getInstance; Type c; if (!GetInstanceAndType(clazzOrInstance, out getInstance, out c)) return false; Type[] paramz = null; if (!CheckBound(memberSpec, blockOn)) return false; EventInfo fi = findEventInfo(memberSpec, c, ref paramz, BindingFlagsALL); if (fi == null) { return Embedded.Error("Cant find event {0} on {1}", memberSpec, (object)c ?? clazzOrInstance); } var wud2 = new WaitUntilDelegate(list, fi, getInstance); list.WaitOns.Add(wud2); return newBlockOn.FromObject(list); } /// /// Block until ResetEvent occures and run the prolog code.. if it fails.. wait again for the reset event /// if over maxTime return time_limit_exceeded /// /// /// /// /// /// [PrologVisible] public static bool cliBlockUntilEvent(PlTerm blockOn, PlTerm maxTime, PlTerm testVarsCode, PlTerm exitCode) { WaitUntilDelegateList list = null; object getInstance1 = GetInstance(blockOn); var wud = getInstance1 as WaitUntilDelegate; if (wud == null) { if (!(getInstance1 is WaitUntilDelegateList)) return Embedded.Error("Not an instance of WaitUntilDelegate: " + blockOn); list = getInstance1 as WaitUntilDelegateList; } else { list = wud.parent; } var timeSpan = TimeSpan.FromDays(3650); if (maxTime.IsInteger) { timeSpan = TimeSpan.FromMilliseconds(maxTime.intValue()); } else if (!maxTime.IsVar) { timeSpan = (TimeSpan) CastTerm(maxTime, typeof (TimeSpan)); } DateTime expireyTime = DateTime.Now.Add(timeSpan); while (DateTime.Now < expireyTime) { var results = list.WaitOne(timeSpan, out wud); if (results == null) { return exitCode.UnifyAtom("time_limit_exceeded"); } PlTerm copyTo = PlTerm.PlVar(); PlTermV newPlTermV = new PlTermV(testVarsCode, copyTo); PlCall("system", "copy_term", newPlTermV); PlTerm ctestVars = copyTo.Arg(0); PlTerm ctestCode = copyTo.Arg(1); PlTerm[] terms = ToTermArray(ctestVars); int idx = terms.Length - 1; int resdex = results.Length - 1; while (idx >= 0 && resdex >= 0) { terms[idx--].FromObject(results[resdex--]); } try { if (PlCall("user", "call", new PlTermV(ctestCode))) return UnifyToProlog(PlCall(null, "=", newPlTermV), exitCode) != 0; } finally { list.Reset(); } } return exitCode.UnifyAtom("time_limit_exceeded"); } } public class WaitUntilDelegateList: IDisposable { public List WaitOns = new List(); public ManualResetEvent mre = new ManualResetEvent(false); public object[] WaitOne(TimeSpan ts, out WaitUntilDelegate wud0) { wud0 = null; if (!mre.WaitOne(ts)) return null; foreach (WaitUntilDelegate wud in WaitOns) { var tr = wud.Result; if (tr != null) { wud0 = wud; return tr; } } return null; } internal void Set() { mre.Set(); } internal void Reset() { mre.Reset(); } #region IDisposable Members public void Dispose() { foreach (WaitUntilDelegate wud in WaitOns) { wud.Dispose(); } mre.Close(); } #endregion } public class WaitUntilDelegate : PrologGenericDelegate, IDisposable { public WaitUntilDelegateList parent; public object[] Result; public EventInfo Event; public object Instance; public WaitUntilDelegate(WaitUntilDelegateList re, EventInfo info, object instance) { parent = re; Event = info; Instance = instance; SetInstanceOfDelegateType(info.EventHandlerType); Event.AddEventHandler(instance, Delegate); } public override object CallProlog(params object[] paramz) { return CallPrologFast(paramz); } public override void CallPrologV(params object[] paramz) { CallPrologFast(paramz); } public override object CallPrologFast(object[] paramz) { Result = paramz; parent.Set(); return null; } #region Implementation of IDisposable /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// /// 2 public void Dispose() { Event.RemoveEventHandler(Instance, Delegate); } #endregion } }