commit 071ee1ece415741372410b6aad80f896d353ee87
parent ee89b4aace41c4346f75824034ab9ea65e9498b7
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Fri, 24 Aug 2012 02:55:27 -0300
Added locking to kenvironment.
Diffstat:
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/src/kenvironment.c b/src/kenvironment.c
@@ -29,6 +29,7 @@
 /* GC: Assumes that parents is rooted */
 TValue kmake_environment(klisp_State *K, TValue parents)
 {
+    klisp_lock(K);
     Environment *new_env = klispM_new(K, Environment);
 
     /* header + gc_fields */
@@ -45,6 +46,8 @@ TValue kmake_environment(klisp_State *K, TValue parents)
     new_env->keyed_parents = KNIL;
     new_env->keyed_node = KNIL;
 
+    /* keep the lock, to avoid problems if the list of parents is mutated */
+
     /* Contruct the list of keyed parents */
     /* MAYBE: this could be optimized to avoid repetition of parents */
     TValue kparents;
@@ -85,6 +88,7 @@ TValue kmake_environment(klisp_State *K, TValue parents)
             kparents = kcar(kparents);
     }
     new_env->keyed_parents = kparents; /* overwrite with the proper value */
+    klisp_unlock(K);
     return gc2env(new_env);
 }
 
@@ -93,6 +97,8 @@ TValue kmake_environment(klisp_State *K, TValue parents)
 ** Only for list environments, table environments are handled elsewhere
 ** returns KNIL or a pair with sym as car.
 */
+
+/* LOCK: GIL should be acquired */
 TValue kfind_local_binding(klisp_State *K, TValue bindings, TValue sym)
 {
     UNUSED(K);
@@ -118,12 +124,12 @@ TValue kfind_local_binding(klisp_State *K, TValue bindings, TValue sym)
 /* GC: Assumes that obj & sym are rooted. */
 void ktry_set_name(klisp_State *K, TValue obj, TValue sym)
 {
+    klisp_lock(K);
     if (kcan_have_name(obj) && !khas_name(obj)) {
         /* TODO: maybe we could have some kind of inheritance so
            that if this object receives a name it can pass on that
            name to other objs, like applicatives to operatives & 
            some applicatives to objects */
-/* XXX lock? */
         gcvalue(obj)->gch.kflags |= K_FLAG_HAS_NAME;
         TValue *node = klispH_set(K, tv2table(G(K)->name_table), obj);
         *node = sym;
@@ -134,7 +140,6 @@ void ktry_set_name(klisp_State *K, TValue obj, TValue sym)
             /* underlying is rooted by means of obj */
             TValue underlying = kunwrap(obj);
             while (kcan_have_name(underlying) && !khas_name(underlying)) {
-/* XXX lock? */
                 gcvalue(underlying)->gch.kflags |= K_FLAG_HAS_NAME;
                 node = klispH_set(K, tv2table(G(K)->name_table), underlying);
                 *node = sym;
@@ -145,12 +150,13 @@ void ktry_set_name(klisp_State *K, TValue obj, TValue sym)
             }
         }
     }
+    klisp_unlock(K);
 }
 
 /* Assumes obj has a name */
 TValue kget_name(klisp_State *K, TValue obj)
 {
-/* XXX lock? */
+    /* LOCK: klispH_get will acquire the GIL */
     const TValue *node = klispH_get(tv2table(G(K)->name_table),
                                     obj);
     klisp_assert(node != &kfree);
@@ -168,6 +174,9 @@ void kadd_binding(klisp_State *K, TValue env, TValue sym, TValue val)
     ktry_set_name(K, val, sym);
 #endif
 
+    /* lock early because it is possible that even the environment
+       type changes (from list to table) */
+    klisp_lock(K);
     TValue bindings = kenv_bindings(K, env);
     if (ttistable(bindings)) {
         TValue *cell = klispH_setsym(K, tv2table(bindings), tv2sym(sym));
@@ -184,6 +193,7 @@ void kadd_binding(klisp_State *K, TValue env, TValue sym, TValue val)
             kset_cdr(oldb, val);
         }
     }
+    klisp_unlock(K);
 }
 
 /* This works no matter if parents is a list or a single environment */
@@ -191,6 +201,7 @@ void kadd_binding(klisp_State *K, TValue env, TValue sym, TValue val)
 static inline bool try_get_binding(klisp_State *K, TValue env, TValue sym, 
                             TValue *value)
 {
+    klisp_lock(K);
     /* assume the stack may be in use, keep track of pushed objs */
     int pushed = 1;
     ks_spush(K, env);
@@ -231,6 +242,8 @@ static inline bool try_get_binding(klisp_State *K, TValue env, TValue sym,
     }
 
     *value = KINERT;
+
+    klisp_unlock(K);
     return false;
 }
 
@@ -263,7 +276,9 @@ TValue kmake_keyed_static_env(klisp_State *K, TValue parent, TValue key,
 {
     TValue new_env = kmake_environment(K, parent);
     krooted_tvs_push(K, new_env); /* keep the env rooted */
+    klisp_lock(K);
     env_keyed_node(new_env) = kcons(K, key, val);
+    klisp_unlock(K);
     krooted_tvs_pop(K);
     return new_env;
 }
@@ -275,6 +290,7 @@ static inline bool try_get_keyed(klisp_State *K, TValue env, TValue key,
     /* MAYBE: this could be optimized to mark environments to avoid
        repetition */
     /* assume the stack may be in use, keep track of pushed objs */
+    /* LOCK: the key info structure is immutable, so no need to lock */
     int pushed = 1;
     if (!env_is_keyed(env))
         env = env_keyed_parents(env);
@@ -326,7 +342,9 @@ TValue kmake_table_environment(klisp_State *K, TValue parents)
     TValue new_env = kmake_environment(K, parents);
     krooted_tvs_push(K, new_env);
     TValue new_table = klispH_new(K, 0, ENVTABSIZE, K_FLAG_WEAK_NOTHING);
+    klisp_lock(K);
     tv2env(new_env)->bindings = new_table;
+    klisp_unlock(K);
     krooted_tvs_pop(K);
     return new_env;
 }