2001-12-17 14:31:42 +00:00
|
|
|
|
/** Implementation of auto release pool for delayed disposal
|
1997-03-03 19:56:37 +00:00
|
|
|
|
Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
|
1995-03-12 19:35:17 +00:00
|
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1995-03-12 19:35:17 +00:00
|
|
|
|
Date: January 1995
|
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1995-03-12 19:35:17 +00:00
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This library 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 Library General Public
|
|
|
|
|
License along with this library; if not, write to the Free
|
1999-09-09 02:56:20 +00:00
|
|
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSAutoreleasePool class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
1995-03-12 19:35:17 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
|
#include <config.h>
|
1998-12-20 21:27:47 +00:00
|
|
|
|
#include <base/preface.h>
|
1995-04-17 21:13:20 +00:00
|
|
|
|
#include <Foundation/NSAutoreleasePool.h>
|
1996-03-26 20:59:42 +00:00
|
|
|
|
#include <Foundation/NSException.h>
|
1996-07-15 18:41:44 +00:00
|
|
|
|
#include <Foundation/NSThread.h>
|
1997-03-03 19:43:25 +00:00
|
|
|
|
#include <Foundation/NSZone.h>
|
1995-04-14 15:01:24 +00:00
|
|
|
|
#include <limits.h>
|
1995-03-12 19:35:17 +00:00
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
/*
|
|
|
|
|
* Set to 1 to count all autoreleases
|
|
|
|
|
*/
|
|
|
|
|
#define COUNT_ALL 0
|
1995-03-12 19:35:17 +00:00
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* When this is `NO', autoreleased objects are never actually recorded
|
|
|
|
|
in an NSAutoreleasePool, and are not sent a `release' message.
|
|
|
|
|
Thus memory for objects use grows, and grows, and... */
|
1995-04-14 15:01:24 +00:00
|
|
|
|
static BOOL autorelease_enabled = YES;
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
/* When the _released_count of a pool gets over this value, we raise
|
|
|
|
|
an exception. This can be adjusted with -setPoolCountThreshhold */
|
1995-04-14 15:01:24 +00:00
|
|
|
|
static unsigned pool_count_warning_threshhold = UINT_MAX;
|
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* The size of the first _released array. */
|
|
|
|
|
#define BEGINNING_POOL_SIZE 32
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
/* Easy access to the thread variables belonging to NSAutoreleasePool. */
|
1999-04-19 14:29:52 +00:00
|
|
|
|
#define ARP_THREAD_VARS (&(GSCurrentThread()->_autorelease_vars))
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
|
|
|
|
|
@interface NSAutoreleasePool (Private)
|
2000-09-30 05:16:53 +00:00
|
|
|
|
- (id) _parentAutoreleasePool;
|
1996-03-30 22:39:48 +00:00
|
|
|
|
- (unsigned) autoreleaseCount;
|
2000-09-30 05:16:53 +00:00
|
|
|
|
- (unsigned) autoreleaseCountForObject: (id)anObject;
|
|
|
|
|
+ (unsigned) autoreleaseCountForObject: (id)anObject;
|
|
|
|
|
+ (id) currentPool;
|
2001-05-10 20:00:02 +00:00
|
|
|
|
- (void) _reallyDealloc;
|
2000-09-30 05:16:53 +00:00
|
|
|
|
- (void) _setChildPool: (id)pool;
|
1996-03-30 22:39:48 +00:00
|
|
|
|
@end
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
|
|
|
|
/* Functions for managing a per-thread cache of NSAutoreleasedPool's
|
|
|
|
|
already alloc'ed. The cache is kept in the autorelease_thread_var
|
|
|
|
|
structure, which is an ivar of NSThread. */
|
|
|
|
|
|
2001-05-10 20:00:02 +00:00
|
|
|
|
static id pop_pool_from_cache (struct autorelease_thread_vars *tv);
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
free_pool_cache (struct autorelease_thread_vars *tv)
|
|
|
|
|
{
|
|
|
|
|
while (tv->pool_cache_count)
|
|
|
|
|
{
|
|
|
|
|
NSAutoreleasePool *pool = pop_pool_from_cache(tv);
|
|
|
|
|
|
|
|
|
|
[pool _reallyDealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tv->pool_cache)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), tv->pool_cache);
|
|
|
|
|
tv->pool_cache = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
static inline void
|
|
|
|
|
init_pool_cache (struct autorelease_thread_vars *tv)
|
|
|
|
|
{
|
|
|
|
|
tv->pool_cache_size = 32;
|
|
|
|
|
tv->pool_cache_count = 0;
|
1999-09-28 11:10:34 +00:00
|
|
|
|
tv->pool_cache = (id*)NSZoneMalloc(NSDefaultMallocZone(),
|
|
|
|
|
sizeof(id) * tv->pool_cache_size);
|
1996-07-15 18:41:44 +00:00
|
|
|
|
}
|
1996-03-30 22:39:48 +00:00
|
|
|
|
|
|
|
|
|
static void
|
1996-07-15 18:41:44 +00:00
|
|
|
|
push_pool_to_cache (struct autorelease_thread_vars *tv, id p)
|
1996-03-30 22:39:48 +00:00
|
|
|
|
{
|
1996-07-15 18:41:44 +00:00
|
|
|
|
if (!tv->pool_cache)
|
2001-05-10 20:00:02 +00:00
|
|
|
|
{
|
|
|
|
|
init_pool_cache (tv);
|
|
|
|
|
}
|
1996-07-15 18:41:44 +00:00
|
|
|
|
else if (tv->pool_cache_count == tv->pool_cache_size)
|
1996-03-30 22:39:48 +00:00
|
|
|
|
{
|
1996-07-15 18:41:44 +00:00
|
|
|
|
tv->pool_cache_size *= 2;
|
1999-09-28 11:10:34 +00:00
|
|
|
|
tv->pool_cache = (id*)NSZoneRealloc(NSDefaultMallocZone(),
|
|
|
|
|
tv->pool_cache, sizeof(id) * tv->pool_cache_size);
|
1996-03-30 22:39:48 +00:00
|
|
|
|
}
|
1996-07-15 18:41:44 +00:00
|
|
|
|
tv->pool_cache[tv->pool_cache_count++] = p;
|
1996-03-30 22:39:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static id
|
1996-07-15 18:41:44 +00:00
|
|
|
|
pop_pool_from_cache (struct autorelease_thread_vars *tv)
|
1996-03-30 22:39:48 +00:00
|
|
|
|
{
|
1996-07-15 18:41:44 +00:00
|
|
|
|
return tv->pool_cache[--(tv->pool_cache_count)];
|
1996-03-30 22:39:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>
|
|
|
|
|
* This class maintains a stack of autorelease pools objects
|
|
|
|
|
* in each thread.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* When an autorelease pool is created, it is automatically
|
|
|
|
|
* added to the stack of pools in the thread.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* When a pool is destroyed, it (and any pool later in
|
|
|
|
|
* the stack) is removed from the stack.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
1995-03-12 19:35:17 +00:00
|
|
|
|
@implementation NSAutoreleasePool
|
|
|
|
|
|
1998-11-20 13:44:59 +00:00
|
|
|
|
static IMP allocImp;
|
|
|
|
|
static IMP initImp;
|
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSAutoreleasePool class])
|
1998-11-20 13:44:59 +00:00
|
|
|
|
{
|
|
|
|
|
allocImp = [self methodForSelector: @selector(allocWithZone:)];
|
|
|
|
|
initImp = [self instanceMethodForSelector: @selector(init)];
|
|
|
|
|
}
|
1996-03-30 22:39:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Allocate and return an autorelease pool instance.<br />
|
|
|
|
|
* If there is an already-allocated NSAutoreleasePool available,
|
|
|
|
|
* save time by just returning that, rather than allocating a new one.
|
|
|
|
|
*/
|
2000-09-30 05:16:53 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)zone
|
1996-03-30 22:39:48 +00:00
|
|
|
|
{
|
1996-07-15 18:41:44 +00:00
|
|
|
|
struct autorelease_thread_vars *tv = ARP_THREAD_VARS;
|
|
|
|
|
if (tv->pool_cache_count)
|
|
|
|
|
return pop_pool_from_cache (tv);
|
1996-03-30 22:39:48 +00:00
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
return NSAllocateObject (self, 0, zone);
|
1996-03-30 22:39:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-09-30 05:16:53 +00:00
|
|
|
|
+ (id) new
|
1998-11-20 13:44:59 +00:00
|
|
|
|
{
|
|
|
|
|
id arp = (*allocImp)(self, @selector(allocWithZone:), NSDefaultMallocZone());
|
|
|
|
|
return (*initImp)(arp, @selector(init));
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-28 11:10:34 +00:00
|
|
|
|
- (id) init
|
1996-03-30 22:39:48 +00:00
|
|
|
|
{
|
|
|
|
|
if (!_released_head)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_addImp = (void (*)(id, SEL, id))
|
1999-05-06 20:22:16 +00:00
|
|
|
|
[self methodForSelector: @selector(addObject:)];
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* Allocate the array that will be the new head of the list of arrays. */
|
|
|
|
|
_released = (struct autorelease_array_list*)
|
1999-09-28 11:10:34 +00:00
|
|
|
|
NSZoneMalloc(NSDefaultMallocZone(),
|
|
|
|
|
sizeof(struct autorelease_array_list)
|
|
|
|
|
+ (BEGINNING_POOL_SIZE * sizeof(id)));
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* Currently no NEXT array in the list, so NEXT == NULL. */
|
|
|
|
|
_released->next = NULL;
|
|
|
|
|
_released->size = BEGINNING_POOL_SIZE;
|
|
|
|
|
_released->count = 0;
|
|
|
|
|
_released_head = _released;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* Already initialized; (it came from autorelease_pool_cache);
|
|
|
|
|
we don't have to allocate new array list memory. */
|
|
|
|
|
{
|
|
|
|
|
_released = _released_head;
|
|
|
|
|
_released->count = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This NSAutoreleasePool contains no objects yet. */
|
|
|
|
|
_released_count = 0;
|
|
|
|
|
|
|
|
|
|
/* Install ourselves as the current pool. */
|
1996-07-15 18:41:44 +00:00
|
|
|
|
{
|
|
|
|
|
struct autorelease_thread_vars *tv = ARP_THREAD_VARS;
|
|
|
|
|
_parent = tv->current_pool;
|
|
|
|
|
_child = nil;
|
1999-05-06 19:37:45 +00:00
|
|
|
|
if (_parent)
|
|
|
|
|
[_parent _setChildPool: self];
|
1996-07-15 18:41:44 +00:00
|
|
|
|
tv->current_pool = self;
|
|
|
|
|
}
|
1996-03-30 22:39:48 +00:00
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-30 05:16:53 +00:00
|
|
|
|
- (void) _setChildPool: (id)pool
|
1996-03-30 22:39:48 +00:00
|
|
|
|
{
|
|
|
|
|
_child = pool;
|
|
|
|
|
}
|
|
|
|
|
|
1995-04-14 15:01:24 +00:00
|
|
|
|
/* This method not in OpenStep */
|
2000-09-30 05:16:53 +00:00
|
|
|
|
- (id) _parentAutoreleasePool
|
1995-04-14 15:01:24 +00:00
|
|
|
|
{
|
1996-03-30 22:39:48 +00:00
|
|
|
|
return _parent;
|
1995-04-14 15:01:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/*
|
|
|
|
|
* Return the number of objects in this pool.
|
|
|
|
|
*/
|
1995-04-14 15:01:24 +00:00
|
|
|
|
- (unsigned) autoreleaseCount
|
|
|
|
|
{
|
1996-03-30 22:39:48 +00:00
|
|
|
|
unsigned count = 0;
|
|
|
|
|
struct autorelease_array_list *released = _released_head;
|
|
|
|
|
while (released && released->count)
|
|
|
|
|
{
|
|
|
|
|
count += released->count;
|
|
|
|
|
released = released->next;
|
|
|
|
|
}
|
|
|
|
|
return count;
|
1995-04-14 15:01:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>
|
|
|
|
|
* Counts the number of times that the specified object occurs
|
|
|
|
|
* in autorelease pools in the current thread.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* This method is <em>slow</em> and should probably only be
|
|
|
|
|
* used for debugging purposes.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
2000-09-30 05:16:53 +00:00
|
|
|
|
- (unsigned) autoreleaseCountForObject: (id)anObject
|
1995-04-14 15:01:24 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned count = 0;
|
1996-03-30 22:39:48 +00:00
|
|
|
|
struct autorelease_array_list *released = _released_head;
|
1995-04-14 15:01:24 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
while (released && released->count)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < released->count; i++)
|
|
|
|
|
if (released->objects[i] == anObject)
|
|
|
|
|
count++;
|
|
|
|
|
released = released->next;
|
|
|
|
|
}
|
1995-04-14 15:01:24 +00:00
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>
|
|
|
|
|
* Counts the number of times that the specified object occurs
|
|
|
|
|
* in autorelease pools in the current thread.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* This method is <em>slow</em> and should probably only be
|
|
|
|
|
* used for debugging purposes.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
2000-09-30 05:16:53 +00:00
|
|
|
|
+ (unsigned) autoreleaseCountForObject: (id)anObject
|
1995-04-14 15:01:24 +00:00
|
|
|
|
{
|
1995-08-02 15:40:33 +00:00
|
|
|
|
unsigned count = 0;
|
1996-07-15 18:41:44 +00:00
|
|
|
|
id pool = ARP_THREAD_VARS->current_pool;
|
1995-04-14 15:01:24 +00:00
|
|
|
|
while (pool)
|
|
|
|
|
{
|
1996-03-30 22:39:48 +00:00
|
|
|
|
count += [pool autoreleaseCountForObject: anObject];
|
|
|
|
|
pool = [pool _parentAutoreleasePool];
|
1995-04-14 15:01:24 +00:00
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the currently active autorelease pool.
|
|
|
|
|
*/
|
2000-09-30 05:16:53 +00:00
|
|
|
|
+ (id) currentPool
|
1995-03-12 19:35:17 +00:00
|
|
|
|
{
|
1996-07-15 18:41:44 +00:00
|
|
|
|
return ARP_THREAD_VARS->current_pool;
|
1995-03-12 19:35:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Adds the specified object to the current autorelease pool.
|
|
|
|
|
* If there is no autorelease pool in the thread,
|
|
|
|
|
* a warning is logged.
|
|
|
|
|
*/
|
2000-09-30 05:16:53 +00:00
|
|
|
|
+ (void) addObject: (id)anObj
|
1995-03-12 19:35:17 +00:00
|
|
|
|
{
|
1998-10-01 03:05:27 +00:00
|
|
|
|
NSAutoreleasePool *pool = ARP_THREAD_VARS->current_pool;
|
|
|
|
|
|
2002-01-30 15:28:50 +00:00
|
|
|
|
if (pool != nil)
|
|
|
|
|
{
|
|
|
|
|
(*pool->_addImp)(pool, @selector(addObject:), anObj);
|
|
|
|
|
}
|
1998-10-01 03:05:27 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
|
|
|
|
|
2002-01-30 15:28:50 +00:00
|
|
|
|
if (anObj != nil)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"autorelease called without pool for object (%x) "
|
|
|
|
|
@"of class %@ in thread %@", anObj,
|
|
|
|
|
NSStringFromClass([anObj class]), [NSThread currentThread]);
|
|
|
|
|
}
|
1998-10-01 03:05:27 +00:00
|
|
|
|
else
|
2002-01-30 15:28:50 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"autorelease called without pool for nil object.");
|
|
|
|
|
}
|
1998-10-01 03:05:27 +00:00
|
|
|
|
[arp release];
|
|
|
|
|
}
|
1995-03-12 19:35:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Adds the specified object to this autorelease pool.
|
|
|
|
|
*/
|
2000-09-30 05:16:53 +00:00
|
|
|
|
- (void) addObject: (id)anObj
|
1995-03-12 19:35:17 +00:00
|
|
|
|
{
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* If the global, static variable AUTORELEASE_ENABLED is not set,
|
|
|
|
|
do nothing, just return. */
|
1995-04-14 15:01:24 +00:00
|
|
|
|
if (!autorelease_enabled)
|
|
|
|
|
return;
|
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
if (_released_count >= pool_count_warning_threshhold)
|
1996-03-26 19:35:47 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
1996-03-26 20:59:42 +00:00
|
|
|
|
format: @"AutoreleasePool count threshhold exceeded."];
|
1995-04-14 15:01:24 +00:00
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* Get a new array for the list, if the current one is full. */
|
|
|
|
|
if (_released->count == _released->size)
|
1995-03-12 19:35:17 +00:00
|
|
|
|
{
|
1996-03-30 22:39:48 +00:00
|
|
|
|
if (_released->next)
|
|
|
|
|
{
|
|
|
|
|
/* There is an already-allocated one in the chain; use it. */
|
|
|
|
|
_released = _released->next;
|
|
|
|
|
_released->count = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* We are at the end of the chain, and need to allocate a new one. */
|
|
|
|
|
struct autorelease_array_list *new_released;
|
|
|
|
|
unsigned new_size = _released->size * 2;
|
|
|
|
|
|
|
|
|
|
new_released = (struct autorelease_array_list*)
|
1999-09-28 11:10:34 +00:00
|
|
|
|
NSZoneMalloc(NSDefaultMallocZone(),
|
|
|
|
|
sizeof(struct autorelease_array_list) + (new_size * sizeof(id)));
|
1996-03-30 22:39:48 +00:00
|
|
|
|
new_released->next = NULL;
|
|
|
|
|
new_released->size = new_size;
|
|
|
|
|
new_released->count = 0;
|
|
|
|
|
_released->next = new_released;
|
|
|
|
|
_released = new_released;
|
|
|
|
|
}
|
1995-03-12 19:35:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* Put the object at the end of the list. */
|
|
|
|
|
_released->objects[_released->count] = anObj;
|
|
|
|
|
(_released->count)++;
|
|
|
|
|
|
1999-04-19 14:29:52 +00:00
|
|
|
|
#if COUNT_ALL
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* Keep track of the total number of objects autoreleased across all
|
|
|
|
|
pools. */
|
1996-07-15 18:41:44 +00:00
|
|
|
|
ARP_THREAD_VARS->total_objects_count++;
|
1999-04-19 14:29:52 +00:00
|
|
|
|
#endif
|
1996-03-30 22:39:48 +00:00
|
|
|
|
|
|
|
|
|
/* Keep track of the total number of objects autoreleased in this pool */
|
|
|
|
|
_released_count++;
|
1995-03-12 19:35:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Raises an exception ... pools should not be retained.
|
|
|
|
|
*/
|
1995-03-12 19:35:17 +00:00
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
1996-03-26 19:35:47 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
1996-03-26 20:59:42 +00:00
|
|
|
|
format: @"Don't call `-retain' on a NSAutoreleasePool"];
|
1995-03-12 19:35:17 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Destroys the receiver (calls -dealloc).
|
|
|
|
|
*/
|
1995-03-12 19:35:17 +00:00
|
|
|
|
- (oneway void) release
|
|
|
|
|
{
|
|
|
|
|
[self dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2000-11-23 10:47:53 +00:00
|
|
|
|
// fprintf (stderr, "Deallocating an NSAutoreleasePool\n");
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* If there are NSAutoreleasePool below us in the stack of
|
|
|
|
|
NSAutoreleasePools, then deallocate them also. The (only) way we
|
|
|
|
|
could get in this situation (in correctly written programs, that
|
|
|
|
|
don't release NSAutoreleasePools in weird ways), is if an
|
|
|
|
|
exception threw us up the stack. */
|
|
|
|
|
if (_child)
|
|
|
|
|
[_child dealloc];
|
1995-03-12 19:35:17 +00:00
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
/* Make debugging easier by checking to see if the user already
|
|
|
|
|
dealloced the object before trying to release it. Also, take the
|
|
|
|
|
object out of the released list just before releasing it, so if
|
|
|
|
|
we are doing "double_release_check"ing, then
|
|
|
|
|
autoreleaseCountForObject: won't find the object we are currently
|
|
|
|
|
releasing. */
|
|
|
|
|
{
|
|
|
|
|
struct autorelease_array_list *released = _released_head;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
while (released)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < released->count; i++)
|
|
|
|
|
{
|
|
|
|
|
id anObject = released->objects[i];
|
1997-03-03 19:56:37 +00:00
|
|
|
|
#if 0
|
|
|
|
|
/* There is no general method to find out whether a memory
|
|
|
|
|
chunk has been deallocated or not, especially when
|
|
|
|
|
custom zone functions might be used. So we #if this
|
|
|
|
|
out. */
|
1997-03-03 19:43:25 +00:00
|
|
|
|
if (!NSZoneMemInUse(anObject))
|
1997-03-03 19:56:37 +00:00
|
|
|
|
[NSException
|
|
|
|
|
raise: NSGenericException
|
|
|
|
|
format: @"Autoreleasing deallocated object.\n"
|
|
|
|
|
@"Suggest you debug after setting [NSObject "
|
1996-03-30 22:39:48 +00:00
|
|
|
|
@"enableDoubleReleaseCheck:YES]\n"
|
|
|
|
|
@"to check for release errors."];
|
1997-03-03 19:56:37 +00:00
|
|
|
|
#endif
|
1996-03-30 22:39:48 +00:00
|
|
|
|
released->objects[i] = nil;
|
|
|
|
|
[anObject release];
|
|
|
|
|
}
|
1999-05-06 19:37:45 +00:00
|
|
|
|
released->count = 0;
|
1996-03-30 22:39:48 +00:00
|
|
|
|
released = released->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
{
|
|
|
|
|
struct autorelease_thread_vars *tv;
|
|
|
|
|
NSAutoreleasePool **cp;
|
|
|
|
|
|
|
|
|
|
/* Uninstall ourselves as the current pool; install our parent pool. */
|
|
|
|
|
tv = ARP_THREAD_VARS;
|
|
|
|
|
cp = &(tv->current_pool);
|
|
|
|
|
*cp = _parent;
|
|
|
|
|
if (*cp)
|
|
|
|
|
(*cp)->_child = nil;
|
|
|
|
|
|
|
|
|
|
/* Don't deallocate ourself, just save us for later use. */
|
|
|
|
|
push_pool_to_cache (tv, self);
|
|
|
|
|
}
|
|
|
|
|
}
|
1996-03-30 22:39:48 +00:00
|
|
|
|
|
2001-05-10 20:00:02 +00:00
|
|
|
|
- (void) _reallyDealloc
|
1996-07-15 18:41:44 +00:00
|
|
|
|
{
|
|
|
|
|
struct autorelease_array_list *a;
|
|
|
|
|
for (a = _released_head; a; )
|
|
|
|
|
{
|
|
|
|
|
void *n = a->next;
|
1999-09-28 11:10:34 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), a);
|
1996-07-15 18:41:44 +00:00
|
|
|
|
a = n;
|
|
|
|
|
}
|
|
|
|
|
[super dealloc];
|
1995-03-12 19:35:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Raises an exception - pools should not be autoreleased.
|
|
|
|
|
*/
|
2000-09-30 05:16:53 +00:00
|
|
|
|
- (id) autorelease
|
1995-03-12 19:35:17 +00:00
|
|
|
|
{
|
1996-03-26 19:35:47 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"Don't call `-autorelease' on a NSAutoreleasePool"];
|
1995-03-12 19:35:17 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-22 08:41:07 +00:00
|
|
|
|
+ (void) _endThread: (NSThread*)thread
|
1999-04-21 20:16:25 +00:00
|
|
|
|
{
|
|
|
|
|
struct autorelease_thread_vars *tv;
|
|
|
|
|
id pool;
|
|
|
|
|
|
2001-05-10 20:00:02 +00:00
|
|
|
|
tv = ARP_THREAD_VARS;
|
1999-04-21 20:16:25 +00:00
|
|
|
|
while (tv->current_pool)
|
|
|
|
|
{
|
|
|
|
|
[tv->current_pool release];
|
|
|
|
|
pool = pop_pool_from_cache(tv);
|
2001-05-10 20:00:02 +00:00
|
|
|
|
[pool _reallyDealloc];
|
1999-04-21 20:16:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-05-10 20:00:02 +00:00
|
|
|
|
free_pool_cache(tv);
|
1999-04-21 20:16:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-30 22:39:48 +00:00
|
|
|
|
+ (void) resetTotalAutoreleasedObjects
|
|
|
|
|
{
|
1996-07-15 18:41:44 +00:00
|
|
|
|
ARP_THREAD_VARS->total_objects_count = 0;
|
1996-03-30 22:39:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (unsigned) totalAutoreleasedObjects
|
|
|
|
|
{
|
1996-07-15 18:41:44 +00:00
|
|
|
|
return ARP_THREAD_VARS->total_objects_count;
|
1996-03-30 22:39:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>
|
|
|
|
|
* Specifies whether objects contained in autorelease pools are to
|
|
|
|
|
* be released when the pools are deallocated (by default YES).
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* You can set this to NO for debugging purposes.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
1995-04-14 15:01:24 +00:00
|
|
|
|
+ (void) enableRelease: (BOOL)enable
|
|
|
|
|
{
|
|
|
|
|
autorelease_enabled = enable;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>
|
|
|
|
|
* When autorelease pools are deallocated, the memory they used
|
|
|
|
|
* is retained in a cache for re-use so that new polls can be
|
|
|
|
|
* created very quickly.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* This method may be used to empty that cache, ensuring that
|
|
|
|
|
* the minimum memory is used by the application.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
2001-05-10 20:00:02 +00:00
|
|
|
|
+ (void) freeCache
|
|
|
|
|
{
|
|
|
|
|
free_pool_cache(ARP_THREAD_VARS);
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>
|
|
|
|
|
* Specifies a limit to the number of objects that may be added to
|
|
|
|
|
* an autorelease pool. When this limit is reached an exception is
|
|
|
|
|
* raised.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* You can set this to a smallish value to catch problems with code
|
|
|
|
|
* that autoreleases too many objects to operate efficiently.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* Default value is maxint.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
1995-04-14 15:01:24 +00:00
|
|
|
|
+ (void) setPoolCountThreshhold: (unsigned)c
|
|
|
|
|
{
|
|
|
|
|
pool_count_warning_threshhold = c;
|
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 19:35:17 +00:00
|
|
|
|
@end
|