X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Futil.c;h=d292634731b662827dc8c0dfbeec0f566ab5a32a;hb=8ab9f6acce5bbc6e56d2f3fa1833be06faf46770;hp=85f6a70ed87abc0801f3fdc4e0acceb003ccd6fd;hpb=03476a3d39444ff2a09174e945ab645508c2224c;p=bluesky.git diff --git a/bluesky/util.c b/bluesky/util.c index 85f6a70..d292634 100644 --- a/bluesky/util.c +++ b/bluesky/util.c @@ -10,11 +10,23 @@ #include #include #include +#include -#include "bluesky.h" +#include "bluesky-private.h" /* Miscellaneous useful functions that don't really fit anywhere else. */ +bluesky_time_hires bluesky_now_hires() +{ + struct timespec time; + + if (clock_gettime(CLOCK_REALTIME, &time) != 0) { + perror("clock_gettime"); + return 0; + } + + return (int64_t)(time.tv_sec) * 1000000000 + time.tv_nsec; +} /* Convert a UTF-8 string to lowercase. This can be used to implement * case-insensitive lookups and comparisons, by normalizing all values to @@ -24,3 +36,186 @@ gchar *bluesky_lowercase(const gchar *s) /* TODO: Unicode handling; for now just do ASCII. */ return g_ascii_strdown(s, -1); } + +gboolean bluesky_inode_is_ready(BlueSkyInode *inode) +{ + if (inode == NULL) + return FALSE; + + g_mutex_lock(inode->lock); + gboolean valid = (inode->type != BLUESKY_PENDING + && inode->type != BLUESKY_INVALID); + + g_mutex_unlock(inode->lock); + + return valid; +} + +/**** Reference-counted strings. ****/ + +/* Create and return a new reference-counted string. The reference count is + * initially one. The newly-returned string takes ownership of the memory + * pointed at by data, and will call g_free on it when the reference count + * drops to zero. */ +BlueSkyRCStr *bluesky_string_new(gpointer data, gsize len) +{ + BlueSkyRCStr *string = g_new(BlueSkyRCStr, 1); + string->mmap = NULL; + string->data = data; + string->len = len; + g_atomic_int_set(&string->refcount, 1); + return string; +} + +/* Create a new BlueSkyRCStr from a GString. The GString is destroyed. */ +BlueSkyRCStr *bluesky_string_new_from_gstring(GString *s) +{ + gsize len = s->len; + return bluesky_string_new(g_string_free(s, FALSE), len); +} + +/* Create a new BlueSkyRCStr from a memory-mapped buffer. */ +BlueSkyRCStr *bluesky_string_new_from_mmap(BlueSkyCacheFile *mmap, + int offset, gsize len) +{ + g_assert(offset + len <= mmap->len); + + BlueSkyRCStr *string = g_new(BlueSkyRCStr, 1); + string->mmap = mmap; + g_atomic_int_inc(&mmap->mapcount); + string->data = (char *)mmap->addr + offset; + string->len = len; + g_atomic_int_set(&string->refcount, 1); + return string; +} + +void bluesky_string_ref(BlueSkyRCStr *string) +{ + if (string == NULL) + return; + + g_atomic_int_inc(&string->refcount); +} + +void bluesky_string_unref(BlueSkyRCStr *string) +{ + if (string == NULL) + return; + + if (g_atomic_int_dec_and_test(&string->refcount)) { + if (string->mmap == NULL) { + g_free(string->data); + } else { + bluesky_mmap_unref(string->mmap); + } + g_free(string); + } +} + +/* Duplicate and return a new reference-counted string, containing a copy of + * the original data, with a reference count of 1. As an optimization, if the + * passed-in string already has a reference count of 1, the original is + * returned. Can be used to make a mutable copy of a shared string. For this + * to truly be safe, it is probably needed that there be some type of lock + * protecting access to the string. */ +BlueSkyRCStr *bluesky_string_dup(BlueSkyRCStr *string) +{ + if (string == NULL) + return NULL; + + if (string->mmap != NULL) { + BlueSkyRCStr *s; + s = bluesky_string_new(g_memdup(string->data, string->len), + string->len); + bluesky_string_unref(string); + return s; + } + + if (g_atomic_int_dec_and_test(&string->refcount)) { + /* There are no other shared copies, so return this one. */ + g_atomic_int_inc(&string->refcount); + return string; + } else { + return bluesky_string_new(g_memdup(string->data, string->len), + string->len); + } +} + +/* Resize the data block used by a BlueSkyRCStr. The data pointer might change + * after making this call, so it should not be cached across calls to this + * function. To avoid confusing any other users, the caller probably ought to + * hold the only reference to the string (by calling bluesky_string_dup first + * if needed). */ +void bluesky_string_resize(BlueSkyRCStr *string, gsize len) +{ + g_assert(string->mmap == NULL); + + if (string->len == len) + return; + + g_warn_if_fail(string->refcount == 1); + + string->data = g_realloc(string->data, len); + string->len = len; +} + +/* Cache LRU list management functions. These manage the doubly-linked list of + * inodes sorted by accessed/modified time. The FS lock should be held while + * calling these. + * + * _remove will unlink an inode from the linked list. + * + * _prepend and _append insert an inode at the head or tail of the linked list, + * and return a pointer to the linked list element (which should be stored in + * the inode); the inode should not already be in the list. + * + * _head and _tail simply return the first or last item inode in the list. */ +void bluesky_list_unlink(GList *head, GList *item) +{ + if (item == NULL) + return; + + if (head->prev == item) + head->prev = item->prev; + head->next = g_list_delete_link(head->next, item); +} + +GList *bluesky_list_prepend(GList *head, BlueSkyInode *inode) +{ + head->next = g_list_prepend(head->next, inode); + if (head->prev == NULL) + head->prev = g_list_last(head->next); + return head->next; +} + +GList *bluesky_list_append(GList *head, BlueSkyInode *inode) +{ + if (head->next == NULL) + return bluesky_list_prepend(head, inode); + + g_assert(head->prev != NULL && head->prev->next == NULL); + + GList *link = g_list_alloc(); + link->data = inode; + link->next = NULL; + link->prev = head->prev; + head->prev->next = link; + head->prev = link; + return link; +} + +BlueSkyInode *bluesky_list_head(GList *head) +{ + if (head->next == NULL) + return NULL; + else + return (BlueSkyInode *)head->next->data; +} + +BlueSkyInode *bluesky_list_tail(GList *head) +{ + if (head->prev == NULL) + return NULL; + else + return (BlueSkyInode *)head->prev->data; +}