mirror of
https://github.com/irssi/irssi.git
synced 2026-08-22 10:02:22 +02:00
Merge bbf52fa7fa into 24ad80177b
This commit is contained in:
commit
27ed3cb652
6 changed files with 164 additions and 11 deletions
|
|
@ -191,9 +191,9 @@ static void cmd_set(char *data)
|
||||||
/* Unpossible! */
|
/* Unpossible! */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
signal_emit("setup changed", 0);
|
|
||||||
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_SET_TITLE, rec->section);
|
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_SET_TITLE, rec->section);
|
||||||
set_print(rec);
|
set_print(rec);
|
||||||
|
signal_emit("setup changed", 0);
|
||||||
} else
|
} else
|
||||||
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_SET_UNKNOWN, key);
|
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_SET_UNKNOWN, key);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,12 @@
|
||||||
#include "XSUB.h"
|
#include "XSUB.h"
|
||||||
#include "irssi-core.pl.h"
|
#include "irssi-core.pl.h"
|
||||||
|
|
||||||
|
#ifdef TRACE_SCRIPT_UNLOADS
|
||||||
|
#define SCRIPT_UNLOAD_DEBUG g_message
|
||||||
|
#else
|
||||||
|
#define SCRIPT_UNLOAD_DEBUG while(0)g_message
|
||||||
|
#endif
|
||||||
|
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
|
|
||||||
GSList *perl_scripts;
|
GSList *perl_scripts;
|
||||||
|
|
@ -72,6 +78,14 @@ static void perl_script_destroy(PERL_SCRIPT_REC *script)
|
||||||
|
|
||||||
signal_emit("script destroyed", 1, script);
|
signal_emit("script destroyed", 1, script);
|
||||||
|
|
||||||
|
perl_script_unref(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void perl_script_free(PERL_SCRIPT_REC *script)
|
||||||
|
{
|
||||||
|
g_return_if_fail(script->refcount == 0);
|
||||||
|
|
||||||
g_free(script->name);
|
g_free(script->name);
|
||||||
g_free(script->package);
|
g_free(script->package);
|
||||||
g_free_not_null(script->path);
|
g_free_not_null(script->path);
|
||||||
|
|
@ -250,7 +264,7 @@ static int perl_script_eval(PERL_SCRIPT_REC *script)
|
||||||
|
|
||||||
if (error != NULL) {
|
if (error != NULL) {
|
||||||
error = g_strdup(error);
|
error = g_strdup(error);
|
||||||
signal_emit("script error", 2, script, error);
|
perl_script_error(script, error);
|
||||||
g_free(error);
|
g_free(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -258,7 +272,7 @@ static int perl_script_eval(PERL_SCRIPT_REC *script)
|
||||||
FREETMPS;
|
FREETMPS;
|
||||||
LEAVE;
|
LEAVE;
|
||||||
|
|
||||||
return error == NULL;
|
return (!script->destroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: name must not be free'd */
|
/* NOTE: name must not be free'd */
|
||||||
|
|
@ -277,12 +291,18 @@ static PERL_SCRIPT_REC *script_load(char *name, const char *path,
|
||||||
script->package = g_strdup_printf("Irssi::Script::%s", name);
|
script->package = g_strdup_printf("Irssi::Script::%s", name);
|
||||||
script->path = g_strdup(path);
|
script->path = g_strdup(path);
|
||||||
script->data = g_strdup(data);
|
script->data = g_strdup(data);
|
||||||
|
script->destroyed = FALSE;
|
||||||
|
script->disable_signals = -1;
|
||||||
|
/* two references: one for the script itself, one for our caller */
|
||||||
|
script->refcount = 2;
|
||||||
|
|
||||||
perl_scripts = g_slist_append(perl_scripts, script);
|
perl_scripts = g_slist_append(perl_scripts, script);
|
||||||
signal_emit("script created", 1, script);
|
signal_emit("script created", 1, script);
|
||||||
|
|
||||||
if (!perl_script_eval(script))
|
if (!perl_script_eval(script)) {
|
||||||
|
perl_script_unref(script);
|
||||||
script = NULL; /* the script is destroyed in "script error" signal */
|
script = NULL; /* the script is destroyed in "script error" signal */
|
||||||
|
}
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,6 +333,13 @@ void perl_script_unload(PERL_SCRIPT_REC *script)
|
||||||
{
|
{
|
||||||
g_return_if_fail(script != NULL);
|
g_return_if_fail(script != NULL);
|
||||||
|
|
||||||
|
g_return_if_fail(script->refcount > 0);
|
||||||
|
|
||||||
|
if (script->destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
script->destroyed = 1;
|
||||||
|
|
||||||
perl_script_destroy_package(script);
|
perl_script_destroy_package(script);
|
||||||
perl_script_destroy(script);
|
perl_script_destroy(script);
|
||||||
}
|
}
|
||||||
|
|
@ -414,7 +441,7 @@ void perl_scripts_autorun(void)
|
||||||
|
|
||||||
fname = g_strdup_printf("%s/%s", path, dp->d_name);
|
fname = g_strdup_printf("%s/%s", path, dp->d_name);
|
||||||
if (stat(fname, &statbuf) == 0 && !S_ISDIR(statbuf.st_mode))
|
if (stat(fname, &statbuf) == 0 && !S_ISDIR(statbuf.st_mode))
|
||||||
perl_script_load_file(fname);
|
perl_script_unref(perl_script_load_file(fname));
|
||||||
g_free(fname);
|
g_free(fname);
|
||||||
}
|
}
|
||||||
closedir(dirp);
|
closedir(dirp);
|
||||||
|
|
@ -484,3 +511,64 @@ void perl_core_abicheck(int *version)
|
||||||
{
|
{
|
||||||
*version = IRSSI_ABI_VERSION;
|
*version = IRSSI_ABI_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int perl_script_ref(PERL_SCRIPT_REC *script)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(script != NULL, FALSE);
|
||||||
|
g_return_val_if_fail(script->refcount > 0, FALSE);
|
||||||
|
|
||||||
|
/* If the script's been destroyed, there's no point calling into it. */
|
||||||
|
|
||||||
|
if (script->destroyed) {
|
||||||
|
g_warning("rejecting attempt to reference destroyed script %p (%s)\n", script, script->name);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++script->refcount == UINT8_MAX) {
|
||||||
|
--script->refcount;
|
||||||
|
/* something is almost certainly wrong here. */
|
||||||
|
/* Report an error; that'll most likely cause the offending script to be unloaded. */
|
||||||
|
perl_script_error(script, "Too much signal/command recursion");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCRIPT_UNLOAD_DEBUG("reference count for %p (%s) is now %d\n", script, script->name, script->refcount);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void perl_script_unref(PERL_SCRIPT_REC *script)
|
||||||
|
{
|
||||||
|
/* this makes it easier to use perl_load_script_data() and perl_load_script_file() */
|
||||||
|
if (script == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_return_if_fail(script->refcount > 0);
|
||||||
|
|
||||||
|
if (--script->refcount == 0) {
|
||||||
|
SCRIPT_UNLOAD_DEBUG("freeing script %p (%s)\n", script, script->name);
|
||||||
|
perl_script_free(script);
|
||||||
|
} else {
|
||||||
|
SCRIPT_UNLOAD_DEBUG("not freeing script %p (%s); refcount is now %d\n",
|
||||||
|
script, script->name, script->refcount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void perl_script_error(PERL_SCRIPT_REC *script, const char *error)
|
||||||
|
{
|
||||||
|
g_return_if_fail(script != NULL);
|
||||||
|
g_return_if_fail(script->refcount > 0);
|
||||||
|
|
||||||
|
/* Don't bother reporting errors in destroyed scripts */
|
||||||
|
if (script->destroyed) {
|
||||||
|
SCRIPT_UNLOAD_DEBUG("suppressing script error notification for destroyed script");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++script->disable_signals > 0) {
|
||||||
|
g_warning("Recursive error detected in script %s", script->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
signal_emit("script error", 2, script, error);
|
||||||
|
|
||||||
|
--script->disable_signals;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef __PERL_CORE_H
|
#ifndef __PERL_CORE_H
|
||||||
#define __PERL_CORE_H
|
#define __PERL_CORE_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name; /* unique name */
|
char *name; /* unique name */
|
||||||
char *package; /* package name */
|
char *package; /* package name */
|
||||||
|
|
@ -8,6 +10,17 @@ typedef struct {
|
||||||
/* Script can be loaded from a file, or from some data in memory */
|
/* Script can be loaded from a file, or from some data in memory */
|
||||||
char *path; /* FILE: full path for file */
|
char *path; /* FILE: full path for file */
|
||||||
char *data; /* DATA: data used for the script */
|
char *data; /* DATA: data used for the script */
|
||||||
|
|
||||||
|
/** Script destruction flag. If TRUE, the script has been
|
||||||
|
* destroyed/unloaded.
|
||||||
|
*/
|
||||||
|
uint8_t destroyed;
|
||||||
|
/** Script signal suppression counter. If greater than zero,
|
||||||
|
* signals and commands should not be delivered to the script.
|
||||||
|
*/
|
||||||
|
int8_t disable_signals;
|
||||||
|
/** PERL_SCRIPT_REC reference counter. */
|
||||||
|
uint8_t refcount;
|
||||||
} PERL_SCRIPT_REC;
|
} PERL_SCRIPT_REC;
|
||||||
|
|
||||||
extern GSList *perl_scripts;
|
extern GSList *perl_scripts;
|
||||||
|
|
@ -19,9 +32,17 @@ void perl_scripts_deinit(void);
|
||||||
/* Load all the scripts in the autorun/ folder */
|
/* Load all the scripts in the autorun/ folder */
|
||||||
void perl_scripts_autorun(void);
|
void perl_scripts_autorun(void);
|
||||||
|
|
||||||
/* Load a perl script, path must be a full path. */
|
/** Load a perl script, path must be a full path.
|
||||||
|
* If an error occurs while loading the script, the return value is NULL.
|
||||||
|
* Otherwise, the returned pointer has an extra reference that must be
|
||||||
|
* released with perl_script_unref().
|
||||||
|
*/
|
||||||
PERL_SCRIPT_REC *perl_script_load_file(const char *path);
|
PERL_SCRIPT_REC *perl_script_load_file(const char *path);
|
||||||
/* Load a perl script from given data */
|
/** Load a perl script from given data.
|
||||||
|
* If an error occurs while loading the script, the return value is NULL.
|
||||||
|
* Otherwise, the returned pointer has an extra reference that must be
|
||||||
|
* released with perl_script_unref().
|
||||||
|
*/
|
||||||
PERL_SCRIPT_REC *perl_script_load_data(const char *data);
|
PERL_SCRIPT_REC *perl_script_load_data(const char *data);
|
||||||
/* Unload perl script */
|
/* Unload perl script */
|
||||||
void perl_script_unload(PERL_SCRIPT_REC *script);
|
void perl_script_unload(PERL_SCRIPT_REC *script);
|
||||||
|
|
@ -55,4 +76,26 @@ int perl_get_api_version(void);
|
||||||
void perl_core_init(void);
|
void perl_core_init(void);
|
||||||
void perl_core_deinit(void);
|
void perl_core_deinit(void);
|
||||||
|
|
||||||
|
/** Attempts to reference a PERL_SCRIPT_REC structure, preventing it from
|
||||||
|
* being freed.
|
||||||
|
*
|
||||||
|
* Returns TRUE if a reference was taken; each reference must be released
|
||||||
|
* by calling perl_script_unref().
|
||||||
|
* Returns FALSE if a reference was not made (this can happen if the
|
||||||
|
* if the associated script has already been destroyed.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int perl_script_ref(PERL_SCRIPT_REC *script);
|
||||||
|
|
||||||
|
/** Releases a PERL_SCRIPT_REC structure, potentially allowing it to be
|
||||||
|
* freed.
|
||||||
|
* If @param script is NULL, this function does nothing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void perl_script_unref(PERL_SCRIPT_REC *script);
|
||||||
|
|
||||||
|
/** Used to report that an error occurred while calling into a script.
|
||||||
|
*/
|
||||||
|
void perl_script_error(PERL_SCRIPT_REC *script, const char *error);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ static void cmd_script_exec(const char *data)
|
||||||
/* not a permanent script, unload immediately */
|
/* not a permanent script, unload immediately */
|
||||||
perl_script_unload(script);
|
perl_script_unload(script);
|
||||||
}
|
}
|
||||||
|
perl_script_unref(script);
|
||||||
|
|
||||||
cmd_params_free(free_arg);
|
cmd_params_free(free_arg);
|
||||||
}
|
}
|
||||||
|
|
@ -87,6 +87,7 @@ static void cmd_script_load(const char *data)
|
||||||
TXT_SCRIPT_LOADED,
|
TXT_SCRIPT_LOADED,
|
||||||
script->name, script->path);
|
script->name, script->path);
|
||||||
}
|
}
|
||||||
|
perl_script_unref(script);
|
||||||
g_free(fname);
|
g_free(fname);
|
||||||
}
|
}
|
||||||
cmd_params_free(free_arg);
|
cmd_params_free(free_arg);
|
||||||
|
|
|
||||||
|
|
@ -302,9 +302,13 @@ static void perl_call_signal(PERL_SCRIPT_REC *script, SV *func,
|
||||||
perl_call_sv(func, G_EVAL|G_DISCARD);
|
perl_call_sv(func, G_EVAL|G_DISCARD);
|
||||||
SPAGAIN;
|
SPAGAIN;
|
||||||
|
|
||||||
|
/* if script->destroyed is nonzero, rec is no longer valid */
|
||||||
|
if (script->destroyed)
|
||||||
|
rec = NULL;
|
||||||
|
|
||||||
if (SvTRUE(ERRSV)) {
|
if (SvTRUE(ERRSV)) {
|
||||||
char *error = g_strdup(SvPV_nolen(ERRSV));
|
char *error = g_strdup(SvPV_nolen(ERRSV));
|
||||||
signal_emit("script error", 2, script, error);
|
perl_script_error(script, error);
|
||||||
g_free(error);
|
g_free(error);
|
||||||
rec = NULL;
|
rec = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -354,13 +358,23 @@ static void sig_func(const void *p1, const void *p2,
|
||||||
const void *p5, const void *p6)
|
const void *p5, const void *p6)
|
||||||
{
|
{
|
||||||
PERL_SIGNAL_REC *rec;
|
PERL_SIGNAL_REC *rec;
|
||||||
|
PERL_SCRIPT_REC *script;
|
||||||
const void *args[6];
|
const void *args[6];
|
||||||
|
|
||||||
args[0] = p1; args[1] = p2; args[2] = p3;
|
args[0] = p1; args[1] = p2; args[2] = p3;
|
||||||
args[3] = p4; args[4] = p5; args[5] = p6;
|
args[3] = p4; args[4] = p5; args[5] = p6;
|
||||||
|
|
||||||
rec = signal_get_user_data();
|
rec = signal_get_user_data();
|
||||||
perl_call_signal(rec->script, rec->func, signal_get_emitted_id(), args);
|
|
||||||
|
/* save off rec->script; after perl_call_signal, rec may be gone */
|
||||||
|
script = rec->script;
|
||||||
|
|
||||||
|
if (script->disable_signals > 0)
|
||||||
|
return;
|
||||||
|
if (!perl_script_ref(script))
|
||||||
|
return;
|
||||||
|
perl_call_signal(script, rec->func, signal_get_emitted_id(), args);
|
||||||
|
perl_script_unref(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perl_signal_add_full_int(const char *signal, SV *func,
|
static void perl_signal_add_full_int(const char *signal, SV *func,
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,11 @@ static int perl_source_event(PERL_SOURCE_REC *rec)
|
||||||
{
|
{
|
||||||
dSP;
|
dSP;
|
||||||
|
|
||||||
|
if (!perl_script_ref(rec->script)) {
|
||||||
|
g_error("Unexpected event for destroyed script %s", rec->script->name);
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
ENTER;
|
ENTER;
|
||||||
SAVETMPS;
|
SAVETMPS;
|
||||||
|
|
||||||
|
|
@ -82,10 +87,12 @@ static int perl_source_event(PERL_SOURCE_REC *rec)
|
||||||
|
|
||||||
if (SvTRUE(ERRSV)) {
|
if (SvTRUE(ERRSV)) {
|
||||||
char *error = g_strdup(SvPV_nolen(ERRSV));
|
char *error = g_strdup(SvPV_nolen(ERRSV));
|
||||||
signal_emit("script error", 2, rec->script, error);
|
perl_script_error(rec->script, error);
|
||||||
g_free(error);
|
g_free(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
perl_script_unref(rec->script);
|
||||||
|
|
||||||
if (perl_source_unref(rec) && rec->once)
|
if (perl_source_unref(rec) && rec->once)
|
||||||
perl_source_destroy(rec);
|
perl_source_destroy(rec);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue