|
||||
Warning, file /jana2/src/python/plugins/janapy/janapy_plugin.cc was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 // 0002 // Copyright 2020, Jefferson Science Associates, LLC. 0003 // Subject to the terms in the LICENSE file found in the top-level directory. 0004 0005 0006 #include <thread> 0007 #include <mutex> 0008 #include <chrono> 0009 using namespace std; 0010 0011 0012 #include <JANA/JApplication.h> 0013 #include <JANA/Utils/JCpuInfo.h> 0014 #include <JANA/Services/JParameterManager.h> 0015 0016 #include <janapy.h> 0017 #include <pybind11/embed.h> 0018 0019 extern std::mutex pymutex; // declared in JEventProcessorPY.h 0020 0021 void JANA_EmbeddedPythonModuleInit(JApplication *sApp); 0022 0023 extern "C"{ 0024 __attribute__((visibility("default"))) // counteract the -fvisibility=hidden compiler option 0025 void InitPlugin(JApplication *app){ 0026 InitJANAPlugin(app); 0027 0028 // Launch thread to set up python interface and execute user script. 0029 // This is done in a thread in case the script needs to continue 0030 // running throughout the life of the process. 0031 std::thread thr(JANA_EmbeddedPythonModuleInit, app); 0032 thr.detach(); 0033 0034 // Wait for python interface to set up and user script to execute 0035 // until it indicates it is ready for JANA system to continue. 0036 // This allows more control from python by stalling the initialization 0037 // so it has a chance to modify things a bit before full JANA 0038 // initialization completes and data processing starts. 0039 while( !PY_INITIALIZED ) std::this_thread::sleep_for (std::chrono::milliseconds(100)); 0040 } 0041 0042 void FinalizePlugin(JApplication */*app*/){ 0043 // Finalize the python interpreter 0044 if( PY_INITIALIZED ) { 0045 // Wait upt to 2 seconds for interpreter to not be in use before finalizing it. 0046 for(int i=0; i<20; i++) { 0047 if (pymutex.try_lock()) { 0048 PY_INITIALIZED = false; 0049 // TODO: Fix this 0050 // There is an issue with seg faults when dlclose is called on the janapy plugin 0051 // if we call finalize here. I tried to ensure no other python methods were being 0052 // called, but couldn't find how to plug things up completely. Thus, to avoid 0053 // crashes when ending (especially when ctl-C is hit) we do not finalize the 0054 // python interpreter. 0055 py::finalize_interpreter(); 0056 break; 0057 } 0058 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 0059 } 0060 } 0061 } 0062 } // "C" 0063 0064 //..................................................... 0065 0066 0067 //================================================================================ 0068 0069 //------------------------------------- 0070 // JANA_EmbeddedPythonModuleInit 0071 //------------------------------------- 0072 void JANA_EmbeddedPythonModuleInit(JApplication *sApp) 0073 { 0074 /// This will initialize the jana Python system and import the 0075 /// JANA module (defined by the routines in this file). This gets called 0076 /// when the janapy plugin gets initialized. It will then automatically 0077 /// look for a file whose name is given by either the JANA_PYTHON_FILE 0078 /// config. parameter or environment variable in that order. If neither 0079 /// exists, it looks for a file name "jana.py" in the current working 0080 /// directory and if found, executes that. If you do not wish to execute 0081 /// a python file, then you can set the JANA_PYTHON_FILE value to an empty 0082 /// string (or better yet, just not attach the janapy plugin!). 0083 /// 0084 /// IMPORTANT: The janapy InitPlugin routine will block (resulting in the whole 0085 /// JANA system pausing) until either this routine finishes or the python script 0086 /// it invokes calls "jana.Start()" or "jana.Run()". This is to give the python script 0087 /// a chance to modify running conditions prior to event processing starting. 0088 /// If the python script intends to run throughout the life of the process, 0089 /// then it MUST call jana.Start() at some point. If the script is small and only 0090 /// runs for a short time, then you don't need to call it since it will be 0091 /// called automatically when the script ends. 0092 0093 // Initialize the python interpreter. It will be finalized (shutdown) 0094 // when the plugin is detached in the FinalizePlugin routine above. 0095 py::initialize_interpreter(); 0096 0097 // Use existing JApplication. 0098 pyjapp = sApp; 0099 0100 // Get name of python file to execute 0101 string fname = "jana.py"; 0102 try{ 0103 fname = pyjapp->GetParameterValue<string>("JANA_PYTHON_FILE"); 0104 }catch(...){ 0105 auto JANA_PYTHON_FILE = getenv("JANA_PYTHON_FILE"); 0106 if( JANA_PYTHON_FILE ) fname = JANA_PYTHON_FILE; 0107 } 0108 0109 // Fill in the script name in sys.argv. This is needed for tkinter which 0110 // is hardcoded to look at sys.argv[0]. 0111 std::vector<wchar_t*> argv; 0112 auto wfname = std::wstring(fname.begin(), fname.end()); 0113 argv.push_back( (wchar_t*)wfname.c_str() ); 0114 PySys_SetArgv(argv.size(), argv.data()); 0115 0116 // Execute python script. 0117 // n.b. The script may choose to run for the lifetime of the program! 0118 try { 0119 std::cout << "[INFO] Executing python script: " << fname << std::endl; 0120 py::eval_file(fname); 0121 std::cout << "[INFO] Finished executing python script " << std::endl; 0122 }catch(std::runtime_error &e){ 0123 std::cerr << std::endl; 0124 std::cerr << string(60, '-') << std::endl; 0125 std::cerr << "ERROR processing python file: \"" << fname << "\"" << std::endl; 0126 std::cerr << e.what() << std::endl; 0127 std::cerr << std::endl; 0128 if( string(e.what()).find("could not be opened!") != string::npos) { 0129 std::cerr << "Please make sure one of the following is true:" << std::endl; 0130 std::cerr << " - The file \"" << fname << "\" exists" << std::endl; 0131 std::cerr << " - The JANA_PYTHON_FILE config. parameter points to a file that exists" << std::endl; 0132 std::cerr << " - The janapy plugin is not in the configuration for the job" << std::endl; 0133 } 0134 std::cerr << string(60, '-') << std::endl; 0135 std::cerr << std::endl; 0136 pyjapp->Quit(); 0137 } 0138 0139 PY_INITIALIZED = true; 0140 } 0141 0142 0143 //================================================================================ 0144 // Module definition 0145 // The arguments of this structure tell Python what to call the extension, 0146 // what it's methods are and where to look for it's method definitions. 0147 // The routines themselves are all defined in src/python/common/janapy.h 0148 // and src/python/common/janapy.cc. 0149 PYBIND11_EMBEDDED_MODULE(jana, m) { 0150 0151 m.doc() = "JANA2 Embedded Python Interface"; 0152 0153 // (see src/python/common/janapy.h) 0154 JANA_MODULE_DEF 0155 }
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |