Browse code

app_python3: Python >= 3.7 call PyOS_AfterFork_Parent in main context after all forks

Anthony Alba authored on 22/11/2021 03:46:25
Showing 1 changed files
... ...
@@ -104,7 +104,13 @@ static int mod_init(void)
104 104
 	char *dname_src, *bname_src;
105 105
 	int i;
106 106
 
107
-	if(apy_sr_init_mod()<0) {
107
+	/*
108
+	 * register the need to be called post-fork of all children
109
+	 * with the special rank PROC_POSTCHILDINIT
110
+	 */
111
+	ksr_module_set_flag(KSRMOD_FLAG_POSTCHILDINIT);
112
+
113
+	if (apy_sr_init_mod()<0) {
108 114
 		LM_ERR("failed to init the sr mod\n");
109 115
 		return -1;
110 116
 	}
... ...
@@ -185,6 +191,16 @@ static int child_init(int rank)
185 191
 		 */
186 192
 #if PY_VERSION_HEX >= 0x03070000
187 193
 		PyOS_BeforeFork() ;
194
+#endif
195
+		return 0;
196
+	}
197
+	if(rank==PROC_POSTCHILDINIT) {
198
+		/*
199
+		 * this is called after forking of all child
200
+		 * processes
201
+		 */
202
+#if PY_VERSION_HEX >= 0x03070000
203
+		PyOS_AfterFork_Parent() ;
188 204
 #endif
189 205
 		return 0;
190 206
 	}
Browse code

app_python3: for Python >= 3.7 call pre-fork hook

Anthony Alba authored on 05/11/2021 09:31:34
Showing 1 changed files
... ...
@@ -175,6 +175,17 @@ static int mod_init(void)
175 175
 static int child_init(int rank)
176 176
 {
177 177
 	if(rank==PROC_INIT) {
178
+		/*
179
+		 * this is called before any process is forked
180
+		 * so the Python internal state handler
181
+		 * should be called now.
182
+		 *
183
+		 * TODO: is PyOS_AfterFork_Parent() necesary
184
+		 * in the main process?
185
+		 */
186
+#if PY_VERSION_HEX >= 0x03070000
187
+		PyOS_BeforeFork() ;
188
+#endif
178 189
 		return 0;
179 190
 	}
180 191
 	_apy_process_rank = rank;
Browse code

app_python3: handle deprecated PyEval_InitThreads()

- https://docs.python.org/3/c-api/init.html#c.PyEval_InitThreads
- GH #2626

Daniel-Constantin Mierla authored on 11/02/2021 08:14:06
Showing 1 changed files
... ...
@@ -346,7 +346,9 @@ int apy_load_script(void)
346 346
 	}
347 347
 
348 348
 	Py_Initialize();
349
+#if PY_VERSION_HEX < 0x03070000
349 350
 	PyEval_InitThreads();
351
+#endif
350 352
 	myThreadState = PyThreadState_Get();
351 353
 
352 354
 	PY_GIL_ENSURE;
Browse code

app_python3: declare global vars extern in header file

Daniel-Constantin Mierla authored on 09/03/2020 07:27:47
Showing 1 changed files
... ...
@@ -53,6 +53,7 @@ static int child_init(int rank);
53 53
 static void mod_destroy(void);
54 54
 
55 55
 PyObject *_sr_apy_handler_obj = NULL;
56
+PyObject *format_exc_obj = NULL;
56 57
 
57 58
 char *dname = NULL, *bname = NULL;
58 59
 
Browse code

app_python3: exported exec function to KEMI also as execx

Daniel-Constantin Mierla authored on 25/02/2019 08:20:47
Showing 1 changed files
... ...
@@ -581,6 +581,11 @@ static sr_kemi_t sr_kemi_app_python_exports[] = {
581 581
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
582 582
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
583 583
 	},
584
+	{ str_init("app_python3"), str_init("execx"),
585
+		SR_KEMIP_INT, ki_app_python_exec,
586
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
587
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
588
+	},
584 589
 	{ str_init("app_python3"), str_init("exec_p1"),
585 590
 		SR_KEMIP_INT, ki_app_python_exec_p1,
586 591
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
Browse code

app_python3: fix Python 3.7 deprecation warnings - check for PY_VERSION_HEX >= 0x03070000

Anthony Messina authored on 14/12/2018 22:32:04
Showing 1 changed files
... ...
@@ -177,7 +177,11 @@ static int child_init(int rank)
177 177
 		return 0;
178 178
 	}
179 179
 	_apy_process_rank = rank;
180
+#if PY_VERSION_HEX >= 0x03070000
181
+	PyOS_AfterFork_Child();
182
+#else
180 183
 	PyOS_AfterFork();
184
+#endif
181 185
 	if (cfg_child_init()) {
182 186
 		return -1;
183 187
 	}
... ...
@@ -431,7 +435,11 @@ int apy_init_script(int rank)
431 435
 {
432 436
 	PyObject *pFunc, *pArgs, *pValue, *pResult;
433 437
 	int rval = -1;
438
+#if PY_VERSION_HEX >= 0x03070000
439
+	const char *classname;
440
+#else
434 441
 	char *classname;
442
+#endif
435 443
 	PyGILState_STATE gstate;
436 444
 
437 445
 
Browse code

app_python3: updated to the new mod interface

Daniel-Constantin Mierla authored on 27/09/2018 21:54:04 • Victor Seva committed on 28/09/2018 11:03:26
Showing 1 changed files
... ...
@@ -82,18 +82,16 @@ static cmd_export_t cmds[] = {
82 82
 
83 83
 /** module exports */
84 84
 struct module_exports exports = {
85
-	"app_python3",                   /* module name */
86
-	RTLD_NOW | RTLD_GLOBAL,         /* dlopen flags */
87
-	cmds,                           /* exported functions */
88
-	params,                         /* exported parameters */
89
-	0,                              /* exported statistics */
90
-	0,                              /* exported MI functions */
91
-	0,                              /* exported pseudo-variables */
92
-	0,                              /* extra processes */
93
-	mod_init,                       /* module initialization function */
94
-	(response_function) NULL,       /* response handling function */
95
-	(destroy_function) mod_destroy, /* destroy function */
96
-	child_init                      /* per-child init function */
85
+	"app_python3",           /* module name */
86
+	RTLD_NOW | RTLD_GLOBAL,  /* dlopen flags */
87
+	cmds,                    /* exported functions */
88
+	params,                  /* exported parameters */
89
+	0,                       /* exported rpc functions */
90
+	0,                       /* exported pseudo-variables */
91
+	0,                       /* response handling function */
92
+	mod_init,                /* module init function */
93
+	child_init,              /* per-child init function */
94
+	mod_destroy              /* destroy function */
97 95
 };
98 96
 
99 97
 
Browse code

app_python3: init cfg vars framework in child init

Daniel-Constantin Mierla authored on 20/08/2018 09:12:34
Showing 1 changed files
... ...
@@ -26,6 +26,7 @@
26 26
 #include "../../core/sr_module.h"
27 27
 #include "../../core/mod_fix.h"
28 28
 #include "../../core/kemi.h"
29
+#include "../../core/cfg/cfg_struct.h"
29 30
 
30 31
 #include "python_exec.h"
31 32
 #include "python_iface.h"
... ...
@@ -179,6 +180,9 @@ static int child_init(int rank)
179 180
 	}
180 181
 	_apy_process_rank = rank;
181 182
 	PyOS_AfterFork();
183
+	if (cfg_child_init()) {
184
+		return -1;
185
+	}
182 186
 	return apy_init_script(rank);
183 187
 }
184 188
 
Browse code

app_python3: renamed main files to match module name

