[Xfce4-commits] <glib-objc:no-foundation-dep> add GOCAutoreleasePool

Brian J. Tarricone noreply at xfce.org
Sun Nov 22 04:02:12 CET 2009


Updating branch refs/heads/no-foundation-dep
         to 1d91dc5a0c829920f3fcace5d9bdf5fdcad4e357 (commit)
       from d921853cce5748585fda21b96a51ec75716736ba (commit)

commit 1d91dc5a0c829920f3fcace5d9bdf5fdcad4e357
Author: Brian J. Tarricone <brian at tarricone.org>
Date:   Tue Jul 7 03:29:33 2009 -0700

    add GOCAutoreleasePool

 .../{GOCComparable.h => GOCAutoreleasePool.h}      |   21 +-
 glib-objc/GOCAutoreleasePool.m                     |  272 ++++++++++++++++++++
 glib-objc/GOCObjectBase.h                          |    2 +
 glib-objc/GOCObjectBase.m                          |   12 +
 glib-objc/Makefile.am                              |    2 +
 5 files changed, 302 insertions(+), 7 deletions(-)

diff --git a/glib-objc/GOCComparable.h b/glib-objc/GOCAutoreleasePool.h
similarity index 70%
copy from glib-objc/GOCComparable.h
copy to glib-objc/GOCAutoreleasePool.h
index 5156add..9853e4d 100644
--- a/glib-objc/GOCComparable.h
+++ b/glib-objc/GOCAutoreleasePool.h
@@ -17,17 +17,24 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-
-#ifndef __GOC_COMPARABLE_H__
-#define __GOC_COMPARABLE_H__
+#ifndef __GOC_AUTORELEASE_POOL_H__
+#define __GOC_AUTORELEASE_POOL_H__
 
 #import <glib-objc/GOCObjectBase.h>
 
- at protocol GOCComparable<GOCObject>
+typedef struct _GOCAutoreleasePoolPriv  GOCAutoreleasePoolPriv;
+
+ at interface GOCAutoreleasePool : GOCObjectBase
+{
+  @private
+    GOCAutoreleasePoolPriv *priv;
+}
+
++ (void)addObject:(id <GOCObject>)obj;
+- (void)addObject:(id <GOCObject>)obj;
 
-- (int)compareTo:(id <GOCComparable>)otherComparable;
-- (BOOL)isEqualTo:(id <GOCComparable>)otherComparable;
+- (void)drain;
 
 @end
 
-#endif  /* __GOC_COMPARABLE_H__ */
+#endif  /* __GOC_AUTORELEASE_POOL_H__ */
diff --git a/glib-objc/GOCAutoreleasePool.m b/glib-objc/GOCAutoreleasePool.m
new file mode 100644
index 0000000..ada7a76
--- /dev/null
+++ b/glib-objc/GOCAutoreleasePool.m
@@ -0,0 +1,272 @@
+/*
+ *  glib-objc - objective-c bindings for glib/gobject
+ *
+ *  Copyright (c) 2009 Brian Tarricone <brian at tarricone.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published
+ *  by the Free Software Foundation; version 2 of the License ONLY.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+#import "GOCAutoreleasePool.h"
+
+#define INITIAL_ARRAY_SIZE  32
+
+struct _GOCAutoreleasePoolPriv
+{
+    GPtrArray *objects;
+};
+
+ at implementation GOCAutoreleasePool
+
+enum
+{
+    THREADING_UNKNOWN = 0,
+    THREADING_DISABLED,
+    THREADING_ENABLED,
+};
+
+static int threading_state = THREADING_UNKNOWN;
+
+G_LOCK_DEFINE_STATIC(thread_pool);
+static GHashTable *thread_pool = NULL;
+/* GPrivate objects can't be destroyed, so we'll cache them when they're no longer
+ * used and then reuse them if new threads get created */
+static GSList *gprivate_cache = NULL;
+
+/* used only when threading is disabled */
+static GList *unthreaded_pools = NULL;
+
+static void
+thread_private_free(GPrivate *thpriv)
+{
+    GList *pools = g_private_get(thpriv), *l;
+
+    for(l = pools; l; l = l->next) {
+        GOCAutoreleasePool *pool = l->data;
+        [pool drain];
+    }
+
+    g_private_set(thpriv, NULL);
+
+    G_LOCK(thread_pool);
+    gprivate_cache = g_slist_prepend(gprivate_cache, thpriv);
+    G_UNLOCK(thread_pool);
+}
+
+static void
+thread_destroyed(GList *pools)
+{
+    /* we don't need to do anything with the pools, as thread_private_free() will
+     * take care of it when we remove it from the hash table */
+
+    /* FIXME: be sure that this actually runs in the thread that's ending so
+     * g_thread_self() returns what we want */
+
+    G_LOCK(thread_pool);
+    g_hash_table_remove(thread_pool, g_thread_self());
+    G_UNLOCK(thread_pool);
+}
+
++ (id)new
+{
+    return [[self alloc] init];
+}
+
+- (id)init
+{
+    if(threading_state == THREADING_UNKNOWN) {
+        threading_state = g_thread_supported() ? THREADING_ENABLED : THREADING_DISABLED;
+
+        if(threading_state == THREADING_ENABLED) {
+            G_LOCK(thread_pool);
+            thread_pool = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+                                                (GDestroyNotify)thread_private_free);
+            G_UNLOCK(thread_pool);
+        }
+    } else {
+        /* sanity check */
+        if(threading_state != THREADING_DISABLED && g_thread_supported())
+            g_critical("Threading state changed after GOCAutoreleasePool initialization.  Things WILL break!");
+    }
+
+    self = [super init];
+    if(self) {
+        priv = g_slice_new0(GOCAutoreleasePoolPriv);
+        priv->objects = g_ptr_array_sized_new(INITIAL_ARRAY_SIZE);
+
+        if(threading_state == THREADING_ENABLED) {
+            GPrivate *thpriv;
+            GList *pools;
+
+            G_LOCK(thread_pool);
+
+            thpriv = g_hash_table_lookup(thread_pool, g_thread_self());
+            if(!thpriv) {
+                if(gprivate_cache) {
+                    thpriv = gprivate_cache->data;
+                    gprivate_cache = g_slist_delete_link(gprivate_cache, gprivate_cache);
+                } else
+                    thpriv = g_private_new((GDestroyNotify)thread_destroyed);
+
+                g_hash_table_insert(thread_pool, g_thread_self(), thpriv);
+            }
+
+            G_UNLOCK(thread_pool);
+
+            pools = g_private_get(thpriv);
+            pools = g_list_prepend(pools, self);
+            g_private_set(thpriv, pools);
+        } else
+            unthreaded_pools = g_list_prepend(unthreaded_pools, self);
+    }
+
+    return self;
+}
+
++ (void)addObject:(id <GOCObject>)obj
+{
+    GOCAutoreleasePool *pool = NULL;
+
+    switch(threading_state) {
+        case THREADING_ENABLED:
+        {
+            GPrivate *thpriv = NULL;
+            GList *pools = NULL;
+
+            G_LOCK(thread_pool);
+            thpriv = g_hash_table_lookup(thread_pool, g_thread_self());
+            G_UNLOCK(thread_pool);
+
+            if(thpriv)
+                pools = g_private_get(thpriv);
+
+            if(pools)
+                pool = pools->data;
+
+            break;
+        }
+
+        case THREADING_DISABLED:
+            if(unthreaded_pools)
+                pool = unthreaded_pools->data;
+            break;
+
+        default:
+            /* warning below should catch it... */
+            break;
+    }
+    
+    if(G_LIKELY(pool))
+        [pool addObject:obj];
+    else
+        g_warning("No GOCAutoreleasePool active.  This will probably cause a memory leak!");
+}
+
+- (void)addObject:(id <GOCObject>)obj
+{
+    g_ptr_array_add(priv->objects, obj);
+}
+
+- (id <GOCObject>)ref
+{
+    /* autorelease pools don't support refcounting */
+    g_warning("Don't call -ref on GOCAutoreleasePool");
+    return self;
+}
+
+- (void)unref
+{
+    /* we'll only ever have a refcount of 1, so this'll trigger a free */
+    [self free];
+}
+
+- (id <GOCObject>)autounref
+{
+    /* autorelease pools don't support refcounting */
+    g_warning("Don't call -autounref on GOCAutoreleasePool");
+    return self;
+}
+
+- (void)_reallyFree
+{
+    GList *poolp = NULL;
+
+    g_ptr_array_free(priv->objects, TRUE);
+    g_slice_free(GOCAutoreleasePoolPriv, priv);
+
+    /* FIXME: we should probably handle the case where 'self' isn't on the top of
+     * the pool stack by draining all the pools above it as well */
+    switch(threading_state) {
+        case THREADING_ENABLED:
+        {
+            GPrivate *thpriv = NULL;
+
+            G_LOCK(thread_pool);
+            thpriv = g_hash_table_lookup(thread_pool, g_thread_self());
+            G_UNLOCK(thread_pool);
+
+            if(thpriv) {
+                GList *pools = g_private_get(thpriv);
+
+                if(pools) {
+                    poolp = g_list_find(pools, self);
+                    if(poolp) {
+                        pools = g_list_delete_link(pools, poolp);
+                        g_private_set(thpriv, pools);
+                    }
+                }
+            }
+            break;
+        }
+
+        case THREADING_DISABLED:
+            poolp = g_list_find(unthreaded_pools, self);
+            if(poolp)
+                unthreaded_pools = g_list_delete_link(unthreaded_pools, poolp);
+            break;
+
+        default:
+            g_assert_not_reached();
+            break;
+    }
+
+    if(G_UNLIKELY(!poolp))
+        g_critical("GOCAutoreleasePool %p not found in stack", self);
+
+    [super free];
+}
+
+- (void)drain
+{
+    int i;
+
+    for(i = 0; i < priv->objects->len; ++i) {
+        id <GOCObject> obj = g_ptr_array_index(priv->objects, i);
+        [obj unref];
+    }
+
+    [self _reallyFree];
+}
+
+- (void)free
+{
+    [self drain];  /* calls -_reallyFree */
+}
+
+ at end
diff --git a/glib-objc/GOCObjectBase.h b/glib-objc/GOCObjectBase.h
index e3a6937..46a9c06 100644
--- a/glib-objc/GOCObjectBase.h
+++ b/glib-objc/GOCObjectBase.h
@@ -27,6 +27,8 @@
 
 - (id <GOCObject>)ref;
 - (void)unref;
