gimp/app/base/tile-swap.c

789 lines
19 KiB
C
Raw Normal View History

/* GIMP - The GNU Image Manipulation Program
app/Makefile.am app/channel_pvt.h app/drawable_pvt.h app/gdisplayF.h 2000-12-29 Michael Natterer <mitch@gimp.org> * app/Makefile.am * app/channel_pvt.h * app/drawable_pvt.h * app/gdisplayF.h * app/gimpdrawableP.h * app/gimpimageP.h * app/layer_pvt.h * app/toolsF.h: removed these files. * app/apptypes.h * tools/pdbgen/enums.pl: added tons of opaque typedefs and enums. * tools/pdbgen/pdb/brush_select.pdb * tools/pdbgen/pdb/brushes.pdb * tools/pdbgen/pdb/channel.pdb * tools/pdbgen/pdb/color.pdb * tools/pdbgen/pdb/convert.pdb * tools/pdbgen/pdb/display.pdb * tools/pdbgen/pdb/drawable.pdb * tools/pdbgen/pdb/fileops.pdb * tools/pdbgen/pdb/gradient_select.pdb * tools/pdbgen/pdb/gradients.pdb * tools/pdbgen/pdb/help.pdb * tools/pdbgen/pdb/image.pdb * tools/pdbgen/pdb/layer.pdb * tools/pdbgen/pdb/pattern_select.pdb * tools/pdbgen/pdb/patterns.pdb * tools/pdbgen/pdb/selection.pdb * tools/pdbgen/pdb/tools.pdb * app/*: chainsaw #include cleanup: - Never (never!!) include stuff in header files except where we need access to structures' contents (like derived objects). - Added prototypes and proper formating in many files. - The #include order in *all* *.c files is as follows: #include "config.h" #include <system stuff> #include <gtk/gtk.h> #include "apptypes.h" #include "gimp stuff" #include "libgimp stuff" #include "libgimp/gimpintl.h" By following this scheme we can easily see a file's dependencies from it's #include's and can grep for the inclusion to find out where a file is used. * tools/pdbgen/app.pl: changed to follow the include scheme above. * libgimp/Makefile.am * libgimp/gimpuitypes.h: new file, included from libgimp/gimpui.h and from app/apptypes.h. * libgimp/gimpcolorbutton.[ch] * libgimp/gimpdialog.[ch] * libgimp/gimphelpui.[ch] * libgimp/gimpparasite.[ch] * libgimp/gimppatheditor.[ch] * libgimp/gimpprotocol.c * libgimp/gimpquerybox.[ch] * libgimp/gimpsizeentry.[ch] * libgimp/gimptypes.h * libgimp/gimpui.h * libgimp/gimpunit.h * libgimp/gimpunitmenu.[ch] * libgimp/gimpwidgets.[ch]: changed accordingly. * plug-ins/FractalExplorer/Dialogs.c * plug-ins/gdyntext/message_window.c * plug-ins/imagemap/imap_default_dialog.c * plug-ins/imagemap/imap_file.c: these files used to include "libgimp/gimpui.h" without including "libgimp/gimp.h". This is no longer possible because the libgimpui headers don't inlcude "libgimp/gimpunit.h" any more.
2000-12-29 23:22:01 +08:00
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
app/Makefile.am app/channel_pvt.h app/drawable_pvt.h app/gdisplayF.h 2000-12-29 Michael Natterer <mitch@gimp.org> * app/Makefile.am * app/channel_pvt.h * app/drawable_pvt.h * app/gdisplayF.h * app/gimpdrawableP.h * app/gimpimageP.h * app/layer_pvt.h * app/toolsF.h: removed these files. * app/apptypes.h * tools/pdbgen/enums.pl: added tons of opaque typedefs and enums. * tools/pdbgen/pdb/brush_select.pdb * tools/pdbgen/pdb/brushes.pdb * tools/pdbgen/pdb/channel.pdb * tools/pdbgen/pdb/color.pdb * tools/pdbgen/pdb/convert.pdb * tools/pdbgen/pdb/display.pdb * tools/pdbgen/pdb/drawable.pdb * tools/pdbgen/pdb/fileops.pdb * tools/pdbgen/pdb/gradient_select.pdb * tools/pdbgen/pdb/gradients.pdb * tools/pdbgen/pdb/help.pdb * tools/pdbgen/pdb/image.pdb * tools/pdbgen/pdb/layer.pdb * tools/pdbgen/pdb/pattern_select.pdb * tools/pdbgen/pdb/patterns.pdb * tools/pdbgen/pdb/selection.pdb * tools/pdbgen/pdb/tools.pdb * app/*: chainsaw #include cleanup: - Never (never!!) include stuff in header files except where we need access to structures' contents (like derived objects). - Added prototypes and proper formating in many files. - The #include order in *all* *.c files is as follows: #include "config.h" #include <system stuff> #include <gtk/gtk.h> #include "apptypes.h" #include "gimp stuff" #include "libgimp stuff" #include "libgimp/gimpintl.h" By following this scheme we can easily see a file's dependencies from it's #include's and can grep for the inclusion to find out where a file is used. * tools/pdbgen/app.pl: changed to follow the include scheme above. * libgimp/Makefile.am * libgimp/gimpuitypes.h: new file, included from libgimp/gimpui.h and from app/apptypes.h. * libgimp/gimpcolorbutton.[ch] * libgimp/gimpdialog.[ch] * libgimp/gimphelpui.[ch] * libgimp/gimpparasite.[ch] * libgimp/gimppatheditor.[ch] * libgimp/gimpprotocol.c * libgimp/gimpquerybox.[ch] * libgimp/gimpsizeentry.[ch] * libgimp/gimptypes.h * libgimp/gimpui.h * libgimp/gimpunit.h * libgimp/gimpunitmenu.[ch] * libgimp/gimpwidgets.[ch]: changed accordingly. * plug-ins/FractalExplorer/Dialogs.c * plug-ins/gdyntext/message_window.c * plug-ins/imagemap/imap_default_dialog.c * plug-ins/imagemap/imap_file.c: these files used to include "libgimp/gimpui.h" without including "libgimp/gimp.h". This is no longer possible because the libgimpui headers don't inlcude "libgimp/gimpunit.h" any more.
2000-12-29 23:22:01 +08:00
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
app/Makefile.am app/channel_pvt.h app/drawable_pvt.h app/gdisplayF.h 2000-12-29 Michael Natterer <mitch@gimp.org> * app/Makefile.am * app/channel_pvt.h * app/drawable_pvt.h * app/gdisplayF.h * app/gimpdrawableP.h * app/gimpimageP.h * app/layer_pvt.h * app/toolsF.h: removed these files. * app/apptypes.h * tools/pdbgen/enums.pl: added tons of opaque typedefs and enums. * tools/pdbgen/pdb/brush_select.pdb * tools/pdbgen/pdb/brushes.pdb * tools/pdbgen/pdb/channel.pdb * tools/pdbgen/pdb/color.pdb * tools/pdbgen/pdb/convert.pdb * tools/pdbgen/pdb/display.pdb * tools/pdbgen/pdb/drawable.pdb * tools/pdbgen/pdb/fileops.pdb * tools/pdbgen/pdb/gradient_select.pdb * tools/pdbgen/pdb/gradients.pdb * tools/pdbgen/pdb/help.pdb * tools/pdbgen/pdb/image.pdb * tools/pdbgen/pdb/layer.pdb * tools/pdbgen/pdb/pattern_select.pdb * tools/pdbgen/pdb/patterns.pdb * tools/pdbgen/pdb/selection.pdb * tools/pdbgen/pdb/tools.pdb * app/*: chainsaw #include cleanup: - Never (never!!) include stuff in header files except where we need access to structures' contents (like derived objects). - Added prototypes and proper formating in many files. - The #include order in *all* *.c files is as follows: #include "config.h" #include <system stuff> #include <gtk/gtk.h> #include "apptypes.h" #include "gimp stuff" #include "libgimp stuff" #include "libgimp/gimpintl.h" By following this scheme we can easily see a file's dependencies from it's #include's and can grep for the inclusion to find out where a file is used. * tools/pdbgen/app.pl: changed to follow the include scheme above. * libgimp/Makefile.am * libgimp/gimpuitypes.h: new file, included from libgimp/gimpui.h and from app/apptypes.h. * libgimp/gimpcolorbutton.[ch] * libgimp/gimpdialog.[ch] * libgimp/gimphelpui.[ch] * libgimp/gimpparasite.[ch] * libgimp/gimppatheditor.[ch] * libgimp/gimpprotocol.c * libgimp/gimpquerybox.[ch] * libgimp/gimpsizeentry.[ch] * libgimp/gimptypes.h * libgimp/gimpui.h * libgimp/gimpunit.h * libgimp/gimpunitmenu.[ch] * libgimp/gimpwidgets.[ch]: changed accordingly. * plug-ins/FractalExplorer/Dialogs.c * plug-ins/gdyntext/message_window.c * plug-ins/imagemap/imap_default_dialog.c * plug-ins/imagemap/imap_file.c: these files used to include "libgimp/gimpui.h" without including "libgimp/gimp.h". This is no longer possible because the libgimpui headers don't inlcude "libgimp/gimpunit.h" any more.
2000-12-29 23:22:01 +08:00
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
app/Makefile.am app/channel_pvt.h app/drawable_pvt.h app/gdisplayF.h 2000-12-29 Michael Natterer <mitch@gimp.org> * app/Makefile.am * app/channel_pvt.h * app/drawable_pvt.h * app/gdisplayF.h * app/gimpdrawableP.h * app/gimpimageP.h * app/layer_pvt.h * app/toolsF.h: removed these files. * app/apptypes.h * tools/pdbgen/enums.pl: added tons of opaque typedefs and enums. * tools/pdbgen/pdb/brush_select.pdb * tools/pdbgen/pdb/brushes.pdb * tools/pdbgen/pdb/channel.pdb * tools/pdbgen/pdb/color.pdb * tools/pdbgen/pdb/convert.pdb * tools/pdbgen/pdb/display.pdb * tools/pdbgen/pdb/drawable.pdb * tools/pdbgen/pdb/fileops.pdb * tools/pdbgen/pdb/gradient_select.pdb * tools/pdbgen/pdb/gradients.pdb * tools/pdbgen/pdb/help.pdb * tools/pdbgen/pdb/image.pdb * tools/pdbgen/pdb/layer.pdb * tools/pdbgen/pdb/pattern_select.pdb * tools/pdbgen/pdb/patterns.pdb * tools/pdbgen/pdb/selection.pdb * tools/pdbgen/pdb/tools.pdb * app/*: chainsaw #include cleanup: - Never (never!!) include stuff in header files except where we need access to structures' contents (like derived objects). - Added prototypes and proper formating in many files. - The #include order in *all* *.c files is as follows: #include "config.h" #include <system stuff> #include <gtk/gtk.h> #include "apptypes.h" #include "gimp stuff" #include "libgimp stuff" #include "libgimp/gimpintl.h" By following this scheme we can easily see a file's dependencies from it's #include's and can grep for the inclusion to find out where a file is used. * tools/pdbgen/app.pl: changed to follow the include scheme above. * libgimp/Makefile.am * libgimp/gimpuitypes.h: new file, included from libgimp/gimpui.h and from app/apptypes.h. * libgimp/gimpcolorbutton.[ch] * libgimp/gimpdialog.[ch] * libgimp/gimphelpui.[ch] * libgimp/gimpparasite.[ch] * libgimp/gimppatheditor.[ch] * libgimp/gimpprotocol.c * libgimp/gimpquerybox.[ch] * libgimp/gimpsizeentry.[ch] * libgimp/gimptypes.h * libgimp/gimpui.h * libgimp/gimpunit.h * libgimp/gimpunitmenu.[ch] * libgimp/gimpwidgets.[ch]: changed accordingly. * plug-ins/FractalExplorer/Dialogs.c * plug-ins/gdyntext/message_window.c * plug-ins/imagemap/imap_default_dialog.c * plug-ins/imagemap/imap_file.c: these files used to include "libgimp/gimpui.h" without including "libgimp/gimp.h". This is no longer possible because the libgimpui headers don't inlcude "libgimp/gimpunit.h" any more.
2000-12-29 23:22:01 +08:00
*/
#include "config.h"
1997-11-25 06:05:25 +08:00
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
1997-11-25 06:05:25 +08:00
#include <unistd.h>
#endif
removed from CVS, they are generated. 2001-12-07 Sven Neumann <sven@gimp.org> * app/core/gimpmarshal.[ch]: removed from CVS, they are generated. * app/base/Makefile.am * app/base/base-enums.h: new file defining enums that are to be registered. Used to build app/base/base-enums.c. * app/base/base-types.h: include base-enums.h. * tools/pdbgen/Makefile.am * tools/pdbgen/enumcode.pl * tools/pdbgen/enums.pl: parse the new base-enums.h file and modified the perl voodoo so it doesn't prefix enums with GIMP_ that are already properly namespaced. * app/core/core-types.h: don't need to chop GIMP from enum. * app/pdb/color_cmds.c * app/pdb/tools_cmds.c * libgimp/gimpenums.h * plug-ins/script-fu/script-fu-constants.c: regenerated. * app/config/gimpconfig-deserialize.[ch] * app/config/gimpconfig-serialize.[ch] * app/config/gimpconfig.[ch]: made GimpConfig an interface including a reasonable default implementation that works on object properties. * app/config/Makefile.am * app/config/gimpbaseconfig.[ch]: new GimpBaseConfig using the GimpConfig interface. Yet only used for testing from app/main.c. * app/main.c: test the new GimpBaseConfig object. * app/gimprc.c * app/base/base-config.h * app/base/*.c * app/core/gimpdatafiles.c * app/core/gimpdrawable-transform.c * app/core/gimppreviewcache.c * app/gui/preferences-dialog.c * app/paint-funcs/paint-funcs.c * app/xcf/xcf-seek.c: need to include glib-object.h since base-config contains registered enums now. Follow name change of InterpolationType to GimpInterpolationType.
2001-12-08 00:10:53 +08:00
#include <glib-object.h>
#include <glib/gstdio.h>
removed from CVS, they are generated. 2001-12-07 Sven Neumann <sven@gimp.org> * app/core/gimpmarshal.[ch]: removed from CVS, they are generated. * app/base/Makefile.am * app/base/base-enums.h: new file defining enums that are to be registered. Used to build app/base/base-enums.c. * app/base/base-types.h: include base-enums.h. * tools/pdbgen/Makefile.am * tools/pdbgen/enumcode.pl * tools/pdbgen/enums.pl: parse the new base-enums.h file and modified the perl voodoo so it doesn't prefix enums with GIMP_ that are already properly namespaced. * app/core/core-types.h: don't need to chop GIMP from enum. * app/pdb/color_cmds.c * app/pdb/tools_cmds.c * libgimp/gimpenums.h * plug-ins/script-fu/script-fu-constants.c: regenerated. * app/config/gimpconfig-deserialize.[ch] * app/config/gimpconfig-serialize.[ch] * app/config/gimpconfig.[ch]: made GimpConfig an interface including a reasonable default implementation that works on object properties. * app/config/Makefile.am * app/config/gimpbaseconfig.[ch]: new GimpBaseConfig using the GimpConfig interface. Yet only used for testing from app/main.c. * app/main.c: test the new GimpBaseConfig object. * app/gimprc.c * app/base/base-config.h * app/base/*.c * app/core/gimpdatafiles.c * app/core/gimpdrawable-transform.c * app/core/gimppreviewcache.c * app/gui/preferences-dialog.c * app/paint-funcs/paint-funcs.c * app/xcf/xcf-seek.c: need to include glib-object.h since base-config contains registered enums now. Follow name change of InterpolationType to GimpInterpolationType.
2001-12-08 00:10:53 +08:00
#include "libgimpbase/gimpbase.h"
#include "libgimpconfig/gimpconfig.h"
#ifdef G_OS_WIN32
#include <windows.h>
#include "libgimpbase/gimpwin32-io.h"
#endif
new directory app/base/ 2001-05-15 Michael Natterer <mitch@gimp.org> * configure.in: new directory app/base/ * app/Makefile.am * app/boundary.[ch] * app/brush_scale.[ch] * app/gimpchecks.h * app/gimplut.[ch] * app/pixel_processor.[ch] * app/pixel_region.[ch] * app/pixel_surround.[ch] * app/temp_buf.[ch] * app/tile.[ch] * app/tile_cache.[ch] * app/tile_manager.[ch] * app/tile_manager_pvt.h * app/tile_pvt.h * app/tile_swap.[ch]: moved to base/ * app/base/Makefile.am * app/base/base-types.h * app/base/*: new directory for the sub-object pixel maniplation and storage stuff. Does not include Gtk+ or anything outside base/. Did some cleanup in all files. * app/appenums.h * app/apptypes.h * app/core/gimpimage.h: removed types which are now in base/base-types.h. * app/base/base-config.[ch] * app/gimprc.[ch]: put the config variables for base/ to their own file so base/ doesn not have to include gimprc.h (does not yet work, i.e. the variables are un-configurable right now) * app/main.c: set a log handler for "Gimp-Base". * app/paint-funcs/Makefile.am * app/paint-funcs/paint-funcs.[ch]: removed the color hash which maps RGB to color indices because it's a totally standalone system which has nothing to do with the paint-funcs and introduced a GimpImage dependency. paint-funcs/ should be considered on the same sub-object (glib-only) level as base/, only in a different directory. * app/core/Makefile.am * app/core/gimpimage-colorhash.[ch]: put the color hash here. * app/gimage.c: don't invalidate the color hash here... * app/core/gimpimage.c: ... but in the colormap_changed() default inplementation. Initialize the hash in class_init(). * tools/pdbgen/Makefile.am: scan app/base/base-types.h for enums. * tools/pdbgen/enums.pl: regenerated. * app/[lots] * app/core/[of] * app/gui/[files] * app/pdb/[all] * app/tools/[over] * app/widgets/[the] * tools/pdbgen/pdb/[place]: changed #includes accordingly. And use base_config->value instead of the stuff from gimprc.h.
2001-05-15 19:25:25 +08:00
#include "base-types.h"
1997-11-25 06:05:25 +08:00
#ifndef _O_BINARY
#define _O_BINARY 0
#endif
#ifndef _O_TEMPORARY
#define _O_TEMPORARY 0
#endif
#include "base-utils.h"
#include "tile.h"
#include "tile-rowhints.h"
new directory app/base/ 2001-05-15 Michael Natterer <mitch@gimp.org> * configure.in: new directory app/base/ * app/Makefile.am * app/boundary.[ch] * app/brush_scale.[ch] * app/gimpchecks.h * app/gimplut.[ch] * app/pixel_processor.[ch] * app/pixel_region.[ch] * app/pixel_surround.[ch] * app/temp_buf.[ch] * app/tile.[ch] * app/tile_cache.[ch] * app/tile_manager.[ch] * app/tile_manager_pvt.h * app/tile_pvt.h * app/tile_swap.[ch]: moved to base/ * app/base/Makefile.am * app/base/base-types.h * app/base/*: new directory for the sub-object pixel maniplation and storage stuff. Does not include Gtk+ or anything outside base/. Did some cleanup in all files. * app/appenums.h * app/apptypes.h * app/core/gimpimage.h: removed types which are now in base/base-types.h. * app/base/base-config.[ch] * app/gimprc.[ch]: put the config variables for base/ to their own file so base/ doesn not have to include gimprc.h (does not yet work, i.e. the variables are un-configurable right now) * app/main.c: set a log handler for "Gimp-Base". * app/paint-funcs/Makefile.am * app/paint-funcs/paint-funcs.[ch]: removed the color hash which maps RGB to color indices because it's a totally standalone system which has nothing to do with the paint-funcs and introduced a GimpImage dependency. paint-funcs/ should be considered on the same sub-object (glib-only) level as base/, only in a different directory. * app/core/Makefile.am * app/core/gimpimage-colorhash.[ch]: put the color hash here. * app/gimage.c: don't invalidate the color hash here... * app/core/gimpimage.c: ... but in the colormap_changed() default inplementation. Initialize the hash in class_init(). * tools/pdbgen/Makefile.am: scan app/base/base-types.h for enums. * tools/pdbgen/enums.pl: regenerated. * app/[lots] * app/core/[of] * app/gui/[files] * app/pdb/[all] * app/tools/[over] * app/widgets/[the] * tools/pdbgen/pdb/[place]: changed #includes accordingly. And use base_config->value instead of the stuff from gimprc.h.
2001-05-15 19:25:25 +08:00
#include "tile-swap.h"
#include "tile-private.h"
#include "tile-cache.h"
#include "gimp-intl.h"
1997-11-25 06:05:25 +08:00
typedef enum
{
SWAP_IN = 1,
SWAP_OUT,
SWAP_DELETE
} SwapCommand;
typedef gint (* SwapFunc) (gint fd,
Tile *tile,
SwapCommand cmd);
app/Makefile.am app/channel_pvt.h app/drawable_pvt.h app/gdisplayF.h 2000-12-29 Michael Natterer <mitch@gimp.org> * app/Makefile.am * app/channel_pvt.h * app/drawable_pvt.h * app/gdisplayF.h * app/gimpdrawableP.h * app/gimpimageP.h * app/layer_pvt.h * app/toolsF.h: removed these files. * app/apptypes.h * tools/pdbgen/enums.pl: added tons of opaque typedefs and enums. * tools/pdbgen/pdb/brush_select.pdb * tools/pdbgen/pdb/brushes.pdb * tools/pdbgen/pdb/channel.pdb * tools/pdbgen/pdb/color.pdb * tools/pdbgen/pdb/convert.pdb * tools/pdbgen/pdb/display.pdb * tools/pdbgen/pdb/drawable.pdb * tools/pdbgen/pdb/fileops.pdb * tools/pdbgen/pdb/gradient_select.pdb * tools/pdbgen/pdb/gradients.pdb * tools/pdbgen/pdb/help.pdb * tools/pdbgen/pdb/image.pdb * tools/pdbgen/pdb/layer.pdb * tools/pdbgen/pdb/pattern_select.pdb * tools/pdbgen/pdb/patterns.pdb * tools/pdbgen/pdb/selection.pdb * tools/pdbgen/pdb/tools.pdb * app/*: chainsaw #include cleanup: - Never (never!!) include stuff in header files except where we need access to structures' contents (like derived objects). - Added prototypes and proper formating in many files. - The #include order in *all* *.c files is as follows: #include "config.h" #include <system stuff> #include <gtk/gtk.h> #include "apptypes.h" #include "gimp stuff" #include "libgimp stuff" #include "libgimp/gimpintl.h" By following this scheme we can easily see a file's dependencies from it's #include's and can grep for the inclusion to find out where a file is used. * tools/pdbgen/app.pl: changed to follow the include scheme above. * libgimp/Makefile.am * libgimp/gimpuitypes.h: new file, included from libgimp/gimpui.h and from app/apptypes.h. * libgimp/gimpcolorbutton.[ch] * libgimp/gimpdialog.[ch] * libgimp/gimphelpui.[ch] * libgimp/gimpparasite.[ch] * libgimp/gimppatheditor.[ch] * libgimp/gimpprotocol.c * libgimp/gimpquerybox.[ch] * libgimp/gimpsizeentry.[ch] * libgimp/gimptypes.h * libgimp/gimpui.h * libgimp/gimpunit.h * libgimp/gimpunitmenu.[ch] * libgimp/gimpwidgets.[ch]: changed accordingly. * plug-ins/FractalExplorer/Dialogs.c * plug-ins/gdyntext/message_window.c * plug-ins/imagemap/imap_default_dialog.c * plug-ins/imagemap/imap_file.c: these files used to include "libgimp/gimpui.h" without including "libgimp/gimp.h". This is no longer possible because the libgimpui headers don't inlcude "libgimp/gimpunit.h" any more.
2000-12-29 23:22:01 +08:00
#define MAX_OPEN_SWAP_FILES 16
1997-11-25 06:05:25 +08:00
typedef struct _SwapFile SwapFile;
typedef struct _SwapFileGap SwapFileGap;
1997-11-25 06:05:25 +08:00
struct _SwapFile
1997-11-25 06:05:25 +08:00
{
gchar *filename;
gint fd;
GList *gaps;
gint64 swap_file_end;
gint64 cur_position;
1997-11-25 06:05:25 +08:00
};
struct _SwapFileGap
1997-11-25 06:05:25 +08:00
{
gint64 start;
gint64 end;
1997-11-25 06:05:25 +08:00
};
static void tile_swap_command (Tile *tile,
gint command);
static void tile_swap_default_in (SwapFile *swap_file,
Tile *tile);
static void tile_swap_default_out (SwapFile *swap_file,
Tile *tile);
static void tile_swap_default_delete (SwapFile *swap_file,
Tile *tile);
1997-11-25 06:05:25 +08:00
static gint64 tile_swap_find_offset (SwapFile *swap_file,
gint64 bytes);
static void tile_swap_open (SwapFile *swap_file);
static void tile_swap_resize (SwapFile *swap_file,
gint64 new_size);
static SwapFileGap * tile_swap_gap_new (gint64 start,
gint64 end);
static void tile_swap_gap_destroy (SwapFileGap *gap);
1997-11-25 06:05:25 +08:00
static SwapFile * gimp_swap_file = NULL;
static const gint64 swap_file_grow = 1024 * TILE_WIDTH * TILE_HEIGHT * 4;
static gboolean seek_err_msg = TRUE;
static gboolean read_err_msg = TRUE;
static gboolean write_err_msg = TRUE;
#ifdef TILE_PROFILING
static gulong tile_total_seek = 0;
/* how many tiles were swapped out under cache pressure but never
swapped back in? This does not count idle swapped tiles, as those
do not contribute to any perceived load or latency */
static gulong tile_total_wasted_swapout = 0;
/* total tile flushes under cache pressure */
gulong tile_total_zorched = 0;
gulong tile_total_zorched_swapout = 0;
static gulong tile_total_zorched_swapin = 0;
/* total tiles swapped out to swap file (not total calls to swap out;
this only counts actual flushes to disk) */
static gulong tile_total_swapout = 0;
static gulong tile_unique_swapout = 0;
gulong tile_idle_swapout = 0;
/* total tiles swapped in from swap file (not total calls to swap in;
this only counts actual tile reads from disk) */
static gulong tile_total_swapin = 0;
static gulong tile_unique_swapin = 0;
/* total dead time spent waiting to read or write */
static glong tile_total_swapwait_sec = 0;
static glong tile_total_swapwait_usec = 0;
/* total time spent in tile cache due to cache pressure */
glong tile_total_interactive_sec = 0;
glong tile_total_interactive_usec = 0;
#endif
#ifdef G_OS_WIN32
#define LARGE_SEEK(f, o, w) _lseeki64 (f, o, w)
#define LARGE_TRUNCATE(f, s) win32_large_truncate (f, s)
static gint
win32_large_truncate (gint fd,
gint64 size)
{
if (LARGE_SEEK (fd, size, SEEK_SET) == size &&
SetEndOfFile ((HANDLE) _get_osfhandle (fd)))
return 0;
else
return -1;
}
#else
#define LARGE_SEEK(f, o, t) lseek (f, o, t)
#define LARGE_TRUNCATE(f, s) ftruncate (f, s)
#endif
#ifdef GIMP_UNSTABLE
1997-11-25 06:05:25 +08:00
static void
tile_swap_print_gaps (SwapFile *swap_file)
1997-11-25 06:05:25 +08:00
{
GList *list;
1997-11-25 06:05:25 +08:00
for (list = swap_file->gaps; list; list = list->next)
1997-11-25 06:05:25 +08:00
{
SwapFileGap *gap = list->data;
1997-11-25 06:05:25 +08:00
g_print (" %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT"\n",
gap->start, gap->end);
1997-11-25 06:05:25 +08:00
}
}
#endif
1997-11-25 06:05:25 +08:00
void
tile_swap_init (const gchar *path)
{
gchar *basename;
gchar *dirname;
g_return_if_fail (gimp_swap_file == NULL);
g_return_if_fail (path != NULL);
dirname = gimp_config_path_expand (path, TRUE, NULL);
basename = g_strdup_printf ("gimpswap.%lu", (unsigned long) get_pid ());
/* create the swap directory if it doesn't exist */
if (! g_file_test (dirname, G_FILE_TEST_EXISTS))
g_mkdir_with_parents (dirname,
S_IRUSR | S_IXUSR | S_IWUSR |
S_IRGRP | S_IXGRP |
S_IROTH | S_IXOTH);
gimp_swap_file = g_slice_new (SwapFile);
gimp_swap_file->filename = g_build_filename (dirname, basename, NULL);
gimp_swap_file->gaps = NULL;
gimp_swap_file->swap_file_end = 0;
gimp_swap_file->cur_position = 0;
gimp_swap_file->fd = -1;
g_free (basename);
g_free (dirname);
}
1997-11-25 06:05:25 +08:00
void
tile_swap_exit (void)
1997-11-25 06:05:25 +08:00
{
#ifdef TILE_PROFILING
extern int tile_exist_peak;
g_printerr ("\n\nPeak Tile usage: %d Tile structs\n\n",
tile_exist_peak);
g_printerr ("Total tiles swapped out to disk: %lu\n",tile_total_swapout);
g_printerr ("Unique tiles swapped out to disk: %lu\n",tile_unique_swapout);
g_printerr ("Total tiles swapped in from disk: %lu\n",tile_total_swapin);
g_printerr ("Unique tiles swapped in from disk: %lu\n",tile_unique_swapin);
g_printerr ("Tiles swapped out by idle swapper: %lu\n",tile_idle_swapout);
g_printerr ("Total seeks during swapping: %lu\n",tile_total_seek);
g_printerr ("Total time spent in swap: %f seconds\n\n",
tile_total_swapwait_sec+.000001*tile_total_swapwait_usec);
g_printerr ("Total zorched tiles: %lu\n",tile_total_zorched);
g_printerr ("Total zorched tiles swapped out: %lu\n",tile_total_zorched_swapout);
g_printerr ("Total zorched tiles swapped back in: %lu\n",tile_total_zorched_swapin);
g_printerr ("Total zorched tiles wasted after swapping out: %lu\n",tile_total_wasted_swapout);
g_printerr ("Total interactive swap/cache delay: %f seconds\n\n",
tile_total_interactive_sec+.000001*tile_total_interactive_usec);
#endif
if (tile_global_refcount () != 0)
g_warning ("tile ref count balance: %d\n", tile_global_refcount ());
1997-11-25 06:05:25 +08:00
g_return_if_fail (gimp_swap_file != NULL);
1997-11-25 06:05:25 +08:00
#ifdef GIMP_UNSTABLE
if (gimp_swap_file->swap_file_end != 0)
1997-11-25 06:05:25 +08:00
{
g_warning ("swap file not empty: \"%s\"\n",
gimp_filename_to_utf8 (gimp_swap_file->filename));
tile_swap_print_gaps (gimp_swap_file);
1997-11-25 06:05:25 +08:00
}
#endif
1997-11-25 06:05:25 +08:00
#ifdef G_OS_WIN32
/* should close before unlink */
if (gimp_swap_file->fd > 0)
{
close (gimp_swap_file->fd);
gimp_swap_file->fd = -1;
}
#endif
g_unlink (gimp_swap_file->filename);
1997-11-25 06:05:25 +08:00
g_free (gimp_swap_file->filename);
g_slice_free (SwapFile, gimp_swap_file);
1997-11-25 06:05:25 +08:00
gimp_swap_file = NULL;
1997-11-25 06:05:25 +08:00
}
/* check if we can open a swap file */
gboolean
tile_swap_test (void)
1997-11-25 06:05:25 +08:00
{
g_return_val_if_fail (gimp_swap_file != NULL, FALSE);
1997-11-25 06:05:25 +08:00
/* make sure this duplicates the open() call from tile_swap_open() */
gimp_swap_file->fd = g_open (gimp_swap_file->filename,
O_CREAT | O_RDWR | _O_BINARY | _O_TEMPORARY,
S_IRUSR | S_IWUSR);
1997-11-25 06:05:25 +08:00
if (gimp_swap_file->fd != -1)
{
close (gimp_swap_file->fd);
gimp_swap_file->fd = -1;
g_unlink (gimp_swap_file->filename);
1997-11-25 06:05:25 +08:00
return TRUE;
}
1997-11-25 06:05:25 +08:00
return FALSE;
1997-11-25 06:05:25 +08:00
}
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);
}
static void
tile_swap_command (Tile *tile,
gint command)
1997-11-25 06:05:25 +08:00
{
if (gimp_swap_file->fd == -1)
1997-11-25 06:05:25 +08:00
{
tile_swap_open (gimp_swap_file);
1997-11-25 06:05:25 +08:00
if (G_UNLIKELY (gimp_swap_file->fd == -1))
return;
1997-11-25 06:05:25 +08:00
}
switch (command)
1997-11-25 06:05:25 +08:00
{
case SWAP_IN:
tile_swap_default_in (gimp_swap_file, tile);
break;
case SWAP_OUT:
tile_swap_default_out (gimp_swap_file, tile);
break;
case SWAP_DELETE:
tile_swap_default_delete (gimp_swap_file, tile);
break;
1997-11-25 06:05:25 +08:00
}
}
/* 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 void
tile_swap_default_in (SwapFile *swap_file,
Tile *tile)
1997-11-25 06:05:25 +08:00
{
gint nleft;
gint64 offset;
#ifdef TILE_PROFILING
GTimeVal now;
GTimeVal later;
#endif
1997-11-25 06:05:25 +08:00
if (tile->data)
return;
tile_cache_suspend_idle_swapper();
#ifdef TILE_PROFILING
g_get_current_time(&now);
tile_total_swapin++;
if (tile->zorched)
tile_total_zorched_swapin++;
if (!tile->inonce)
tile_unique_swapin++;
tile->inonce = TRUE;
#endif
if (swap_file->cur_position != tile->swap_offset)
1997-11-25 06:05:25 +08:00
{
swap_file->cur_position = tile->swap_offset;
1997-11-25 06:05:25 +08:00
#ifdef TILE_PROFILING
tile_total_seek++;
#endif
offset = LARGE_SEEK (swap_file->fd, tile->swap_offset, SEEK_SET);
1997-11-25 06:05:25 +08:00
if (offset == -1)
{
if (seek_err_msg)
g_message ("unable to seek to tile location on disk: %s",
g_strerror (errno));
seek_err_msg = FALSE;
return;
}
1997-11-25 06:05:25 +08:00
}
tile_alloc (tile);
nleft = tile->size;
1997-11-25 06:05:25 +08:00
while (nleft > 0)
{
gint err;
do
{
err = read (swap_file->fd, tile->data + tile->size - nleft, nleft);
}
while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
1997-11-25 06:05:25 +08:00
if (err <= 0)
{
if (read_err_msg)
g_message ("unable to read tile data from disk: "
"%s (%d/%d bytes read)",
g_strerror (errno), err, nleft);
read_err_msg = FALSE;
return;
}
1997-11-25 06:05:25 +08:00
nleft -= err;
}
#ifdef TILE_PROFILING
g_get_current_time(&later);
tile_total_swapwait_usec += later.tv_usec - now.tv_usec;
tile_total_swapwait_sec += later.tv_sec - now.tv_sec;
if (tile_total_swapwait_usec < 0)
{
tile_total_swapwait_usec += 1000000;
tile_total_swapwait_sec--;
}
if (tile_total_swapwait_usec > 1000000)
{
tile_total_swapwait_usec -= 1000000;
tile_total_swapwait_sec++;
}
tile_total_interactive_usec += later.tv_usec - now.tv_usec;
tile_total_interactive_sec += later.tv_sec - now.tv_sec;
if (tile_total_interactive_usec < 0)
{
tile_total_interactive_usec += 1000000;
tile_total_interactive_sec--;
}
if (tile_total_interactive_usec > 1000000)
{
tile_total_interactive_usec -= 1000000;
tile_total_interactive_sec++;
}
tile->zorched = FALSE;
tile->zorchout = FALSE;
#endif
swap_file->cur_position += tile->size;
1997-11-25 06:05:25 +08:00
/* Do not delete the swap from the file */
/* tile_swap_default_delete (swap_file, fd, tile); */
read_err_msg = seek_err_msg = TRUE;
1997-11-25 06:05:25 +08:00
}
static void
tile_swap_default_out (SwapFile *swap_file,
Tile *tile)
1997-11-25 06:05:25 +08:00
{
gint bytes;
gint nleft;
gint64 offset;
gint64 newpos;
#ifdef TILE_PROFILING
GTimeVal now;
GTimeVal later;
g_get_current_time(&now);
tile_total_swapout++;
if (!tile->outonce)
tile_unique_swapout++;
tile->outonce = TRUE;
#endif
1997-11-25 06:05:25 +08:00
bytes = TILE_WIDTH * TILE_HEIGHT * tile->bpp;
/* If there is already a valid swap_offset, use it */
if (tile->swap_offset == -1)
newpos = tile_swap_find_offset (swap_file, bytes);
else
newpos = tile->swap_offset;
1997-11-25 06:05:25 +08:00
if (swap_file->cur_position != newpos)
1997-11-25 06:05:25 +08:00
{
#ifdef TILE_PROFILING
tile_total_seek++;
#endif
offset = LARGE_SEEK (swap_file->fd, newpos, SEEK_SET);
1997-11-25 06:05:25 +08:00
if (offset == -1)
{
if (seek_err_msg)
g_message ("unable to seek to tile location on disk: %s",
g_strerror (errno));
seek_err_msg = FALSE;
return;
}
swap_file->cur_position = newpos;
1997-11-25 06:05:25 +08:00
}
nleft = tile->size;
1997-11-25 06:05:25 +08:00
while (nleft > 0)
{
gint err = write (swap_file->fd, tile->data + tile->size - nleft, nleft);
1997-11-25 06:05:25 +08:00
if (err <= 0)
{
if (write_err_msg)
g_message ("unable to write tile data to disk: "
"%s (%d/%d bytes written)",
g_strerror (errno), err, nleft);
write_err_msg = FALSE;
return;
}
1997-11-25 06:05:25 +08:00
nleft -= err;
}
#ifdef TILE_PROFILING
g_get_current_time(&later);
tile_total_swapwait_usec += later.tv_usec - now.tv_usec;
tile_total_swapwait_sec += later.tv_sec - now.tv_sec;
if (tile_total_swapwait_usec < 0)
{
tile_total_swapwait_usec += 1000000;
tile_total_swapwait_sec--;
}
if (tile_total_swapwait_usec > 1000000)
{
tile_total_swapwait_usec -= 1000000;
tile_total_swapwait_sec++;
}
#endif
swap_file->cur_position += tile->size;
1997-11-25 06:05:25 +08:00
/* 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;
1997-11-25 06:05:25 +08:00
}
static void
tile_swap_default_delete (SwapFile *swap_file,
Tile *tile)
1997-11-25 06:05:25 +08:00
{
SwapFileGap *gap;
SwapFileGap *gap2;
GList *tmp;
GList *tmp2;
gint64 start;
gint64 end;
1997-11-25 06:05:25 +08:00
if (tile->swap_offset == -1)
return;
#ifdef TILE_PROFILING
if (tile->zorchout)
tile_total_wasted_swapout++;
tile->zorched=FALSE;
tile->zorchout=FALSE;
#endif
1997-11-25 06:05:25 +08:00
start = tile->swap_offset;
end = start + TILE_WIDTH * TILE_HEIGHT * tile->bpp;
tile->swap_offset = -1;
tmp = swap_file->gaps;
1997-11-25 06:05:25 +08:00
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);
swap_file->gaps =
g_list_remove_link (swap_file->gaps, tmp);
g_list_free (tmp);
}
}
break;
}
1997-11-25 06:05:25 +08:00
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);
swap_file->gaps =
g_list_remove_link (swap_file->gaps, tmp);
g_list_free (tmp);
}
}
break;
}
1997-11-25 06:05:25 +08:00
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 == swap_file->gaps)
swap_file->gaps = tmp2;
break;
}
1997-11-25 06:05:25 +08:00
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;
}
1997-11-25 06:05:25 +08:00
tmp = tmp->next;
}
if (!swap_file->gaps)
1997-11-25 06:05:25 +08:00
{
gap = tile_swap_gap_new (start, end);
swap_file->gaps = g_list_append (swap_file->gaps, gap);
1997-11-25 06:05:25 +08:00
}
tmp = g_list_last (swap_file->gaps);
1997-11-25 06:05:25 +08:00
gap = tmp->data;
if (gap->end == swap_file->swap_file_end)
1997-11-25 06:05:25 +08:00
{
tile_swap_resize (swap_file, gap->start);
1997-11-25 06:05:25 +08:00
tile_swap_gap_destroy (gap);
swap_file->gaps = g_list_remove_link (swap_file->gaps, tmp);
1997-11-25 06:05:25 +08:00
g_list_free (tmp);
}
}
static void
tile_swap_open (SwapFile *swap_file)
{
g_return_if_fail (swap_file->fd == -1);
/* duplicate this open() call in tile_swap_test() */
swap_file->fd = g_open (swap_file->filename,
O_CREAT | O_RDWR | _O_BINARY | _O_TEMPORARY,
S_IRUSR | S_IWUSR);
if (swap_file->fd == -1)
g_message (_("Unable to open swap file. GIMP has run out of memory "
"and cannot use the swap file. Some parts of your images "
"may be corrupted. Try to save your work using different "
"filenames, restart GIMP and check the location of the "
"swap directory in your Preferences."));
}
static void
tile_swap_resize (SwapFile *swap_file,
gint64 new_size)
1997-11-25 06:05:25 +08:00
{
if (swap_file->swap_file_end > new_size)
{
if (LARGE_TRUNCATE (swap_file->fd, new_size) != 0)
{
g_message (_("Failed to resize swap file: %s"), g_strerror (errno));
return;
}
}
swap_file->swap_file_end = new_size;
1997-11-25 06:05:25 +08:00
}
static gint64
tile_swap_find_offset (SwapFile *swap_file,
gint64 bytes)
1997-11-25 06:05:25 +08:00
{
SwapFileGap *gap;
GList *tmp;
gint64 offset;
1997-11-25 06:05:25 +08:00
tmp = swap_file->gaps;
1997-11-25 06:05:25 +08:00
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);
swap_file->gaps = g_list_remove_link (swap_file->gaps, tmp);
g_list_free (tmp);
}
return offset;
}
1997-11-25 06:05:25 +08:00
tmp = tmp->next;
}
offset = swap_file->swap_file_end;
1997-11-25 06:05:25 +08:00
tile_swap_resize (swap_file, swap_file->swap_file_end + swap_file_grow);
1997-11-25 06:05:25 +08:00
if ((offset + bytes) < (swap_file->swap_file_end))
1997-11-25 06:05:25 +08:00
{
gap = tile_swap_gap_new (offset + bytes, swap_file->swap_file_end);
swap_file->gaps = g_list_append (swap_file->gaps, gap);
1997-11-25 06:05:25 +08:00
}
return offset;
}
static SwapFileGap *
tile_swap_gap_new (gint64 start,
gint64 end)
1997-11-25 06:05:25 +08:00
{
SwapFileGap *gap = g_slice_new (SwapFileGap);
1997-11-25 06:05:25 +08:00
gap->start = start;
gap->end = end;
1997-11-25 06:05:25 +08:00
return gap;
}
static void
tile_swap_gap_destroy (SwapFileGap *gap)
1997-11-25 06:05:25 +08:00
{
g_slice_free (SwapFileGap, gap);
1997-11-25 06:05:25 +08:00
}