Mercurial > hg > forks > geeqie
changeset 2236:b7e253153aa4
Add "lock" functionality to keep FileDatas in memory
Adds two primitives to keep a FileData in memory even after its refcount
drops to zero. Intended to be used in situations when an entire group of
FileDatas _should_ stay in memory as an optimization, even if the code
would continue to function properly even if the FileData were freed.
author | Omari Stephens <xsdg@xsdg.org> |
---|---|
date | Mon, 12 Nov 2012 06:03:02 +0000 |
parents | 4617e1d83e9b |
children | db10022a79f3 |
files | src/filedata.c src/filedata.h src/typedefs.h |
diffstat | 3 files changed, 99 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/src/filedata.c Sun Oct 28 12:07:41 2012 +0100 +++ b/src/filedata.c Mon Nov 12 06:03:02 2012 +0000 @@ -549,6 +549,57 @@ g_free(fd); } +/** + * \brief Checks if the FileData is referenced + * + * Checks the refcount and whether the FileData is locked. + */ +static gboolean file_data_check_has_ref(FileData *fd) +{ + return fd->ref > 0 || fd->locked; +} + +/** + * \brief Consider freeing a FileData. + * + * This function will free a FileData and its children provided that neither its parent nor it has + * a positive refcount, and provided that neither is locked. + */ +static void file_data_consider_free(FileData *fd) +{ + GList *work; + FileData *parent = fd->parent ? fd->parent : fd; + + g_assert(fd->magick == FD_MAGICK); + if (file_data_check_has_ref(fd)) return; + if (file_data_check_has_ref(parent)) return; + + work = parent->sidecar_files; + while (work) + { + FileData *sfd = work->data; + if (file_data_check_has_ref(sfd)) return; + work = work->next; + } + + /* Neither the parent nor the siblings are referenced, so we can free everything */ + DEBUG_2("file_data_consider_free: deleting '%s', parent '%s'", + fd->path, fd->parent ? parent->path : "-"); + + work = parent->sidecar_files; + while (work) + { + FileData *sfd = work->data; + file_data_free(sfd); + work = work->next; + } + + g_list_free(parent->sidecar_files); + parent->sidecar_files = NULL; + + file_data_free(parent); +} + #ifdef DEBUG_FILEDATA void file_data_unref_debug(const gchar *file, gint line, FileData *fd) #else @@ -566,45 +617,54 @@ fd->ref--; #ifdef DEBUG_FILEDATA - DEBUG_2("file_data_unref fd=%p (%d): '%s' @ %s:%d", fd, fd->ref, fd->path, file, line); + DEBUG_2("file_data_unref fd=%p (%d:%d): '%s' @ %s:%d", fd, fd->ref, fd->locked, fd->path, + file, line); #else - DEBUG_2("file_data_unref fd=%p (%d): '%s'", fd, fd->ref, fd->path); + DEBUG_2("file_data_unref fd=%p (%d:%d): '%s'", fd, fd->ref, fd->locked, fd->path); #endif - if (fd->ref == 0) - { - GList *work; - FileData *parent = fd->parent ? fd->parent : fd; - - if (parent->ref > 0) return; - - work = parent->sidecar_files; - while (work) - { - FileData *sfd = work->data; - if (sfd->ref > 0) return; - work = work->next; - } - - /* none of parent/children is referenced, we can free everything */ - - DEBUG_2("file_data_unref: deleting '%s', parent '%s'", fd->path, fd->parent ? parent->path : "-"); - - work = parent->sidecar_files; - while (work) - { - FileData *sfd = work->data; - file_data_free(sfd); - work = work->next; - } - - g_list_free(parent->sidecar_files); - parent->sidecar_files = NULL; - - file_data_free(parent); - } + + // Free FileData if it's no longer ref'd + file_data_consider_free(fd); } - +/** + * \brief Lock the FileData in memory. + * + * This allows the caller to prevent a FileData from being freed, even + * after its refcount is zero. + * <p /> + * This differs from file_data_ref in that the behavior is reentrant -- after N calls to + * file_data_lock, a single call to file_data_unlock will unlock the FileData. + */ +void file_data_lock(FileData *fd) +{ + if (fd == NULL) return; + if (fd->magick != FD_MAGICK) DEBUG_0("fd magick mismatch fd=%p", fd); + + g_assert(fd->magick == FD_MAGICK); + fd->locked = TRUE; + + DEBUG_2("file_data_ref fd=%p (%d): '%s'", fd, fd->ref, fd->path); +} + +/** + * \brief Reset the maintain-FileData-in-memory lock + * + * This again allows the FileData to be freed when its refcount drops to zero. Automatically frees + * the FileData if its refcount is already zero (which will happen if the lock is the only thing + * keeping it from being freed. + */ +void file_data_unlock(FileData *fd) +{ + if (fd == NULL) return; + if (fd->magick != FD_MAGICK) DEBUG_0("fd magick mismatch fd=%p", fd); + + g_assert(fd->magick == FD_MAGICK); + fd->locked = FALSE; + + // Free FileData if it's no longer ref'd + file_data_consider_free(fd); +} /* *-----------------------------------------------------------------------------
--- a/src/filedata.h Sun Oct 28 12:07:41 2012 +0100 +++ b/src/filedata.h Mon Nov 12 06:03:02 2012 +0000 @@ -43,6 +43,9 @@ void file_data_unref(FileData *fd); #endif +void file_data_lock(FileData *fd); +void file_data_unlock(FileData *fd); + gboolean file_data_check_changed_files(FileData *fd); void file_data_increment_version(FileData *fd);