Re: Re-entrant and multi-entrant ABCL calls

Blake McBride <[email protected]>
Newsgroups gmane.editors.j.devel
Message-ID <CABwHSOunkRWQYDdKT45Zjd--MJzqX5RhoqYHSVte93eSVaw2Nw__47194.0584750429$1524223333$gmane$org@mail.gmail.com>
Thanks, Mark.  Here is a portion of what I am doing (written many years
ago):

public class ABCL {
   private static Interpreter interpreter;
   private static boolean invertCase = false;
   private static Function makeWebServiceArgs;
   private static int lispRelease = 0;
   private static boolean once = true;

   public static void init() {  // only called once
      interpreter = Interpreter.createInstance();
      invertCase();

      load("com/xxx/lisp/clos-utils");
      load("com/xxx/lisp/package-lru");
      load("com/xxx/lisp/utils");
      load("com/xxx/lisp/mappings");
      makeWebServiceArgs = findLispFunction("UTILS",
"make-web-service-args"); // this line is repeated in multiple places
   }

   private static void invertCase() {
      interpreter.eval("(setf (readtable-case *readtable*) :invert)");
 // make lisp case sensitive
      invertCase = true;
   }

   public static String fixCase(String symbol) {
      if (invertCase) {
         int ucl = 0, lcl = 0;
         char[] vec = symbol.toCharArray();
         for (int i=0 ; i < vec.length && (ucl == 0  ||  lcl == 0) ; i++)
            if (Character.isUpperCase(vec[i]))
               ucl++;
            else if (Character.isLowerCase(vec[i]))
               lcl++;
         if (ucl != 0  &&  lcl != 0  ||  ucl == 0  &&  lcl == 0)
            return symbol;
         else
            if (ucl != 0)
               return symbol.toLowerCase();
            else
               return symbol.toUpperCase();
      } else
         return symbol.toUpperCase();
   }

   public static void reset() {
//    if (interpreter == null)
//       return;
//    try {
//       interpreter.eval("(delete-package \"ARAHANT-UTILS\")");
//    } catch (Throwable t) {
//    }

      if (interpreter == null)
         return;
      try {
         interpreter.eval("(delete-package \"MAPPINGS\")");
      } catch (Throwable t) {
      }
      if (interpreter == null)
         return;
      try {
         interpreter.eval("(delete-package \"UTILS\")");
      } catch (Throwable t) {
      }
      if (interpreter == null)
         return;
      try {
         interpreter.eval("(delete-package \"PACKAGE-LRU\")");
      } catch (Throwable t) {
      }
      if (interpreter == null)
         return;
      try {
         interpreter.eval("(delete-package \"CLOS-UTILS\")");
      } catch (Throwable t) {
      }
      load("com/xxx/lisp/clos-utils");
      load("com/xxx/lisp/package-lru");
      load("com/xxx/lisp/utils");
      load("com/xxx/lisp/mappings");
      makeWebServiceArgs = findLispFunction("UTILS",
"make-web-service-args"); // this line is repeated in multiple places
   }

   public static LispObject load(String fileName) {
      return eval("(load \"" + FileSystemUtils.getSourcePath() +
fileName + "\")");
   }

   public static LispObject compileFile(String fileName) {
      return eval("(compile-file \"" + FileSystemUtils.getSourcePath()
+ fileName + "\")");
   }

   public static void loadPackage(String lispPackage, String fileName)
throws Exception {
      try {
         eval("(package-lru:load-package \"" + lispPackage + "\" \"" +
FileSystemUtils.getSourcePath() + fileName + "\")");
      } catch (Throwable t) {
         // Convert Throwable to Exception
         throw new Exception("Error loading lisp file " + fileName, t);
      }
   }

   public static void packageDone(String lispPackage) {
      if (FileSystemUtils.isUnderIDE())
         eval("(package-lru:package-done-unload \"" + lispPackage + "\")");
      else
         eval("(package-lru:package-done \"" + lispPackage + "\")");
   }

    public static LispObject eval(String str) {
        return interpreter.eval(str);
    }

    public static Function findLispFunction(String packageName, String
funName) {
        if (packageName == null  ||  packageName.isEmpty())
            packageName = "CL-USER";
//        else
//            packageName = fixCase(packageName);
        org.armedbear.lisp.Package lispPackage =
Packages.findPackage(packageName);
      if (lispPackage == null)
         throw new RuntimeException("Package " + packageName + " not found");
        Symbol symbol = lispPackage.findAccessibleSymbol(fixCase(funName));
      if (symbol == null)
         throw new RuntimeException("Symbol " + packageName + ":" +
fixCase(funName) + " not found");
        Function fun = (Function) symbol.getSymbolFunction();
        return fun;
    }

    public static LispObject executeLispFunction(Function fun, Object
... args) {
        LispObject [] jargs;
        jargs = new LispObject[args.length];
        for (int i=0 ; i < args.length ; i++)
            jargs[i] = JavaObject.getInstance(args[i], true);
        return fun.execute(jargs);
    }

    public static LispObject executeLisp(String packageName, String
funName, Object ... args) {
        Function fun = findLispFunction(packageName, funName);
      if (fun == null)
         return null;
        LispObject [] jargs;
        jargs = new LispObject[args.length];
        for (int i=0 ; i < args.length ; i++)
            jargs[i] = JavaObject.getInstance(args[i], true);
        return fun.execute(jargs);
    }

    public static LispObject executeLispArray(String packageName,
String funName, Object [] args) {
        Function fun = findLispFunction(packageName, funName);
      if (fun == null)
         return null;
        LispObject [] jargs;
        jargs = new LispObject[args.length];
        for (int i=0 ; i < args.length ; i++)
            jargs[i] = JavaObject.getInstance(args[i], true);
        return fun.execute(jargs);
    }

