Changes by wacko@power1.snu.ac.kr (Yoo C. Chung). See ChangeLog Feb 6

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@2206 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Andrew McCallum 1997-03-03 19:58:17 +00:00
parent 8a77b79ada
commit 3e2ce5f1fd
3 changed files with 440 additions and 40 deletions

View file

@ -3,6 +3,85 @@ Mon Mar 3 14:41:01 1997 Andrew McCallum <mccallum@jprc.com>
* src/NSHost.m, src/include/NSHost.h: New files from Luke Howard
<lukeh@xedoc.com.au>.
Thu Feb 6 09:20:05 1997 Yoo C. Chung <wacko@power1.snu.ac.kr>
* src/NSZone.m (fcheck): Implemented.
(fstats): Likewise.
(ncheck): Likewise.
(nstats): Likewise.
* src/include/NSZone.h: New declarations of 'NSZoneRegisterChunk'
and 'NSZoneChunkOverhead'.
Include <objc/objc.h> instead of <objc/thr.h>.
* src/NSZone.m: Removed 'outmemstr'. Better reasons given when
raising exceptions.
(frecycle): Use objc_free().
(nrecycle): Likewise.
(NSCreateZone): Check allocation of 'zone'.
(default_check): New function.
(default_stats): Likewise.
(fcheck): Likewise.
(fstats): Likewise.
(ncheck): Likewise.
(nstats): Likewise.
(NSZoneChunkOverhead): Likewise.
(NSZoneRegisterChunk): Likewise.
(NSZoneCheck): Likewise.
(NSZoneStats): Likewise.
(default_zone): Set the zone name to "default".
Wed Feb 5 21:29:23 1997 Yoo C. Chung <wacko@power1.snu.ac.kr>
* src/include/NSZone.h (struct _NSZoneStats): New structure.
(struct _NSZone): Added 'check' and 'stats'.
(NSZoneCheck): New declaration.
(NSZoneStats): Likewise.
Tue Feb 4 22:39:50 1997 Yoo C. Chung <wacko@power1.snu.ac.kr>
* src/NSZone.m (nmalloc): Return NULL when size is 0.
Tue Feb 4 09:16:05 1997 Yoo C. Chung <wacko@power1.snu.ac.kr>
* src/NSZone.m (NSSetDefaultMallocZone): New function.
(get_chunk): Use objc_malloc() to get more memory.
(nmalloc): Likewise.
(NSCreateZone): Likewise.
(NSSetZoneName): Removed locks.
* src/NSAutoreleasePool.m ([NSAutoreleasePool -dealloc]): Don't
check whether we're releasing an already deallocated object.
* src/include/NSZone.h (struct _NSZone): Removed mutex.
Removed NSZoneMemInUse().
Added NSSetDefaultMallocZone().
* src/NSZone.m: Changed comments.
Uses objc_malloc() and friends for default zone.
Moved mutex out of NSZone structure.
Use mutex functions even in single threaded case.
(NSZoneMemInUse): Removed.
Fri Jan 24 19:12:18 1997 Yoo C. Chung <wacko@power1.snu.ac.kr>
* src/NSZone.m: Spell checked comments.
Tue Jan 21 13:31:11 1997 Yoo C. Chung <wacko@power1.snu.ac.kr>
* src/NSZone.m (default_recycle): New function.
(nrealloc): Likewise.
(nfree): Likewise.
(default_zone): Set common.recycle to default_recycle.
(NSCreateZone): Set realloc and free for nonfreeable zone.
* src/include/NSThread.h: Add comments.
* src/NSThread.m ([NSThread -setExceptionHandler:]): Add comments.
([NSThread -exceptionHandler]): Likewise.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Set
entered_multi_threaded_state to YES.
Tue Jan 21 11:18:32 1997 Yoo C. Chung <wacko@power1.snu.ac.kr>
* checks/thread-except.m: New file.

View file

@ -23,7 +23,8 @@
#ifndef __NSZone_h_GNUSTEP_BASE_INCLUDE
#define __NSZone_h_GNUSTEP_BASE_INCLUDE
#include <objc/thr.h>
#include <objc/objc.h>
@class NSString;
@ -32,6 +33,17 @@
typedef struct _NSZone NSZone;
/* The members are the same as the structure mstats which is in the
GNU C library. */
struct NSZoneStats
{
size_t bytes_total;
size_t chunks_used;
size_t bytes_used;
size_t chunks_free;
size_t bytes_free;
};
struct _NSZone
{
/* Functions for zone. */
@ -39,7 +51,9 @@ struct _NSZone
void *(*realloc)(struct _NSZone *zone, void *ptr, size_t size);
void (*free)(struct _NSZone *zone, void *ptr);
void (*recycle)(struct _NSZone *zone);
BOOL (*check)(struct _NSZone *zone);
struct NSZoneStats (*stats)(struct _NSZone *zone);
size_t gran; // Zone granularity
NSString *name; // Name of zone (default is 'nil')
};
@ -79,4 +93,15 @@ extern void NSSetZoneName (NSZone *zone, NSString *name);
extern inline NSString* NSZoneName (NSZone *zone)
{ return zone->name; }
/* Not in OpenStep */
extern void* NSZoneRegisterChunk (NSZone *zone, void *chunk);
extern size_t NSZoneChunkOverhead (void); // Not in OpenStep
extern inline BOOL NSZoneCheck (NSZone *zone) // Not in OpenStep
{ return (zone->check)(zone); }
extern inline struct NSZoneStats NSZoneStats (NSZone *zone) // Not in OpenStep
{ return (zone->stats)(zone); }
#endif /* not __NSZone_h_GNUSTEP_BASE_INCLUDE */

View file

