From 4c7ecef577aa6d5761c583be52f95fadfcde8e37 Mon Sep 17 00:00:00 2001 From: Unbit Date: Sun, 6 Oct 2013 10:52:27 +0200 Subject: [PATCH] added perl auto reloader --- plugins/psgi/psgi.h | 7 +++++ plugins/psgi/psgi_plugin.c | 56 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/plugins/psgi/psgi.h b/plugins/psgi/psgi.h index 9da90a5b..1f56c5d0 100644 --- a/plugins/psgi/psgi.h +++ b/plugins/psgi/psgi.h @@ -53,6 +53,11 @@ struct uwsgi_perl { struct uwsgi_string_list *exec; struct uwsgi_string_list *exec_post_fork; + + int auto_reload; + time_t last_auto_reload; + struct uwsgi_string_list *auto_reload_ignore; + HV *auto_reload_hash; }; void init_perl_embedded_module(void); @@ -70,3 +75,5 @@ PerlInterpreter *uwsgi_perl_new_interpreter(void); int uwsgi_perl_mule(char *); void uwsgi_perl_run_hook(SV *); void uwsgi_perl_exec(char *); + +void uwsgi_perl_check_auto_reload(void); diff --git a/plugins/psgi/psgi_plugin.c b/plugins/psgi/psgi_plugin.c index 915da55d..7af504b1 100644 --- a/plugins/psgi/psgi_plugin.c +++ b/plugins/psgi/psgi_plugin.c @@ -23,10 +23,58 @@ struct uwsgi_option uwsgi_perl_options[] = { {"perl-arg", required_argument, 0, "add an item to @ARGV", uwsgi_opt_add_string_list, &uperl.argv_item, 0}, {"perl-exec", required_argument, 0, "exec the specified perl file before fork()", uwsgi_opt_add_string_list, &uperl.exec, 0}, {"perl-exec-post-fork", required_argument, 0, "exec the specified perl file after fork()", uwsgi_opt_add_string_list, &uperl.exec_post_fork, 0}, + {"perl-auto-reload", required_argument, 0, "enable perl auto-reloader with the specified frequency", uwsgi_opt_set_int, &uperl.auto_reload, UWSGI_OPT_MASTER}, + {"perl-auto-reload-ignore", required_argument, 0, "ignore the specified files when auto-reload is enabled", uwsgi_opt_add_string_list, &uperl.auto_reload_ignore, UWSGI_OPT_MASTER}, {0, 0, 0, 0, 0, 0, 0}, }; +int uwsgi_perl_check_mtime(time_t now, HV *list, SV *key) { + // insert item with the current time + if (!hv_exists_ent(list, key, 0)) { + hv_store_ent(list, key, newSViv(now), 0); + } + else { + // compare mtime + struct stat st; + if (stat(SvPV_nolen(key), &st)) return 0; + HE *mtime = hv_fetch_ent(list, key, 0, 0); + if (!mtime) return 0; + if (st.st_mtime > SvIV(HeVAL(mtime))) { + uwsgi_log_verbose("[perl-auto-reloader] %s has been modified !!!\n", SvPV_nolen(key)); + kill(uwsgi.workers[0].pid, SIGHUP); + return 1; + } + } + + return 0; +} + +void uwsgi_perl_check_auto_reload() { + time_t now = uwsgi_now(); + HE *he; + if (!uperl.auto_reload_hash) { + uperl.auto_reload_hash = newHV(); + SvREFCNT_inc(uperl.auto_reload_hash); + } + GV *gv_inc = gv_fetchpv("INC", TRUE, SVt_PV); + if (!gv_inc) return; + HV *inc = GvHV(gv_inc); + hv_iterinit(inc); + while((he = hv_iternext(inc))) { + SV *filename = hv_iterval(inc, he); + struct uwsgi_string_list *usl; + int found = 0; + uwsgi_foreach(usl, uperl.auto_reload_ignore) { + if (!strcmp(usl->value, SvPV_nolen(filename))) { + found = 1; break; + } + } + if (found) continue; + if (uwsgi_perl_check_mtime(now, uperl.auto_reload_hash, filename)) return; + } +} + SV *uwsgi_perl_obj_new(char *class, size_t class_len) { SV *newobj; @@ -563,6 +611,14 @@ void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) { // clear the env SvREFCNT_dec(wsgi_req->async_environ); + // now we can check for changed files + if (uperl.auto_reload) { + time_t now = uwsgi_now(); + if (now - uperl.last_auto_reload > uperl.auto_reload) { + uwsgi_perl_check_auto_reload(); + } + } + } int uwsgi_perl_magic(char *mountpoint, char *lazy) {