From: Adrien Bustany Date: Wed, 18 Jul 2012 18:34:31 +0000 (+0300) Subject: [PATCH 3/7] go: Allow notmuch objects to be garbage collected X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=712bb0801ed5b4bb0344204c3a7b2c05d469dfd2;p=notmuch-archives.git [PATCH 3/7] go: Allow notmuch objects to be garbage collected --- diff --git a/db/3a9ad84ec00c33e7e6241f94a1aaedda51adb2 b/db/3a9ad84ec00c33e7e6241f94a1aaedda51adb2 new file mode 100644 index 000000000..523329f4f --- /dev/null +++ b/db/3a9ad84ec00c33e7e6241f94a1aaedda51adb2 @@ -0,0 +1,363 @@ +Return-Path: +X-Original-To: notmuch@notmuchmail.org +Delivered-To: notmuch@notmuchmail.org +Received: from localhost (localhost [127.0.0.1]) + by olra.theworths.org (Postfix) with ESMTP id 677E7431FDE + for ; Wed, 18 Jul 2012 11:41:09 -0700 (PDT) +X-Virus-Scanned: Debian amavisd-new at olra.theworths.org +X-Spam-Flag: NO +X-Spam-Score: 0 +X-Spam-Level: +X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none] + autolearn=disabled +Received: from olra.theworths.org ([127.0.0.1]) + by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) + with ESMTP id Fgysct7-kN8i for ; + Wed, 18 Jul 2012 11:41:07 -0700 (PDT) +Received: from mail.bustany.org (bustany.org [176.31.244.208]) + by olra.theworths.org (Postfix) with ESMTP id 81E4A431FC4 + for ; Wed, 18 Jul 2012 11:41:05 -0700 (PDT) +Received: from localhost.localdomain (91-158-2-79.elisa-laajakaista.fi + [91.158.2.79]) + by mail.bustany.org (Postfix) with ESMTPSA id 6A6D91400C2 + for ; Wed, 18 Jul 2012 20:37:08 +0200 (CEST) +From: Adrien Bustany +To: notmuch@notmuchmail.org +Subject: [PATCH 3/7] go: Allow notmuch objects to be garbage collected +Date: Wed, 18 Jul 2012 21:34:31 +0300 +Message-Id: <1342636475-16057-4-git-send-email-adrien@bustany.org> +X-Mailer: git-send-email 1.7.7.6 +In-Reply-To: <1342636475-16057-1-git-send-email-adrien@bustany.org> +References: <1342636475-16057-1-git-send-email-adrien@bustany.org> +X-BeenThere: notmuch@notmuchmail.org +X-Mailman-Version: 2.1.13 +Precedence: list +List-Id: "Use and development of the notmuch mail system." + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +X-List-Received-Date: Wed, 18 Jul 2012 18:41:10 -0000 + +This makes notmuch appropriately free the underlying notmuch C objects +when garbage collecting their Go wrappers. To make sure we don't break +the underlying links between objects (for example, a notmuch_messages_t +being GC'ed before a notmuch_message_t belonging to it), we add for each +wraper struct a pointer to the owner object (Go objects with a reference +pointing to them don't get garbage collected). +--- + bindings/go/src/notmuch/notmuch.go | 153 +++++++++++++++++++++++++++++++----- + 1 files changed, 134 insertions(+), 19 deletions(-) + +diff --git a/bindings/go/src/notmuch/notmuch.go b/bindings/go/src/notmuch/notmuch.go +index 1d77fd2..3f436a0 100644 +--- a/bindings/go/src/notmuch/notmuch.go ++++ b/bindings/go/src/notmuch/notmuch.go +@@ -11,6 +11,7 @@ package notmuch + #include "notmuch.h" + */ + import "C" ++import "runtime" + import "unsafe" + + // Status codes used for the return values of most functions +@@ -47,40 +48,152 @@ func (self Status) String() string { + /* Various opaque data types. For each notmuch__t see the various + * notmuch_ functions below. */ + ++type Object interface {} ++ + type Database struct { + db *C.notmuch_database_t + } + ++func createDatabase(db *C.notmuch_database_t) *Database { ++ self := &Database{db: db} ++ ++ runtime.SetFinalizer(self, func(x *Database) { ++ if (x.db != nil) { ++ C.notmuch_database_destroy(x.db) ++ } ++ }) ++ ++ return self ++} ++ + type Query struct { + query *C.notmuch_query_t ++ owner Object ++} ++ ++func createQuery(query *C.notmuch_query_t, owner Object) *Query { ++ self := &Query{query: query, owner: owner} ++ ++ runtime.SetFinalizer(self, func(x *Query) { ++ if (x.query != nil) { ++ C.notmuch_query_destroy(x.query) ++ } ++ }) ++ ++ return self + } + + type Threads struct { + threads *C.notmuch_threads_t ++ owner Object ++} ++ ++func createThreads(threads *C.notmuch_threads_t, owner Object) *Threads { ++ self := &Threads{threads: threads, owner: owner} ++ ++ runtime.SetFinalizer(self, func(x *Threads) { ++ if (x.threads != nil) { ++ C.notmuch_threads_destroy(x.threads) ++ } ++ }) ++ ++ return self + } + + type Thread struct { + thread *C.notmuch_thread_t ++ owner Object ++} ++ ++func createThread(thread *C.notmuch_thread_t, owner Object) *Thread { ++ self := &Thread{thread: thread, owner: owner} ++ ++ runtime.SetFinalizer(self, func(x *Thread) { ++ if (x.thread != nil) { ++ C.notmuch_thread_destroy(x.thread) ++ } ++ }) ++ ++ return self + } + + type Messages struct { + messages *C.notmuch_messages_t ++ owner Object ++} ++ ++func createMessages(messages *C.notmuch_messages_t, owner Object) *Messages { ++ self := &Messages{messages: messages, owner: owner} ++ ++ return self + } + + type Message struct { + message *C.notmuch_message_t ++ owner Object ++} ++ ++func createMessage(message *C.notmuch_message_t, owner Object) *Message { ++ self := &Message{message: message, owner: owner} ++ ++ runtime.SetFinalizer(self, func(x *Message) { ++ if (x.message != nil) { ++ C.notmuch_message_destroy(x.message) ++ } ++ }) ++ ++ return self + } + + type Tags struct { + tags *C.notmuch_tags_t ++ owner Object ++} ++ ++func createTags(tags *C.notmuch_tags_t, owner Object) *Tags { ++ self := &Tags{tags: tags, owner: owner} ++ ++ runtime.SetFinalizer(self, func(x *Tags) { ++ if (x.tags != nil) { ++ C.notmuch_tags_destroy(x.tags) ++ } ++ }) ++ ++ return self + } + + type Directory struct { + dir *C.notmuch_directory_t ++ owner Object ++} ++ ++func createDirectory(directory *C.notmuch_directory_t, owner Object) *Directory { ++ self := &Directory{dir: directory, owner: owner} ++ ++ runtime.SetFinalizer(self, func(x *Directory) { ++ if (x.dir != nil) { ++ C.notmuch_directory_destroy(x.dir) ++ } ++ }) ++ ++ return self + } + + type Filenames struct { + fnames *C.notmuch_filenames_t ++ owner Object ++} ++ ++func createFilenames(filenames *C.notmuch_filenames_t, owner Object) *Filenames { ++ self := &Filenames{fnames: filenames, owner: owner} ++ ++ runtime.SetFinalizer(self, func(x *Filenames) { ++ if (x.fnames != nil) { ++ C.notmuch_filenames_destroy(x.fnames) ++ } ++ }) ++ ++ return self + } + + type DatabaseMode C.notmuch_database_mode_t +@@ -100,12 +213,13 @@ func NewDatabase(path string) (*Database, Status) { + return nil, STATUS_OUT_OF_MEMORY + } + +- self := &Database{db: nil} +- st := Status(C.notmuch_database_create(c_path, &self.db)) ++ var db *C.notmuch_database_t; ++ st := Status(C.notmuch_database_create(c_path, &db)) + if st != STATUS_SUCCESS { + return nil, st + } +- return self, st ++ ++ return createDatabase(db), st + } + + /* Open an existing notmuch database located at 'path'. +@@ -134,12 +248,13 @@ func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) { + return nil, STATUS_OUT_OF_MEMORY + } + +- self := &Database{db: nil} +- st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db)) ++ var db *C.notmuch_database_t; ++ st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &db)) + if st != STATUS_SUCCESS { + return nil, st + } +- return self, st ++ ++ return createDatabase(db), st + } + + /* Close the given notmuch database, freeing all associated +@@ -204,7 +319,7 @@ func (self *Database) GetDirectory(path string) (*Directory, Status) { + if st != STATUS_SUCCESS || c_dir == nil { + return nil, st + } +- return &Directory{dir: c_dir}, st ++ return createDirectory(c_dir, nil), st + } + + /* Add a new message to the given notmuch database. +@@ -258,7 +373,7 @@ func (self *Database) AddMessage(fname string) (*Message, Status) { + var c_msg *C.notmuch_message_t = new(C.notmuch_message_t) + st := Status(C.notmuch_database_add_message(self.db, c_fname, &c_msg)) + +- return &Message{message: c_msg}, st ++ return createMessage(c_msg, nil), st + } + + /* Remove a message from the given notmuch database. +@@ -319,12 +434,12 @@ func (self *Database) FindMessage(message_id string) (*Message, Status) { + return nil, STATUS_OUT_OF_MEMORY + } + +- msg := &Message{message: nil} +- st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg.message)) ++ var msg *C.notmuch_message_t ++ st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg)) + if st != STATUS_SUCCESS { + return nil, st + } +- return msg, st ++ return createMessage(msg, nil), st + } + + /* Return a list of all tags found in the database. +@@ -339,7 +454,7 @@ func (self *Database) GetAllTags() *Tags { + if tags == nil { + return nil + } +- return &Tags{tags: tags} ++ return createTags(tags, nil) + } + + /* Create a new query for 'database'. +@@ -379,7 +494,7 @@ func (self *Database) CreateQuery(query string) *Query { + if q == nil { + return nil + } +- return &Query{query: q} ++ return createQuery(q, nil) + } + + /* Sort values for notmuch_query_set_sort */ +@@ -459,7 +574,7 @@ func (self *Query) SearchThreads() *Threads { + if threads == nil { + return nil + } +- return &Threads{threads: threads} ++ return createThreads(threads, self) + } + + /* Execute a query for messages, returning a notmuch_messages_t object +@@ -505,7 +620,7 @@ func (self *Query) SearchMessages() *Messages { + if msgs == nil { + return nil + } +- return &Messages{messages: msgs} ++ return createMessages(msgs, self) + } + + /* Destroy a notmuch_query_t along with any associated resources. +@@ -607,7 +722,7 @@ func (self *Messages) Get() *Message { + if msg == nil { + return nil + } +- return &Message{message: msg} ++ return createMessage(msg, self) + } + + /* Move the 'messages' iterator to the next message. +@@ -659,7 +774,7 @@ func (self *Messages) CollectTags() *Tags { + if tags == nil { + return nil + } +- return &Tags{tags: tags} ++ return createTags(tags, self) + } + + /* Get the message ID of 'message'. +@@ -739,7 +854,7 @@ func (self *Message) GetReplies() *Messages { + if msgs == nil { + return nil + } +- return &Messages{messages: msgs} ++ return createMessages(msgs, self) + } + + /* Get a filename for the email corresponding to 'message'. +@@ -871,7 +986,7 @@ func (self *Message) GetTags() *Tags { + if tags == nil { + return nil + } +- return &Tags{tags: tags} ++ return createTags(tags, self) + } + + /* The longest possible tag value. */ +-- +1.7.7.6 +