[sr-dev] git:4.1: app_perl: added mechanism to avoid leaks specific to persistent perl interpreter

Daniel-Constantin Mierla miconda at gmail.com
Wed Dec 4 14:01:18 CET 2013


Module: sip-router
Branch: 4.1
Commit: 6a654f18f579aaf812a325a0b1a678ace5236051
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=6a654f18f579aaf812a325a0b1a678ace5236051

Author: Daniel-Constantin Mierla <miconda at gmail.com>
Committer: Daniel-Constantin Mierla <miconda at gmail.com>
Date:   Fri Nov 15 09:28:25 2013 +0100

app_perl: added mechanism to avoid leaks specific to persistent perl interpreter

- it is not easy to track the scope of variables, especially in libs,
  the solution being to re-init the interpreter
- new module parameter reset_cycles to specify the number of execution
  cycles after which the interpreter is reset. Default is 0 - don't
  reset at all

(cherry picked from commit b5527627601c9e41ebbfaccb98bc2cf0bc003bdb)

---

 modules/app_perl/app_perl_mod.c |   95 ++++++++++++++++++++++++++++++++------
 modules/app_perl/perlfunc.c     |    3 +
 modules/app_perl/perlfunc.h     |    2 +
 3 files changed, 85 insertions(+), 15 deletions(-)

diff --git a/modules/app_perl/app_perl_mod.c b/modules/app_perl/app_perl_mod.c
index a27e503..c35ece4 100644
--- a/modules/app_perl/app_perl_mod.c
+++ b/modules/app_perl/app_perl_mod.c
@@ -31,9 +31,11 @@
 #include <stdlib.h>
 #include <string.h>
 #include <dlfcn.h>
+#include <sys/time.h>
 
 #include "../../sr_module.h"
 #include "../../mem/mem.h"
+#include "../../mem/shm_mem.h"
 #include "../../lib/kmi/mi.h"
 #include "../../modules/rr/api.h"
 #include "../../modules/sl/sl.h"
@@ -61,6 +63,11 @@ char *modpath = NULL;
  * memory leaks, the variable thus is not documented! */
 int unsafemodfnc = 0;
 
+/* number of execution cycles after which perl interpreter is reset */
+int _ap_reset_cycles_init = 0;
+int _ap_exec_cycles = 0;
+int *_ap_reset_cycles = 0;
+
 /* Reference to the running Perl interpreter instance */
 PerlInterpreter *my_perl = NULL;
 
@@ -115,6 +122,7 @@ static param_export_t params[] = {
 	{"filename", STR_PARAM, &filename},
 	{"modpath", STR_PARAM, &modpath},
 	{"unsafemodfnc", INT_PARAM, &unsafemodfnc},
+	{"reset_cycles", INT_PARAM, &_ap_reset_cycles_init},
 	{ 0, 0, 0 }
 };
 
