Implemented a new system to provide a context-specific global rooted object
authorMatthew Mondor <mmondor@pulsar-zone.net>
Thu, 5 Oct 2006 18:43:38 +0000 (18:43 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Thu, 5 Oct 2006 18:43:38 +0000 (18:43 +0000)
on which other casses may attach arbitrary objects which should not be sweaped
away by the garbage collector.

Although the system clobbers context-specific user data pointer by using
JS_GetContextPrivate() and JS_SetContextPrivate(), it also exports two
functions to perform the same functionality if it was required:
js_GCRoot_udata_get() and js_GCRoot_udata_set().

It is important to call js_InitGCRoot() after JS_NewContext() and to
call js_DestroyGCRoot() before JS_DestroyContext() in applications which
depend on this library (such as js_pgsql.[ch]).

mmsoftware/js/classes/js_gcroot.c
mmsoftware/js/classes/js_gcroot.h
mmsoftware/js/classes/js_pgsql.c
mmsoftware/js/js-appserv/src/GNUmakefile
mmsoftware/js/js-appserv/src/js-appserv.c
mmsoftware/js/js-sh/src/GNUmakefile
mmsoftware/js/js-sh/src/js-sh.c

index 8d9ee71..fe99071 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: js_gcroot.c,v 1.1 2006/10/05 17:43:06 mmondor Exp $ */
+/* $Id: js_gcroot.c,v 1.2 2006/10/05 18:43:30 mmondor Exp $ */
 
 /*
  * Copyright (c) 2006, Matthew Mondor
 
 
 /*
+ * We define a structure allowing to continue storing context-specific
+ * user-data, while also storing the gcroot which requires a unique address in
+ * the process space (and can't be on the stack) to be rooted.
+ */
+typedef struct cxspec {
+       JSObject        *gcroot;
+       void            *udata;
+} cxspec_t;
+
+
+
+/*
  * Static globals
  */
 
@@ -35,11 +47,6 @@ static JSClass gcroot_class = {
        JS_FinalizeStub
 };
 
-/*
- * Exported globals
- */
-JSObject       *gcroot = NULL;
-
 
 
 /*
@@ -47,31 +54,82 @@ JSObject    *gcroot = NULL;
  */
 
 JSBool
-js_InitGCRootClass(JSContext *cx)
+js_InitGCRoot(JSContext *cx)
 {
+       cxspec_t        *d = NULL;
+
+       if ((d = malloc(sizeof(cxspec_t))) == NULL) {
+               (void) fprintf(stderr, "GCRoot: malloc()\n");
+               return JS_FALSE;
+       }
+       d->udata = NULL;
 
        /* Instantiate new object */
-       if ((gcroot = JS_NewObject(cx, &gcroot_class, NULL, NULL)) == NULL) {
+       if ((d->gcroot = JS_NewObject(cx, &gcroot_class, NULL, NULL))
+           == NULL) {
                (void) fprintf(stderr, "GCRoot: JS_NewObject(gcroot)\n");
-               return JS_FALSE;
+               goto err;
        }
-       if (!JS_AddRoot(cx, &gcroot)) {
+       if (!JS_AddRoot(cx, &d->gcroot)) {
                (void) fprintf(stderr, "GCRoot: JS_AddRoot(gcroot)\n");
-               gcroot = NULL;
-               return JS_FALSE;
+               goto err;
        }
+       JS_SetContextPrivate(cx, d);
 
        return JS_TRUE;
+
+err:
+       if (d != NULL)
+               free(d);
+
+       return JS_FALSE;
 }
 
 void
-js_DestroyGCRootClass(JSContext *cx)
+js_DestroyGCRoot(JSContext *cx)
 {
-
-       if (gcroot != NULL) {
-               if (!JS_RemoveRoot(cx, &gcroot))
-                       (void) fprintf(stderr,
-                           "GCRoot: JS_RemoveRoot(gcroot)\n");
-               gcroot = NULL;
+       cxspec_t        *d;
+
+       if ((d = JS_GetContextPrivate(cx)) != NULL) {
+               if (d->gcroot != NULL) {
+                       if (!JS_RemoveRoot(cx, &d->gcroot))
+                               (void) fprintf(stderr,
+                                   "GCRoot: JS_RemoveRoot(gcroot)\n");
+               }
+               free(d);
+               JS_SetContextPrivate(cx, NULL);
        }
 }
+
+JSObject *
+js_GCRoot(JSContext *cx)
+{
+       cxspec_t        *d;
+
+       d = JS_GetContextPrivate(cx);
+       assert(d != NULL);
+
+       return d->gcroot;
+}
+
+void
+js_GCRoot_udata_set(JSContext *cx, void *udata)
+{
+       cxspec_t        *d;
+
+       d = JS_GetContextPrivate(cx);
+       assert(d != NULL);
+
+       d->udata = udata;
+}
+
+void *
+js_GCroot_udata_get(JSContext *cx)
+{
+       cxspec_t        *d;
+
+       d = JS_GetContextPrivate(cx);
+       assert(d != NULL);
+
+       return d->udata;
+}
index 03e4e5a..c52ba44 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: js_gcroot.h,v 1.1 2006/10/05 17:43:06 mmondor Exp $ */
+/* $Id: js_gcroot.h,v 1.2 2006/10/05 18:43:30 mmondor Exp $ */
 
 /*
  * Copyright (c) 2006, Matthew Mondor
 
 #include <js_gcroot.h>
 
-extern JSBool  js_InitGCRootClass(JSContext *);
-extern void    js_DestroyGCRootClass(JSContext *);
-
-/* This rooted object can be added properties to by any class as needed */
-extern JSObject *gcroot;
+extern JSBool  js_InitGCRoot(JSContext *);
+extern void    js_DestroyGCRoot(JSContext *);
+extern JSObject        *js_GCRoot(JSContext *);
+extern void    js_GCRoot_udata_set(JSContext *, void *);
+extern void    *js_GCRoot_udata_get(JSContext *);
 
 #endif
index b72cc70..a6c6863 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: js_pgsql.c,v 1.8 2006/10/05 17:43:06 mmondor Exp $ */
+/* $Id: js_pgsql.c,v 1.9 2006/10/05 18:43:30 mmondor Exp $ */
 
 /*
  * Copyright (c) 2006, Matthew Mondor
@@ -2609,6 +2609,7 @@ pgconn_m_PQtrace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 {
        PGconn          *pgc;
        FILE            *fh;
+       JSObject        *gcroot;
 
        *rval = OBJECT_TO_JSVAL(NULL);
 
@@ -2628,6 +2629,8 @@ pgconn_m_PQtrace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         * Unroot previously rooted File object, if any, then root newly
         * provided File object.
         */
+       gcroot = js_GCRoot(cx);
+       assert(gcroot != NULL);
        (void) JS_DeleteProperty(cx, gcroot, "trace_file_root");
        if (!JS_DefineProperty(cx, gcroot, "trace_file_root", argv[0],
            NULL, NULL, 0)) {
@@ -2648,6 +2651,7 @@ pgconn_m_PQuntrace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
     jsval *rval)
 {
        PGconn          *pgc;
+       JSObject        *gcroot;
 
        *rval = OBJECT_TO_JSVAL(NULL);
 
@@ -2662,6 +2666,8 @@ pgconn_m_PQuntrace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
        /*
         * Unroot previously rooted File object
         */
+       gcroot = js_GCRoot(cx);
+       assert(gcroot != NULL);
        (void) JS_DeleteProperty(cx, gcroot, "trace_file_root");
 
        PQuntrace(pgc);
index 4c91606..4c56233 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: GNUmakefile,v 1.2 2006/09/08 12:50:45 mmondor Exp $
+# $Id: GNUmakefile,v 1.3 2006/10/05 18:43:36 mmondor Exp $
 
 CFLAGS += -Wall -DDEBUG
 
@@ -13,7 +13,8 @@ PG_LDFLAGS += -lpq
 
 MMOBJS := $(addprefix ../../../mmlib/,mmpool.o mmlog.o mmreadcfg.o \
        mmstring.o mmhash.o mmalarm.o mmheap.o mmlimitrate.o mmserver2.o)
-JSOBJS := $(addprefix ../../classes/,js_errno.o js_fd.o js_pgsql.o js_dir.o)
+JSOBJS := $(addprefix ../../classes/,js_gcroot.o js_errno.o js_fd.o js_file.o \
+       js_pgsql.o js_dir.o)
 
 
 CFLAGS += $(JS_CFLAGS) $(PG_CFLAGS) -I. -I../../../mmlib -I../../classes
index 7bdccfc..3a3c2b8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: js-appserv.c,v 1.2 2006/09/08 12:50:45 mmondor Exp $ */
+/* $Id: js-appserv.c,v 1.3 2006/10/05 18:43:36 mmondor Exp $ */
 
 /*
  * Copyright (C) 2006, Matthew Mondor
@@ -72,6 +72,7 @@
 #include <mmstring.h>
 #include <mmserver2.h>
 
+#include <js_gcroot.h>
 #include <js_errno.h>
 #include <js_fd.h>
 #include <js_pgsql.h>
@@ -641,6 +642,7 @@ branch_callback(JSContext *ctx, JSScript *s)
 static void
 context_error_reporter(JSContext *cx, const char *msg, JSErrorReport *rep)
 {
+
        syslog(LOG_NOTICE, "context_error_reporter() - %s : %s",
            msg, rep->linebuf);
 }
@@ -666,6 +668,10 @@ context_create(JSRuntime *rt, size_t stacksize, JSObject **obj)
        }
 
        /* Wanted custom classes */
+       if (!js_InitGCRoot(ctx)) {
+               syslog(LOG_NOTICE, "context_create() - js_InitGCRoot()");
+               goto err;
+       }
        if (!js_InitErrnoClass(ctx, *obj)) {
                syslog(LOG_NOTICE, "context_create() - js_InitErrnoClass()");
                goto err;
@@ -687,8 +693,10 @@ context_create(JSRuntime *rt, size_t stacksize, JSObject **obj)
        return ctx;
 
 err:
-       if (ctx)
+       if (ctx != NULL) {
+               js_DestroyGCRoot(ctx);
                JS_DestroyContext(ctx);
+       }
 
        return NULL;
 }
@@ -718,6 +726,7 @@ script_reload(const char *file)
                }
                if (p_ctx != NULL) {
                        (void) JS_RemoveRoot(p_ctx, &p_robj);
+                       js_DestroyGCRoot(p_ctx);
                        JS_DestroyContext(p_ctx);
                        p_ctx = NULL;
                }
@@ -772,8 +781,10 @@ script_reload(const char *file)
 err:
        if (script && ctx)
                JS_DestroyScript(ctx, script);
-       if (ctx)
+       if (ctx) {
+               js_DestroyGCRoot(ctx);
                JS_DestroyContext(ctx);
+       }
        if (rt)
                JS_DestroyRuntime(rt);
 
index 65f84df..40bab4e 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: GNUmakefile,v 1.4 2006/09/25 23:06:28 mmondor Exp $
+# $Id: GNUmakefile,v 1.5 2006/10/05 18:43:38 mmondor Exp $
 
 #CFLAGS += -g
 CFLAGS += -Wall
@@ -14,8 +14,8 @@ GD_CFLAGS := $(shell gdlib-config --cflags)
 GD_LDFLAGS := $(shell gdlib-config --ldflags --libs)
 GD_LDFLAGS += -lgd
 
-OBJS := $(addprefix ../../classes/,js_fd.o js_errno.o js_signal.o js_file.o \
-       js_pgsql.o js_dir.o js_fs.o js_gd.o)
+OBJS := $(addprefix ../../classes/,js_gcroot.o js_fd.o js_errno.o js_signal.o \
+       js_file.o js_pgsql.o js_dir.o js_fs.o js_gd.o)
 OBJS += js-sh.o
 
 CFLAGS += $(JS_CFLAGS) $(PG_CFLAGS) $(GD_CFLAGS) -I../../classes -Wall
index 91d6271..09be511 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: js-sh.c,v 1.6 2006/09/25 23:06:28 mmondor Exp $ */
+/* $Id: js-sh.c,v 1.7 2006/10/05 18:43:38 mmondor Exp $ */
 
 /*
  * Copyright (c) 2004-2005, Matthew Mondor
@@ -36,6 +36,7 @@
 
 #include <jsapi.h>
 
+#include <js_gcroot.h>
 #include <js_fd.h>
 #include <js_errno.h>
 #include <js_signal.h>
@@ -233,6 +234,7 @@ js_context_init(size_t gc_size, size_t stack_size)
            (cctx->global = JS_NewObject(cctx->ctx, &global_class, NULL,
                NULL)) == NULL ||
            !JS_InitStandardClasses(cctx->ctx, cctx->global) ||
+           !js_InitGCRoot(cctx->ctx) ||
            (cctx->class_fd = js_InitFDClass(cctx->ctx, cctx->global))
                == NULL ||
            (cctx->class_errno = js_InitErrnoClass(cctx->ctx, cctx->global))
@@ -263,8 +265,10 @@ js_context_destroy(js_context_t *cctx)
 
        assert(cctx != NULL);
 
-       if (cctx->ctx != NULL)
+       if (cctx->ctx != NULL) {
+               js_DestroyGCRoot(cctx->ctx);
                JS_DestroyContext(cctx->ctx);
+       }
        if (cctx->rt != NULL)
                JS_DestroyRuntime(cctx->rt);