Commit c7893408 (ruby: Kill garbage collection related cruft., 2010-05-26) removed garbage collection because the order of objects freed couldn't be ensured in Ruby.
However, we can use talloc for reference counting and thus preventing Ruby from destroying the objects. First we create a wrapper object with no talloc parent, which will be owned by the Ruby object (e.g. Notmuch::Thread). The notmuch object (notmuch_thread_t) will have two parents then (notmuch_threads_t and Notmuch::Thread). If Ruby destroys the other parent first (notmuch_threads_t), that still doesn't destroy the object, since we still own a reference (from Notmuch::Thread). It's only when both are destroyed that the object is actually freed. Signed-off-by: Felipe Contreras <felipe.contre...@gmail.com> --- bindings/ruby/defs.h | 24 +++++++++++++++++++++++- bindings/ruby/extconf.rb | 1 + bindings/ruby/thread.c | 6 +++--- bindings/ruby/threads.c | 2 +- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index 48544ca2..56a70a4f 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -23,6 +23,7 @@ #include <notmuch.h> #include <ruby.h> +#include <talloc.h> extern VALUE notmuch_rb_cDatabase; extern VALUE notmuch_rb_cDirectory; @@ -50,6 +51,25 @@ extern ID ID_call; extern ID ID_db_create; extern ID ID_db_mode; +typedef struct { + void *pointer; +} notmuch_rb_object_t; + +static inline void +notmuch_rb_object_free (void *object) +{ + talloc_free (object); +} + +static inline VALUE +notmuch_rb_object_wrap (VALUE klass, void *ptr) +{ + notmuch_rb_object_t *object = talloc (NULL, typeof (*object)); + object->pointer = ptr; + talloc_reference (object, ptr); + return Data_Wrap_Struct (klass, NULL, ¬much_rb_object_free, object); +} + /* RSTRING_PTR() is new in ruby-1.9 */ #if !defined(RSTRING_PTR) # define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -105,10 +125,12 @@ extern ID ID_db_mode; #define Data_Get_Notmuch_Thread(obj, ptr) \ do { \ + notmuch_rb_object_t *object; \ Check_Type ((obj), T_DATA); \ if (DATA_PTR ((obj)) == NULL) \ rb_raise (rb_eRuntimeError, "thread destroyed"); \ - Data_Get_Struct ((obj), notmuch_thread_t, (ptr)); \ + Data_Get_Struct ((obj), typeof (*object), object); \ + (ptr) = object->pointer; \ } while (0) #define Data_Get_Notmuch_Message(obj, ptr) \ diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb index 161de5a2..d914537c 100644 --- a/bindings/ruby/extconf.rb +++ b/bindings/ruby/extconf.rb @@ -19,6 +19,7 @@ if not ENV['LIBNOTMUCH'] end $LOCAL_LIBS += ENV['LIBNOTMUCH'] +$LIBS += " -ltalloc" # Create Makefile dir_config('notmuch') diff --git a/bindings/ruby/thread.c b/bindings/ruby/thread.c index 9b295981..5705b556 100644 --- a/bindings/ruby/thread.c +++ b/bindings/ruby/thread.c @@ -28,11 +28,11 @@ VALUE notmuch_rb_thread_destroy (VALUE self) { - notmuch_thread_t *thread; + notmuch_rb_object_t *object; - Data_Get_Notmuch_Thread (self, thread); + Data_Get_Struct (self, typeof (*object), object); - notmuch_thread_destroy (thread); + notmuch_rb_object_free (object); DATA_PTR (self) = NULL; return Qnil; diff --git a/bindings/ruby/threads.c b/bindings/ruby/threads.c index ed403a8f..302ffd91 100644 --- a/bindings/ruby/threads.c +++ b/bindings/ruby/threads.c @@ -53,7 +53,7 @@ notmuch_rb_threads_each (VALUE self) for (; notmuch_threads_valid (threads); notmuch_threads_move_to_next (threads)) { thread = notmuch_threads_get (threads); - rb_yield (Data_Wrap_Struct (notmuch_rb_cThread, NULL, NULL, thread)); + rb_yield (notmuch_rb_object_wrap (notmuch_rb_cThread, thread)); } return self; -- 2.31.0 _______________________________________________ notmuch mailing list -- notmuch@notmuchmail.org To unsubscribe send an email to notmuch-le...@notmuchmail.org