compiles, but untested
This commit is contained in:
parent
c5c3d48da7
commit
b4d6d6c590
55
TODO
55
TODO
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
- rework buffer.c, it's getting ugly
|
- rework buffer.c, it's getting ugly
|
||||||
|
|
||||||
how about getting rid of buffercache for non-worker threads, it won't be
|
how about getting rid of buffercache for non-worker threads, it won't be
|
||||||
|
@ -8,6 +9,60 @@
|
||||||
|
|
||||||
no reserve list, just discard them on unref
|
no reserve list, just discard them on unref
|
||||||
|
|
||||||
|
shouldwe use atomic stuff for the buffer ref count?
|
||||||
|
|
||||||
|
buffer_dump has:
|
||||||
|
|
||||||
|
if( buffer->im &&
|
||||||
|
buffer->buf &&
|
||||||
|
buffer->cache ) {
|
||||||
|
printf( "buffer %p, %.3g MB\n",
|
||||||
|
buffer, buffer->bsize / (1024 * 1024.0) );
|
||||||
|
*alive += buffer->bsize;
|
||||||
|
}
|
||||||
|
else if( buffer->im &&
|
||||||
|
buffer->buf &&
|
||||||
|
!buffer->cache )
|
||||||
|
*reserve += buffer->bsize;
|
||||||
|
else
|
||||||
|
printf( "buffer craziness!\n" );
|
||||||
|
|
||||||
|
is this right?
|
||||||
|
|
||||||
|
I think we now have three states:
|
||||||
|
|
||||||
|
global buffer (not on any cache, undone)
|
||||||
|
|
||||||
|
buffer->ref_count >= 1
|
||||||
|
buffer->im
|
||||||
|
buffer->buf
|
||||||
|
!buffer->cache
|
||||||
|
!buffer->done (since all done buffers must be on a cache buffers list)
|
||||||
|
|
||||||
|
buffer published on a cache (done)
|
||||||
|
|
||||||
|
buffer->ref_count >= 1
|
||||||
|
buffer->im
|
||||||
|
buffer->buf
|
||||||
|
buffer->cache
|
||||||
|
buffer->done
|
||||||
|
|
||||||
|
buffer held in reserve on a thread, ready for reuse
|
||||||
|
|
||||||
|
buffer->ref_count == 0
|
||||||
|
buffer->im
|
||||||
|
buffer->buf
|
||||||
|
buffer->cache
|
||||||
|
!buffer->done
|
||||||
|
|
||||||
|
vips_buffer_done() on a global buffer takes ownership and publishes to this
|
||||||
|
thread's public list
|
||||||
|
|
||||||
|
what if ref_count > 1? is this possible?
|
||||||
|
|
||||||
|
vips_buffer_undone() relinquishes ownership and makes it global
|
||||||
|
|
||||||
|
|
||||||
- not sure about utf8 error messages on win
|
- not sure about utf8 error messages on win
|
||||||
|
|
||||||
- strange:
|
- strange:
|
||||||
|
|
|
@ -89,13 +89,16 @@ typedef struct {
|
||||||
GThread *thread; /* Just for sanity checking */
|
GThread *thread; /* Just for sanity checking */
|
||||||
} VipsBufferThread;
|
} VipsBufferThread;
|
||||||
|
|
||||||
/* Per-image buffer cache. Hash to this from VipsBufferThread::hash.
|
/* Per-image buffer cache. This keeps a list of "done" VipsBuffer that this
|
||||||
|
* worker has generated. We use this to reuse results within a thread.
|
||||||
|
*
|
||||||
|
* Hash to this from VipsBufferThread::hash.
|
||||||
* We can't store the GSList directly in the hash table as GHashTable lacks an
|
* We can't store the GSList directly in the hash table as GHashTable lacks an
|
||||||
* update operation and we'd need to _remove() and _insert() on every list
|
* update operation and we'd need to _remove() and _insert() on every list
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
typedef struct _VipsBufferCache {
|
typedef struct _VipsBufferCache {
|
||||||
GSList *buffers; /* GSList of VipsBuffer* */
|
GSList *buffers; /* GSList of "done" VipsBuffer* */
|
||||||
GThread *thread; /* Just for sanity checking */
|
GThread *thread; /* Just for sanity checking */
|
||||||
struct _VipsImage *im;
|
struct _VipsImage *im;
|
||||||
VipsBufferThread *buffer_thread;
|
VipsBufferThread *buffer_thread;
|
||||||
|
@ -105,13 +108,15 @@ typedef struct _VipsBufferCache {
|
||||||
|
|
||||||
/* What we track for each pixel buffer. These can move between caches and
|
/* What we track for each pixel buffer. These can move between caches and
|
||||||
* between threads, but not between images.
|
* between threads, but not between images.
|
||||||
|
*
|
||||||
|
* Moving between threads is difficult, use region ownership stuff.
|
||||||
*/
|
*/
|
||||||
typedef struct _VipsBuffer {
|
typedef struct _VipsBuffer {
|
||||||
int ref_count; /* # of regions referencing us */
|
int ref_count; /* # of regions referencing us */
|
||||||
struct _VipsImage *im; /* VipsImage we are attached to */
|
struct _VipsImage *im; /* VipsImage we are attached to */
|
||||||
|
|
||||||
VipsRect area; /* Area this pixel buffer covers */
|
VipsRect area; /* Area this pixel buffer covers */
|
||||||
gboolean done; /* Calculated and in cache */
|
gboolean done; /* Calculated and in a cache */
|
||||||
VipsBufferCache *cache; /* The cache this buffer is published on */
|
VipsBufferCache *cache; /* The cache this buffer is published on */
|
||||||
VipsPel *buf; /* Private malloc() area */
|
VipsPel *buf; /* Private malloc() area */
|
||||||
size_t bsize; /* Size of private malloc() */
|
size_t bsize; /* Size of private malloc() */
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
* 6/6/16
|
* 6/6/16
|
||||||
* - free buffers on image close as well as thread exit, so main thread
|
* - free buffers on image close as well as thread exit, so main thread
|
||||||
* buffers don't clog up the system
|
* buffers don't clog up the system
|
||||||
|
* 13/10/16
|
||||||
|
* - better solution: don't keep a buffercache for non-workers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -53,11 +55,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
*/
|
||||||
#define DEBUG_VERBOSE
|
#define DEBUG_VERBOSE
|
||||||
#define DEBUG_CREATE
|
#define DEBUG_CREATE
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
#define DEBUG_GLOBAL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
@ -85,21 +86,24 @@ static GSList *vips__buffer_cache_all = NULL;
|
||||||
*/
|
*/
|
||||||
static const int buffer_cache_max_reserve = 2;
|
static const int buffer_cache_max_reserve = 2;
|
||||||
|
|
||||||
/* Workers have a buffer_thread in a GPrivate they have exclusive access to.
|
/* Workers have a BufferThread (and BufferCache) in a GPrivate they have
|
||||||
|
* exclusive access to.
|
||||||
*/
|
*/
|
||||||
static GPrivate *buffer_thread_key = NULL;
|
static GPrivate *buffer_thread_key = NULL;
|
||||||
|
|
||||||
/* All non-worker threads share a single global set of buffers protected by a
|
void
|
||||||
* mutex.
|
vips_buffer_print( VipsBuffer *buffer )
|
||||||
*/
|
{
|
||||||
static VipsBufferThread *vips_buffer_thread_global = NULL;
|
printf( "VipsBuffer: %p ref_count = %d, ", buffer, buffer->ref_count );
|
||||||
|
printf( "im = %p, ", buffer->im );
|
||||||
#ifdef DEBUG_GLOBAL
|
printf( "area.left = %d, ", buffer->area.left );
|
||||||
/* Count main thread buffers in and out.
|
printf( "area.top = %d, ", buffer->area.top );
|
||||||
*/
|
printf( "area.width = %d, ", buffer->area.width );
|
||||||
static int vips_buffer_thread_global_n = 0;
|
printf( "area.height = %d, ", buffer->area.height );
|
||||||
static int vips_buffer_thread_global_highwater = 0;
|
printf( "done = %d, ", buffer->done );
|
||||||
#endif /*DEBUG_GLOBAL*/
|
printf( "buf = %p, ", buffer->buf );
|
||||||
|
printf( "bsize = %zd\n", buffer->bsize );
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static void *
|
static void *
|
||||||
|
@ -107,18 +111,38 @@ vips_buffer_dump( VipsBuffer *buffer, size_t *reserve, size_t *alive )
|
||||||
{
|
{
|
||||||
vips_buffer_print( buffer );
|
vips_buffer_print( buffer );
|
||||||
|
|
||||||
if( buffer->im &&
|
g_assert( buffer->im );
|
||||||
buffer->buf &&
|
g_assert( buffer->buf );
|
||||||
buffer->cache ) {
|
|
||||||
printf( "buffer %p, %.3g MB\n",
|
if( !buffer->cache &&
|
||||||
|
!buffer->done ) {
|
||||||
|
/* Global buffer, not linked to any cache.
|
||||||
|
*/
|
||||||
|
printf( "global buffer %p, %.3g MB\n",
|
||||||
buffer, buffer->bsize / (1024 * 1024.0) );
|
buffer, buffer->bsize / (1024 * 1024.0) );
|
||||||
*alive += buffer->bsize;
|
*alive += buffer->bsize;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
if( buffer->im &&
|
else if( buffer->cache &&
|
||||||
buffer->buf &&
|
buffer->done &&
|
||||||
!buffer->cache )
|
!vips_rect_isempty( &buffer->area ) &&
|
||||||
|
g_slist_find( buffer->cache->buffers, buffer ) ) {
|
||||||
|
/* Published on a thread.
|
||||||
|
*/
|
||||||
|
printf( "thread buffer %p, %.3g MB\n",
|
||||||
|
buffer, buffer->bsize / (1024 * 1024.0) );
|
||||||
|
*alive += buffer->bsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( buffer->ref_count == 0 &&
|
||||||
|
buffer->cache &&
|
||||||
|
!buffer->done &&
|
||||||
|
vips_rect_isempty( &buffer->area ) &&
|
||||||
|
g_slist_find( buffer->cache->reserve, buffer ) )
|
||||||
|
/* Held in reserve.
|
||||||
|
*/
|
||||||
*reserve += buffer->bsize;
|
*reserve += buffer->bsize;
|
||||||
|
|
||||||
else
|
else
|
||||||
printf( "buffer craziness!\n" );
|
printf( "buffer craziness!\n" );
|
||||||
|
|
||||||
|
@ -169,12 +193,6 @@ vips_buffer_dump_all( void )
|
||||||
}
|
}
|
||||||
#endif /*DEBUG_CREATE*/
|
#endif /*DEBUG_CREATE*/
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
#ifdef DEBUG_GLOBAL
|
|
||||||
printf( "buffers: %d global buffers\n", vips_buffer_thread_global_n );
|
|
||||||
printf( "buffers: %d high water global buffers\n",
|
|
||||||
vips_buffer_thread_global_highwater );
|
|
||||||
#endif /*DEBUG_GLOBAL*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -197,20 +215,11 @@ vips_buffer_free( VipsBuffer *buffer )
|
||||||
static void
|
static void
|
||||||
buffer_thread_free( VipsBufferThread *buffer_thread )
|
buffer_thread_free( VipsBufferThread *buffer_thread )
|
||||||
{
|
{
|
||||||
/* We only come here from workers, so no need to lock.
|
|
||||||
*/
|
|
||||||
VIPS_FREEF( g_hash_table_destroy, buffer_thread->hash );
|
VIPS_FREEF( g_hash_table_destroy, buffer_thread->hash );
|
||||||
VIPS_FREE( buffer_thread );
|
VIPS_FREE( buffer_thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This can be called via two routes:
|
/* Run for GDestroyNotify on the VipsBufferThread hash.
|
||||||
*
|
|
||||||
* - on thread shutdown, the enclosing hash is destroyed, and that will
|
|
||||||
* trigger this via GDestroyNotify.
|
|
||||||
* - if the BufferCache has been allocated by the main thread, this will be
|
|
||||||
* triggered from postclose on the image
|
|
||||||
*
|
|
||||||
* These can happen in either order.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
buffer_cache_free( VipsBufferCache *cache )
|
buffer_cache_free( VipsBufferCache *cache )
|
||||||
|
@ -235,7 +244,11 @@ buffer_cache_free( VipsBufferCache *cache )
|
||||||
for( p = cache->buffers; p; p = p->next ) {
|
for( p = cache->buffers; p; p = p->next ) {
|
||||||
VipsBuffer *buffer = (VipsBuffer *) p->data;
|
VipsBuffer *buffer = (VipsBuffer *) p->data;
|
||||||
|
|
||||||
|
g_assert( buffer->done );
|
||||||
|
g_assert( buffer->cache == cache );
|
||||||
|
|
||||||
buffer->done = FALSE;
|
buffer->done = FALSE;
|
||||||
|
buffer->cache = NULL;
|
||||||
}
|
}
|
||||||
VIPS_FREEF( g_slist_free, cache->buffers );
|
VIPS_FREEF( g_slist_free, cache->buffers );
|
||||||
|
|
||||||
|
@ -249,32 +262,6 @@ buffer_cache_free( VipsBufferCache *cache )
|
||||||
g_free( cache );
|
g_free( cache );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
buffer_cache_image_postclose( VipsImage *im, VipsBufferCache *cache )
|
|
||||||
{
|
|
||||||
VipsBufferThread *buffer_thread = cache->buffer_thread;
|
|
||||||
|
|
||||||
/* Runs to clean up main thread buffers on image close.
|
|
||||||
*/
|
|
||||||
g_assert( cache->im == im );
|
|
||||||
g_assert( !vips_thread_isworker() );
|
|
||||||
|
|
||||||
/* All non-worker threads come through here, so we need to lock around
|
|
||||||
* changes to the global buffer_thread.
|
|
||||||
*/
|
|
||||||
g_mutex_lock( vips__global_lock );
|
|
||||||
|
|
||||||
g_hash_table_remove( buffer_thread->hash, im );
|
|
||||||
|
|
||||||
#ifdef DEBUG_GLOBAL
|
|
||||||
vips_buffer_thread_global_n -= 1;
|
|
||||||
printf( "buffer_cache_image_postclose: %d global buffers\n",
|
|
||||||
vips_buffer_thread_global_n );
|
|
||||||
#endif /*DEBUG_GLOBAL*/
|
|
||||||
|
|
||||||
g_mutex_unlock( vips__global_lock );
|
|
||||||
}
|
|
||||||
|
|
||||||
static VipsBufferCache *
|
static VipsBufferCache *
|
||||||
buffer_cache_new( VipsBufferThread *buffer_thread, VipsImage *im )
|
buffer_cache_new( VipsBufferThread *buffer_thread, VipsImage *im )
|
||||||
{
|
{
|
||||||
|
@ -288,29 +275,6 @@ buffer_cache_new( VipsBufferThread *buffer_thread, VipsImage *im )
|
||||||
cache->reserve = NULL;
|
cache->reserve = NULL;
|
||||||
cache->n_reserve = 0;
|
cache->n_reserve = 0;
|
||||||
|
|
||||||
/* VipsBufferCache allocated from worker threads will be freed when
|
|
||||||
* workers shut down. This won't happen for VipsBufferCache allocated
|
|
||||||
* from the main thread, since (obviously) thread shutdown will never
|
|
||||||
* happen. In this case, we need to free resources on image close.
|
|
||||||
*/
|
|
||||||
if( !vips_thread_isworker() ) {
|
|
||||||
g_signal_connect( im, "postclose",
|
|
||||||
G_CALLBACK( buffer_cache_image_postclose ), cache );
|
|
||||||
|
|
||||||
#ifdef DEBUG_GLOBAL
|
|
||||||
/* No need to lock. Main thread buffer_cache_new() calls are
|
|
||||||
* always inside a lock already.
|
|
||||||
*/
|
|
||||||
vips_buffer_thread_global_n += 1;
|
|
||||||
vips_buffer_thread_global_highwater = VIPS_MAX(
|
|
||||||
vips_buffer_thread_global_highwater,
|
|
||||||
vips_buffer_thread_global_n );
|
|
||||||
|
|
||||||
printf( "buffer_cache_new: %d global buffers\n",
|
|
||||||
vips_buffer_thread_global_n );
|
|
||||||
#endif /*DEBUG_GLOBAL*/
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_CREATE
|
#ifdef DEBUG_CREATE
|
||||||
g_mutex_lock( vips__global_lock );
|
g_mutex_lock( vips__global_lock );
|
||||||
vips__buffer_cache_all =
|
vips__buffer_cache_all =
|
||||||
|
@ -340,6 +304,8 @@ buffer_thread_new( void )
|
||||||
return( buffer_thread );
|
return( buffer_thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get our private VipsBufferThread. NULL for non-worker threads.
|
||||||
|
*/
|
||||||
static VipsBufferThread *
|
static VipsBufferThread *
|
||||||
buffer_thread_get( void )
|
buffer_thread_get( void )
|
||||||
{
|
{
|
||||||
|
@ -355,47 +321,33 @@ buffer_thread_get( void )
|
||||||
|
|
||||||
g_assert( buffer_thread->thread == g_thread_self() );
|
g_assert( buffer_thread->thread == g_thread_self() );
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
/* All main threads share a single set of buffers.
|
/* Non-workers don't have one.
|
||||||
*/
|
*/
|
||||||
g_mutex_lock( vips__global_lock );
|
buffer_thread = NULL;
|
||||||
|
|
||||||
if( !vips_buffer_thread_global ) {
|
|
||||||
vips_buffer_thread_global = buffer_thread_new();
|
|
||||||
|
|
||||||
/* Shared by many threads, so no checking.
|
|
||||||
*/
|
|
||||||
vips_buffer_thread_global->thread = NULL;
|
|
||||||
}
|
|
||||||
buffer_thread = vips_buffer_thread_global;
|
|
||||||
|
|
||||||
g_mutex_unlock( vips__global_lock );
|
|
||||||
}
|
|
||||||
|
|
||||||
return( buffer_thread );
|
return( buffer_thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the VipsBufferCache for this image, or NULL for a non-worker.
|
||||||
|
*/
|
||||||
static VipsBufferCache *
|
static VipsBufferCache *
|
||||||
buffer_cache_get( VipsImage *im )
|
buffer_cache_get( VipsImage *im )
|
||||||
{
|
{
|
||||||
VipsBufferThread *buffer_thread = buffer_thread_get();
|
VipsBufferThread *buffer_thread;
|
||||||
|
|
||||||
VipsBufferCache *cache;
|
VipsBufferCache *cache;
|
||||||
|
|
||||||
if( !vips_thread_isworker() )
|
if( (buffer_thread = buffer_thread_get()) ) {
|
||||||
g_mutex_lock( vips__global_lock );
|
if( !(cache = (VipsBufferCache *)
|
||||||
|
g_hash_table_lookup( buffer_thread->hash, im )) ) {
|
||||||
|
cache = buffer_cache_new( buffer_thread, im );
|
||||||
|
g_hash_table_insert( buffer_thread->hash, im, cache );
|
||||||
|
}
|
||||||
|
|
||||||
if( !(cache = (VipsBufferCache *)
|
g_assert( cache->thread == g_thread_self() );
|
||||||
g_hash_table_lookup( buffer_thread->hash, im )) ) {
|
|
||||||
cache = buffer_cache_new( buffer_thread, im );
|
|
||||||
g_hash_table_insert( buffer_thread->hash, im, cache );
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if( !vips_thread_isworker() )
|
cache = NULL;
|
||||||
g_mutex_unlock( vips__global_lock );
|
|
||||||
|
|
||||||
g_assert( !cache->thread ||
|
|
||||||
cache->thread == g_thread_self() );
|
|
||||||
|
|
||||||
return( cache );
|
return( cache );
|
||||||
}
|
}
|
||||||
|
@ -405,10 +357,11 @@ buffer_cache_get( VipsImage *im )
|
||||||
void
|
void
|
||||||
vips_buffer_done( VipsBuffer *buffer )
|
vips_buffer_done( VipsBuffer *buffer )
|
||||||
{
|
{
|
||||||
if( !buffer->done ) {
|
VipsImage *im = buffer->im;
|
||||||
VipsImage *im = buffer->im;
|
VipsBufferCache *cache;
|
||||||
VipsBufferCache *cache = buffer_cache_get( im );
|
|
||||||
|
|
||||||
|
if( !buffer->done &&
|
||||||
|
(cache = buffer_cache_get( im )) ) {
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
printf( "vips_buffer_done: thread %p adding to cache %p\n",
|
printf( "vips_buffer_done: thread %p adding to cache %p\n",
|
||||||
g_thread_self(), cache );
|
g_thread_self(), cache );
|
||||||
|
@ -439,20 +392,18 @@ vips_buffer_undone( VipsBuffer *buffer )
|
||||||
g_thread_self(), buffer, cache );
|
g_thread_self(), buffer, cache );
|
||||||
#endif /*DEBUG_VERBOSE*/
|
#endif /*DEBUG_VERBOSE*/
|
||||||
|
|
||||||
g_assert( !cache->thread ||
|
g_assert( cache->thread == g_thread_self() );
|
||||||
cache->thread == g_thread_self() );
|
g_assert( cache->buffer_thread->thread == cache->thread );
|
||||||
g_assert( !cache->thread ||
|
|
||||||
cache->buffer_thread->thread == cache->thread );
|
|
||||||
g_assert( g_slist_find( cache->buffers, buffer ) );
|
g_assert( g_slist_find( cache->buffers, buffer ) );
|
||||||
|
g_assert( buffer_thread_get() );
|
||||||
g_assert( cache->buffer_thread == buffer_thread_get() );
|
g_assert( cache->buffer_thread == buffer_thread_get() );
|
||||||
|
|
||||||
cache->buffers = g_slist_remove( cache->buffers, buffer );
|
cache->buffers = g_slist_remove( cache->buffers, buffer );
|
||||||
|
|
||||||
buffer->done = FALSE;
|
buffer->done = FALSE;
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
printf( "vips_buffer_undone: %d buffers left\n",
|
printf( "vips_buffer_undone: %d buffers left\n",
|
||||||
g_slist_length( cache_list->buffers ) );
|
g_slist_length( cache->buffers ) );
|
||||||
#endif /*DEBUG_VERBOSE*/
|
#endif /*DEBUG_VERBOSE*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,13 +428,7 @@ vips_buffer_unref( VipsBuffer *buffer )
|
||||||
buffer->ref_count -= 1;
|
buffer->ref_count -= 1;
|
||||||
|
|
||||||
if( buffer->ref_count == 0 ) {
|
if( buffer->ref_count == 0 ) {
|
||||||
/* We are not always the creating thread, for example if we
|
VipsBufferCache *cache;
|
||||||
* come here during vips_region_dispose(). cache may have been
|
|
||||||
* NULLed out during thread exit.
|
|
||||||
VipsBufferCache *cache = buffer->cache;
|
|
||||||
*/
|
|
||||||
|
|
||||||
VipsBufferCache *cache = buffer_cache_get( buffer->im );
|
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
if( !buffer->done )
|
if( !buffer->done )
|
||||||
|
@ -494,7 +439,7 @@ vips_buffer_unref( VipsBuffer *buffer )
|
||||||
|
|
||||||
/* Place on this thread's reserve list for reuse.
|
/* Place on this thread's reserve list for reuse.
|
||||||
*/
|
*/
|
||||||
if( cache &&
|
if( (cache = buffer_cache_get( buffer->im )) &&
|
||||||
cache->n_reserve < buffer_cache_max_reserve ) {
|
cache->n_reserve < buffer_cache_max_reserve ) {
|
||||||
g_assert( !buffer->cache );
|
g_assert( !buffer->cache );
|
||||||
|
|
||||||
|
@ -502,6 +447,7 @@ vips_buffer_unref( VipsBuffer *buffer )
|
||||||
g_slist_prepend( cache->reserve, buffer );
|
g_slist_prepend( cache->reserve, buffer );
|
||||||
cache->n_reserve += 1;
|
cache->n_reserve += 1;
|
||||||
|
|
||||||
|
buffer->cache = cache;
|
||||||
buffer->area.width = 0;
|
buffer->area.width = 0;
|
||||||
buffer->area.height = 0;
|
buffer->area.height = 0;
|
||||||
}
|
}
|
||||||
|
@ -541,20 +487,21 @@ buffer_move( VipsBuffer *buffer, VipsRect *area )
|
||||||
VipsBuffer *
|
VipsBuffer *
|
||||||
vips_buffer_new( VipsImage *im, VipsRect *area )
|
vips_buffer_new( VipsImage *im, VipsRect *area )
|
||||||
{
|
{
|
||||||
VipsBufferCache *cache = buffer_cache_get( im );
|
VipsBufferCache *cache;
|
||||||
|
|
||||||
VipsBuffer *buffer;
|
VipsBuffer *buffer;
|
||||||
|
|
||||||
if( cache->reserve ) {
|
if( (cache = buffer_cache_get( im )) &&
|
||||||
|
cache->reserve ) {
|
||||||
buffer = (VipsBuffer *) cache->reserve->data;
|
buffer = (VipsBuffer *) cache->reserve->data;
|
||||||
cache->reserve = g_slist_remove( cache->reserve, buffer );
|
cache->reserve = g_slist_remove( cache->reserve, buffer );
|
||||||
cache->n_reserve -= 1;
|
cache->n_reserve -= 1;
|
||||||
|
|
||||||
g_assert( buffer->im == im );
|
g_assert( buffer->im == im );
|
||||||
g_assert( buffer->done == FALSE );
|
g_assert( buffer->done == FALSE );
|
||||||
g_assert( !buffer->cache );
|
g_assert( buffer->cache );
|
||||||
|
|
||||||
buffer->ref_count = 1;
|
buffer->ref_count = 1;
|
||||||
|
buffer->cache = NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
buffer = g_new0( VipsBuffer, 1 );
|
buffer = g_new0( VipsBuffer, 1 );
|
||||||
|
@ -581,19 +528,23 @@ vips_buffer_new( VipsImage *im, VipsRect *area )
|
||||||
return( buffer );
|
return( buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find an existing buffer that encloses area and return a ref.
|
/* Find an existing buffer that encloses area and return a ref. Or NULL for no
|
||||||
|
* existing buffer.
|
||||||
*/
|
*/
|
||||||
static VipsBuffer *
|
static VipsBuffer *
|
||||||
buffer_find( VipsImage *im, VipsRect *r )
|
buffer_find( VipsImage *im, VipsRect *r )
|
||||||
{
|
{
|
||||||
VipsBufferCache *cache = buffer_cache_get( im );
|
VipsBufferCache *cache;
|
||||||
|
|
||||||
VipsBuffer *buffer;
|
VipsBuffer *buffer;
|
||||||
GSList *p;
|
GSList *p;
|
||||||
VipsRect *area;
|
VipsRect *area;
|
||||||
|
|
||||||
|
if( !(cache = buffer_cache_get( im )) )
|
||||||
|
return( NULL );
|
||||||
|
|
||||||
/* This needs to be quick :-( don't use
|
/* This needs to be quick :-( don't use
|
||||||
* vips_slist_map2()/vips_rect_includesrect(), do the search inline.
|
* vips_slist_map2()/vips_rect_includesrect(), do the search
|
||||||
|
* inline.
|
||||||
*
|
*
|
||||||
* FIXME we return the first enclosing buffer, perhaps we should
|
* FIXME we return the first enclosing buffer, perhaps we should
|
||||||
* search for the largest?
|
* search for the largest?
|
||||||
|
@ -609,7 +560,7 @@ buffer_find( VipsImage *im, VipsRect *r )
|
||||||
buffer->ref_count += 1;
|
buffer->ref_count += 1;
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
printf( "vips_buffer_find: left = %d, top = %d, "
|
printf( "buffer_find: left = %d, top = %d, "
|
||||||
"width = %d, height = %d, count = %d (%p)\n",
|
"width = %d, height = %d, count = %d (%p)\n",
|
||||||
buffer->area.left, buffer->area.top,
|
buffer->area.left, buffer->area.top,
|
||||||
buffer->area.width, buffer->area.height,
|
buffer->area.width, buffer->area.height,
|
||||||
|
@ -632,13 +583,10 @@ vips_buffer_ref( VipsImage *im, VipsRect *area )
|
||||||
{
|
{
|
||||||
VipsBuffer *buffer;
|
VipsBuffer *buffer;
|
||||||
|
|
||||||
if( !(buffer = buffer_find( im, area )) )
|
if( (buffer = buffer_find( im, area )) )
|
||||||
/* No existing buffer ... make a new one.
|
return( buffer );
|
||||||
*/
|
else
|
||||||
if( !(buffer = vips_buffer_new( im, area )) )
|
return( vips_buffer_new( im, area ) );
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
return( buffer );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unref old, ref new, in a single operation. Reuse stuff if we can. The
|
/* Unref old, ref new, in a single operation. Reuse stuff if we can. The
|
||||||
|
@ -686,20 +634,6 @@ vips_buffer_unref_ref( VipsBuffer *old_buffer, VipsImage *im, VipsRect *area )
|
||||||
return( buffer );
|
return( buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
vips_buffer_print( VipsBuffer *buffer )
|
|
||||||
{
|
|
||||||
printf( "VipsBuffer: %p ref_count = %d, ", buffer, buffer->ref_count );
|
|
||||||
printf( "im = %p, ", buffer->im );
|
|
||||||
printf( "area.left = %d, ", buffer->area.left );
|
|
||||||
printf( "area.top = %d, ", buffer->area.top );
|
|
||||||
printf( "area.width = %d, ", buffer->area.width );
|
|
||||||
printf( "area.height = %d, ", buffer->area.height );
|
|
||||||
printf( "done = %d, ", buffer->done );
|
|
||||||
printf( "buf = %p, ", buffer->buf );
|
|
||||||
printf( "bsize = %zd\n", buffer->bsize );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
buffer_thread_destroy_notify( VipsBufferThread *buffer_thread )
|
buffer_thread_destroy_notify( VipsBufferThread *buffer_thread )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue