Skip to content

IDL_IDLBridge (as GDL2GDL) with only a simple posix message queue per subprocess. #1879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading