# HG changeset patch # User samer # Date 1328056068 0 # Node ID 440734a35533f5519b42b1591370925773281d39 # Parent 85c19a49cf7e17ace939fb6455e1fabe8d98f7a1 Almost working work around. diff -r 85c19a49cf7e -r 440734a35533 cpp/Makefile --- a/cpp/Makefile Mon Jan 30 23:10:44 2012 +0000 +++ b/cpp/Makefile Wed Feb 01 00:27:48 2012 +0000 @@ -4,7 +4,7 @@ TARGET=plml.$(SO) INCML=$(MATLAB)/extern/include LIBML=$(MATLAB)/bin/$(MLARCH) -PLLDFLAGS=$(CXX) $(INCLUDES) -I$(INCML) -Wall +PLLDFLAGS=$(CXX) $(INCLUDES) -I$(INCML) -Wall -g3 .SUFFIXES: .cpp .o .so .dylib diff -r 85c19a49cf7e -r 440734a35533 cpp/plml.cpp --- a/cpp/plml.cpp Mon Jan 30 23:10:44 2012 +0000 +++ b/cpp/plml.cpp Wed Feb 01 00:27:48 2012 +0000 @@ -88,7 +88,7 @@ #define BUFSIZE 32768 // buffer for matlab output #define MAXCMDLEN 256 // #define EVALFMT "t__ex=[];\ntry\n%s\ncatch t__ex\ndisp(getReport(t__ex))\nend" -#define EVALFMT "lasterr(''); %s\nt__ex=lasterr;if ~isempty(t__ex), beep; end" +#define EVALFMT "lasterr('');disp(' ');%s\nt__ex=lasterr;" using namespace std; @@ -473,6 +473,22 @@ } } + +static int raise_exception(const char *msg) { + printf("\n!! raising exception: %s\n",msg); + // return FALSE; + + term_t ex = PL_new_term_ref(); + int rc; + + rc = PL_unify_term(ex, PL_FUNCTOR_CHARS, "error", 2, + PL_FUNCTOR_CHARS, "plml_error", 1, + PL_CHARS, msg, + PL_VARIABLE); + + return PL_raise_exception(ex); +} + /* * Workspace variable handling */ @@ -485,35 +501,40 @@ foreign_t mlWSAlloc(term_t eng, term_t blob) { // if varname is already bound, we should check // that the name has not been used in the workspace - try { - class eng *engine=findEngine(eng); - struct wsvar x; - int rc; + class eng *engine; + try { engine=findEngine(eng); } + catch (PlException ex) { return ex.plThrow(); } - // in a threaded world, there would either need to be precisely - // one engine per thread (so that there are no race conditions on - // the Matlab side) or else these lines (down to PL_unify_blob) - // need to be atomic. - x.engine = engine->ep; - x.id = engine->id; + //printf("-- Entering mlWSALLOC \r"); fflush(stdout); + struct wsvar x; + int rc; - if (engEvalString(x.engine, "t__0=uniquevar([]);")) - throw PlException("Cannot execute uniquevar"); + x.engine = engine->ep; + x.id = engine->id; - memset(x.name,sizeof(x.name),0); - mxArray *newname=engGetVariable(x.engine, "t__0"); - if (newname==NULL) { - engEvalString(x.engine,"clear(t__0)"); // half arsed attempt to fix variable leak - throw PlException("Cannot get new variable name."); - } - rc = mxGetString(newname,x.name, sizeof(x.name)); - mxDestroyArray(newname); - if (rc) throw PlException("Cannot read new variable name."); + // printf("-- mlWSAlloc: Calling uniquevar... \r"); fflush(stdout); + if (engEvalString(x.engine, "t__0=uniquevar([])")) { + return raise_exception("mlWSAlloc: Cannot execute uniquevar"); + } - return PL_unify_blob(blob,&x,sizeof(x),&ws_blob); - } catch (PlException &e) { - return e.plThrow(); + // fputs("\n>",stdout); fputs(engine->outbuf,stdout); fputs("<\n",stdout); + if (strlen(engine->outbuf)==0) { + return raise_exception("mlWSAlloc: Empty output buffer."); } + memset(x.name,sizeof(x.name),0); + // printf(" - mlWSAlloc: Getting variable name... \r"); fflush(stdout); + mxArray *newname=engGetVariable(x.engine, "t__0"); + if (newname==NULL) { + return raise_exception("mlWSAlloc: Cannot get new variable name."); + } + rc = mxGetString(newname,x.name, sizeof(x.name)); + mxDestroyArray(newname); + if (rc) { + return raise_exception("mlWSAlloc: Cannot read new variable name."); + } + + // printf(" \r"); fflush(stdout); + return PL_unify_blob(blob,&x,sizeof(x),&ws_blob); } foreign_t mlWSName(term_t blob, term_t name, term_t engine) { @@ -533,9 +554,9 @@ foreign_t mlWSGet(term_t var, term_t val) { try { struct wsvar *x = term_to_wsvar(var); - printf("-- Entering mlWSGET \r"); fflush(stdout); + //printf(" - mlWSGET \r"); fflush(stdout); mxArray *p = engGetVariable(x->engine, x->name); - printf("-- Leaving mlWSGET \r"); fflush(stdout); + //printf(" \r"); fflush(stdout); return PL_unify_blob(val, (void **)&p, sizeof(p), &mx_blob); } catch (PlException &e) { return e.plThrow(); @@ -560,7 +581,7 @@ // Call a Matlab engine to execute the given command foreign_t mlExec(term_t engine, term_t cmd) { - printf("-- Entering mlEXEC \r"); fflush(stdout); + // printf(" - mlExec: Entering \r"); fflush(stdout); try { eng *eng=findEngine(engine); const char *cmdstr=PlTerm(cmd); @@ -580,52 +601,35 @@ eval_cmd = new char[cmdlen+strlen(EVALFMT)-1]; if (eval_cmd==NULL) throw PlException("Failed to allocate memory for command"); sprintf(eval_cmd, EVALFMT, cmdstr); - printf("-- Calling Matlab engine... \r"); fflush(stdout); + //printf("-- Calling Matlab engine... \r"); fflush(stdout); rc=engEvalString(eng->ep,eval_cmd); - printf("-- Returned from Matlab engine... \r"); fflush(stdout); + //printf("-- Returned from Matlab engine... \r"); fflush(stdout); delete [] eval_cmd; - if (rc) printf("** MATLAB evaluation error. Output buffer contains:\n"); + // EVALFMT starts with disp(' '). This means that the output buffer should + // contain at least the 5 characters: ">> *\n". If they are not there, + // something is terribly wrong and we must throw an exeption to avoid + // locking up. + if (strlen(eng->outbuf)<5) { + printf("\n** mlExec: evaluation error. Empty output buffer.\n"); + throw PlException("mlExec: empty output buffer"); + } + if (rc) printf("\n** mlExec: evaluation error. Output buffer contains:\n"); // write whatever is in the output buffer now. - fputs(eng->outbuf,stdout); + fputs(eng->outbuf+5,stdout); if (PL_handle_signals()<0) { - printf("** ml_exec: evaluation interrupted by signal.\n"); + printf("\n** mlExec: evaluation interrupted by signal.\n"); return FALSE; } - /* { - int rc; - printf( "--- sleeping for 3 seconds\n"); - rc=usleep(3000000); - //printf("press return.\n"); - //rc=getchar(); - printf( "--- returned %d.\n",rc); - } */ - - // SA 2010. Giving up any pretence of being thread-safe - - // each engine is to be used by one Prolog thread ONLY. - // If you want fancy threading stuff, do it in Prolog. - - - printf("-- Getting last error... \r"); fflush(stdout); + //printf(" - mlExec: Getting last error... \r"); fflush(stdout); mxArray *lasterr = engGetVariable(eng->ep, "t__ex"); - printf("-- Got last error (%p) \r",lasterr); fflush(stdout); - -// if (PL_handle_signals()<0) { -// printf(" * ml_exec: getting lasterr interrupted by signal.\n"); -// return FALSE; -// } + //printf(" - mlExec: Got last error (%p) \r",lasterr); fflush(stdout); if (!lasterr) { - printf("** Failing due to inability to get lasterr.\n"); - return FALSE; - - //PlTerm msg=PlTerm("Failed to get Matlab lasterr."); - //printf("Preparing lasterr=0 exception.\n"); - //PlException ex=PlException(msg); - //printf("Throwing lasterr=0 exception.\n"); - //throw ex; + printf("\n** mlExec: unable to get lasterr.\n"); + throw PlException("mlExec: unable to get lasterr"); } if (mxGetNumberOfElements(lasterr)>0) { @@ -646,10 +650,10 @@ } else mxDestroyArray(lasterr); // if we've got this far, then everything went well, so - printf("-- Returning from mlEXEC \r"); fflush(stdout); + printf(" \r"); fflush(stdout); return TRUE; } catch (PlException &e) { - printf("** Throwing exception\n"); + printf("\n** mlExec: Throwing exception\n"); return e.plThrow(); } } diff -r 85c19a49cf7e -r 440734a35533 prolog/plml.pl --- a/prolog/plml.pl Mon Jan 30 23:10:44 2012 +0000 +++ b/prolog/plml.pl Wed Feb 01 00:27:48 2012 +0000 @@ -338,7 +338,7 @@ % even when multiple values are required. ml_eval(Id,X,Types,Vals) :- maplist(alloc_ws(Id),Types,Vars), - ml_exec(Id,hide(wsx(Vars)=X)), flush_output, + ml_exec(Id,hide(wsx(Vars)=X)), maplist(convert_ws,Types,Vars,Vals). alloc_ws(I,_,Z) :- mlWSALLOC(I,Z). @@ -625,7 +625,8 @@ bt_call(db_save_all(I,ws(Z),L,Size), db_drop_all(I,L,Size)). % Most other conversions from ws(_) go via mx(_) -convert_ws(T,Z,A) :- mlWSGET(Z,X), convert_mx(T,X,A). +convert_ws(T,Z,A) :- + mlWSGET(Z,X), convert_mx(T,X,A). %% convert_mx( +Type:type, +In:mx_blob, -Out:Type) is det.