Skip to content

Commit

Permalink
IDL_IDLBridge (as GDL2GDL) with only a simple posix message queue per…
Browse files Browse the repository at this point in the history
… subprocess. (#1879)
  • Loading branch information
GillesDuvert authored Sep 12, 2024
1 parent bc3197a commit 210068d
Show file tree
Hide file tree
Showing 12 changed files with 529 additions and 367 deletions.
2 changes: 1 addition & 1 deletion src/GDLInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// gets inserted after the antlr generated includes in the cpp file
#include "dinterpreter.hpp"
#include "prognodeexpr.hpp"

#include "gdleventhandler.hpp"
#include <cassert>

// tweaking ANTLR
Expand Down
12 changes: 7 additions & 5 deletions src/basic_pro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,8 @@ namespace lib {
for (int p = 0; p < maxLun; ++p) { //and NOT userlun!
fileUnits[p].Flush();
}
//before stopping a client, acknowledge the last ("EXIT") command otherwise the master is hanged.
if (signalOnCommandReturn) { //cout is NOT a tty. We just send GDL_SIGUSR2 to parent
signalOnCommandReturn = false;
gdl_ipc_sendsignalToParent();
// std::cout<<"signalOnCommandReturn is now "<<signalOnCommandReturn<<std::endl;
if (!iAmMaster){
gdl_ipc_ClientClosesMailBox();
}

BaseGDL* status = e->GetKW(1);
Expand Down Expand Up @@ -1174,6 +1171,7 @@ namespace lib {
}

void stop(EnvT* e) {
if (iAmMaster) {
if ( e->Interpreter()->IsInBatchProcedureAtMain() ) {
debugMode = DEBUG_STOP;
e->Throw("Prematurely closing batch file:");
Expand All @@ -1183,6 +1181,10 @@ namespace lib {
print(e);
debugMode = DEBUG_STOP_SILENT;
} else debugMode = DEBUG_STOP;
} else {
gdl_ipc_ClientSendReturn(2,"");
e->Throw("Use of STOP in Client mode!");
}
}

void defsysv(EnvT* e) {
Expand Down
101 changes: 50 additions & 51 deletions src/dinterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1081,7 +1081,7 @@ DInterpreter::CommandCode DInterpreter::ExecuteLine( istream* in, SizeT lineOffs
{
string line = (in != NULL) ? ::GetLine(in) : GetLine();

// cout << "ExecuteLine: " << line << endl;
// cout << "ExecuteLine: " << line << endl;

string firstChar = line.substr(0,1);

Expand Down Expand Up @@ -1365,6 +1365,7 @@ DInterpreter::CommandCode DInterpreter::ExecuteLine( istream* in, SizeT lineOffs
if( actualLine != "") lib::write_journal( actualLine);

if( retCode == RC_RETURN) return CC_RETURN;
if( retCode == RC_ABORT) return CC_ABORT;
return CC_OK;
}
catch( GDLException& e)
Expand All @@ -1386,13 +1387,17 @@ DInterpreter::CommandCode DInterpreter::ExecuteLine( istream* in, SizeT lineOffs
}
#define GDL_MAX_INPUT_STR_LENGTH 32766 //current limitation of our esteemed model

void inputThread() {
void KeyboardInputThread() {
while (1) {
// patch by Ole, 2017-01-06
//char ch = getchar(); if (ch==EOF) return NULL;
int ch = getchar(); //see #1377
if (ch==EOF) {
return;
if (ch == EOF) {
if( inputstr.size() == 0) {inputstr.assign("\x04"); return;}
else {
inputstr += '\n';
break;
}
}
inputstr += ch;
if (ch == '\n')
Expand All @@ -1401,39 +1406,40 @@ void inputThread() {
}

// if readline is not available or !EDIT_INPUT set to zero
char* DInterpreter::NoReadline( const string& prompt)
{
static const size_t inputStrMaxSize = MIN(GDL_MAX_INPUT_STR_LENGTH, inputstr.max_size()/2); //plenty of room left!!!
char* DInterpreter::NoReadline( const string& prompt) {
static const size_t inputStrMaxSize = MIN(GDL_MAX_INPUT_STR_LENGTH, inputstr.max_size() / 2); //plenty of room left!!!
if (isatty(0)) cout << prompt << flush;
if( feof(stdin)) return NULL;
if (feof(stdin)) return NULL;

std::thread th(inputThread);
std::thread::native_handle_type h=th.native_handle();
for (;;)
{
GDLEventHandler();
if (inputstr.size() > inputStrMaxSize) {
Warning ("Input line is too long for input buffer of " + i2s(inputStrMaxSize) + " characters.");
pthread_cancel(h);

exit (EXIT_FAILURE);
}
if (inputstr.size() && inputstr[inputstr.size() - 1] == '\n') break;
if (feof(stdin))
{
th.join();
return NULL;
}
std::thread th(KeyboardInputThread);
std::thread::native_handle_type h = th.native_handle();
for (;;) {
GDLEventHandler();
if (inputstr.size() > inputStrMaxSize) {
Warning("Input line is too long for input buffer of " + i2s(inputStrMaxSize) + " characters.");
pthread_cancel(h);

exit(EXIT_FAILURE);
}
//with precedent version, obviously not tested, the eventloop was not active as the exiting test on feof(stdin)
//was immediately true --- since no keyboard line was ever available!
if (inputstr.size()) {
if (inputstr[inputstr.size() - 1] == '\n') break;
if (inputstr == "\x04") { //KeyboardInputThread detected a ^D
th.join();
return NULL;
}
}
#ifdef _WIN32
Sleep(10);
Sleep(GDL_INPUT_TIMEOUT);
#else
usleep(10);
usleep(GDL_INPUT_TIMEOUT);
#endif
}
}
inputstr = inputstr.substr(0, inputstr.size() - 1); // removes '\n'
//if (inputstr[inputstr.size() - 1] == '\r')
// inputstr = inputstr.substr(0, inputstr.size() - 1); // removes '\r' too, if exists
char *result = (char*)malloc((inputstr.length() + 1) * sizeof(char));
char *result = (char*) malloc((inputstr.length() + 1) * sizeof (char));
strcpy(result, inputstr.c_str()); // copies including terminating '\0'
inputstr.clear();

Expand All @@ -1452,18 +1458,10 @@ void ControlCHandler(int)
sigControlC = true;
signal(SIGINT,ControlCHandler);
}
//for child: make it send a SIGUSR2 at end of command processed
void SignalMasterHandler(int)
{
std::cout<<"SignalMasterHandler received!";
signal(GDL_SIGUSR1,SignalMasterHandler);
}
//for child: make it send a SIGUSR2 at end of command processed
void SignalChildHandler(int)
void ChildControlCHandler(int)
{
// std::cout<<"signalOnCommandReturn was "<<signalOnCommandReturn<<std::endl;
signalOnCommandReturn=true;
signal(GDL_SIGUSR1,SignalChildHandler);
sigControlC = true;
signal(SIGINT,ChildControlCHandler);
}
string DInterpreter::GetLine()
{
Expand Down Expand Up @@ -1829,9 +1827,8 @@ RetCode DInterpreter::InterpreterLoop(const string& startup,
#endif
}
else {
signalOnCommandReturn = false;
gdl_ipc_acknowledge_suprocess_started(getpid());
}
gdl_ipc_ClientSignalsOperationsOK();
}
bool runCmd = false; // should tree from $MAIN$ be executed?
bool continueCmd = false; // .CONTINUE command given already?

Expand All @@ -1844,11 +1841,12 @@ RetCode DInterpreter::InterpreterLoop(const string& startup,
RunDelTree();
} else {
DInterpreter::CommandCode ret = ExecuteLine();
if (signalOnCommandReturn) { //cout is NOT a tty. We just send GDL_SIGUSR2 to parent
signalOnCommandReturn = false;
gdl_ipc_sendsignalToParent();
// std::cout<<"signalOnCommandReturn is now "<<signalOnCommandReturn<<std::endl;
}
if (!iAmMaster) {
if (ret == CC_OK) gdl_ipc_ClientSendReturn(2,"");
else if (ret == CC_ABORT) gdl_ipc_ClientSendReturn(4,"aborted");
ret=CC_OK;
} else {
if (ret == CC_ABORT) ret=CC_OK;
// stop stepping when at main level
stepCount = 0;
debugMode = DEBUG_CLEAR;
Expand All @@ -1870,6 +1868,7 @@ RetCode DInterpreter::InterpreterLoop(const string& startup,
cout << SysVar::MsgPrefix() <<
"Cannot continue from this point." << endl;
}
}
}
} catch (RetAllException& retAllEx) {
runCmd = (retAllEx.Code() == RetAllException::RUN);
Expand Down Expand Up @@ -1941,11 +1940,11 @@ RetCode DInterpreter::InterpreterLoop(const string& startup,
} // if( startup...
}
} catch (exception& e) {
cerr << "InterpreterLoop: Exception: " << e.what() << endl;
if (!iAmMaster) gdl_ipc_ClientSendReturn(3,e.what()); else cerr << "InterpreterLoop: Exception: " << e.what() << endl;
} catch (GDLException &e ) {
Warning(e.getMessage());
if (!iAmMaster) gdl_ipc_ClientSendReturn(3,e.getMessage()); else Warning(e.getMessage());
} catch (...) {
cerr << "InterpreterLoop: Unhandled Error." << endl;
if (!iAmMaster) gdl_ipc_ClientSendReturn(3,"InterpreterLoop: Unhandled Error." ); else cerr << "InterpreterLoop: Unhandled Error." << endl;
}
}
}
Expand Down
25 changes: 11 additions & 14 deletions src/dinterpreter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#ifndef DINTERPRETER_HPP_
#define DINTERPRETER_HPP_

#define GDL_INPUT_TIMEOUT 167 //16667 //microseconds -> 60 per second

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
Expand All @@ -26,18 +28,13 @@
#include <csignal>

#if defined(_WIN32) && !defined(__CYGWIN__)
#define GDL_SIGUSR1 SIGABRT //working replacement avoidng changing code?
#define GDL_SIGUSR2 SIGILL
extern int gdl_ipc_sendsignalToParent();
extern void gdl_ipc_acknowledge_suprocess_started(long long pid);
extern void gdl_ipc_ClientSignalsOperationsOK();
extern void gdl_ipc_ClientSendReturn(unsigned char status, std::string s);
extern void gdl_ipc_ClientClosesMailBox();
#else
#define GDL_SIGUSR1 SIGUSR1
#define GDL_SIGUSR2 SIGUSR2
extern int gdl_ipc_sendsignalToParent();
extern int gdl_ipc_sendCtrlCToChild(int pid);
extern int gdl_ipc_sendsignalToChild(int pid);
extern int gdl_ipc_SetReceiverForChildSignal(void (* handler)(int sig, siginfo_t *siginfo, void *context));
extern void gdl_ipc_acknowledge_suprocess_started(pid_t pid);
extern void gdl_ipc_ClientSignalsOperationsOK();
extern void gdl_ipc_ClientSendReturn(unsigned char status, std::string s);
extern void gdl_ipc_ClientClosesMailBox();
#endif

#include <cfenv>
Expand All @@ -59,8 +56,7 @@ extern void gdl_ipc_acknowledge_suprocess_started(pid_t pid);
#define AUTO_PRINT_EXPR

void ControlCHandler(int);
void SignalChildHandler(int);
void SignalMasterHandler(int);
void ChildControlCHandler(int);

extern bool lineEdit; // = false;
extern bool historyIntialized;
Expand All @@ -74,7 +70,8 @@ class DInterpreter: public GDLInterpreter
CC_CONTINUE,
CC_STEP,
CC_SKIP,
CC_RETURN
CC_RETURN,
CC_ABORT
};

char* NoReadline(const std::string&);
Expand Down
31 changes: 6 additions & 25 deletions src/gdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,6 @@
//initialize wxWidgets system: create an instance of wxAppGDL
#ifdef HAVE_LIBWXWIDGETS
#include "gdlwidget.hpp"
//displaced in gdlwidget.cpp to make wxGetApp() available under Python (in GDL.so)
//#ifndef __WXMAC__
//wxIMPLEMENT_APP_NO_MAIN( wxAppGDL);
//#else
//wxIMPLEMENT_APP_NO_MAIN( wxApp);
//#endif
#endif

#include "version.hpp"
Expand Down Expand Up @@ -164,6 +158,7 @@ void InitGDL()
//Our handler takes too long
//when editing the command line with ARROW keys. (bug 562). (used also in dinterpreted.cpp )
//but... without it we have no graphics event handler! FIXME!!!
rl_set_keyboard_input_timeout (GDL_INPUT_TIMEOUT);
rl_event_hook = GDLEventHandler;
#endif

Expand Down Expand Up @@ -240,7 +235,7 @@ int main(int argc, char *argv[])
bool gdlde = false;
bool setQuietSysvar=false;
bool willSuppressEditInput=false;
pid_t passed_pid=0;
std::string myMessageBoxName="";

//The default installation location --- will not always be there.
gdlDataDir = std::string(GDLDATADIR);
Expand Down Expand Up @@ -333,7 +328,6 @@ int main(int argc, char *argv[])
useDSFMTAcceleration = true;
iAmANotebook=false; //option --notebook
iAmMaster=true; //special option --subprocess
signalOnCommandReturn=false; //special option --subprocess
#ifdef HAVE_LIBWXWIDGETS

#if defined (__WXMAC__)
Expand Down Expand Up @@ -510,7 +504,7 @@ int main(int argc, char *argv[])
cerr << "gdl: --subprocess must be followed by the parent's pid" << endl;
return 0;
}
passed_pid = atoi(argv[++a]);
myMessageBoxName = argv[++a];
iAmMaster = false;
setQuietSysvar = true;
willSuppressEditInput = true;
Expand Down Expand Up @@ -543,13 +537,7 @@ int main(int argc, char *argv[])
}

//depending on master or not, attach to respective message boxes
if (iAmMaster) {
DefineG2GParentPid();
StartMasterMessageChannel();
} else {
DefineG2GParentPid(passed_pid);
AttachToMasterMessageChannel();
}
if (!iAmMaster) gdl_ipc_ClientGetsMailboxAddress(myMessageBoxName);

//before InitGDL() as InitGDL() starts graphic!

Expand All @@ -575,21 +563,14 @@ int main(int argc, char *argv[])
// for debug one could turn on all floating point exceptions, it will stop at first one.
// feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );

signal(SIGINT, ControlCHandler);

#if !defined(_WIN32)
if (iAmMaster) {
signal(GDL_SIGUSR1,SIG_IGN);
// signal(GDL_SIGUSR2,SIG_IGN);
signal(GDL_SIGUSR2,SignalMasterHandler);
signal(SIGINT, ControlCHandler);
signal(SIGCHLD,SIG_IGN); //end subprocess is by sending it 'EXIT'.
//This should avoid zombies after a IDL_IDLBridge::Cleanup for example.
// but we do not trap a subprocess crashing, which may be desirable!
}
else {
signal(GDL_SIGUSR1,SignalChildHandler);
signal(GDL_SIGUSR2,SIG_IGN);
}
} else signal(SIGINT, ChildControlCHandler);
#endif

// must be after !cpu initialisation
Expand Down
Loading

0 comments on commit 210068d

Please sign in to comment.