From 20cfbeb9744a8d44b8e9dcce23d0c8e0f26842a1 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 15 Sep 2011 23:33:23 +0000 Subject: context: Add optional signal emitted after a GC finishes Embedders may want to perform garbage collection profiling; support this with an optional signal emitted after a collection finishes. I added a boolean to avoid calling JS_SetGCCallback() if not used, because there's no way for that API to chain. https://bugzilla.gnome.org/show_bug.cgi?id=659253 --- diff --git a/gjs/context.c b/gjs/context.c index d931a3b..5688477 100644 --- a/gjs/context.c +++ b/gjs/context.c @@ -56,6 +56,8 @@ static void gjs_context_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static JSBool gjs_on_context_gc (JSContext *cx, + JSGCStatus status); struct _GjsContext { GObject parent; @@ -70,7 +72,10 @@ struct _GjsContext { char **search_path; - unsigned int we_own_runtime : 1; + guint idle_emit_gc_id; + + guint we_own_runtime : 1; + guint gc_notifications_enabled : 1; }; struct _GjsContextClass { @@ -79,19 +84,19 @@ struct _GjsContextClass { G_DEFINE_TYPE(GjsContext, gjs_context, G_TYPE_OBJECT); -#if 0 enum { + SIGNAL_GC, LAST_SIGNAL }; static int signals[LAST_SIGNAL]; -#endif enum { PROP_0, PROP_JS_VERSION, PROP_SEARCH_PATH, - PROP_RUNTIME + PROP_RUNTIME, + PROP_GC_NOTIFICATIONS }; @@ -335,6 +340,22 @@ gjs_context_class_init(GjsContextClass *klass) PROP_JS_VERSION, pspec); + pspec = g_param_spec_boolean("gc-notifications", + "", + "Whether or not to emit the \"gc\" signal", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_property(object_class, + PROP_GC_NOTIFICATIONS, + pspec); + + signals[SIGNAL_GC] = g_signal_new("gc", G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + gjs_register_native_module("byteArray", gjs_define_byte_array_stuff, 0); } @@ -386,6 +407,11 @@ gjs_context_finalize(GObject *object) js_context = GJS_CONTEXT(object); + if (js_context->idle_emit_gc_id > 0) { + g_source_remove (js_context->idle_emit_gc_id); + js_context->idle_emit_gc_id = 0; + } + if (js_context->search_path != NULL) { g_strfreev(js_context->search_path); js_context->search_path = NULL; @@ -674,6 +700,9 @@ gjs_context_constructor (GType type, /* For GjsDBus */ g_irepository_prepend_search_path(PKGLIBDIR); + if (js_context->gc_notifications_enabled) + JS_SetGCCallback(js_context->context, gjs_on_context_gc); + JS_EndRequest(js_context->context); g_static_mutex_lock (&contexts_lock); @@ -697,6 +726,9 @@ gjs_context_get_property (GObject *object, case PROP_JS_VERSION: g_value_set_string(value, js_context->jsversion_string); break; + case PROP_GC_NOTIFICATIONS: + g_value_set_boolean(value, js_context->gc_notifications_enabled); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -727,7 +759,9 @@ gjs_context_set_property (GObject *object, else js_context->jsversion_string = g_value_dup_string(value); break; - + case PROP_GC_NOTIFICATIONS: + js_context->gc_notifications_enabled = g_value_get_boolean(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -865,6 +899,32 @@ gjs_context_maybe_gc (GjsContext *context) gjs_maybe_gc(context->context); } +static gboolean +gjs_context_idle_emit_gc (gpointer data) +{ + GjsContext *gjs_context = data; + + gjs_context->idle_emit_gc_id = 0; + + g_signal_emit (gjs_context, signals[SIGNAL_GC], 0); + + return FALSE; +} + +static JSBool +gjs_on_context_gc (JSContext *cx, + JSGCStatus status) +{ + GjsContext *gjs_context = JS_GetContextPrivate(cx); + + if (status == JSGC_END) { + if (gjs_context->idle_emit_gc_id == 0) + gjs_context->idle_emit_gc_id = g_idle_add (gjs_context_idle_emit_gc, gjs_context); + } + + return TRUE; +} + /** * gjs_context_get_all: * -- cgit v0.9.0.2