"Fossies" - the Fresh Open Source Software Archive 
Member "netxms-3.8.166/src/libnxpython/manager.cpp" (23 Feb 2021, 11007 Bytes) of package /linux/misc/netxms-3.8.166.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "manager.cpp" see the
Fossies "Dox" file reference documentation.
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2018 Raden Solutions
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: manager.cpp
20 **
21 **/
22
23 #include "libnxpython.h"
24 #include <nxqueue.h>
25
26 #define DEBUG_TAG _T("python")
27
28 /**
29 * "netxms" module initialization function
30 */
31 PyObject *PyInit_netxms();
32
33 /**
34 * Extra modules
35 */
36 static NXPYTHON_MODULE_INFO *s_extraModules = NULL;
37
38 /**
39 * Manager request queue
40 */
41 static Queue s_managerRequestQueue;
42
43 /**
44 * Manager request
45 */
46 struct PythonManagerRequest
47 {
48 int command;
49 PyThreadState *interpreter;
50 CONDITION condition;
51
52 PythonManagerRequest()
53 {
54 command = 0; // create interpreter
55 interpreter = NULL;
56 condition = ConditionCreate(true);
57 }
58
59 PythonManagerRequest(PyThreadState *pi)
60 {
61 command = 1; // destroy interpreter
62 interpreter = pi;
63 condition = ConditionCreate(true);
64 }
65
66 ~PythonManagerRequest()
67 {
68 ConditionDestroy(condition);
69 }
70
71 void wait()
72 {
73 ConditionWait(condition, INFINITE);
74 }
75
76 void notify()
77 {
78 ConditionSet(condition);
79 }
80 };
81
82 /**
83 * Manager thread
84 */
85 static THREAD_RESULT THREAD_CALL PythonManager(void *arg)
86 {
87 PyImport_AppendInittab("netxms", PyInit_netxms);
88 if (s_extraModules != NULL)
89 {
90 for(int i = 0; s_extraModules[i].name != NULL; i++)
91 {
92 PyImport_AppendInittab(s_extraModules[i].name, s_extraModules[i].initFunction);
93 }
94 }
95 Py_InitializeEx(0);
96 char version[128];
97 strlcpy(version, Py_GetVersion(), 128);
98 char *p = strchr(version, ' ');
99 if (p != NULL)
100 *p = 0;
101
102 PyEval_InitThreads();
103 PyThreadState *mainPyThread = PyEval_SaveThread();
104 ConditionSet(static_cast<CONDITION>(arg));
105 nxlog_debug_tag(DEBUG_TAG, 1, _T("Embedded Python interpreter (version %hs) initialized"), version);
106
107 while(true)
108 {
109 PythonManagerRequest *request = static_cast<PythonManagerRequest*>(s_managerRequestQueue.getOrBlock());
110 if (request == INVALID_POINTER_VALUE)
111 break;
112
113 PyEval_AcquireThread(mainPyThread);
114 switch(request->command)
115 {
116 case 0: // create interpreter
117 request->interpreter = Py_NewInterpreter();
118 if (request->interpreter != NULL)
119 {
120 PyRun_SimpleString(
121 "import importlib.abc\n"
122 "import importlib.machinery\n"
123 "import sys\n"
124 "\n"
125 "class Finder(importlib.abc.MetaPathFinder):\n"
126 " def find_spec(self, fullname, path, target=None):\n"
127 " if fullname in sys.builtin_module_names:\n"
128 " return importlib.machinery.ModuleSpec(\n"
129 " fullname,\n"
130 " importlib.machinery.BuiltinImporter,\n"
131 " )\n"
132 "\n"
133 "sys.meta_path.append(Finder())\n"
134 );
135
136 PyThreadState_Swap(mainPyThread);
137 nxlog_debug_tag(DEBUG_TAG, 6, _T("Created Python interpreter instance %p"), request->interpreter);
138 }
139 else
140 {
141 nxlog_debug_tag(DEBUG_TAG, 6, _T("Cannot create Python interpreter instance"));
142 }
143 break;
144 case 1: // destroy interpreter
145 PyThreadState_Swap(request->interpreter);
146 Py_EndInterpreter(request->interpreter);
147 PyThreadState_Swap(mainPyThread);
148 nxlog_debug_tag(DEBUG_TAG, 6, _T("Destroyed Python interpreter instance %p"), request->interpreter);
149 break;
150 }
151 PyEval_ReleaseThread(mainPyThread);
152 request->notify();
153 }
154
155 PyEval_RestoreThread(mainPyThread);
156 Py_Finalize();
157 nxlog_debug_tag(DEBUG_TAG, 1, _T("Embedded Python interpreter terminated"));
158 return THREAD_OK;
159 }
160
161 /**
162 * Create Python sub-interpreter
163 */
164 PythonInterpreter *PythonInterpreter::create()
165 {
166 PythonManagerRequest r;
167 s_managerRequestQueue.put(&r);
168 r.wait();
169 return (r.interpreter != NULL) ? new PythonInterpreter(r.interpreter) : NULL;
170 }
171
172 /**
173 * Internal constructor
174 */
175 PythonInterpreter::PythonInterpreter(PyThreadState *s)
176 {
177 m_threadState = s;
178 m_mainModule = NULL;
179 }
180
181 /**
182 * Destructor
183 */
184 PythonInterpreter::~PythonInterpreter()
185 {
186 if (m_mainModule != NULL)
187 {
188 PyEval_AcquireThread(m_threadState);
189 Py_DECREF(m_mainModule);
190 m_mainModule = NULL;
191 PyEval_ReleaseThread(m_threadState);
192 }
193 PythonManagerRequest r(m_threadState);
194 s_managerRequestQueue.put(&r);
195 r.wait();
196 }
197
198 /**
199 * Log execution error
200 */
201 void PythonInterpreter::logExecutionError(const TCHAR *format)
202 {
203 PyObject *type, *value, *traceback;
204 PyErr_Fetch(&type, &value, &traceback);
205 PyObject *text = (value != NULL) ? PyObject_Str(value) : NULL;
206 #ifdef UNICODE
207 nxlog_debug_tag(DEBUG_TAG, 6, format, (text != NULL) ? PyUnicode_AsUnicode(text) : L"error text not provided");
208 #else
209 nxlog_debug_tag(DEBUG_TAG, 6, format, (text != NULL) ? PyUnicode_AsUTF8(text) : "error text not provided");
210 #endif
211 if (text != NULL)
212 Py_DECREF(text);
213 if (type != NULL)
214 Py_DECREF(type);
215 if (value != NULL)
216 Py_DECREF(value);
217 if (traceback != NULL)
218 Py_DECREF(traceback);
219 }
220
221 /**
222 * Load and execute module from given source
223 */
224 PyObject *PythonInterpreter::loadModule(const char *source, const char *moduleName, const char *fileName)
225 {
226 PyObject *module = NULL;
227 PyEval_AcquireThread(m_threadState);
228
229 PyObject *code = Py_CompileString(source, (fileName != NULL) ? fileName : ":memory:", Py_file_input);
230 if (code != NULL)
231 {
232 module = PyImport_ExecCodeModuleEx(moduleName, code, fileName);
233 if (module == NULL)
234 {
235 TCHAR format[256];
236 _sntprintf(format, 256, _T("Cannot import module %hs (%%s)"), moduleName);
237 logExecutionError(format);
238 }
239 Py_DECREF(code);
240 }
241 else
242 {
243 logExecutionError(_T("Source compilation failed (%s)"));
244 }
245
246 PyEval_ReleaseThread(m_threadState);
247 return module;
248 }
249
250 /**
251 * Load source code from file and execute
252 */
253 PyObject *PythonInterpreter::loadModuleFromFile(const TCHAR *fileName, const char *moduleName)
254 {
255 char *source = LoadFileAsUTF8String(fileName);
256 if (source == NULL)
257 return NULL;
258 #ifdef UNICODE
259 char *utfFileName = UTF8StringFromWideString(fileName);
260 PyObject *module = loadModule(source, moduleName, utfFileName);
261 free(utfFileName);
262 #else
263 bool success = loadModule(source, moduleName, fileName);
264 #endif
265 free(source);
266 return module;
267 }
268
269 /**
270 * Load main module
271 */
272 bool PythonInterpreter::loadMainModule(const char *source, const char *fileName)
273 {
274 bool success = false;
275 PyEval_AcquireThread(m_threadState);
276
277 if (m_mainModule != NULL)
278 {
279 Py_DECREF(m_mainModule);
280 m_mainModule = NULL;
281 }
282
283 PyObject *code = Py_CompileString(source, (fileName != NULL) ? fileName : ":memory:", Py_file_input);
284 if (code != NULL)
285 {
286 m_mainModule = PyImport_ExecCodeModuleEx("__main__", code, fileName);
287 if (m_mainModule != NULL)
288 {
289 success = true;
290 }
291 else
292 {
293 logExecutionError(_T("Cannot create __main__ module (%s)"));
294 }
295 Py_DECREF(code);
296 }
297 else
298 {
299 logExecutionError(_T("Source compilation failed (%s)"));
300 }
301
302 PyEval_ReleaseThread(m_threadState);
303 return success;
304 }
305
306 /**
307 * Load main module from file
308 */
309 bool PythonInterpreter::loadMainModuleFromFile(const TCHAR *fileName)
310 {
311 char *source = LoadFileAsUTF8String(fileName);
312 if (source == NULL)
313 return false;
314 #ifdef UNICODE
315 char *utfFileName = UTF8StringFromWideString(fileName);
316 bool success = loadMainModule(source, utfFileName);
317 free(utfFileName);
318 #else
319 bool success = loadMainModule(source, fileName);
320 #endif
321 free(source);
322 return success;
323 }
324
325 /**
326 * Call function in main module with C arguments
327 */
328 PyObject *PythonInterpreter::call(const char *name, const char *format, ...)
329 {
330 va_list args;
331 va_start(args, format);
332 PyObject *result = callv(m_mainModule, name, format, args);
333 va_end(args);
334 return result;
335 }
336
337 /**
338 * Call function with C arguments
339 */
340 PyObject *PythonInterpreter::call(PyObject *module, const char *name, const char *format, ...)
341 {
342 if (module == NULL)
343 return NULL;
344
345 va_list args;
346 va_start(args, format);
347 PyObject *result = callv(module, name, format, args);
348 va_end(args);
349 return result;
350 }
351
352 /**
353 * Call function with C arguments
354 */
355 PyObject *PythonInterpreter::callv(PyObject *module, const char *name, const char *format, va_list args)
356 {
357 if (module == NULL)
358 return NULL;
359
360 PyObject *result = NULL;
361 PyEval_AcquireThread(m_threadState);
362
363 PyObject *func = PyObject_GetAttrString(module, name);
364 if ((func != NULL) && PyCallable_Check(func))
365 {
366 PyObject *pargs = (format != NULL) ? Py_VaBuildValue(format, args) : NULL;
367 result = PyObject_CallObject(func, pargs);
368 if (result == NULL)
369 {
370 logExecutionError(_T("Function call failed (%s)"));
371 }
372 if (pargs != NULL)
373 Py_DECREF(pargs);
374 }
375 else
376 {
377 nxlog_debug_tag(DEBUG_TAG, 6, _T("Function %hs does not exist"), name);
378 }
379
380 PyEval_ReleaseThread(m_threadState);
381 return result;
382 }
383
384 /**
385 * Decrement object reference
386 */
387 void PythonInterpreter::decref(PyObject *object)
388 {
389 PyEval_AcquireThread(m_threadState);
390 Py_DECREF(object);
391 PyEval_ReleaseThread(m_threadState);
392 }
393
394 /**
395 * Manager thread handle
396 */
397 static THREAD s_managerThread = INVALID_THREAD_HANDLE;
398
399 /**
400 * Initialize embedded Python
401 */
402 void LIBNXPYTHON_EXPORTABLE InitializeEmbeddedPython(NXPYTHON_MODULE_INFO *modules)
403 {
404 s_extraModules = modules;
405 CONDITION initCompleted = ConditionCreate(true);
406 s_managerThread = ThreadCreateEx(PythonManager, 0, initCompleted);
407 ConditionWait(initCompleted, INFINITE);
408 ConditionDestroy(initCompleted);
409 }
410
411 /**
412 * Shutdown embedded Python
413 */
414 void LIBNXPYTHON_EXPORTABLE ShutdownEmbeddedPython()
415 {
416 s_managerRequestQueue.put(INVALID_POINTER_VALUE);
417 ThreadJoin(s_managerThread);
418 }
419
420 /**
421 * Create Python interpreter
422 */
423 PythonInterpreter LIBNXPYTHON_EXPORTABLE *CreatePythonInterpreter()
424 {
425 return PythonInterpreter::create();
426 }