Daniel-Constantin Mierla authored on 10/03/2018 11:18:28
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,595 @@
1
+/*
2
+ * Copyright (C) 2009 Sippy Software, Inc., http://www.sippysoft.com
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
+ *
20
+ */
21
+
22
+#include <Python.h>
23
+#include <libgen.h>
24
+
25
+#include "../../core/str.h"
26
+#include "../../core/sr_module.h"
27
+#include "../../core/mod_fix.h"
28
+#include "../../core/kemi.h"
29
+
30
+#include "python_exec.h"
31
+#include "python_iface.h"
32
+#include "python_msgobj.h"
33
+#include "python_support.h"
34
+#include "app_python3_mod.h"
35
+
36
+#include "mod_Router.h"
37
+#include "mod_Core.h"
38
+#include "mod_Ranks.h"
39
+#include "mod_Logger.h"
40
+
41
+#include "apy_kemi.h"
42
+
43
+MODULE_VERSION
44
+
45
+
46
+str _sr_python_load_file = str_init("/usr/local/etc/" NAME "/handler.py");
47
+static str mod_init_fname = str_init("mod_init");
48
+static str child_init_mname = str_init("child_init");
49
+
50
+static int mod_init(void);
51
+static int child_init(int rank);
52
+static void mod_destroy(void);
53
+
54
+PyObject *_sr_apy_handler_obj = NULL;
55
+
56
+char *dname = NULL, *bname = NULL;
57
+
58
+int _apy_process_rank = 0;
59
+
60
+PyThreadState *myThreadState;
61
+
62
+/** module parameters */
63
+static param_export_t params[]={
64
+	{"script_name",        PARAM_STR, &_sr_python_load_file },
65
+	{"load",               PARAM_STR, &_sr_python_load_file },
66
+	{"mod_init_function",  PARAM_STR, &mod_init_fname },
67
+	{"child_init_method",  PARAM_STR, &child_init_mname },
68
+	{0,0,0}
69
+};
70
+
71
+/*
72
+ * Exported functions
73
+ */
74
+static cmd_export_t cmds[] = {
75
+	{ "python_exec", (cmd_function)python_exec1, 1,  fixup_spve_null,
76
+		0,	ANY_ROUTE },
77
+	{ "python_exec", (cmd_function)python_exec2, 2,  fixup_spve_spve,
78
+		0,	ANY_ROUTE },
79
+	{ 0, 0, 0, 0, 0, 0 }
80
+};
81
+
82
+/** module exports */
83
+struct module_exports exports = {
84
+	"app_python3",                   /* module name */
85
+	RTLD_NOW | RTLD_GLOBAL,         /* dlopen flags */
86
+	cmds,                           /* exported functions */
87
+	params,                         /* exported parameters */
88
+	0,                              /* exported statistics */
89
+	0,                              /* exported MI functions */
90
+	0,                              /* exported pseudo-variables */
91
+	0,                              /* extra processes */
92
+	mod_init,                       /* module initialization function */
93
+	(response_function) NULL,       /* response handling function */
94
+	(destroy_function) mod_destroy, /* destroy function */
95
+	child_init                      /* per-child init function */
96
+};
97
+
98
+
99
+/**
100
+ *
101
+ */
102
+static int mod_init(void)
103
+{
104
+	char *dname_src, *bname_src;
105
+	int i;
106
+
107
+	if(apy_sr_init_mod()<0) {
108
+		LM_ERR("failed to init the sr mod\n");
109
+		return -1;
110
+	}
111
+	if(app_python_init_rpc()<0) {
112
+		LM_ERR("failed to register RPC commands\n");
113
+		return -1;
114
+	}
115
+
116
+	dname_src = as_asciiz(&_sr_python_load_file);
117
+	bname_src = as_asciiz(&_sr_python_load_file);
118
+
119
+	if(dname_src==NULL || bname_src==NULL)
120
+	{
121
+		LM_ERR("no more pkg memory\n");
122
+		if(dname_src) pkg_free(dname_src);
123
+		if(bname_src) pkg_free(bname_src);
124
+		return -1;
125
+	}
126
+
127
+	dname = strdup(dirname(dname_src));
128
+	if(dname==NULL) {
129
+		LM_ERR("no more system memory\n");
130
+		pkg_free(dname_src);
131
+		pkg_free(bname_src);
132
+		return -1;
133
+	}
134
+	if (strlen(dname) == 0) {
135
+		free(dname);
136
+		dname = malloc(2);
137
+		if(dname==NULL) {
138
+			LM_ERR("no more system memory\n");
139
+			pkg_free(dname_src);
140
+			pkg_free(bname_src);
141
+			return -1;
142
+		}
143
+		dname[0] = '.';
144
+		dname[1] = '\0';
145
+	}
146
+	bname = strdup(basename(bname_src));
147
+	i = strlen(bname);
148
+	if (bname[i - 1] == 'c' || bname[i - 1] == 'o')
149
+		i -= 1;
150
+	if (bname[i - 3] == '.' && bname[i - 2] == 'p' && bname[i - 1] == 'y') {
151
+		bname[i - 3] = '\0';
152
+	} else {
153
+		LM_ERR("%s: script_name doesn't look like a python script\n",
154
+				_sr_python_load_file.s);
155
+		pkg_free(dname_src);
156
+		pkg_free(bname_src);
157
+		return -1;
158
+	}
159
+
160
+	if(apy_load_script()<0) {
161
+		pkg_free(dname_src);
162
+		pkg_free(bname_src);
163
+		LM_ERR("failed to load python script\n");
164
+		return -1;
165
+	}
166
+
167
+	pkg_free(dname_src);
168
+	pkg_free(bname_src);
169
+	return 0;
170
+}
171
+
172
+/**
173
+ *
174
+ */
175
+static int child_init(int rank)
176
+{
177
+	if(rank==PROC_INIT) {
178
+		return 0;
179
+	}
180
+	_apy_process_rank = rank;
181
+	PyOS_AfterFork();
182
+	return apy_init_script(rank);
183
+}
184
+
185
+/**
186
+ *
187
+ */
188
+static void mod_destroy(void)
189
+{
190
+	if (dname)
191
+		free(dname);	// dname was strdup'ed
192
+	if (bname)
193
+		free(bname);	// bname was strdup'ed
194
+
195
+	destroy_mod_Core();
196
+	destroy_mod_Ranks();
197
+	destroy_mod_Logger();
198
+	destroy_mod_Router();
199
+}
200
+
201
+
202
+#define PY_GIL_ENSURE gstate = PyGILState_Ensure()
203
+#define PY_GIL_RELEASE PyGILState_Release(gstate)
204
+int apy_mod_init(PyObject* pModule)
205
+{
206
+
207
+	/*
208
+	 * pModule: managed by caller, no need to Py_DECREF
209
+	 */
210
+	PyObject *pFunc, *pArgs, *pHandler;
211
+	PyGILState_STATE gstate;
212
+	int rval = -1;
213
+
214
+	PY_GIL_ENSURE;
215
+	pFunc = PyObject_GetAttrString(pModule, mod_init_fname.s);
216
+
217
+	/* pFunc is a new reference */
218
+
219
+	if (pFunc == NULL) {
220
+		if (!PyErr_Occurred())
221
+			PyErr_Format(PyExc_AttributeError,
222
+					"'module' object '%s' has no attribute '%s'",
223
+					bname, mod_init_fname.s);
224
+		python_handle_exception("mod_init");
225
+		Py_DECREF(format_exc_obj);
226
+		Py_XDECREF(pFunc);
227
+		goto err;
228
+	}
229
+
230
+	if (!PyCallable_Check(pFunc)) {
231
+		if (!PyErr_Occurred())
232
+			PyErr_Format(PyExc_AttributeError,
233
+					"module object '%s' has is not callable attribute '%s'",
234
+					bname, mod_init_fname.s);
235
+		python_handle_exception("mod_init");
236
+		Py_DECREF(format_exc_obj);
237
+		Py_XDECREF(pFunc);
238
+		goto err;
239
+	}
240
+
241
+
242
+	pArgs = PyTuple_New(0);
243
+	if (pArgs == NULL) {
244
+		python_handle_exception("mod_init");
245
+		Py_DECREF(format_exc_obj);
246
+		Py_DECREF(pFunc);
247
+		goto err;
248
+	}
249
+
250
+	pHandler = PyObject_CallObject(pFunc, pArgs);
251
+
252
+	Py_XDECREF(pFunc);
253
+	Py_XDECREF(pArgs);
254
+
255
+	if (pHandler == Py_None) {
256
+		if (!PyErr_Occurred())
257
+			PyErr_Format(PyExc_TypeError,
258
+					"Function '%s' of module '%s' has returned None."
259
+					" Should be a class instance.", mod_init_fname.s, bname);
260
+		python_handle_exception("mod_init");
261
+		Py_DECREF(format_exc_obj);
262
+		goto err;
263
+	}
264
+
265
+	if (PyErr_Occurred()) {
266
+		python_handle_exception("mod_init");
267
+		Py_XDECREF(_sr_apy_handler_obj);
268
+		Py_DECREF(format_exc_obj);
269
+		goto err;
270
+	}
271
+
272
+	if (pHandler == NULL) {
273
+		LM_ERR("PyObject_CallObject() returned NULL but no exception!\n");
274
+		if (!PyErr_Occurred())
275
+			PyErr_Format(PyExc_TypeError,
276
+					"Function '%s' of module '%s' has returned not returned"
277
+					" object. Should be a class instance.",
278
+					mod_init_fname.s, bname);
279
+		python_handle_exception("mod_init");
280
+		Py_DECREF(format_exc_obj);
281
+		goto err;
282
+	}
283
+	Py_XDECREF(_sr_apy_handler_obj);
284
+	_sr_apy_handler_obj = pHandler;
285
+	rval = 0;
286
+ err:
287
+	PY_GIL_RELEASE;
288
+	return rval;
289
+}
290
+
291
+
292
+/*
293
+ * reference to the module to allow reload
294
+ */
295
+static PyObject *_sr_apy_module;
296
+
297
+int apy_reload_script(void)
298
+{
299
+	PyGILState_STATE gstate;
300
+	int rval = -1;
301
+
302
+	PY_GIL_ENSURE;
303
+	PyObject *pModule = PyImport_ReloadModule(_sr_apy_module);
304
+	if (!pModule) {
305
+		if (!PyErr_Occurred())
306
+			PyErr_Format(PyExc_ImportError, "Reload module '%s'", bname);
307
+		python_handle_exception("mod_init");
308
+		Py_DECREF(format_exc_obj);
309
+		goto err;
310
+	}
311
+	if (apy_mod_init(pModule)) {
312
+		LM_ERR("Error calling mod_init on reload\n");
313
+		Py_DECREF(pModule);
314
+		goto err;
315
+	}
316
+	Py_DECREF(_sr_apy_module);
317
+	_sr_apy_module = pModule;
318
+
319
+        if(apy_init_script(_apy_process_rank)<0) {
320
+                LM_ERR("failed to init script\n");
321
+		goto err;
322
+        }
323
+        rval =  0;
324
+ err:
325
+	PY_GIL_RELEASE;
326
+	return rval;
327
+}
328
+
329
+#define  INTERNAL_VERSION  "1002\n"
330
+
331
+int apy_load_script(void)
332
+{
333
+	PyObject *sys_path, *pDir, *pModule;
334
+	PyGILState_STATE gstate;
335
+	int rc, rval = -1;
336
+
337
+	if (ap_init_modules() != 0) {
338
+		return -1;
339
+	}
340
+
341
+	Py_Initialize();
342
+	PyEval_InitThreads();
343
+	myThreadState = PyThreadState_Get();
344
+
345
+	PY_GIL_ENSURE;
346
+
347
+	// Py3 does not create a package-like hierarchy of modules
348
+	// make legacy modules importable using Py2 syntax
349
+	// import Router.Logger
350
+
351
+	rc = PyRun_SimpleString("import sys\n"
352
+			   "import Router\n"
353
+			   "import KSR\n"
354
+			   "KSR.__version__ = " INTERNAL_VERSION
355
+			   "sys.modules['Router.Core'] = Router.Core\n"
356
+			   "sys.modules['Router.Logger'] = Router.Logger\n"
357
+			   "sys.modules['Router.Ranks'] = Router.Ranks\n"
358
+			   "sys.modules['KSR.pv'] = KSR.pv\n"
359
+			   "sys.modules['KSR.x'] = KSR.x\n"
360
+			   );
361
+	if (rc) {
362
+		LM_ERR("Early imports of modules failed\n");
363
+		goto err;
364
+	}
365
+
366
+	format_exc_obj = InitTracebackModule();
367
+
368
+	if (format_exc_obj == NULL || !PyCallable_Check(format_exc_obj))
369
+	{
370
+		Py_XDECREF(format_exc_obj);
371
+		goto err;
372
+	}
373
+
374
+	sys_path = PySys_GetObject("path");
375
+	/* PySys_GetObject doesn't pass reference! No need to DEREF */
376
+	if (sys_path == NULL) {
377
+		if (!PyErr_Occurred())
378
+			PyErr_Format(PyExc_AttributeError,
379
+					"'module' object 'sys' has no attribute 'path'");
380
+		python_handle_exception("mod_init");
381
+		Py_DECREF(format_exc_obj);
382
+		goto err;
383
+	}
384
+
385
+	pDir = PyUnicode_FromString(dname);
386
+	if (pDir == NULL) {
387
+		if (!PyErr_Occurred())
388
+			PyErr_Format(PyExc_AttributeError,
389
+					"PyUnicode_FromString() has failed");
390
+		python_handle_exception("mod_init");
391
+		Py_DECREF(format_exc_obj);
392
+		goto err;
393
+	}
394
+
395
+	PyList_Insert(sys_path, 0, pDir);
396
+	Py_DECREF(pDir);
397
+
398
+	if (python_msgobj_init() != 0) {
399
+		if (!PyErr_Occurred())
400
+			PyErr_SetString(PyExc_AttributeError,
401
+					"python_msgobj_init() has failed");
402
+		python_handle_exception("mod_init");
403
+		Py_DECREF(format_exc_obj);
404
+		goto err;
405
+	}
406
+
407
+	pModule = PyImport_ImportModule(bname);
408
+	if (pModule == NULL) {
409
+		if (!PyErr_Occurred())
410
+			PyErr_Format(PyExc_ImportError, "No module named '%s'", bname);
411
+		python_handle_exception("mod_init");
412
+		Py_DECREF(format_exc_obj);
413
+		goto err;
414
+	}
415
+	if (apy_mod_init(pModule) != 0) {
416
+		LM_ERR("Error calling mod_init\n");
417
+		Py_DECREF(pModule);
418
+		goto err;
419
+	}
420
+	_sr_apy_module = pModule;
421
+
422
+	rval = 0;
423
+ err:
424
+	PY_GIL_RELEASE;
425
+	return rval;
426
+}
427
+
428
+int apy_init_script(int rank)
429
+{
430
+	PyObject *pFunc, *pArgs, *pValue, *pResult;
431
+	int rval = -1;
432
+	char *classname;
433
+	PyGILState_STATE gstate;
434
+
435
+
436
+	PY_GIL_ENSURE;
437
+
438
+	// get instance class name
439
+	classname = get_instance_class_name(_sr_apy_handler_obj);
440
+	if (classname == NULL)
441
+	{
442
+		if (!PyErr_Occurred())
443
+			PyErr_Format(PyExc_AttributeError,
444
+					"'module' instance has no class name");
445
+		python_handle_exception("child_init");
446
+		Py_DECREF(format_exc_obj);
447
+		goto err;
448
+	}
449
+
450
+	pFunc = PyObject_GetAttrString(_sr_apy_handler_obj, child_init_mname.s);
451
+
452
+	if (pFunc == NULL) {
453
+		python_handle_exception("child_init");
454
+		Py_XDECREF(pFunc);
455
+		Py_DECREF(format_exc_obj);
456
+		goto err;
457
+	}
458
+
459
+	if (!PyCallable_Check(pFunc)) {
460
+		if (!PyErr_Occurred())
461
+			PyErr_Format(PyExc_AttributeError,
462
+					"class object '%s' has is not callable attribute '%s'",
463
+					classname, mod_init_fname.s);
464
+		python_handle_exception("child_init");
465
+		Py_DECREF(format_exc_obj);
466
+		Py_XDECREF(pFunc);
467
+		goto err;
468
+	}
469
+
470
+	pArgs = PyTuple_New(1);
471
+	if (pArgs == NULL) {
472
+		python_handle_exception("child_init");
473
+		Py_DECREF(format_exc_obj);
474
+		Py_DECREF(pFunc);
475
+		goto err;
476
+	}
477
+
478
+	pValue = PyLong_FromLong((long)rank);
479
+	if (pValue == NULL) {
480
+		python_handle_exception("child_init");
481
+		Py_DECREF(format_exc_obj);
482
+		Py_DECREF(pArgs);
483
+		Py_DECREF(pFunc);
484
+		goto err;
485
+	}
486
+	PyTuple_SetItem(pArgs, 0, pValue);
487
+	/* pValue has been stolen */
488
+
489
+	pResult = PyObject_CallObject(pFunc, pArgs);
490
+	Py_DECREF(pFunc);
491
+	Py_DECREF(pArgs);
492
+
493
+	if (PyErr_Occurred()) {
494
+		python_handle_exception("child_init");
495
+		Py_DECREF(format_exc_obj);
496
+		Py_XDECREF(pResult);
497
+		goto err;
498
+	}
499
+
500
+	if (pResult == NULL) {
501
+		LM_ERR("PyObject_CallObject() returned NULL but no exception!\n");
502
+		goto err;
503
+	}
504
+
505
+	if (!PyLong_Check(pResult))
506
+	{
507
+		if (!PyErr_Occurred())
508
+			PyErr_Format(PyExc_TypeError,
509
+					"method '%s' of class '%s' should return 'int' type",
510
+					child_init_mname.s, classname);
511
+		python_handle_exception("child_init");
512
+		Py_DECREF(format_exc_obj);
513
+		Py_XDECREF(pResult);
514
+		goto err;
515
+	}
516
+
517
+	rval = PyLong_AsLong(pResult);
518
+	Py_DECREF(pResult);
519
+ err:
520
+	PY_GIL_RELEASE;
521
+	return rval;
522
+}
523
+/**
524
+ *
525
+ */
526
+static int ki_app_python_exec(sip_msg_t *msg, str *method)
527
+{
528
+	if(method==NULL || method->s==NULL || method->len<=0) {
529
+		LM_ERR("invalid method name\n");
530
+		return -1;
531
+	}
532
+	if(method->s[method->len]!='\0') {
533
+		LM_ERR("invalid terminated method name\n");
534
+		return -1;
535
+	}
536
+	return apy_exec(msg, method->s, NULL, 1);
537
+}
538
+
539
+/**
540
+ *
541
+ */
542
+static int ki_app_python_exec_p1(sip_msg_t *msg, str *method, str *p1)
543
+{
544
+	if(method==NULL || method->s==NULL || method->len<=0) {
545
+		LM_ERR("invalid method name\n");
546
+		return -1;
547
+	}
548
+	if(method->s[method->len]!='\0') {
549
+		LM_ERR("invalid terminated method name\n");
550
+		return -1;
551
+	}
552
+	if(p1==NULL || p1->s==NULL || p1->len<0) {
553
+		LM_ERR("invalid p1 value\n");
554
+		return -1;
555
+	}
556
+	if(p1->s[p1->len]!='\0') {
557
+		LM_ERR("invalid terminated p1 value\n");
558
+		return -1;
559
+	}
560
+
561
+	return apy_exec(msg, method->s, p1->s, 1);
562
+}
563
+
564
+/**
565
+ *
566
+ */
567
+/* clang-format off */
568
+static sr_kemi_t sr_kemi_app_python_exports[] = {
569
+	{ str_init("app_python3"), str_init("exec"),
570
+		SR_KEMIP_INT, ki_app_python_exec,
571
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
572
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
573
+	},
574
+	{ str_init("app_python3"), str_init("exec_p1"),
575
+		SR_KEMIP_INT, ki_app_python_exec_p1,
576
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
577
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
578
+	},
579
+
580
+	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
581
+};
582
+/* clang-format on */
583
+
584
+/**
585
+ *
586
+ */
587
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
588
+{
589
+	str ename = str_init("python");
590
+
591
+	sr_kemi_eng_register(&ename, sr_kemi_config_engine_python);
592
+	sr_kemi_modules_add(sr_kemi_app_python_exports);
593
+
594
+	return 0;
595
+}