@Override public Object[] returningFeval(String functionName, int nargout, Object... args) throws MatlabInvocationException { // Functions with no arguments should be passed null, not an empty array if (args != null && args.length == 0) { args = null; } try { Object matlabResult = Matlab.mtFevalConsoleOutput(functionName, args, nargout); Object[] resultArray; if (nargout == 0) { resultArray = new Object[0]; } else if (nargout == 1) { resultArray = new Object[] {matlabResult}; } // If multiple return values then an Object[] should have been returned else { if (matlabResult == null) { String errorMsg = "Expected " + nargout + " return arguments, instead null was returned"; throw MatlabInvocationException.Reason.NARGOUT_MISMATCH.asException(errorMsg); } else if (!matlabResult.getClass().equals(Object[].class)) { String errorMsg = "Expected " + nargout + " return arguments, instead 1 argument was returned"; throw MatlabInvocationException.Reason.NARGOUT_MISMATCH.asException(errorMsg); } resultArray = (Object[]) matlabResult; if (nargout != resultArray.length) { String errorMsg = "Expected " + nargout + " return arguments, instead " + resultArray.length + (resultArray.length == 1 ? " argument was" : " arguments were") + " returned"; throw MatlabInvocationException.Reason.NARGOUT_MISMATCH.asException(errorMsg); } } return resultArray; } catch (Exception e) { throw MatlabInvocationException.Reason.INTERNAL_EXCEPTION.asException( new ThrowableWrapper(e)); } }
/** * Exits MATLAB without waiting for MATLAB to return, because MATLAB will not return when exiting. * * @throws MatlabInvocationException */ static void exit() { Runnable runnable = new Runnable() { @Override public void run() { try { Matlab.mtFevalConsoleOutput("exit", null, 0); } // This should never fail, and if it does there is no way to consistently report it back // to the caller // because this method does not block catch (Exception e) { } } }; if (NativeMatlab.nativeIsMatlabThread()) { runnable.run(); } else { Matlab.whenMatlabIdle(runnable); } }
/** * Invokes the {@code callable} on the main MATLAB thread and waits for the computation to be * completed. * * @param <T> * @param callable * @return * @throws MatlabInvocationException */ static <T> T invokeAndWait(final MatlabThreadCallable<T> callable) throws MatlabInvocationException { T result; if (NativeMatlab.nativeIsMatlabThread()) { try { result = callable.call(THREAD_OPERATIONS); } catch (RuntimeException e) { ThrowableWrapper cause = new ThrowableWrapper(e); throw MatlabInvocationException.Reason.RUNTIME_EXCEPTION.asException(cause); } } else if (EventQueue.isDispatchThread()) { final AtomicReference<MatlabReturn<T>> returnRef = new AtomicReference<MatlabReturn<T>>(); Matlab.whenMatlabIdle( new Runnable() { @Override public void run() { MatlabReturn<T> matlabReturn; try { matlabReturn = new MatlabReturn<T>(callable.call(THREAD_OPERATIONS)); } catch (MatlabInvocationException e) { matlabReturn = new MatlabReturn<T>(e); } catch (RuntimeException e) { ThrowableWrapper cause = new ThrowableWrapper(e); MatlabInvocationException userCausedException = MatlabInvocationException.Reason.RUNTIME_EXCEPTION.asException(cause); matlabReturn = new MatlabReturn<T>(userCausedException); } returnRef.set(matlabReturn); } }); // Pump event queue while waiting for MATLAB to complete the computation try { while (returnRef.get() == null) { if (EVENT_QUEUE.peekEvent() != null) { EVENT_QUEUE_DISPATCH_METHOD.invoke(EVENT_QUEUE, EVENT_QUEUE.getNextEvent()); } } } catch (InterruptedException e) { throw MatlabInvocationException.Reason.EVENT_DISPATCH_THREAD.asException(e); } catch (IllegalAccessException e) { throw MatlabInvocationException.Reason.EVENT_DISPATCH_THREAD.asException(e); } catch (InvocationTargetException e) { throw MatlabInvocationException.Reason.EVENT_DISPATCH_THREAD.asException(e); } // Process return MatlabReturn<T> matlabReturn = returnRef.get(); // If exception was thrown, rethrow it if (matlabReturn.exception != null) { throw matlabReturn.exception; } // Return data computed by MATLAB else { result = matlabReturn.data; } } else { // Used to block the calling thread while waiting for MATLAB to finish computing final ArrayBlockingQueue<MatlabReturn<T>> returnQueue = new ArrayBlockingQueue<MatlabReturn<T>>(1); Matlab.whenMatlabIdle( new Runnable() { @Override public void run() { MatlabReturn<T> matlabReturn; try { matlabReturn = new MatlabReturn<T>(callable.call(THREAD_OPERATIONS)); } catch (MatlabInvocationException e) { matlabReturn = new MatlabReturn<T>(e); } catch (RuntimeException e) { ThrowableWrapper cause = new ThrowableWrapper(e); MatlabInvocationException userCausedException = MatlabInvocationException.Reason.RUNTIME_EXCEPTION.asException(cause); matlabReturn = new MatlabReturn<T>(userCausedException); } returnQueue.add(matlabReturn); } }); try { // Wait for MATLAB's main thread to finish computation MatlabReturn<T> matlabReturn = returnQueue.take(); // If exception was thrown, rethrow it if (matlabReturn.exception != null) { throw matlabReturn.exception; } // Return data computed by MATLAB else { result = matlabReturn.data; } } catch (InterruptedException e) { throw MatlabInvocationException.Reason.INTERRRUPTED.asException(e); } } return result; }