+- (id <GOCObject>)autounref;
+- (unsigned int)refCount;
 
 @end
 
diff --git a/glib-objc/GOCObjectBase.m b/glib-objc/GOCObjectBase.m
index 263f527..bbe1210 100644
--- a/glib-objc/GOCObjectBase.m
+++ b/glib-objc/GOCObjectBase.m
@@ -24,6 +24,7 @@
 #include <glib.h>
 
 #import "GOCObjectBase.h"
+#import "GOCAutoreleasePool.h"
 
 @implementation GOCObjectBase
 
@@ -50,4 +51,15 @@
     [self free];
 }
 
+- (id <GOCObject>)autounref
+{
+    [GOCAutoreleasePool addObject:self];
+    return self;
+}
+
+- (unsigned int)refCount
+{
+    return ref_count;
+}
+
 @end
diff --git a/glib-objc/Makefile.am b/glib-objc/Makefile.am
index 43d01d7..c06efe2 100644
--- a/glib-objc/Makefile.am
+++ b/glib-objc/Makefile.am
@@ -5,6 +5,7 @@ glibobjcmaininclude_HEADERS = \
 	glib-objc.h
 glibobjcincludedir = $(glibobjcmainincludedir)/glib-objc
 glibobjcinclude_HEADERS = \
+	GOCAutoreleasePool.h \
 	GOCComparable.h \
 	GOCHashable.h \
 	GOCHashTable.h \
@@ -16,6 +17,7 @@ glibobjcinclude_HEADERS = \
 libglib_objc_2_0_la_SOURCES = \
 	$(glibobjcmaininclude_HEADERS) \
 	$(glibobjcinclude_HEADERS) \
+	GOCAutoreleasePool.m \
 	GOCHashTable.m \
 	GOCList.m \
 	GOCMain.m \



More information about the Xfce4-commits mailing list