Commit 1a7ab04bb202135b3bd35d49fb4413b14a3fc0c6

Thomas de Grivel 2023-03-26T21:29:44

facts_lock

diff --git a/libc3/facts.c b/libc3/facts.c
index a8b944b..6f8d841 100644
--- a/libc3/facts.c
+++ b/libc3/facts.c
@@ -45,7 +45,7 @@ s_fact * facts_add_fact (s_facts *facts, const s_fact *fact)
   tmp.predicate = facts_ref_tag(facts, fact->predicate);
   tmp.object    = facts_ref_tag(facts, fact->object);
   if ((item = set_get__fact(&facts->facts, &tmp))) {
-    facts_lock_unlock(facts);
+    facts_lock_unlock_w(facts);
     return &item->data;
   }
   if (facts->log)
@@ -55,7 +55,7 @@ s_fact * facts_add_fact (s_facts *facts, const s_fact *fact)
   skiplist_insert__fact(facts->index_spo, f);
   skiplist_insert__fact(facts->index_pos, f);
   skiplist_insert__fact(facts->index_osp, f);
-  facts_lock_unlock(facts);
+  facts_lock_unlock_w(facts);
   return f;
 }
 
@@ -134,7 +134,7 @@ sw facts_dump (s_facts *facts, s_buf *buf)
       goto ko;
     result += r;
   }
-  facts_lock_unlock(facts);
+  facts_lock_unlock_r(facts);
   if ((r = buf_write_1(buf, "%{hash: 0x")) < 0)
     return r;
   result += r;
@@ -146,7 +146,7 @@ sw facts_dump (s_facts *facts, s_buf *buf)
   result += r;
   return result;
  ko:
-  facts_lock_unlock(facts);
+  facts_lock_unlock_r(facts);
   return r;
 }
 
@@ -183,7 +183,7 @@ s_fact * facts_find_fact (s_facts *facts, const s_fact *fact)
       (f.object    = facts_find_tag(facts, fact->object))    &&
       (item = set_get__fact((const s_set__fact *) &facts->facts, &f)))
     result = &item->data;
-  facts_lock_unlock(facts);
+  facts_lock_unlock_r(facts);
   return result;
 }
 
@@ -196,7 +196,7 @@ s_tag * facts_find_tag (s_facts *facts, const s_tag *tag)
   facts_lock_r(facts);
   if ((item = set_get__tag(&facts->tags, tag)))
     result = &item->data;
-  facts_lock_unlock(facts);
+  facts_lock_unlock_r(facts);
   return result;
 }
 
@@ -262,7 +262,7 @@ sw facts_load (s_facts *facts, s_buf *buf)
     }
     result += r;
   }
-  facts_lock_unlock(facts);
+  facts_lock_unlock_w(facts);
   hash_u64 = hash_to_u64(&hash);
   if ((r = buf_read_1(buf, "%{hash: 0x")) <= 0)
     goto ko_hash;
@@ -290,6 +290,7 @@ sw facts_load (s_facts *facts, s_buf *buf)
   warnx("facts_load: invalid or missing header");
   return -1;
  ko_fact:
+  facts_lock_unlock_w(facts);
   warnx("facts_load: %s fact line %lu", r ? "invalid" : "missing",
         (unsigned long) i + 4);
   return -1;
@@ -331,27 +332,50 @@ void facts_lock_init (s_facts *facts)
   assert(facts);
   if (pthread_rwlock_init(&facts->rwlock, NULL))
     errx(1, "facts_lock_init: pthread_rwlock_init");
+  facts->rwlock_count = 0;
+  facts->rwlock_thread = 0;
 }
 
 void facts_lock_r (s_facts *facts)
 {
+  pthread_t thread;
   assert(facts);
+  thread = pthread_self();
+  if (facts->rwlock_thread == thread)
+    return;
   if (pthread_rwlock_rdlock(&facts->rwlock))
     errx(1, "facts_lock_r: pthread_rwlock_rdlock");
 }
 
-void facts_lock_unlock (s_facts *facts)
+void facts_lock_unlock_r (s_facts *facts)
 {
   assert(facts);
   if (pthread_rwlock_unlock(&facts->rwlock))
-    errx(1, "facts_lock_unlock: pthread_rwlock_unlock");
+    errx(1, "facts_lock_unlock_r: pthread_rwlock_unlock");
+}
+
+void facts_lock_unlock_w (s_facts *facts)
+{
+  assert(facts);
+  facts->rwlock_count--;
+  if (! facts->rwlock_count) {
+    facts->rwlock_thread = NULL;
+    if (pthread_rwlock_unlock(&facts->rwlock))
+      errx(1, "facts_lock_unlock_w: pthread_rwlock_unlock");
+  }
 }
 
 void facts_lock_w (s_facts *facts)
 {
+  pthread_t thread;
   assert(facts);
-  if (pthread_rwlock_wrlock(&facts->rwlock))
-    errx(1, "facts_lock_w: pthread_rwlock_wrlock");
+  thread = pthread_self();
+  if (facts->rwlock_thread != thread) {
+    if (pthread_rwlock_wrlock(&facts->rwlock))
+      errx(1, "facts_lock_w: pthread_rwlock_wrlock");
+    facts->rwlock_thread = thread;
+  }
+  facts->rwlock_count++;
 }
 
 sw facts_log_add (s_log *log, const s_fact *fact)
@@ -550,7 +574,7 @@ e_bool facts_remove_fact (s_facts *facts, const s_fact *fact)
     facts_unref_tag(facts, f.object);
     result = true;
   }
-  facts_lock_unlock(facts);
+  facts_lock_unlock_w(facts);
   return result;
 }
 
diff --git a/libc3/facts.h b/libc3/facts.h
index 15802ee..228237e 100644
--- a/libc3/facts.h
+++ b/libc3/facts.h
@@ -40,7 +40,8 @@ sw       facts_load_file (s_facts *facts, const s8 *path);
 void     facts_lock_clean (s_facts *facts);
 void     facts_lock_init (s_facts *facts);
 void     facts_lock_r (s_facts *facts);
-void     facts_lock_unlock (s_facts *facts);
+void     facts_lock_unlock_r (s_facts *facts);
+void     facts_lock_unlock_w (s_facts *facts);
 void     facts_lock_w (s_facts *facts);
 sw       facts_open_file (s_facts *facts, const s8 *path);
 s_tag *  facts_ref_tag (s_facts *facts, const s_tag *tag);
diff --git a/libc3/types.h b/libc3/types.h
index 216c2ff..20a2956 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -411,6 +411,8 @@ struct facts {
   s_skiplist__fact *index_osp;
   s_log            *log;
   pthread_rwlock_t  rwlock;
+  sw                rwlock_count;
+  pthread_t         rwlock_thread;
 };
 
 struct facts_cursor {