@ -38,7 +38,8 @@
- The default zone uses objc_malloc() and friends. We assume that
they're thread safe and that they return NULL if we're out of
memory. We also need to prepend a zone pointer.
memory (they currently don't, unfortunately, so this is a FIXME).
We also need to prepend a zone pointer.
- For freeable zones, a small linear buffer is used for
deallocating and allocating. Anything that can't go into the
@ -56,11 +57,11 @@
/* Other information:
- This uses some GCC specific extensions. But since the library is
supposed to compile on GCC 2.7.2 (patched) or higher, and the only
other Objective-C compiler I know of (other than NeXT's, which is
based on GCC as far as I know) is the StepStone compiler, which I
haven't the foggiest idea why anyone would prefer it to GCC ;), it
should be OK.
supposed to compile on GCC 2.7.2.1 (patched) or higher, and the
only other Objective-C compiler I know of (other than NeXT's, which
is based on GCC as far as I know) is the StepStone compiler, which
I haven't the foggiest idea why anyone would prefer it to GCC ;),
it should be OK.
- We cannot use malloc() and friends (or objc_malloc() and friends)
for memory allocated from zones if we want a fast
@ -70,6 +71,7 @@
- These functions should be thread safe, but I haven't really
tested them extensively in multithreaded cases. */
/* Define to turn off assertions. */
#define NDEBUG
@ -172,12 +174,16 @@ static void* default_malloc (NSZone *zone, size_t size);
static void* default_realloc (NSZone *zone, void *ptr, size_t size);
static void default_free (NSZone *zone, void *ptr);
static void default_recycle (NSZone *zone);
static BOOL default_check (NSZone *zone);
static struct NSZoneStats default_stats (NSZone *zone);
/* Memory management functions for freeable zones. */
static void* fmalloc (NSZone *zone, size_t size);
static void* frealloc (NSZone *zone, void *ptr, size_t size);
static void ffree (NSZone *zone, void *ptr);
static void frecycle (NSZone *zone);
static BOOL fcheck (NSZone *zone);
static struct NSZoneStats fstats (NSZone *zone);
static inline size_t segindex (size_t size);
static void* get_chunk (ffree_zone *zone, size_t size);
@ -191,15 +197,14 @@ static void* nmalloc (NSZone *zone, size_t size);
static void nrecycle (NSZone *zone);
static void* nrealloc (NSZone *zone, void *ptr, size_t size);
static void nfree (NSZone *zone, void *ptr);
static BOOL ncheck (NSZone *zone);
static struct NSZoneStats nstats (NSZone *zone);
/* Error message. */
static NSString *outmemstr = @"Out of memory";
static NSZone default_zone =
{
default_malloc, default_realloc, default_free, default_recycle,
DEFBLOCK, nil
default_check, default_stats, DEFBLOCK, @"default"
};
/* Default zone. Name is hopelessly long so that no one will ever
@ -222,7 +227,8 @@ default_malloc (NSZone *zone, size_t size)
mem = objc_malloc(ZPTRSZ+size);
if (mem == NULL)
[NSException raise: NSMallocException format: outmemstr];
[NSException raise: NSMallocException
format: @"Default zone has run out of memory"];
*mem = zone;
return mem+1;
}
@ -234,7 +240,8 @@ default_realloc (NSZone *zone, void *ptr, size_t size)
mem = objc_realloc(mem, size+ZPTRSZ);
if ((size != 0) && (mem == NULL))
[NSException raise: NSMallocException format: outmemstr];
[NSException raise: NSMallocException
format: @"Default zone has run out of memory"];
return mem+1;
}
@ -252,6 +259,24 @@ default_recycle (NSZone *zone)
format: @"Trying to recycle default zone"];
}
static BOOL
default_check (NSZone *zone)
{
/* We can't check memory managed by objc_malloc(). */
[NSException raise: NSGenericException format: @"Not implemented"];
return NO;
}
static struct NSZoneStats
default_stats (NSZone *zone)
{
struct NSZoneStats dummy;
/* We can't obtain statistics from the memory managed by objc_malloc(). */
[NSException raise: NSGenericException format: @"Not implemented"];
return dummy;
}
/* Search the buffer to see if there is any memory chunks large enough
to satisfy request using first fit. If the memory chunk found has
a size exactly equal to the one requested, remove it from the buffer
@ -319,7 +344,13 @@ fmalloc (NSZone *zone, size_t size)
if (chunkhead == NULL)
{
objc_mutex_unlock(zptr->lock);
[NSException raise: NSMallocException format: outmemstr];
if (zone->name != nil)
[NSException raise: NSMallocException
format: @"Zone %s has run out of memory",
[zone->name cString]];
else
[NSException raise: NSMallocException
format: @"Out of memory"];
}
assert(*chunkhead & INUSE);
@ -404,7 +435,13 @@ frealloc (NSZone *zone, void *ptr, size_t size)
if (newchunk == NULL)
{
objc_mutex_unlock(zptr->lock);
[NSException raise: NSMallocException format: outmemstr];
if (zone->name != nil)
[NSException raise: NSMallocException
format: @"Zone %s has run out of memory",
[zone->name cString]];
else
[NSException raise: NSMallocException
format: @"Out of memory"];
}
memcpy((void*)newchunk+SZSZ+ZPTRSZ, (void*)chunkhead+SZSZ+ZPTRSZ,
chunksize-SZSZ-ZPTRSZ);
@ -426,11 +463,10 @@ ffree (NSZone *zone, void *ptr)
objc_mutex_unlock(((ffree_zone*)zone)->lock);
}
/* Recycle the zone. We should give objects that are still alive to
the default zone by looking into each block and resetting the zone
pointers in each used memory chunks and adding the free chunks to
the default zone's buffer, but I'm lazy, so I'll do it later. For
now, we just release all the blocks. */
/* Recycle the zone. According to OpenStep, we need to return live
objects to the default zone, but there is no easy way to return
them in the current implementation, and doing so will prevent easy
customization. */
static void
frecycle (NSZone *zone)
{
@ -442,13 +478,158 @@ frecycle (NSZone *zone)
while (block != NULL)
{
nextblock = block->next;
ffree(NSDefaultMallocZone(), block);
objc_free(block);
block = nextblock;
/* FIXME: should return live objects to default zone. */
}
if (zone->name != nil)
[zone->name release];
ffree(NSDefaultMallocZone(), zptr);
objc_free(zptr);
}
/* Check integrity of a freeable zone. Doesn't have to be
particularly efficient. */
static BOOL
fcheck (NSZone *zone)
{
size_t i;
ffree_zone *zptr = (ffree_zone*)zone;
ff_block *block;
size_t *chunk;
objc_mutex_lock(zptr->lock);
/* Check integrity of each block the zone owns. */
block = zptr->blocks;
while (block != NULL)
{
size_t blocksize, pos;
size_t *nextchunk;
blocksize = block->size;
pos = FF_HEAD;
while (pos < blocksize-(SZSZ+ZPTRSZ))
{
size_t chunksize;
chunk = (void*)block+pos;
chunksize = *chunk & ~SIZE_BITS;
nextchunk = (void*)chunk+chunksize;
if (*chunk & INUSE)
/* Check whether this is a valid used chunk. */
{
NSZone **zoneptr;
zoneptr = (NSZone**)(chunk+1);
if ((*zoneptr != zone) || !(*nextchunk & PREVUSE))
goto inconsistent;
}
else
/* Check whether this is a valid free chunk. */
{
size_t *footer;
footer = nextchunk-1;
if ((*footer != chunksize) || (*nextchunk & PREVUSE))
goto inconsistent;
}
pos += chunksize;
}
chunk = (void*)block+pos;
/* Check whether the block ends properly. */
if (((*chunk & ~SIZE_BITS) != 0) || !(*chunk & INUSE))
goto inconsistent;
block = block->next;
}
/* Check the integrity of the segregated list. */
for (i = 0; i < MAX_SEG; i++)
{
chunk = zptr->segheadlist[i];
while (chunk != NULL)
{
size_t *nextchunk;
nextchunk = ((ff_link*)(chunk+1))->next;
/* Isn't this one ugly if statement? */
if ((*chunk & INUSE)
|| (segindex(*chunk & ~SIZE_BITS) != i)
|| ((nextchunk != NULL)
&& (chunk != ((ff_link*)(nextchunk+1))->prev))
|| ((nextchunk == NULL) && (chunk != zptr->segtaillist[i])))
goto inconsistent;
chunk = nextchunk;
}
}
/* Check the buffer. */
if (zptr->bufsize >= BUFFER)
goto inconsistent;
for (i = 0; i < zptr->bufsize; i++)
{
chunk = zptr->ptr_buf[i];
if ((zptr->size_buf[i] != (*chunk & ~SIZE_BITS)) || !(*chunk & INUSE))
goto inconsistent;
}
objc_mutex_unlock(zptr->lock);
return YES;
inconsistent: // Jump here if an inconsistency was found.
objc_mutex_unlock(zptr->lock);
return NO;
}
static struct NSZoneStats
fstats (NSZone *zone)
{
size_t i;
struct NSZoneStats stats;
ffree_zone *zptr = (ffree_zone*)zone;
ff_block *block;
stats.bytes_total = 0;
stats.chunks_used = 0;
stats.bytes_used = 0;
stats.chunks_free = 0;
stats.bytes_free = 0;
objc_mutex_lock(zptr->lock);
block = zptr->blocks;
/* Go through each block. */
while (block != NULL)
{
size_t blocksize;
size_t *chunk;
blocksize = block->size;
stats.bytes_total += blocksize;
chunk = (void*)block+FF_HEAD;
while ((void*)chunk < (void*)block+(blocksize-ZPTRSZ-SZSZ))
{
size_t chunksize;
chunksize = *chunk & ~SIZE_BITS;
if (*chunk & INUSE)
{
stats.chunks_used++;
stats.bytes_used += chunksize;
}
else
{
stats.chunks_free++;
stats.bytes_free += chunksize;
}
chunk = (void*)chunk+chunksize;
}
block = block->next;
}
/* Go through buffer. */
for (i = 0; i < zptr->bufsize; i++)
{
stats.chunks_used--;
stats.chunks_free++;
stats.bytes_used -= zptr->size_buf[i];
stats.bytes_free += zptr->size_buf[i];
}
objc_mutex_unlock(zptr->lock);
/* Remove overhead. */
stats.bytes_used -= (SZSZ+ZPTRSZ)*stats.chunks_used;
return stats;
}
static inline size_t
@ -739,6 +920,8 @@ nmalloc (NSZone *zone, size_t size)
size_t chunksize = roundupto(size+ZPTRSZ, ALIGN);
NSZone **chunkhead;
if (size == 0)
return NULL;
objc_mutex_lock(zptr->lock);
top = zptr->blocks->top;
/* No need to worry about (block == NULL), since a nonfreeable zone
@ -778,7 +961,13 @@ nmalloc (NSZone *zone, size_t size)
if (block == NULL)
{
objc_mutex_unlock(zptr->lock);
[NSException raise: NSMallocException format: outmemstr];
if (zone->name != nil)
[NSException raise: NSMallocException
format: @"Zone %s has run out of memory",
[zone->name cString]];
else
[NSException raise: NSMallocException
format: @"Out of memory"];
}
block->next = zptr->blocks;
block->size = blocksize;
@ -794,11 +983,7 @@ nmalloc (NSZone *zone, size_t size)
}
/* Return the blocks to the default zone, then deallocate mutex, and
then release zone name if it exists.
No locking is done because I don't think someone would use a zone
when they're going to recycle it. If they do that, it's a
programming error. */
then release zone name if it exists. */
static void
nrecycle (NSZone *zone)
{
@ -809,27 +994,97 @@ nrecycle (NSZone *zone)
while (block != NULL)
{
nextblock = block->next;
ffree(NSDefaultMallocZone(), block);
objc_free(block);
block = nextblock;
}
if (zone->name != nil)
[zone->name release];
ffree(NSDefaultMallocZone(), zone);
objc_free(zone);
}
static void*
nrealloc (NSZone *zone, void *ptr, size_t size)
{
[NSException raise: NSGenericException
format: @"Trying to reallocate in nonfreeable zone"];
if (zone->name != nil)
[NSException raise: NSGenericException
format: @"Trying to reallocate in nonfreeable zone %s",
[zone->name cString]];
else
[NSException raise: NSGenericException
format: @"Trying to reallocate in nonfreeable zone"];
return NULL; // Useless return
}
static void
nfree (NSZone *zone, void *ptr)
{
[NSException raise: NSGenericException
format: @"Trying to free memory from nonfreeable zone"];
if (zone->name != nil)
[NSException raise: NSGenericException
format: @"Trying to free memory from nonfreeable zone %s",
[zone->name cString]];
else
[NSException raise: NSGenericException
format: @"Trying to free memory from nonfreeable zone"];
}
static BOOL
ncheck (NSZone *zone)
{
nfree_zone *zptr = (nfree_zone*)zone;
nf_block *block;
objc_mutex_lock(zptr->lock);
block = zptr->blocks;
while (block != NULL)
{
if (block->size < block->top)
{
objc_mutex_unlock(zptr->lock);
return NO;
}
block = block->next;
}
/* FIXME: Do more checking? */
objc_mutex_unlock(zptr->lock);
return YES;
}
static struct NSZoneStats
nstats (NSZone *zone)
{
struct NSZoneStats stats;
nfree_zone *zptr = (nfree_zone*)zone;
nf_block *block;
stats.bytes_total = 0;
stats.chunks_used = 0;
stats.bytes_used = 0;
stats.chunks_free = 0;
stats.bytes_free = 0;
objc_mutex_lock(zptr->lock);
block = zptr->blocks;
while (block != NULL)
{
size_t *chunk;
stats.bytes_total += block->size;
chunk = (void*)block+NF_HEAD;
while ((void*)chunk < (void*)block+block->top)
{
stats.chunks_used++;
stats.bytes_used += *chunk;
chunk = (void*)chunk+(*chunk);
}
if (block->size != block->top)
{
stats.chunks_free++;
stats.bytes_free += block->size-block->top;
}
block = block->next;
}
objc_mutex_unlock(zptr->lock);
stats.bytes_used -= ZPTRSZ*stats.chunks_used;
return stats;
}
NSZone*
@ -854,11 +1109,14 @@ NSCreateZone (size_t start, size_t gran, BOOL canFree)
zone = objc_malloc(sizeof(ffree_zone));
if (zone == NULL)
[NSException raise: NSMallocException format: outmemstr];
[NSException raise: NSMallocException
format: @"No memory to create zone"];
zone->common.malloc = fmalloc;
zone->common.realloc = frealloc;
zone->common.free = ffree;
zone->common.recycle = frecycle;
zone->common.check = fcheck;
zone->common.stats = fstats;
zone->common.gran = granularity;
zone->common.name = nil;
zone->lock = objc_mutex_allocate();
@ -873,7 +1131,8 @@ NSCreateZone (size_t start, size_t gran, BOOL canFree)
{
objc_mutex_deallocate(zone->lock);
objc_free(zone);
[NSException raise: NSMallocException format: outmemstr];
[NSException raise: NSMallocException
format: @"No memory to create zone"];
}
block = zone->blocks;
block->next = NULL;
@ -893,10 +1152,15 @@ NSCreateZone (size_t start, size_t gran, BOOL canFree)
nfree_zone *zone;
zone = objc_malloc(sizeof(nfree_zone));
if (zone == NULL)
[NSException raise: NSMallocException
format: @"No memory to create zone"];
zone->common.malloc = nmalloc;
zone->common.realloc = nrealloc;
zone->common.free = nfree;
zone->common.recycle = nrecycle;
zone->common.check = ncheck;
zone->common.stats = nstats;
zone->common.gran = granularity;
zone->common.name = nil;
zone->lock = objc_mutex_allocate();
@ -905,7 +1169,8 @@ NSCreateZone (size_t start, size_t gran, BOOL canFree)
{
objc_mutex_deallocate(zone->lock);
objc_free(zone);
[NSException raise: NSMallocException format: outmemstr];
[NSException raise: NSMallocException
format: @"No memory to create zone"];
}
block = zone->blocks;
block->next = NULL;
@ -921,7 +1186,7 @@ NSDefaultMallocZone (void)
return __nszone_private_hidden_default_zone;
}
// Not in OpenStep
/* Not in OpenStep. */
void
NSSetDefaultMallocZone (NSZone *zone)
{
@ -981,3 +1246,34 @@ NSZoneName (NSZone *zone)
{
return zone->name;
}
/* Not in OpenStep. */
void*
NSZoneRegisterChunk (NSZone *zone, void *chunk)
{
NSZone **zoneptr = chunk;
*zoneptr = zone;
return zoneptr+1;
}
/* Not in OpenStep. */
size_t
NSZoneChunkOverhead (void)
{
return ZPTRSZ;
}
/* Not in OpenStep. */
inline BOOL
NSZoneCheck (NSZone *zone)
{
return (zone->check)(zone);
}
/* Not in OpenStep. */
inline struct NSZoneStats
NSZoneStats (NSZone *zone)
{
return (zone->stats)(zone);
}