1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include <stdlib.h>
3 #include <string.h>
4 #include <inttypes.h>
5 #include <assert.h>
6 
7 #ifndef NDEBUG
8 #include <signal.h>
9 #endif
10 
11 #include "cache.h"
12 
13 #ifndef NDEBUG
14 const uint64_t redzone_pattern = 0xdeadbeefcafedeed;
15 int cache_error = 0;
16 #endif
17 
cache_create(const char * name,size_t bufsize,size_t align)18 cache_t* cache_create(const char *name, size_t bufsize, size_t align) {
19     cache_t* ret = calloc(1, sizeof(cache_t));
20     char* nm = strdup(name);
21     if (ret == NULL || nm == NULL ||
22         pthread_mutex_init(&ret->mutex, NULL) == -1) {
23         free(ret);
24         free(nm);
25         return NULL;
26     }
27 
28     ret->name = nm;
29     STAILQ_INIT(&ret->head);
30 
31 #ifndef NDEBUG
32     ret->bufsize = bufsize + 2 * sizeof(redzone_pattern);
33 #else
34     ret->bufsize = bufsize;
35 #endif
36     assert(ret->bufsize >= sizeof(struct cache_free_s));
37 
38     return ret;
39 }
40 
cache_set_limit(cache_t * cache,int limit)41 void cache_set_limit(cache_t *cache, int limit) {
42     pthread_mutex_lock(&cache->mutex);
43     cache->limit = limit;
44     pthread_mutex_unlock(&cache->mutex);
45 }
46 
get_object(void * ptr)47 static inline void* get_object(void *ptr) {
48 #ifndef NDEBUG
49     uint64_t *pre = ptr;
50     return pre + 1;
51 #else
52     return ptr;
53 #endif
54 }
55 
cache_destroy(cache_t * cache)56 void cache_destroy(cache_t *cache) {
57     while (!STAILQ_EMPTY(&cache->head)) {
58         struct cache_free_s *o = STAILQ_FIRST(&cache->head);
59         STAILQ_REMOVE_HEAD(&cache->head, c_next);
60         free(o);
61     }
62     free(cache->name);
63     pthread_mutex_destroy(&cache->mutex);
64     free(cache);
65 }
66 
cache_alloc(cache_t * cache)67 void* cache_alloc(cache_t *cache) {
68     void *ret;
69     pthread_mutex_lock(&cache->mutex);
70     ret = do_cache_alloc(cache);
71     pthread_mutex_unlock(&cache->mutex);
72     return ret;
73 }
74 
do_cache_alloc(cache_t * cache)75 void* do_cache_alloc(cache_t *cache) {
76     void *ret;
77     void *object;
78     if (cache->freecurr > 0) {
79         ret = STAILQ_FIRST(&cache->head);
80         STAILQ_REMOVE_HEAD(&cache->head, c_next);
81         object = get_object(ret);
82         cache->freecurr--;
83     } else if (cache->limit == 0 || cache->total < cache->limit) {
84         object = ret = malloc(cache->bufsize);
85         if (ret != NULL) {
86             object = get_object(ret);
87 
88             cache->total++;
89         }
90     } else {
91         object = NULL;
92     }
93 
94 #ifndef NDEBUG
95     if (object != NULL) {
96         /* add a simple form of buffer-check */
97         uint64_t *pre = ret;
98         *pre = redzone_pattern;
99         ret = pre+1;
100         memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)),
101                &redzone_pattern, sizeof(redzone_pattern));
102     }
103 #endif
104 
105     return object;
106 }
107 
cache_free(cache_t * cache,void * ptr)108 void cache_free(cache_t *cache, void *ptr) {
109     pthread_mutex_lock(&cache->mutex);
110     do_cache_free(cache, ptr);
111     pthread_mutex_unlock(&cache->mutex);
112 }
113 
do_cache_free(cache_t * cache,void * ptr)114 void do_cache_free(cache_t *cache, void *ptr) {
115 #ifndef NDEBUG
116     /* validate redzone... */
117     if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)),
118                &redzone_pattern, sizeof(redzone_pattern)) != 0) {
119         raise(SIGABRT);
120         cache_error = 1;
121         return;
122     }
123     uint64_t *pre = ptr;
124     --pre;
125     if (*pre != redzone_pattern) {
126         raise(SIGABRT);
127         cache_error = -1;
128         return;
129     }
130     ptr = pre;
131 #endif
132     if (cache->limit != 0 && cache->limit < cache->total) {
133         free(ptr);
134         cache->total--;
135     } else {
136         STAILQ_INSERT_TAIL(&cache->head, (struct cache_free_s *)ptr, c_next);
137         cache->freecurr++;
138     }
139 }
140 
141