   public static Function getMakeWebServiceArgs() {
      return makeWebServiceArgs;
   }

@SuppressWarnings("unchecked")
   public static Object LispObjectToJavaObject(LispObject obj) {
      if (obj.atom())
         if (obj.characterp())
            return obj.princToString().charAt(0);
         else if (obj.stringp())
            return obj.princToString();
         else if (obj.integerp())
            return obj.intValue();
         else if (obj.realp())
            return obj.doubleValue();
         else if (obj.listp())
            return null;
         else if (obj.constantp())
            return true;
         else
            return obj.princToString();
      else if (obj.listp()) {
         LinkedList ll = new LinkedList();
         while (!obj.endp()) {
            ll.addLast(LispObjectToJavaObject(obj.car()));
            obj = obj.cdr();
         }
         return ll;
      } else if (obj.vectorp()) {
         int len = obj.length();
         Object [] vec = new Object[len];
         for (int i=0 ; i < len ; i++)
            vec[i] = LispObjectToJavaObject(obj.AREF(i));
         return vec;
      } else
         return null;
   }

   public static LispObject JavaObjectToLispObject(Object jobj) {
      if (jobj instanceof Boolean)
         return ((Boolean)jobj) ? Lisp.T : Lisp.NIL;
      else if (jobj instanceof Character)
         return LispCharacter.getInstance((Character)jobj);
      else if (jobj instanceof Short)
         return LispInteger.getInstance((Short)jobj);
      else if (jobj instanceof Integer)
         return LispInteger.getInstance((Integer)jobj);
      else if (jobj instanceof Long)
         return LispInteger.getInstance((Long)jobj);
      else if (jobj instanceof Float)
         return SingleFloat.getInstance((Float)jobj);
      else if (jobj instanceof Double)
         return DoubleFloat.getInstance((Double)jobj);
      else if (jobj instanceof String)
         return new SimpleString((String)jobj);
      else if (jobj instanceof StringBuilder)
         return new SimpleString((StringBuilder)jobj);
      else if (jobj instanceof LinkedList) {
         LispObject lobj = Lisp.NIL;
         ListIterator it = ((LinkedList) jobj).listIterator();
         while (it.hasNext())
            lobj = new Cons(JavaObjectToLispObject(it.next()), lobj);
         return lobj;
      } else if (jobj instanceof Set) {
         LispObject lobj = Lisp.NIL;
         Iterator it = ((Set) jobj).iterator();
         while (it.hasNext())
            lobj = new Cons(JavaObjectToLispObject(it.next()), lobj);
         return lobj;
      } else if (jobj instanceof Array) {
         Array a = (Array) jobj;
         int len = Array.getLength(a);
         SimpleVector vec = new SimpleVector(len);
         for (int i=0 ; i < len ; i++)
            vec.setSlotValue(i, JavaObjectToLispObject(Array.get(a, i)));
         return null;
      }
      return null;
   }

   public static void printStackTrace(Throwable e) {
      try {
         Function fun = findLispFunction("UTILS", "print-stack-trace");
         if (fun != null) {
            LispObject stackTrace = LispThread.currentThread().backtrace(0);
            if (stackTrace != null && stackTrace != Lisp.NIL) {
               System.err.println("Lisp execution error");
               fun.execute(stackTrace);
            }
         }
      } catch (Throwable t) {
      }
      e.printStackTrace();
   }

   public static int getLispRelease() {
      return lispRelease;
   }

   public static void setLispRelease(int lispRelease) {
      ABCL.lispRelease = lispRelease;
   }

}





On Fri, Apr 20, 2018 at 5:36 AM, Mark Evenson <[email protected]> wrote:

>
>
> > On Apr 20, 2018, at 11:10, Blake McBride <[email protected]> wrote:
> >
> > Greetings,
> >
> > Does ABCL safely support re-entrant and multi-entrant calls?  What I
> mean by that is the following:
> >
> > Re-entrant:  on a single OS thread - my Java program calls into ABCL,
> then ABCL calls into my Java application, and then the Java application
> calls back into ABCL.  So the stack has Java, ABCL, JAVA, and then ABCL
> again.
> >
> > Multi-entrant:  my Java application has many threads.  One of my threads
> calls into ABCL.  Then, while one thread is still in ABCL, another thread
> evokes ABCL.  So now we have two calls into ABCL by two independent Java/OS
> threads running at the same time.
> >
> > I understand the typical problems associated with application-level
> shared variables.  This is expected.  The question revolves around ABCL's
> internals.  I presume ABCL would have some shared data that is internal to
> ABCL.  That's what I am unclear about.  ABCL would have had to be designed
> for these scenarios from the ground up.
> >
> > This is a little hard to test because if it can't always correctly
> handle these situations, it may not become clear until certain scenarios
> arrive.  It may be hard for any "test" program I write to cause those
> scenarios, so I thought this may be a known answer.
>
>
> As long as one is referencing the org.armedbear.lisp.Interpreter singleton
> for
> the calls into ABCL, everything should work fine.  Most of the logic can be
> understood by studying what [LispThread.java][1] does to mark global/local
> special variables, and how each Java thread is associated with a LispThread
> call stack.
>
> [1]: https://gitlab.common-lisp.net/abcl/abcl/blob/master/src/
> org/armedbear/lisp/LispThread.java#L55
>
> How exactly are you calling into ABCL from Java?  A snippet of code would
> be
> useful.
>
>
>
>
> --
> "A screaming comes across the sky.  It has happened before but there is
> nothing
> to compare to it now."
>
>
>
>
>
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.