home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / tile_swap.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-02-03  |  19.4 KB  |  886 lines

  1. #include "config.h"
  2.  
  3. #include <glib.h>
  4.  
  5. #include <errno.h>
  6. #include <string.h>
  7. #include <stdio.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <fcntl.h>
  11. #ifdef HAVE_UNISTD_H
  12. #include <unistd.h>
  13. #endif
  14. #ifdef USE_PTHREADS
  15. #include <pthread.h>
  16. #endif
  17.  
  18. #ifdef G_OS_WIN32
  19. #include <io.h>
  20. #endif
  21.  
  22. #ifndef _O_BINARY
  23. #define _O_BINARY 0
  24. #endif
  25. #ifndef _O_TEMPORARY
  26. #define _O_TEMPORARY 0
  27. #endif
  28.  
  29. #define MAX_OPEN_SWAP_FILES  16
  30.  
  31. #include "tile.h"
  32. #include "tile_swap.h"
  33. #include "tile_pvt.h"            /* ick. */
  34.  
  35. typedef struct _SwapFile      SwapFile;
  36. typedef struct _DefSwapFile   DefSwapFile;
  37. typedef struct _Gap           Gap;
  38. typedef struct _AsyncSwapArgs AsyncSwapArgs;
  39.  
  40. struct _SwapFile
  41. {
  42.   char *filename;
  43.   int swap_num;
  44.   SwapFunc swap_func;
  45.   gpointer user_data;
  46.   int fd;
  47. };
  48.  
  49. struct _DefSwapFile
  50. {
  51.   GList *gaps;
  52.   long swap_file_end;
  53.   off_t cur_position;
  54. };
  55.  
  56. struct _Gap
  57. {
  58.   long start;
  59.   long end;
  60. };
  61.  
  62. struct _AsyncSwapArgs
  63. {
  64.   DefSwapFile *def_swap_file;
  65.   int          fd;
  66.   Tile        *tile;
  67. };
  68.  
  69.  
  70. static void  tile_swap_init    (void);
  71. static guint tile_swap_hash    (int      *key);
  72. static gint  tile_swap_compare (int      *a,
  73.                 int      *b);
  74. static void  tile_swap_command (Tile     *tile,
  75.                 int       command);
  76. static void  tile_swap_open    (SwapFile *swap_file);
  77.  
  78. static int   tile_swap_default        (int       fd,
  79.                        Tile     *tile,
  80.                        int       cmd,
  81.                        gpointer  user_data);
  82. static void  tile_swap_default_in     (DefSwapFile *def_swap_file,
  83.                        int          fd,
  84.                        Tile        *tile);
  85. static void  tile_swap_default_in_async (DefSwapFile *def_swap_file,
  86.                         int          fd,
  87.                         Tile        *tile);
  88. static void  tile_swap_default_out    (DefSwapFile *def_swap_file,
  89.                        int          fd,
  90.                        Tile        *tile);
  91. static void  tile_swap_default_delete (DefSwapFile *def_swap_file,
  92.                        int          fd,
  93.                        Tile        *tile);
  94. static long  tile_swap_find_offset    (DefSwapFile *def_swap_file,
  95.                        int          fd,
  96.                        int          bytes);
  97. static void  tile_swap_resize         (DefSwapFile *def_swap_file,
  98.                        int          fd,
  99.                        long         new_size);
  100. static Gap*  tile_swap_gap_new        (long         start,
  101.                        long         end);
  102. static void  tile_swap_gap_destroy    (Gap         *gap);
  103. #ifdef USE_PTHREADS
  104. static void* tile_swap_in_thread      (void *);
  105. #endif
  106.  
  107.  
  108. static int initialize = TRUE;
  109. static GHashTable *swap_files = NULL;
  110. static GList *open_swap_files = NULL;
  111. static int nopen_swap_files = 0;
  112. static int next_swap_num = 1;
  113. static long swap_file_grow = 16 * TILE_WIDTH * TILE_HEIGHT * 4;
  114. #ifdef USE_PTHREADS
  115. static pthread_mutex_t swapfile_mutex = PTHREAD_MUTEX_INITIALIZER;
  116.  
  117. /* async_swapin_mutex protects only the list, not the tiles therein */
  118. static pthread_t swapin_thread;
  119. static pthread_mutex_t async_swapin_mutex = PTHREAD_MUTEX_INITIALIZER;
  120. static pthread_cond_t async_swapin_signal = PTHREAD_COND_INITIALIZER;
  121. static GSList *async_swapin_tiles = NULL;
  122. static GSList *async_swapin_tiles_end = NULL;
  123. #endif
  124.  
  125. static gboolean seek_err_msg = TRUE, read_err_msg = TRUE, write_err_msg = TRUE;
  126.  
  127. static void
  128. tile_swap_print_gaps (DefSwapFile *def_swap_file)
  129. {
  130.   GList *gaps;
  131.   Gap *gap;
  132.  
  133.   gaps = def_swap_file->gaps;
  134.   while (gaps)
  135.     {
  136.       gap = gaps->data;
  137.       gaps = gaps->next;
  138.  
  139.       g_print ("  %6ld - %6ld\n", gap->start, gap->end);
  140.     }
  141. }
  142.  
  143. static void
  144. tile_swap_exit1 (gpointer key,
  145.          gpointer value,
  146.          gpointer data)
  147. {
  148.   extern int tile_ref_count;
  149.   SwapFile *swap_file;
  150.   DefSwapFile *def_swap_file;
  151.  
  152.   if (tile_ref_count != 0)
  153.     g_warning ("tile ref count balance: %d\n", tile_ref_count);
  154.  
  155.   swap_file = value;
  156.   if (swap_file->swap_func == tile_swap_default)
  157.     {
  158.       def_swap_file = swap_file->user_data;
  159.       if (def_swap_file->swap_file_end != 0)
  160.     {
  161.       g_warning ("swap file not empty: \"%s\"\n", swap_file->filename);
  162.       tile_swap_print_gaps (def_swap_file);
  163.     }
  164.  
  165. #if defined (__EMX__) || defined (G_OS_WIN32)
  166.       /* should close before unlink */
  167.       if (swap_file->fd > 0)
  168.     {
  169.       close (swap_file->fd);
  170.       swap_file->fd = -1;
  171.     }
  172. #endif
  173.       unlink (swap_file->filename);
  174.     }
  175. }
  176.  
  177.  
  178. void
  179. tile_swap_exit ()
  180. {
  181. #ifdef HINTS_SANITY
  182.   extern int tile_exist_peak;
  183.  
  184.   fprintf(stderr,"Tile exist peak was %d Tile structs (%d bytes)",
  185.        tile_exist_peak, tile_exist_peak * sizeof(Tile));
  186. #endif
  187.  
  188.   if (swap_files)
  189.     g_hash_table_foreach (swap_files, tile_swap_exit1, NULL);
  190. }
  191.  
  192. int
  193. tile_swap_add (char     *filename,
  194.            SwapFunc  swap_func,
  195.            gpointer  user_data)
  196. {
  197.   SwapFile *swap_file;
  198.   DefSwapFile *def_swap_file;
  199.  
  200. #ifdef USE_PTHREADS
  201.   pthread_mutex_lock(&swapfile_mutex);
  202. #endif
  203.  
  204.   if (initialize)
  205.     tile_swap_init ();
  206.  
  207.   swap_file = g_new (SwapFile, 1);
  208.   swap_file->filename = g_strdup (filename);
  209.   swap_file->swap_num = next_swap_num++;
  210.  
  211.   if (!swap_func)
  212.     {
  213.       swap_func = tile_swap_default;
  214.  
  215.       def_swap_file = g_new (DefSwapFile, 1);
  216.       def_swap_file->gaps = NULL;
  217.       def_swap_file->swap_file_end = 0;
  218.       def_swap_file->cur_position = 0;
  219.  
  220.       user_data = def_swap_file;
  221.     }
  222.  
  223.   swap_file->swap_func = swap_func;
  224.   swap_file->user_data = user_data;
  225.   swap_file->fd = -1;
  226.  
  227.   g_hash_table_insert (swap_files, &swap_file->swap_num, swap_file);
  228.  
  229. #ifdef USE_PTHREADS
  230.   pthread_mutex_unlock(&swapfile_mutex);
  231. #endif
  232.   return swap_file->swap_num;
  233. }
  234.  
  235. void
  236. tile_swap_remove (int swap_num)
  237. {
  238.   SwapFile *swap_file;
  239.  
  240. #ifdef USE_PTHREADS
  241.   pthread_mutex_lock(&swapfile_mutex);
  242. #endif
  243.  
  244.   if (initialize)
  245.     tile_swap_init ();
  246.  
  247.   swap_file = g_hash_table_lookup (swap_files, &swap_num);
  248.   if (!swap_file)
  249.     goto out;
  250.  
  251.   g_hash_table_remove (swap_files, &swap_num);
  252.  
  253.   if (swap_file->fd != -1)
  254.     close (swap_file->fd);
  255.  
  256.   g_free (swap_file);
  257. out:
  258. #ifdef USE_PTHREADS
  259.   pthread_mutex_unlock(&swapfile_mutex);
  260. #endif
  261.   return;
  262. }
  263.  
  264. void
  265. tile_swap_in_async (Tile *tile)
  266. {
  267.   if (tile->swap_offset == -1)
  268.     return;
  269.  
  270.   tile_swap_command (tile, SWAP_IN_ASYNC);
  271. }
  272.  
  273. void
  274. tile_swap_in (Tile *tile)
  275. {
  276.   if (tile->swap_offset == -1)
  277.     {
  278.       tile_alloc (tile);
  279.       return;
  280.     }
  281.  
  282.   tile_swap_command (tile, SWAP_IN);
  283. }
  284.  
  285. void
  286. tile_swap_out (Tile *tile)
  287. {
  288.   tile_swap_command (tile, SWAP_OUT);
  289. }
  290.  
  291. void
  292. tile_swap_delete (Tile *tile)
  293. {
  294.   tile_swap_command (tile, SWAP_DELETE);
  295. }
  296.  
  297. void
  298. tile_swap_compress (int swap_num)
  299. {
  300.   tile_swap_command (NULL, SWAP_COMPRESS);
  301. }
  302.  
  303. static void
  304. tile_swap_init ()
  305. {
  306.  
  307.   if (initialize)
  308.     {
  309.       initialize = FALSE;
  310.  
  311.       swap_files = g_hash_table_new ((GHashFunc) tile_swap_hash,
  312.                      (GCompareFunc) tile_swap_compare);
  313.  
  314. #ifdef NOTDEF /* USE_PTHREADS */
  315.       pthread_create (&swapin_thread, NULL, &tile_swap_in_thread, NULL);
  316. #endif
  317.     }
  318. }
  319.  
  320. static guint
  321. tile_swap_hash (int *key)
  322. {
  323.   return ((guint) *key);
  324. }
  325.  
  326. static gint
  327. tile_swap_compare (int *a,
  328.            int *b)
  329. {
  330.   return (*a == *b);
  331. }
  332.  
  333. static void
  334. tile_swap_command (Tile *tile,
  335.            int   command)
  336. {
  337.   SwapFile *swap_file;
  338. #ifdef USE_PTHREADS
  339.   pthread_mutex_lock(&swapfile_mutex);
  340. #endif
  341.  
  342.   if (initialize)
  343.     tile_swap_init ();
  344.  
  345.   do {
  346.     swap_file = g_hash_table_lookup (swap_files, &tile->swap_num);
  347.     if (!swap_file)
  348.       {
  349.     g_warning ("could not find swap file for tile");
  350.     goto out;
  351.       }
  352.  
  353.     if (swap_file->fd == -1)
  354.       {
  355.     tile_swap_open (swap_file);
  356.  
  357.     if (swap_file->fd == -1)
  358.       goto out;
  359.       }
  360.   } while ((* swap_file->swap_func) (swap_file->fd, tile, command, swap_file->user_data));
  361. out:
  362. #ifdef USE_PTHREADS
  363.   pthread_mutex_unlock(&swapfile_mutex);
  364. #endif
  365.   return;
  366. }
  367.  
  368. static void
  369. tile_swap_open (SwapFile *swap_file)
  370. {
  371.   SwapFile *tmp;
  372.  
  373.   if (swap_file->fd != -1)
  374.     return;
  375.  
  376.   if (nopen_swap_files == MAX_OPEN_SWAP_FILES)
  377.     {
  378.       tmp = open_swap_files->data;
  379.       close (tmp->fd);
  380.       tmp->fd = -1;
  381.  
  382.       open_swap_files = g_list_remove (open_swap_files, open_swap_files->data);
  383.       nopen_swap_files -= 1;
  384.     }
  385.  
  386.   swap_file->fd = open (swap_file->filename,
  387.                   O_CREAT | O_RDWR | _O_BINARY | _O_TEMPORARY,
  388.             S_IREAD | S_IWRITE);
  389.  
  390.   if (swap_file->fd == -1)
  391.     {
  392.       g_message ("unable to open swap file...BAD THINGS WILL HAPPEN SOON");
  393.       return;
  394.     }
  395.  
  396.   open_swap_files = g_list_append (open_swap_files, swap_file);
  397.   nopen_swap_files += 1;
  398. }
  399.  
  400. /* The actual swap file code. The swap file consists of tiles
  401.  *  which have been moved out to disk in order to conserve memory.
  402.  *  The swap file format is free form. Any tile in memory may
  403.  *  end up anywhere on disk.
  404.  * An actual tile in the swap file consists only of the tile data.
  405.  *  The offset of the tile on disk is stored in the tile data structure
  406.  *  in memory.
  407.  */
  408.  
  409. static int
  410. tile_swap_default (int       fd,
  411.            Tile     *tile,
  412.            int       cmd,
  413.            gpointer  user_data)
  414. {
  415.   DefSwapFile *def_swap_file;
  416.  
  417.   def_swap_file = (DefSwapFile*) user_data;
  418.  
  419.   switch (cmd)
  420.     {
  421.     case SWAP_IN:
  422.       tile_swap_default_in (def_swap_file, fd, tile);
  423.       break;
  424.     case SWAP_IN_ASYNC:
  425.       tile_swap_default_in_async (def_swap_file, fd, tile);
  426.       break;
  427.     case SWAP_OUT:
  428.       tile_swap_default_out (def_swap_file, fd, tile);
  429.       break;
  430.     case SWAP_DELETE:
  431.       tile_swap_default_delete (def_swap_file, fd, tile);
  432.       break;
  433.     case SWAP_COMPRESS:
  434.       g_warning ("tile_swap_default: SWAP_COMPRESS: UNFINISHED");
  435.       break;
  436.     }
  437.  
  438.   return FALSE;
  439. }
  440.  
  441. static void
  442. tile_swap_default_in_async (DefSwapFile *def_swap_file,
  443.                     int          fd,
  444.                     Tile        *tile)
  445. {
  446. #ifdef NOTDEF /* USE_PTHREADS */
  447.   AsyncSwapArgs *args;
  448.  
  449.   args = g_new(AsyncSwapArgs, 1);
  450.   args->def_swap_file = def_swap_file;
  451.   args->fd = fd;
  452.   args->tile = tile;
  453.  
  454.   /* add this tile to the list of tiles for the async swapin task */
  455.   pthread_mutex_lock (&async_swapin_mutex);
  456.   g_slist_append (async_swapin_tiles_end, args);
  457.  
  458.   if (!async_swapin_tiles)
  459.     async_swapin_tiles = async_swapin_tiles_end;
  460.   
  461.   pthread_cond_signal (&async_swapin_signal);
  462.   pthread_mutex_unlock (&async_swapin_mutex);
  463.  
  464. #else
  465.   /* ignore; it's only a hint anyway */
  466.   /* this could be changed to call out to another program that
  467.    * tries to make the OS read the data in from disk.
  468.    */
  469. #endif
  470.  
  471.   return;
  472. }
  473.  
  474. /* NOTE: if you change this function, check to see if your changes
  475.  * apply to tile_swap_in_attempt() near the end of the file.  The
  476.  * difference is that this version makes guarantees about what it
  477.  * provides, but tile_swap_in_attempt() just tries and gives up if
  478.  * anything goes wrong.
  479.  *
  480.  * I'm not sure that it is worthwhile to try to pull out common
  481.  * bits; I think the two functions are (at least for now) different
  482.  * enough to keep as two functions.
  483.  *
  484.  * N.B. the mutex on the tile must already have been locked on entry
  485.  * to this function.  DO NOT LOCK IT HERE.
  486.  */
  487. static void
  488. tile_swap_default_in (DefSwapFile *def_swap_file,
  489.               int          fd,
  490.               Tile        *tile)
  491. {
  492.   int bytes;
  493.   int err;
  494.   int nleft;
  495.   off_t offset;
  496.  
  497.   err = -1;
  498.  
  499.   if (tile->data)
  500.     {
  501.       return;
  502.     }
  503.  
  504.   if (def_swap_file->cur_position != tile->swap_offset)
  505.     {
  506.       def_swap_file->cur_position = tile->swap_offset;
  507.  
  508.       offset = lseek (fd, tile->swap_offset, SEEK_SET);
  509.       if (offset == -1)
  510.     {
  511.       if (seek_err_msg)
  512.         g_message ("unable to seek to tile location on disk: %d", err);
  513.       seek_err_msg = FALSE;
  514.       return;
  515.     }
  516.     }
  517.  
  518.   bytes = tile_size (tile);
  519.   tile_alloc (tile);
  520.  
  521.   nleft = bytes;
  522.   while (nleft > 0)
  523.     {
  524.       do {
  525.     err = read (fd, tile->data + bytes - nleft, nleft);
  526.       } while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
  527.  
  528.       if (err <= 0)
  529.     {
  530.       if (read_err_msg)
  531.         g_message ("unable to read tile data from disk: %d/%d ( %d ) bytes read", err, errno, nleft);
  532.       read_err_msg = FALSE;
  533.       return;
  534.     }
  535.  
  536.       nleft -= err;
  537.     }
  538.  
  539.   def_swap_file->cur_position += bytes;
  540.  
  541.   /*  Do not delete the swap from the file  */
  542.   /*  tile_swap_default_delete (def_swap_file, fd, tile);  */
  543.  
  544.   read_err_msg = seek_err_msg = TRUE;
  545. }
  546.  
  547. static void
  548. tile_swap_default_out (DefSwapFile *def_swap_file,
  549.                int          fd,
  550.                Tile        *tile)
  551. {
  552.   int bytes;
  553.   int rbytes;
  554.   int err;
  555.   int nleft;
  556.   off_t offset;
  557.  
  558.   off_t newpos;
  559.  
  560.   bytes = TILE_WIDTH * TILE_HEIGHT * tile->bpp;
  561.   rbytes = tile_size (tile);
  562.  
  563.   /*  If there is already a valid swap_offset, use it  */
  564.   if (tile->swap_offset == -1)
  565.     newpos = tile_swap_find_offset (def_swap_file, fd, bytes);
  566.   else 
  567.     newpos = tile->swap_offset;
  568.  
  569.   if (def_swap_file->cur_position != newpos)
  570.     {
  571.       offset = lseek (fd, newpos, SEEK_SET);
  572.       if (offset == -1)
  573.     {
  574.       if (seek_err_msg)
  575.         g_message ("unable to seek to tile location on disk: %d", errno);
  576.       seek_err_msg = FALSE;
  577.       return;
  578.     }
  579.       def_swap_file->cur_position = newpos;
  580.     }
  581.  
  582.   nleft = rbytes;
  583.   while (nleft > 0)
  584.     {
  585.       err = write (fd, tile->data + rbytes - nleft, nleft);
  586.       if (err <= 0)
  587.     {
  588.       if (write_err_msg)
  589.         g_message ("unable to write tile data to disk: %d ( %d ) bytes written", err, nleft);
  590.       write_err_msg = FALSE;
  591.       return;
  592.     }
  593.  
  594.       nleft -= err;
  595.     }
  596.  
  597.   def_swap_file->cur_position += rbytes;
  598.  
  599.   /* Do NOT free tile->data because we may be pre-swapping.
  600.    * tile->data is freed in tile_cache_zorch_next
  601.    */
  602.   tile->dirty = FALSE;
  603.   tile->swap_offset = newpos;
  604.  
  605.   write_err_msg = seek_err_msg = TRUE;
  606. }
  607.  
  608. static void
  609. tile_swap_default_delete (DefSwapFile *def_swap_file,
  610.               int          fd,
  611.               Tile        *tile)
  612. {
  613.   GList *tmp;
  614.   GList *tmp2;
  615.   Gap *gap;
  616.   Gap *gap2;
  617.   long start;
  618.   long end;
  619.  
  620.   if (tile->swap_offset == -1)
  621.     return;
  622.  
  623.   start = tile->swap_offset;
  624.   end = start + TILE_WIDTH * TILE_HEIGHT * tile->bpp;
  625.   tile->swap_offset = -1;
  626.  
  627.   tmp = def_swap_file->gaps;
  628.   while (tmp)
  629.     {
  630.       gap = tmp->data;
  631.  
  632.       if (end == gap->start)
  633.     {
  634.       gap->start = start;
  635.  
  636.       if (tmp->prev)
  637.         {
  638.           gap2 = tmp->prev->data;
  639.           if (gap->start == gap2->end)
  640.         {
  641.           gap2->end = gap->end;
  642.           tile_swap_gap_destroy (gap);
  643.           def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
  644.           g_list_free (tmp);
  645.         }
  646.         }
  647.       break;
  648.     }
  649.       else if (start == gap->end)
  650.     {
  651.       gap->end = end;
  652.  
  653.       if (tmp->next)
  654.         {
  655.           gap2 = tmp->next->data;
  656.           if (gap->end == gap2->start)
  657.         {
  658.           gap2->start = gap->start;
  659.           tile_swap_gap_destroy (gap);
  660.           def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
  661.           g_list_free (tmp);
  662.         }
  663.         }
  664.       break;
  665.     }
  666.       else if (end < gap->start)
  667.     {
  668.       gap = tile_swap_gap_new (start, end);
  669.  
  670.       tmp2 = g_list_alloc ();
  671.       tmp2->data = gap;
  672.       tmp2->next = tmp;
  673.       tmp2->prev = tmp->prev;
  674.       if (tmp->prev)
  675.         tmp->prev->next = tmp2;
  676.       tmp->prev = tmp2;
  677.  
  678.       if (tmp == def_swap_file->gaps)
  679.         def_swap_file->gaps = tmp2;
  680.       break;
  681.     }
  682.       else if (!tmp->next)
  683.     {
  684.       gap = tile_swap_gap_new (start, end);
  685.       tmp->next = g_list_alloc ();
  686.       tmp->next->data = gap;
  687.       tmp->next->prev = tmp;
  688.       break;
  689.     }
  690.  
  691.       tmp = tmp->next;
  692.     }
  693.  
  694.   if (!def_swap_file->gaps)
  695.     {
  696.       gap = tile_swap_gap_new (start, end);
  697.       def_swap_file->gaps = g_list_append (def_swap_file->gaps, gap);
  698.     }
  699.  
  700.   tmp = g_list_last (def_swap_file->gaps);
  701.   gap = tmp->data;
  702.  
  703.   if (gap->end == def_swap_file->swap_file_end)
  704.     {
  705.       tile_swap_resize (def_swap_file, fd, gap->start);
  706.       tile_swap_gap_destroy (gap);
  707.       def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
  708.       g_list_free (tmp);
  709.     }
  710. }
  711.  
  712. static void
  713. tile_swap_resize (DefSwapFile *def_swap_file,
  714.           int          fd,
  715.           long         new_size)
  716. {
  717.   if (def_swap_file->swap_file_end > new_size)
  718.     {
  719.       ftruncate (fd, new_size);
  720.       /*fprintf(stderr, "TRUNCATED SWAP from %d to %d bytes.\n",
  721.     (int)def_swap_file->swap_file_end, (int) new_size);*/
  722.     }
  723.   def_swap_file->swap_file_end = new_size;
  724. }
  725.  
  726. static long
  727. tile_swap_find_offset (DefSwapFile *def_swap_file,
  728.                int          fd,
  729.                int          bytes)
  730. {
  731.   GList *tmp;
  732.   Gap *gap;
  733.   long offset;
  734.  
  735.   tmp = def_swap_file->gaps;
  736.   while (tmp)
  737.     {
  738.       gap = tmp->data;
  739.  
  740.       if ((gap->end - gap->start) >= bytes)
  741.     {
  742.       offset = gap->start;
  743.       gap->start += bytes;
  744.  
  745.       if (gap->start == gap->end)
  746.         {
  747.           tile_swap_gap_destroy (gap);
  748.           def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
  749.           g_list_free (tmp);
  750.         }
  751.  
  752.       return offset;
  753.     }
  754.  
  755.       tmp = tmp->next;
  756.     }
  757.  
  758.   offset = def_swap_file->swap_file_end;
  759.  
  760.   tile_swap_resize (def_swap_file, fd, def_swap_file->swap_file_end + swap_file_grow);
  761.  
  762.   if ((offset + bytes) < (def_swap_file->swap_file_end))
  763.     {
  764.       gap = tile_swap_gap_new (offset + bytes, def_swap_file->swap_file_end);
  765.       def_swap_file->gaps = g_list_append (def_swap_file->gaps, gap);
  766.     }
  767.  
  768.   return offset;
  769. }
  770.  
  771. static Gap*
  772. tile_swap_gap_new (long start,
  773.            long end)
  774. {
  775.   Gap *gap;
  776.  
  777.   gap = g_new (Gap, 1);
  778.   gap->start = start;
  779.   gap->end = end;
  780.  
  781.   return gap;
  782. }
  783.  
  784. static void
  785. tile_swap_gap_destroy (Gap *gap)
  786. {
  787.   g_free (gap);
  788. }
  789.  
  790.  
  791. #ifdef NOTDEF /* USE_PTHREADS */
  792. /* go through the list of tiles that are likely to be used soon and
  793.  * try to swap them in.  If any tile is not in a state to be swapped
  794.  * in, ignore it, and the error will get dealt with when the tile
  795.  * is really needed -- assuming that the error still happens.
  796.  *
  797.  * Potential future enhancement: for non-threaded systems, we could
  798.  * fork() a process which merely attempts to bring tiles into the
  799.  * OS's buffer/page cache, where they will be read into the gimp
  800.  * more quickly.  This would be pretty trivial, actually.
  801.  */
  802.  
  803. static void
  804. tile_swap_in_attempt (DefSwapFile *def_swap_file,
  805.               int          fd,
  806.               Tile        *tile)
  807. {
  808.   int bytes;
  809.   int err;
  810.   int nleft;
  811.   off_t offset;
  812.  
  813.   err = -1;
  814.  
  815.   TILE_MUTEX_LOCK (tile);
  816.   if (tile->data)
  817.     goto out;
  818.  
  819.   if (!tile->swap_num || !tile->swap_offset)
  820.     goto out;
  821.  
  822.   if (def_swap_file->cur_position != tile->swap_offset)
  823.     {
  824.       def_swap_file->cur_position = tile->swap_offset;
  825.  
  826.       offset = lseek (fd, tile->swap_offset, SEEK_SET);
  827.       if (offset == -1)
  828.     return;
  829.     }
  830.  
  831.   bytes = tile_size (tile);
  832.   tile_alloc (tile);
  833.  
  834.   nleft = bytes;
  835.   while (nleft > 0)
  836.     {
  837.       do {
  838.     err = read (fd, tile->data + bytes - nleft, nleft);
  839.       } while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
  840.  
  841.       if (err <= 0)
  842.         {
  843.       g_free (tile->data);
  844.       return;
  845.         }
  846.  
  847.       nleft -= err;
  848.     }
  849.  
  850.   def_swap_file->cur_position += bytes;
  851.  
  852. out:
  853.   TILE_MUTEX_UNLOCK (tile);
  854. }
  855.  
  856. static void *
  857. tile_swap_in_thread (void *data)
  858. {
  859.   AsyncSwapArgs *args;
  860.   GSList *free_item;
  861.  
  862.   while (1)
  863.     {
  864.       pthread_mutex_lock (&async_swapin_mutex);
  865.  
  866.       if (!async_swapin_tiles)
  867.         {
  868.           pthread_cond_wait (&async_swapin_signal, &async_swapin_mutex);
  869.         }
  870.       args = async_swapin_tiles->data;
  871.  
  872.       free_item = async_swapin_tiles;
  873.       async_swapin_tiles = async_swapin_tiles->next;
  874.       g_slist_free_1(free_item);
  875.       if (!async_swapin_tiles)
  876.         async_swapin_tiles_end = NULL;
  877.  
  878.       pthread_mutex_unlock (&async_swapin_mutex);
  879.  
  880.       tile_swap_in_attempt(args->def_swap_file, args->fd, args->tile);
  881.  
  882.       g_free(args);
  883.     }
  884. }
  885. #endif
  886.