@@ -275,7 +283,8 @@ int unload_perl(PerlInterpreter *p) {
  * Reinitializes the interpreter. Works, but execution for _all_
  * children is difficult.
  */
-int perl_reload(struct sip_msg *m, char *a, char *b) {
+int perl_reload(void)
+{
 
 	PerlInterpreter *new_perl;
 
@@ -291,9 +300,9 @@ int perl_reload(struct sip_msg *m, char *a, char *b) {
 #warning This binary will be unsupported.
 		PL_exit_flags |= PERL_EXIT_EXPECTED;
 #endif
-		return 1;
-	} else {
 		return 0;
+	} else {
+		return -1;
 	}
 
 }
@@ -305,10 +314,10 @@ int perl_reload(struct sip_msg *m, char *a, char *b) {
  */
 struct mi_root* perl_mi_reload(struct mi_root *cmd_tree, void *param)
 {
-	if (perl_reload(NULL, NULL, NULL)) {
-		return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
-	} else {
+	if (perl_reload()<0) {
 		return init_mi_tree( 500, "Perl reload failed", 18);
+	} else {
+		return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
 	}
 
 }
@@ -324,6 +333,8 @@ static int mod_init(void) {
 	int argc = 1;
 	char *argt[] = { MOD_NAME, NULL };
 	char **argv;
+	struct timeval t1;
+	struct timeval t2;
 
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	{
@@ -342,22 +353,39 @@ static int mod_init(void) {
 		return -1;
 	}
 
+	_ap_reset_cycles = shm_malloc(sizeof(int));
+	if(_ap_reset_cycles == NULL) {
+		LM_ERR("no more shared memory\n");
+		return -1;
+	}
+	*_ap_reset_cycles = _ap_reset_cycles_init;
+
 	argv = argt;
 	PERL_SYS_INIT3(&argc, &argv, &environ);
 
-	if ((my_perl = parser_init())) {
-		ret = 0;
+	gettimeofday(&t1, NULL);
+	my_perl = parser_init();
+	gettimeofday(&t2, NULL);
+
+	if (my_perl==NULL)
+		goto error;
+
+	LM_INFO("perl interpreter has been initialized (%d.%06d => %d.%06d)\n",
+				(int)t1.tv_sec, (int)t1.tv_usec,
+				(int)t2.tv_sec, (int)t2.tv_usec);
+
 #ifdef PERL_EXIT_DESTRUCT_END
-		PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+	PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
 #else
-		PL_exit_flags |= PERL_EXIT_EXPECTED;
+	PL_exit_flags |= PERL_EXIT_EXPECTED;
 #endif
+	return 0;
 
-	} else {
-		ret = -1;
-	}
-
-	return ret;
+error:
+	if(_ap_reset_cycles!=NULL)
+		shm_free(_ap_reset_cycles);
+	_ap_reset_cycles = NULL;
+	return -1;
 }
 
 /*
@@ -372,3 +400,40 @@ static void destroy(void)
 	PERL_SYS_TERM();
 	my_perl = NULL;
 }
+
+
+/**
+ * count executions and rest interpreter
+ *
+ */
+int app_perl_reset_interpreter(void)
+{
+	struct timeval t1;
+	struct timeval t2;
+
+	if(*_ap_reset_cycles==0)
+		return 0;
+
+	_ap_exec_cycles++;
+	LM_DBG("perl interpreter exec cycle [%d/%d]\n",
+				_ap_exec_cycles, *_ap_reset_cycles);
+
+	if(_ap_exec_cycles<=*_ap_reset_cycles)
+		return 0;
+
+	gettimeofday(&t1, NULL);
+	if (perl_reload()<0) {
+		LM_ERR("perl interpreter cannot be reset [%d/%d]\n",
+				_ap_exec_cycles, *_ap_reset_cycles);
+		return -1;
+	}
+	gettimeofday(&t2, NULL);
+
+	LM_INFO("perl interpreter has been reset [%d/%d] (%d.%06d => %d.%06d)\n",
+				_ap_exec_cycles, *_ap_reset_cycles,
+				(int)t1.tv_sec, (int)t1.tv_usec,
+				(int)t2.tv_sec, (int)t2.tv_usec);
+	_ap_exec_cycles = 0;
+
+	return 0;
+}
diff --git a/modules/app_perl/perlfunc.c b/modules/app_perl/perlfunc.c
index 06d3314..e67c81f 100644
--- a/modules/app_perl/perlfunc.c
+++ b/modules/app_perl/perlfunc.c
@@ -58,6 +58,7 @@ int perl_checkfnc(char *fnc) {
 
 int perl_exec_simple(char* fnc, char* args[], int flags) {
 
+	app_perl_reset_interpreter();
 	if (perl_checkfnc(fnc)) {
 		LM_DBG("running perl function \"%s\"", fnc);
 
@@ -94,6 +95,8 @@ int perl_exec2(struct sip_msg* _msg, char* fnc, char* mystr) {
 	SV *m;
 	str reason;
 
+	app_perl_reset_interpreter();
+
 	dSP;
 
 	if (!perl_checkfnc(fnc)) {
diff --git a/modules/app_perl/perlfunc.h b/modules/app_perl/perlfunc.h
index 2d380b9..9f40ce8 100644
--- a/modules/app_perl/perlfunc.h
+++ b/modules/app_perl/perlfunc.h
@@ -42,4 +42,6 @@ int perl_exec_simple2(struct sip_msg* _msg, char* fnc, char* str2);
 int perl_exec1(struct sip_msg* _msg, char* fnc, char *foobar);
 int perl_exec2(struct sip_msg* _msg, char* fnc, char* mystr);
 
+int app_perl_reset_interpreter(void);
+
 #endif /* PERL_FUNC_H */




More information about the sr-dev mailing list