mirror of
https://gitlab.gnome.org/GNOME/gimp
synced 2024-10-23 04:51:44 +00:00
a60cd2f202
Thu Jan 6 18:39:05 GMT 2000 Adam D. Moss <adam@gimp.org> * app/tile_cache.c * app/tile_swap.c: Maybe fixed tile_cache_set_size() so that it actually works now. You can use this to set GIMP's tile cache size at runtime without restarting. If the prefs guys (Sven, Michael?) don't wire it in I'll look at it, but it can't be soon.
888 lines
19 KiB
C
888 lines
19 KiB
C
#include "config.h"
|
|
|
|
#include <glib.h>
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef USE_PTHREADS
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#ifdef G_OS_WIN32
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#ifndef _O_BINARY
|
|
#define _O_BINARY 0
|
|
#endif
|
|
#ifndef _O_TEMPORARY
|
|
#define _O_TEMPORARY 0
|
|
#endif
|
|
|
|
#include "libgimp/gimpintl.h"
|
|
|
|
#define MAX_OPEN_SWAP_FILES 16
|
|
|
|
#include "tile.h"
|
|
#include "tile_swap.h"
|
|
#include "tile_pvt.h" /* ick. */
|
|
|
|
typedef struct _SwapFile SwapFile;
|
|
typedef struct _DefSwapFile DefSwapFile;
|
|
typedef struct _Gap Gap;
|
|
typedef struct _AsyncSwapArgs AsyncSwapArgs;
|
|
|
|
struct _SwapFile
|
|
{
|
|
char *filename;
|
|
int swap_num;
|
|
SwapFunc swap_func;
|
|
gpointer user_data;
|
|
int fd;
|
|
};
|
|
|
|
struct _DefSwapFile
|
|
{
|
|
GList *gaps;
|
|
long swap_file_end;
|
|
off_t cur_position;
|
|
};
|
|
|
|
struct _Gap
|
|
{
|
|
long start;
|
|
long end;
|
|
};
|
|
|
|
struct _AsyncSwapArgs
|
|
{
|
|
DefSwapFile *def_swap_file;
|
|
int fd;
|
|
Tile *tile;
|
|
};
|
|
|
|
|
|
static void tile_swap_init (void);
|
|
static guint tile_swap_hash (int *key);
|
|
static gint tile_swap_compare (int *a,
|
|
int *b);
|
|
static void tile_swap_command (Tile *tile,
|
|
int command);
|
|
static void tile_swap_open (SwapFile *swap_file);
|
|
|
|
static int tile_swap_default (int fd,
|
|
Tile *tile,
|
|
int cmd,
|
|
gpointer user_data);
|
|
static void tile_swap_default_in (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
Tile *tile);
|
|
static void tile_swap_default_in_async (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
Tile *tile);
|
|
static void tile_swap_default_out (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
Tile *tile);
|
|
static void tile_swap_default_delete (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
Tile *tile);
|
|
static long tile_swap_find_offset (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
int bytes);
|
|
static void tile_swap_resize (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
long new_size);
|
|
static Gap* tile_swap_gap_new (long start,
|
|
long end);
|
|
static void tile_swap_gap_destroy (Gap *gap);
|
|
#ifdef USE_PTHREADS
|
|
static void* tile_swap_in_thread (void *);
|
|
#endif
|
|
|
|
|
|
static int initialize = TRUE;
|
|
static GHashTable *swap_files = NULL;
|
|
static GList *open_swap_files = NULL;
|
|
static int nopen_swap_files = 0;
|
|
static int next_swap_num = 1;
|
|
static long swap_file_grow = 16 * TILE_WIDTH * TILE_HEIGHT * 4;
|
|
#ifdef USE_PTHREADS
|
|
static pthread_mutex_t swapfile_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
/* async_swapin_mutex protects only the list, not the tiles therein */
|
|
static pthread_t swapin_thread;
|
|
static pthread_mutex_t async_swapin_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
static pthread_cond_t async_swapin_signal = PTHREAD_COND_INITIALIZER;
|
|
static GSList *async_swapin_tiles = NULL;
|
|
static GSList *async_swapin_tiles_end = NULL;
|
|
#endif
|
|
|
|
static gboolean seek_err_msg = TRUE, read_err_msg = TRUE, write_err_msg = TRUE;
|
|
|
|
static void
|
|
tile_swap_print_gaps (DefSwapFile *def_swap_file)
|
|
{
|
|
GList *gaps;
|
|
Gap *gap;
|
|
|
|
gaps = def_swap_file->gaps;
|
|
while (gaps)
|
|
{
|
|
gap = gaps->data;
|
|
gaps = gaps->next;
|
|
|
|
g_print (" %6ld - %6ld\n", gap->start, gap->end);
|
|
}
|
|
}
|
|
|
|
static void
|
|
tile_swap_exit1 (gpointer key,
|
|
gpointer value,
|
|
gpointer data)
|
|
{
|
|
extern int tile_ref_count;
|
|
SwapFile *swap_file;
|
|
DefSwapFile *def_swap_file;
|
|
|
|
if (tile_ref_count != 0)
|
|
g_warning ("tile ref count balance: %d\n", tile_ref_count);
|
|
|
|
swap_file = value;
|
|
if (swap_file->swap_func == tile_swap_default)
|
|
{
|
|
def_swap_file = swap_file->user_data;
|
|
if (def_swap_file->swap_file_end != 0)
|
|
{
|
|
g_warning ("swap file not empty: \"%s\"\n", swap_file->filename);
|
|
tile_swap_print_gaps (def_swap_file);
|
|
}
|
|
|
|
#if defined (__EMX__) || defined (G_OS_WIN32)
|
|
/* should close before unlink */
|
|
if (swap_file->fd > 0)
|
|
{
|
|
close (swap_file->fd);
|
|
swap_file->fd = -1;
|
|
}
|
|
#endif
|
|
unlink (swap_file->filename);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
tile_swap_exit ()
|
|
{
|
|
#ifdef HINTS_SANITY
|
|
extern int tile_exist_peak;
|
|
|
|
fprintf(stderr,"Tile exist peak was %d Tile structs (%d bytes)",
|
|
tile_exist_peak, tile_exist_peak * sizeof(Tile));
|
|
#endif
|
|
|
|
if (swap_files)
|
|
g_hash_table_foreach (swap_files, tile_swap_exit1, NULL);
|
|
}
|
|
|
|
int
|
|
tile_swap_add (char *filename,
|
|
SwapFunc swap_func,
|
|
gpointer user_data)
|
|
{
|
|
SwapFile *swap_file;
|
|
DefSwapFile *def_swap_file;
|
|
|
|
#ifdef USE_PTHREADS
|
|
pthread_mutex_lock(&swapfile_mutex);
|
|
#endif
|
|
|
|
if (initialize)
|
|
tile_swap_init ();
|
|
|
|
swap_file = g_new (SwapFile, 1);
|
|
swap_file->filename = g_strdup (filename);
|
|
swap_file->swap_num = next_swap_num++;
|
|
|
|
if (!swap_func)
|
|
{
|
|
swap_func = tile_swap_default;
|
|
|
|
def_swap_file = g_new (DefSwapFile, 1);
|
|
def_swap_file->gaps = NULL;
|
|
def_swap_file->swap_file_end = 0;
|
|
def_swap_file->cur_position = 0;
|
|
|
|
user_data = def_swap_file;
|
|
}
|
|
|
|
swap_file->swap_func = swap_func;
|
|
swap_file->user_data = user_data;
|
|
swap_file->fd = -1;
|
|
|
|
g_hash_table_insert (swap_files, &swap_file->swap_num, swap_file);
|
|
|
|
#ifdef USE_PTHREADS
|
|
pthread_mutex_unlock(&swapfile_mutex);
|
|
#endif
|
|
return swap_file->swap_num;
|
|
}
|
|
|
|
void
|
|
tile_swap_remove (int swap_num)
|
|
{
|
|
SwapFile *swap_file;
|
|
|
|
#ifdef USE_PTHREADS
|
|
pthread_mutex_lock(&swapfile_mutex);
|
|
#endif
|
|
|
|
if (initialize)
|
|
tile_swap_init ();
|
|
|
|
swap_file = g_hash_table_lookup (swap_files, &swap_num);
|
|
if (!swap_file)
|
|
goto out;
|
|
|
|
g_hash_table_remove (swap_files, &swap_num);
|
|
|
|
if (swap_file->fd != -1)
|
|
close (swap_file->fd);
|
|
|
|
g_free (swap_file);
|
|
out:
|
|
#ifdef USE_PTHREADS
|
|
pthread_mutex_unlock(&swapfile_mutex);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
void
|
|
tile_swap_in_async (Tile *tile)
|
|
{
|
|
if (tile->swap_offset == -1)
|
|
return;
|
|
|
|
tile_swap_command (tile, SWAP_IN_ASYNC);
|
|
}
|
|
|
|
void
|
|
tile_swap_in (Tile *tile)
|
|
{
|
|
if (tile->swap_offset == -1)
|
|
{
|
|
tile_alloc (tile);
|
|
return;
|
|
}
|
|
|
|
tile_swap_command (tile, SWAP_IN);
|
|
}
|
|
|
|
void
|
|
tile_swap_out (Tile *tile)
|
|
{
|
|
tile_swap_command (tile, SWAP_OUT);
|
|
}
|
|
|
|
void
|
|
tile_swap_delete (Tile *tile)
|
|
{
|
|
tile_swap_command (tile, SWAP_DELETE);
|
|
}
|
|
|
|
void
|
|
tile_swap_compress (int swap_num)
|
|
{
|
|
tile_swap_command (NULL, SWAP_COMPRESS);
|
|
}
|
|
|
|
static void
|
|
tile_swap_init ()
|
|
{
|
|
|
|
if (initialize)
|
|
{
|
|
initialize = FALSE;
|
|
|
|
swap_files = g_hash_table_new ((GHashFunc) tile_swap_hash,
|
|
(GCompareFunc) tile_swap_compare);
|
|
|
|
#ifdef NOTDEF /* USE_PTHREADS */
|
|
pthread_create (&swapin_thread, NULL, &tile_swap_in_thread, NULL);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static guint
|
|
tile_swap_hash (int *key)
|
|
{
|
|
return ((guint) *key);
|
|
}
|
|
|
|
static gint
|
|
tile_swap_compare (int *a,
|
|
int *b)
|
|
{
|
|
return (*a == *b);
|
|
}
|
|
|
|
static void
|
|
tile_swap_command (Tile *tile,
|
|
int command)
|
|
{
|
|
SwapFile *swap_file;
|
|
#ifdef USE_PTHREADS
|
|
pthread_mutex_lock(&swapfile_mutex);
|
|
#endif
|
|
|
|
if (initialize)
|
|
tile_swap_init ();
|
|
|
|
do {
|
|
swap_file = g_hash_table_lookup (swap_files, &tile->swap_num);
|
|
if (!swap_file)
|
|
{
|
|
g_warning ("could not find swap file for tile");
|
|
goto out;
|
|
}
|
|
|
|
if (swap_file->fd == -1)
|
|
{
|
|
tile_swap_open (swap_file);
|
|
|
|
if (swap_file->fd == -1)
|
|
goto out;
|
|
}
|
|
} while ((* swap_file->swap_func) (swap_file->fd, tile, command, swap_file->user_data));
|
|
out:
|
|
#ifdef USE_PTHREADS
|
|
pthread_mutex_unlock(&swapfile_mutex);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
static void
|
|
tile_swap_open (SwapFile *swap_file)
|
|
{
|
|
SwapFile *tmp;
|
|
|
|
if (swap_file->fd != -1)
|
|
return;
|
|
|
|
if (nopen_swap_files == MAX_OPEN_SWAP_FILES)
|
|
{
|
|
tmp = open_swap_files->data;
|
|
close (tmp->fd);
|
|
tmp->fd = -1;
|
|
|
|
open_swap_files = g_list_remove (open_swap_files, open_swap_files->data);
|
|
nopen_swap_files -= 1;
|
|
}
|
|
|
|
swap_file->fd = open (swap_file->filename,
|
|
O_CREAT | O_RDWR | _O_BINARY | _O_TEMPORARY,
|
|
S_IREAD | S_IWRITE);
|
|
|
|
if (swap_file->fd == -1)
|
|
{
|
|
g_message ("unable to open swap file...BAD THINGS WILL HAPPEN SOON");
|
|
return;
|
|
}
|
|
|
|
open_swap_files = g_list_append (open_swap_files, swap_file);
|
|
nopen_swap_files += 1;
|
|
}
|
|
|
|
/* The actual swap file code. The swap file consists of tiles
|
|
* which have been moved out to disk in order to conserve memory.
|
|
* The swap file format is free form. Any tile in memory may
|
|
* end up anywhere on disk.
|
|
* An actual tile in the swap file consists only of the tile data.
|
|
* The offset of the tile on disk is stored in the tile data structure
|
|
* in memory.
|
|
*/
|
|
|
|
static int
|
|
tile_swap_default (int fd,
|
|
Tile *tile,
|
|
int cmd,
|
|
gpointer user_data)
|
|
{
|
|
DefSwapFile *def_swap_file;
|
|
|
|
def_swap_file = (DefSwapFile*) user_data;
|
|
|
|
switch (cmd)
|
|
{
|
|
case SWAP_IN:
|
|
tile_swap_default_in (def_swap_file, fd, tile);
|
|
break;
|
|
case SWAP_IN_ASYNC:
|
|
tile_swap_default_in_async (def_swap_file, fd, tile);
|
|
break;
|
|
case SWAP_OUT:
|
|
tile_swap_default_out (def_swap_file, fd, tile);
|
|
break;
|
|
case SWAP_DELETE:
|
|
tile_swap_default_delete (def_swap_file, fd, tile);
|
|
break;
|
|
case SWAP_COMPRESS:
|
|
g_warning ("tile_swap_default: SWAP_COMPRESS: UNFINISHED");
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
tile_swap_default_in_async (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
Tile *tile)
|
|
{
|
|
#ifdef NOTDEF /* USE_PTHREADS */
|
|
AsyncSwapArgs *args;
|
|
|
|
args = g_new(AsyncSwapArgs, 1);
|
|
args->def_swap_file = def_swap_file;
|
|
args->fd = fd;
|
|
args->tile = tile;
|
|
|
|
/* add this tile to the list of tiles for the async swapin task */
|
|
pthread_mutex_lock (&async_swapin_mutex);
|
|
g_slist_append (async_swapin_tiles_end, args);
|
|
|
|
if (!async_swapin_tiles)
|
|
async_swapin_tiles = async_swapin_tiles_end;
|
|
|
|
pthread_cond_signal (&async_swapin_signal);
|
|
pthread_mutex_unlock (&async_swapin_mutex);
|
|
|
|
#else
|
|
/* ignore; it's only a hint anyway */
|
|
/* this could be changed to call out to another program that
|
|
* tries to make the OS read the data in from disk.
|
|
*/
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
/* NOTE: if you change this function, check to see if your changes
|
|
* apply to tile_swap_in_attempt() near the end of the file. The
|
|
* difference is that this version makes guarantees about what it
|
|
* provides, but tile_swap_in_attempt() just tries and gives up if
|
|
* anything goes wrong.
|
|
*
|
|
* I'm not sure that it is worthwhile to try to pull out common
|
|
* bits; I think the two functions are (at least for now) different
|
|
* enough to keep as two functions.
|
|
*
|
|
* N.B. the mutex on the tile must already have been locked on entry
|
|
* to this function. DO NOT LOCK IT HERE.
|
|
*/
|
|
static void
|
|
tile_swap_default_in (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
Tile *tile)
|
|
{
|
|
int bytes;
|
|
int err;
|
|
int nleft;
|
|
off_t offset;
|
|
|
|
err = -1;
|
|
|
|
if (tile->data)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (def_swap_file->cur_position != tile->swap_offset)
|
|
{
|
|
def_swap_file->cur_position = tile->swap_offset;
|
|
|
|
offset = lseek (fd, tile->swap_offset, SEEK_SET);
|
|
if (offset == -1)
|
|
{
|
|
if (seek_err_msg)
|
|
g_message ("unable to seek to tile location on disk: %d", err);
|
|
seek_err_msg = FALSE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
bytes = tile_size (tile);
|
|
tile_alloc (tile);
|
|
|
|
nleft = bytes;
|
|
while (nleft > 0)
|
|
{
|
|
do {
|
|
err = read (fd, tile->data + bytes - nleft, nleft);
|
|
} while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
|
|
|
|
if (err <= 0)
|
|
{
|
|
if (read_err_msg)
|
|
g_message ("unable to read tile data from disk: %d/%d ( %d ) bytes read", err, errno, nleft);
|
|
read_err_msg = FALSE;
|
|
return;
|
|
}
|
|
|
|
nleft -= err;
|
|
}
|
|
|
|
def_swap_file->cur_position += bytes;
|
|
|
|
/* Do not delete the swap from the file */
|
|
/* tile_swap_default_delete (def_swap_file, fd, tile); */
|
|
|
|
read_err_msg = seek_err_msg = TRUE;
|
|
}
|
|
|
|
static void
|
|
tile_swap_default_out (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
Tile *tile)
|
|
{
|
|
int bytes;
|
|
int rbytes;
|
|
int err;
|
|
int nleft;
|
|
off_t offset;
|
|
|
|
off_t newpos;
|
|
|
|
bytes = TILE_WIDTH * TILE_HEIGHT * tile->bpp;
|
|
rbytes = tile_size (tile);
|
|
|
|
/* If there is already a valid swap_offset, use it */
|
|
if (tile->swap_offset == -1)
|
|
newpos = tile_swap_find_offset (def_swap_file, fd, bytes);
|
|
else
|
|
newpos = tile->swap_offset;
|
|
|
|
if (def_swap_file->cur_position != newpos)
|
|
{
|
|
offset = lseek (fd, newpos, SEEK_SET);
|
|
if (offset == -1)
|
|
{
|
|
if (seek_err_msg)
|
|
g_message ("unable to seek to tile location on disk: %d", errno);
|
|
seek_err_msg = FALSE;
|
|
return;
|
|
}
|
|
def_swap_file->cur_position = newpos;
|
|
}
|
|
|
|
nleft = rbytes;
|
|
while (nleft > 0)
|
|
{
|
|
err = write (fd, tile->data + rbytes - nleft, nleft);
|
|
if (err <= 0)
|
|
{
|
|
if (write_err_msg)
|
|
g_message ("unable to write tile data to disk: %d ( %d ) bytes written", err, nleft);
|
|
write_err_msg = FALSE;
|
|
return;
|
|
}
|
|
|
|
nleft -= err;
|
|
}
|
|
|
|
def_swap_file->cur_position += rbytes;
|
|
|
|
/* Do NOT free tile->data because we may be pre-swapping.
|
|
* tile->data is freed in tile_cache_zorch_next
|
|
*/
|
|
tile->dirty = FALSE;
|
|
tile->swap_offset = newpos;
|
|
|
|
write_err_msg = seek_err_msg = TRUE;
|
|
}
|
|
|
|
static void
|
|
tile_swap_default_delete (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
Tile *tile)
|
|
{
|
|
GList *tmp;
|
|
GList *tmp2;
|
|
Gap *gap;
|
|
Gap *gap2;
|
|
long start;
|
|
long end;
|
|
|
|
if (tile->swap_offset == -1)
|
|
return;
|
|
|
|
start = tile->swap_offset;
|
|
end = start + TILE_WIDTH * TILE_HEIGHT * tile->bpp;
|
|
tile->swap_offset = -1;
|
|
|
|
tmp = def_swap_file->gaps;
|
|
while (tmp)
|
|
{
|
|
gap = tmp->data;
|
|
|
|
if (end == gap->start)
|
|
{
|
|
gap->start = start;
|
|
|
|
if (tmp->prev)
|
|
{
|
|
gap2 = tmp->prev->data;
|
|
if (gap->start == gap2->end)
|
|
{
|
|
gap2->end = gap->end;
|
|
tile_swap_gap_destroy (gap);
|
|
def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
|
|
g_list_free (tmp);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
else if (start == gap->end)
|
|
{
|
|
gap->end = end;
|
|
|
|
if (tmp->next)
|
|
{
|
|
gap2 = tmp->next->data;
|
|
if (gap->end == gap2->start)
|
|
{
|
|
gap2->start = gap->start;
|
|
tile_swap_gap_destroy (gap);
|
|
def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
|
|
g_list_free (tmp);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
else if (end < gap->start)
|
|
{
|
|
gap = tile_swap_gap_new (start, end);
|
|
|
|
tmp2 = g_list_alloc ();
|
|
tmp2->data = gap;
|
|
tmp2->next = tmp;
|
|
tmp2->prev = tmp->prev;
|
|
if (tmp->prev)
|
|
tmp->prev->next = tmp2;
|
|
tmp->prev = tmp2;
|
|
|
|
if (tmp == def_swap_file->gaps)
|
|
def_swap_file->gaps = tmp2;
|
|
break;
|
|
}
|
|
else if (!tmp->next)
|
|
{
|
|
gap = tile_swap_gap_new (start, end);
|
|
tmp->next = g_list_alloc ();
|
|
tmp->next->data = gap;
|
|
tmp->next->prev = tmp;
|
|
break;
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
if (!def_swap_file->gaps)
|
|
{
|
|
gap = tile_swap_gap_new (start, end);
|
|
def_swap_file->gaps = g_list_append (def_swap_file->gaps, gap);
|
|
}
|
|
|
|
tmp = g_list_last (def_swap_file->gaps);
|
|
gap = tmp->data;
|
|
|
|
if (gap->end == def_swap_file->swap_file_end)
|
|
{
|
|
tile_swap_resize (def_swap_file, fd, gap->start);
|
|
tile_swap_gap_destroy (gap);
|
|
def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
|
|
g_list_free (tmp);
|
|
}
|
|
}
|
|
|
|
static void
|
|
tile_swap_resize (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
long new_size)
|
|
{
|
|
if (def_swap_file->swap_file_end > new_size)
|
|
{
|
|
ftruncate (fd, new_size);
|
|
/*fprintf(stderr, "TRUNCATED SWAP from %d to %d bytes.\n",
|
|
(int)def_swap_file->swap_file_end, (int) new_size);*/
|
|
}
|
|
def_swap_file->swap_file_end = new_size;
|
|
}
|
|
|
|
static long
|
|
tile_swap_find_offset (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
int bytes)
|
|
{
|
|
GList *tmp;
|
|
Gap *gap;
|
|
long offset;
|
|
|
|
tmp = def_swap_file->gaps;
|
|
while (tmp)
|
|
{
|
|
gap = tmp->data;
|
|
|
|
if ((gap->end - gap->start) >= bytes)
|
|
{
|
|
offset = gap->start;
|
|
gap->start += bytes;
|
|
|
|
if (gap->start == gap->end)
|
|
{
|
|
tile_swap_gap_destroy (gap);
|
|
def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
|
|
g_list_free (tmp);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
offset = def_swap_file->swap_file_end;
|
|
|
|
tile_swap_resize (def_swap_file, fd, def_swap_file->swap_file_end + swap_file_grow);
|
|
|
|
if ((offset + bytes) < (def_swap_file->swap_file_end))
|
|
{
|
|
gap = tile_swap_gap_new (offset + bytes, def_swap_file->swap_file_end);
|
|
def_swap_file->gaps = g_list_append (def_swap_file->gaps, gap);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
static Gap*
|
|
tile_swap_gap_new (long start,
|
|
long end)
|
|
{
|
|
Gap *gap;
|
|
|
|
gap = g_new (Gap, 1);
|
|
gap->start = start;
|
|
gap->end = end;
|
|
|
|
return gap;
|
|
}
|
|
|
|
static void
|
|
tile_swap_gap_destroy (Gap *gap)
|
|
{
|
|
g_free (gap);
|
|
}
|
|
|
|
|
|
#ifdef NOTDEF /* USE_PTHREADS */
|
|
/* go through the list of tiles that are likely to be used soon and
|
|
* try to swap them in. If any tile is not in a state to be swapped
|
|
* in, ignore it, and the error will get dealt with when the tile
|
|
* is really needed -- assuming that the error still happens.
|
|
*
|
|
* Potential future enhancement: for non-threaded systems, we could
|
|
* fork() a process which merely attempts to bring tiles into the
|
|
* OS's buffer/page cache, where they will be read into the gimp
|
|
* more quickly. This would be pretty trivial, actually.
|
|
*/
|
|
|
|
static void
|
|
tile_swap_in_attempt (DefSwapFile *def_swap_file,
|
|
int fd,
|
|
Tile *tile)
|
|
{
|
|
int bytes;
|
|
int err;
|
|
int nleft;
|
|
off_t offset;
|
|
|
|
err = -1;
|
|
|
|
TILE_MUTEX_LOCK (tile);
|
|
if (tile->data)
|
|
goto out;
|
|
|
|
if (!tile->swap_num || !tile->swap_offset)
|
|
goto out;
|
|
|
|
if (def_swap_file->cur_position != tile->swap_offset)
|
|
{
|
|
def_swap_file->cur_position = tile->swap_offset;
|
|
|
|
offset = lseek (fd, tile->swap_offset, SEEK_SET);
|
|
if (offset == -1)
|
|
return;
|
|
}
|
|
|
|
bytes = tile_size (tile);
|
|
tile_alloc (tile);
|
|
|
|
nleft = bytes;
|
|
while (nleft > 0)
|
|
{
|
|
do {
|
|
err = read (fd, tile->data + bytes - nleft, nleft);
|
|
} while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
|
|
|
|
if (err <= 0)
|
|
{
|
|
g_free (tile->data);
|
|
return;
|
|
}
|
|
|
|
nleft -= err;
|
|
}
|
|
|
|
def_swap_file->cur_position += bytes;
|
|
|
|
out:
|
|
TILE_MUTEX_UNLOCK (tile);
|
|
}
|
|
|
|
static void *
|
|
tile_swap_in_thread (void *data)
|
|
{
|
|
AsyncSwapArgs *args;
|
|
GSList *free_item;
|
|
|
|
while (1)
|
|
{
|
|
pthread_mutex_lock (&async_swapin_mutex);
|
|
|
|
if (!async_swapin_tiles)
|
|
{
|
|
pthread_cond_wait (&async_swapin_signal, &async_swapin_mutex);
|
|
}
|
|
args = async_swapin_tiles->data;
|
|
|
|
free_item = async_swapin_tiles;
|
|
async_swapin_tiles = async_swapin_tiles->next;
|
|
g_slist_free_1(free_item);
|
|
if (!async_swapin_tiles)
|
|
async_swapin_tiles_end = NULL;
|
|
|
|
pthread_mutex_unlock (&async_swapin_mutex);
|
|
|
|
tile_swap_in_attempt(args->def_swap_file, args->fd, args->tile);
|
|
|
|
g_free(args);
|
|
}
|
|
}
|
|
#endif
|