localmemcache 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/INTERNALS +26 -0
- data/README +18 -58
- data/Rakefile +11 -4
- data/THANKS +1 -0
- data/VERSION +1 -1
- data/configure +0 -0
- data/example/compile.sh +3 -0
- data/example/hello +10 -0
- data/example/hello.bin +0 -0
- data/example/hello.c +28 -0
- data/example/hello.rb +8 -0
- data/src/Makefile.in +5 -4
- data/src/lmc_common.c +43 -0
- data/src/lmc_common.h +26 -0
- data/src/lmc_error.c +9 -3
- data/src/lmc_error.h +12 -2
- data/src/lmc_hashtable.c +163 -35
- data/src/lmc_hashtable.h +14 -6
- data/src/lmc_lock.c +69 -11
- data/src/lmc_lock.h +3 -0
- data/src/lmc_shm.c +25 -8
- data/src/lmc_shm.h +1 -0
- data/src/lmc_valloc.c +211 -59
- data/src/lmc_valloc.h +23 -3
- data/src/localmemcache.c +193 -31
- data/src/localmemcache.h +17 -5
- data/src/ruby-binding/localmemcache.rb +13 -3
- data/src/ruby-binding/rblocalmemcache.c +107 -17
- data/src/tests/alloc +0 -0
- data/src/tests/allocfailure +15 -0
- data/src/tests/allocfailure.rb +20 -0
- data/src/tests/bench +0 -0
- data/src/tests/bench.rb +15 -0
- data/src/tests/bench_keys +11 -0
- data/src/tests/bench_keys.rb +24 -0
- data/src/tests/crash +19 -0
- data/src/tests/crash.rb +41 -0
- data/src/tests/lmc +0 -0
- data/src/tests/lmc.rb +22 -47
- data/src/tests/parallelwrite +15 -0
- data/src/tests/parallelwrite.rb +27 -0
- data/src/tests/runtest.sh +0 -0
- data/src/tests/shm +0 -0
- data/src/tests/ttalloc +0 -0
- data/src/tests/ttlmc +0 -0
- data/src/tests/ttlmc.rb +18 -2
- metadata +22 -4
data/src/lmc_hashtable.h
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
#ifndef _LMC_HASHTABLE_H_INCLUDED_
|
6
6
|
#define _LMC_HASHTABLE_H_INCLUDED_
|
7
7
|
#include "lmc_error.h"
|
8
|
+
#include "lmc_valloc.h"
|
8
9
|
|
9
10
|
typedef size_t va_string_t;
|
10
11
|
typedef size_t va_ht_hash_entry_t;
|
@@ -16,18 +17,25 @@ typedef struct {
|
|
16
17
|
} ht_hash_entry_t;
|
17
18
|
|
18
19
|
#define HT_BUCKETS 499
|
20
|
+
#define ITERATOR_P(n) int ((n)) (void *ctx, const char *key, const char *value)
|
19
21
|
|
20
22
|
typedef size_t va_ht_hash_t;
|
21
23
|
typedef struct {
|
22
24
|
va_ht_hash_entry_t va_buckets[HT_BUCKETS];
|
23
25
|
} ht_hash_t;
|
24
26
|
|
25
|
-
|
26
27
|
va_ht_hash_t ht_hash_create(void *base, lmc_error_t *e);
|
27
|
-
int ht_set(void *base, va_ht_hash_t va_ht, const char *key,
|
28
|
-
lmc_error_t*
|
29
|
-
ht_hash_entry_t *ht_lookup(void *base, va_ht_hash_t va_ht, const char *key
|
30
|
-
|
31
|
-
|
28
|
+
int ht_set(void *base, va_ht_hash_t va_ht, const char *key,
|
29
|
+
size_t n_key, const char *value, size_t n_value, lmc_error_t *e);
|
30
|
+
ht_hash_entry_t *ht_lookup(void *base, va_ht_hash_t va_ht, const char *key,
|
31
|
+
size_t n_key);
|
32
|
+
const char *ht_get(void *base, va_ht_hash_t va_ht, const char *key, size_t n_key,
|
33
|
+
size_t *n_value);
|
34
|
+
int ht_delete(void *base, va_ht_hash_t va_ht, const char *key, size_t n_key);
|
32
35
|
int ht_hash_destroy(void *base, va_ht_hash_t ht);
|
36
|
+
int ht_hash_iterate(void *base, va_ht_hash_t ht, void *ctx, ITERATOR_P(iter));
|
37
|
+
|
38
|
+
int ht_check_memory(void *base, va_ht_hash_t va_ht);
|
39
|
+
int ht_redo(void *base, va_ht_hash_t va_ht, lmc_log_descriptor_t *l,
|
40
|
+
lmc_error_t *e);
|
33
41
|
#endif
|
data/src/lmc_lock.c
CHANGED
@@ -4,27 +4,41 @@
|
|
4
4
|
#include <sys/stat.h>
|
5
5
|
#include <errno.h>
|
6
6
|
#include <string.h>
|
7
|
+
#include <sys/types.h>
|
8
|
+
#include <unistd.h>
|
7
9
|
#include <time.h>
|
8
10
|
#include "lmc_lock.h"
|
9
11
|
|
10
12
|
int c_l(lmc_lock_t *l, lmc_error_t *e) {
|
11
|
-
if (!l) {
|
13
|
+
if (!l) {
|
14
|
+
lmc_handle_error_with_err_string("check_lock",
|
15
|
+
"Semaphore not initialized", "LocalMemCacheError", e);
|
16
|
+
}
|
12
17
|
return l != NULL;
|
13
18
|
}
|
14
19
|
|
15
|
-
|
16
|
-
|
17
20
|
lmc_lock_t *lmc_lock_init(const char *namespace, int init, lmc_error_t *e) {
|
18
21
|
lmc_lock_t *l = malloc(sizeof(lmc_lock_t));
|
19
22
|
if (!l) return NULL;
|
20
23
|
strncpy((char *)&l->namespace, namespace, 1023);
|
21
24
|
|
22
25
|
lmc_handle_error((l->sem = sem_open(l->namespace, O_CREAT, 0600, init)) == NULL,
|
23
|
-
"sem_open", e);
|
26
|
+
"sem_open", "LockError", e);
|
24
27
|
if (!l->sem) { free(l); return NULL; }
|
25
28
|
return l;
|
26
29
|
}
|
27
30
|
|
31
|
+
int lmc_clear_namespace_lock(const char *namespace) {
|
32
|
+
lmc_error_t e;
|
33
|
+
lmc_lock_t *l = lmc_lock_init(namespace, 1, &e);
|
34
|
+
//printf("clear_namespace locks: %s %d\n", namespace, lmc_lock_get_value(l));
|
35
|
+
lmc_lock_repair(l);
|
36
|
+
//printf("AFTER clear_namespace locks: %s %d\n", namespace,
|
37
|
+
//lmc_lock_get_value(l));
|
38
|
+
free(l);
|
39
|
+
return 1;
|
40
|
+
}
|
41
|
+
|
28
42
|
int lmc_is_locked(lmc_lock_t* l, lmc_error_t *e) {
|
29
43
|
if (!c_l(l, e)) { return 0; }
|
30
44
|
if (sem_trywait(l->sem) == -1) {
|
@@ -35,12 +49,27 @@ int lmc_is_locked(lmc_lock_t* l, lmc_error_t *e) {
|
|
35
49
|
}
|
36
50
|
}
|
37
51
|
|
38
|
-
int
|
39
|
-
if (!c_l(l, e)) { return 0; }
|
52
|
+
int lmc_sem_timed_wait(lmc_lock_t* l) {
|
40
53
|
struct timespec ts;
|
41
54
|
clock_gettime(CLOCK_REALTIME, &ts);
|
55
|
+
#ifdef DO_TEST_CRASH
|
56
|
+
ts.tv_sec += 1;
|
57
|
+
#else
|
42
58
|
ts.tv_sec += 2;
|
43
|
-
|
59
|
+
#endif
|
60
|
+
return sem_timedwait(l->sem, &ts);
|
61
|
+
}
|
62
|
+
|
63
|
+
int lmc_sem_timed_wait_mandatory(lmc_lock_t* l) {
|
64
|
+
struct timespec ts;
|
65
|
+
clock_gettime(CLOCK_REALTIME, &ts);
|
66
|
+
ts.tv_sec += 20;
|
67
|
+
return sem_timedwait(l->sem, &ts);
|
68
|
+
}
|
69
|
+
|
70
|
+
int lmc_is_lock_working(lmc_lock_t* l, lmc_error_t *e) {
|
71
|
+
if (!c_l(l, e)) { return 0; }
|
72
|
+
if (lmc_sem_timed_wait(l) == -1) {
|
44
73
|
return 0;
|
45
74
|
} else {
|
46
75
|
sem_post(l->sem);
|
@@ -51,15 +80,44 @@ int lmc_is_lock_working(lmc_lock_t* l, lmc_error_t *e) {
|
|
51
80
|
void lmc_lock_repair(lmc_lock_t *l) {
|
52
81
|
int v;
|
53
82
|
sem_getvalue(l->sem, &v);
|
54
|
-
if (v == 0) {
|
83
|
+
if (v == 0) {
|
84
|
+
sem_post(l->sem);
|
85
|
+
}
|
86
|
+
sem_getvalue(l->sem, &v);
|
87
|
+
while (v > 1) {
|
88
|
+
sem_wait(l->sem);
|
89
|
+
sem_getvalue(l->sem, &v);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
int lmc_lock_get_value(lmc_lock_t* l) {
|
94
|
+
int v = 0;
|
55
95
|
sem_getvalue(l->sem, &v);
|
56
|
-
|
96
|
+
return v;
|
57
97
|
}
|
58
98
|
|
59
99
|
int lmc_lock_obtain(const char *where, lmc_lock_t* l, lmc_error_t *e) {
|
60
|
-
|
100
|
+
if (!c_l(l,e)) { return 0; }
|
101
|
+
int r = lmc_sem_timed_wait(l);
|
102
|
+
if (r == -1 && errno == ETIMEDOUT) {
|
103
|
+
lmc_handle_error_with_err_string("sem_timedwait", strerror(errno),
|
104
|
+
"LockTimedOut", e);
|
105
|
+
return 0;
|
106
|
+
}
|
107
|
+
return lmc_handle_error(r, "sem_timedwait", "LockError", e);
|
108
|
+
}
|
109
|
+
|
110
|
+
int lmc_lock_obtain_mandatory(const char *where, lmc_lock_t* l, lmc_error_t *e) {
|
111
|
+
int r = lmc_sem_timed_wait_mandatory(l);
|
112
|
+
if (r == -1 && errno == ETIMEDOUT) {
|
113
|
+
lmc_handle_error_with_err_string("sem_timedwait", strerror(errno),
|
114
|
+
"LockTimedOut", e);
|
115
|
+
return 0;
|
116
|
+
}
|
117
|
+
return c_l(l,e) && lmc_handle_error(r, "sem_wait", "LockError", e);
|
61
118
|
}
|
62
119
|
|
63
120
|
int lmc_lock_release(const char *where, lmc_lock_t* l, lmc_error_t *e) {
|
64
|
-
return c_l(l, e) && lmc_handle_error(sem_post(l->sem) == -1, "sem_post",
|
121
|
+
return c_l(l, e) && lmc_handle_error(sem_post(l->sem) == -1, "sem_post",
|
122
|
+
"LockError", e);
|
65
123
|
}
|
data/src/lmc_lock.h
CHANGED
@@ -14,9 +14,12 @@ typedef struct {
|
|
14
14
|
|
15
15
|
lmc_lock_t *lmc_lock_init(const char *namespace, int init, lmc_error_t *e);
|
16
16
|
int lmc_lock_obtain(const char *where, lmc_lock_t* l, lmc_error_t *e);
|
17
|
+
int lmc_lock_obtain_mandatory(const char *where, lmc_lock_t* l, lmc_error_t *e);
|
17
18
|
int lmc_lock_release(const char *where, lmc_lock_t* l, lmc_error_t *e);
|
18
19
|
|
19
20
|
int lmc_is_locked(lmc_lock_t* l, lmc_error_t *e);
|
20
21
|
int lmc_is_lock_working(lmc_lock_t* l, lmc_error_t *e);
|
21
22
|
void lmc_lock_repair(lmc_lock_t *l);
|
23
|
+
int lmc_lock_get_value(lmc_lock_t* l);
|
24
|
+
int lmc_clear_namespace_lock(const char *namespace);
|
22
25
|
#endif
|
data/src/lmc_shm.c
CHANGED
@@ -20,6 +20,12 @@ int lmc_does_file_exist(const char *fn) {
|
|
20
20
|
return stat(fn, &st) != -1;
|
21
21
|
}
|
22
22
|
|
23
|
+
int lmc_file_size(const char *fn) {
|
24
|
+
struct stat st;
|
25
|
+
if (stat(fn, &st) == -1) return 0;
|
26
|
+
return st.st_size;
|
27
|
+
}
|
28
|
+
|
23
29
|
void lmc_shm_ensure_root_path() {
|
24
30
|
if (!lmc_does_file_exist(LMC_SHM_ROOT_PATH)) {
|
25
31
|
mkdir(LMC_SHM_ROOT_PATH, 01777);
|
@@ -36,12 +42,20 @@ int lmc_does_namespace_exist(const char *ns) {
|
|
36
42
|
return lmc_does_file_exist(fn);
|
37
43
|
}
|
38
44
|
|
45
|
+
int lmc_namespace_size(const char *ns) {
|
46
|
+
char fn[1024];
|
47
|
+
lmc_file_path_for_namespace((char *)&fn, ns);
|
48
|
+
if (!lmc_does_file_exist(fn)) { return 0; }
|
49
|
+
return lmc_file_size(fn);
|
50
|
+
}
|
51
|
+
|
39
52
|
int lmc_clean_namespace(const char *ns, lmc_error_t *e) {
|
40
53
|
lmc_shm_ensure_root_path();
|
41
54
|
char fn[1024];
|
42
55
|
lmc_file_path_for_namespace((char *)&fn, ns);
|
43
56
|
if (lmc_does_namespace_exist(ns)) {
|
44
|
-
if (!lmc_handle_error(unlink(fn) == -1, "unlink",
|
57
|
+
if (!lmc_handle_error(unlink(fn) == -1, "unlink", "ShmError",
|
58
|
+
e)) { return 0; }
|
45
59
|
}
|
46
60
|
return 1;
|
47
61
|
}
|
@@ -57,7 +71,7 @@ lmc_shm_t *lmc_shm_create(const char* namespace, size_t size, int use_persistenc
|
|
57
71
|
lmc_error_t *e) {
|
58
72
|
lmc_shm_t *mc = calloc(1, sizeof(lmc_shm_t));
|
59
73
|
if (!mc) {
|
60
|
-
|
74
|
+
STD_OUT_OF_MEMORY_ERROR("lmc_shm_create");
|
61
75
|
return NULL;
|
62
76
|
}
|
63
77
|
strncpy((char *)&mc->namespace, namespace, 1023);
|
@@ -68,13 +82,15 @@ lmc_shm_t *lmc_shm_create(const char* namespace, size_t size, int use_persistenc
|
|
68
82
|
char fn[1024];
|
69
83
|
lmc_file_path_for_namespace((char *)&fn, mc->namespace);
|
70
84
|
if (!lmc_handle_error((mc->fd = open(fn, O_RDWR, (mode_t)0777)) == -1,
|
71
|
-
"open", e)) goto open_failed;
|
72
|
-
if (!lmc_handle_error(lseek(mc->fd, mc->size - 1, SEEK_SET) == -1,
|
73
|
-
goto failed;
|
74
|
-
if (!lmc_handle_error(write(mc->fd, "", 1) != 1, "write",
|
85
|
+
"open", "ShmError", e)) goto open_failed;
|
86
|
+
if (!lmc_handle_error(lseek(mc->fd, mc->size - 1, SEEK_SET) == -1,
|
87
|
+
"lseek", "ShmError", e)) goto failed;
|
88
|
+
if (!lmc_handle_error(write(mc->fd, "", 1) != 1, "write",
|
89
|
+
"ShmError", e)) goto failed;
|
75
90
|
mc->base = mmap(0, mc->size, PROT_READ | PROT_WRITE, MAP_SHARED, mc->fd,
|
76
91
|
(off_t)0);
|
77
|
-
if (!lmc_handle_error(mc->base == MAP_FAILED, "mmap", e))
|
92
|
+
if (!lmc_handle_error(mc->base == MAP_FAILED, "mmap", "ShmError", e))
|
93
|
+
goto failed;
|
78
94
|
return mc;
|
79
95
|
|
80
96
|
failed:
|
@@ -85,7 +101,8 @@ open_failed:
|
|
85
101
|
}
|
86
102
|
|
87
103
|
int lmc_shm_destroy(lmc_shm_t *mc, lmc_error_t *e) {
|
88
|
-
int r = lmc_handle_error(munmap(mc->base, mc->size) == -1, "munmap",
|
104
|
+
int r = lmc_handle_error(munmap(mc->base, mc->size) == -1, "munmap",
|
105
|
+
"ShmError", e);
|
89
106
|
close(mc->fd);
|
90
107
|
free(mc);
|
91
108
|
return r;
|
data/src/lmc_shm.h
CHANGED
@@ -18,5 +18,6 @@ lmc_shm_t *lmc_shm_create(const char *namespace, size_t size, int use_persistenc
|
|
18
18
|
lmc_error_t *e);
|
19
19
|
int lmc_shm_destroy(lmc_shm_t *mc, lmc_error_t *e);
|
20
20
|
int lmc_does_namespace_exist(const char *ns);
|
21
|
+
int lmc_namespace_size(const char *ns);
|
21
22
|
int lmc_clean_namespace(const char *ns, lmc_error_t *e);
|
22
23
|
#endif
|
data/src/lmc_valloc.c
CHANGED
@@ -12,20 +12,17 @@
|
|
12
12
|
#include <sys/mman.h>
|
13
13
|
|
14
14
|
#include "lmc_valloc.h"
|
15
|
-
|
16
15
|
#include "lmc_lock.h"
|
16
|
+
#include "lmc_common.h"
|
17
17
|
|
18
|
-
|
19
|
-
size_t next;
|
20
|
-
size_t size;
|
21
|
-
} mem_chunk_descriptor_t;
|
18
|
+
#undef lmc_valloc
|
22
19
|
|
23
|
-
|
24
|
-
|
20
|
+
lmc_mem_chunk_descriptor_t *md_first_free(void *base) {
|
21
|
+
lmc_mem_descriptor_t *md = base;
|
25
22
|
return md->first_free == 0 ? 0 : base + md->first_free;
|
26
23
|
}
|
27
24
|
|
28
|
-
void lmc_dump_chunk(void *base,
|
25
|
+
void lmc_dump_chunk(void *base, lmc_mem_chunk_descriptor_t* c) {
|
29
26
|
size_t va_c = (void *)c - base;
|
30
27
|
printf("chunk %zd:\n"
|
31
28
|
" start: %zd\n"
|
@@ -36,7 +33,7 @@ void lmc_dump_chunk(void *base, mem_chunk_descriptor_t* c) {
|
|
36
33
|
, va_c, va_c, va_c + c->size, c->size, c->next);
|
37
34
|
}
|
38
35
|
|
39
|
-
void lmc_dump_chunk_brief(char *who, void *base,
|
36
|
+
void lmc_dump_chunk_brief(char *who, void *base, lmc_mem_chunk_descriptor_t* c) {
|
40
37
|
if (!c) { return; }
|
41
38
|
size_t va_c = (void *)c - base;
|
42
39
|
printf("[%s] chunk %zd:\n", who, va_c);
|
@@ -44,7 +41,7 @@ void lmc_dump_chunk_brief(char *who, void *base, mem_chunk_descriptor_t* c) {
|
|
44
41
|
|
45
42
|
|
46
43
|
void lmc_dump(void *base) {
|
47
|
-
|
44
|
+
lmc_mem_chunk_descriptor_t* c = md_first_free(base);
|
48
45
|
size_t free = 0;
|
49
46
|
long chunks = 0;
|
50
47
|
while (c) {
|
@@ -55,22 +52,23 @@ void lmc_dump(void *base) {
|
|
55
52
|
}
|
56
53
|
}
|
57
54
|
|
58
|
-
int
|
59
|
-
|
60
|
-
|
61
|
-
return !(((void *)c < base ) ||
|
55
|
+
int lmc_is_va_valid(void *base, size_t va) {
|
56
|
+
lmc_mem_descriptor_t *md = base;
|
57
|
+
lmc_mem_chunk_descriptor_t* c = base + va;
|
58
|
+
return !(((void *)c < base ) ||
|
59
|
+
(base + md->total_size + sizeof(lmc_mem_descriptor_t)) < (void *)c);
|
62
60
|
}
|
63
61
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
lmc_mem_status_t lmc_status(void *base, char *where) {
|
63
|
+
lmc_mem_descriptor_t *md = base;
|
64
|
+
lmc_mem_chunk_descriptor_t* c = md_first_free(base);
|
65
|
+
lmc_mem_status_t ms;
|
68
66
|
size_t free = 0;
|
69
67
|
size_t largest_chunk = 0;
|
70
68
|
long chunks = 0;
|
71
69
|
ms.total_mem = md->total_size;
|
72
70
|
while (c) {
|
73
|
-
if (!
|
71
|
+
if (!lmc_is_va_valid(base, (void *)c - base)) {
|
74
72
|
printf("[%s] invalid pointer detected: %ld...\n", where, (void *)c - base);
|
75
73
|
lmc_dump(base);
|
76
74
|
abort();
|
@@ -88,13 +86,13 @@ mem_status_t lmc_status(void *base, char *where) {
|
|
88
86
|
}
|
89
87
|
|
90
88
|
void lmc_show_status(void *base) {
|
91
|
-
|
89
|
+
lmc_mem_status_t ms = lmc_status(base, "lmc_ss");
|
92
90
|
printf("total: %zu\n", ms.total_mem);
|
93
91
|
printf("chunks: %zu, free: %zu\n", ms.free_chunks, ms.free_mem);
|
94
92
|
}
|
95
93
|
|
96
94
|
int is_lmc_already_initialized(void *base) {
|
97
|
-
|
95
|
+
lmc_mem_descriptor_t *md = base;
|
98
96
|
if (md->magic == 0xF00D) {
|
99
97
|
#ifdef LMC_DEBUG_ALLOC
|
100
98
|
printf("memory already initialized, skipping...\n");
|
@@ -105,14 +103,14 @@ int is_lmc_already_initialized(void *base) {
|
|
105
103
|
}
|
106
104
|
|
107
105
|
void lmc_init_memory(void *ptr, size_t size) {
|
108
|
-
|
109
|
-
size_t s = size - sizeof(
|
110
|
-
// size: enough space for
|
111
|
-
md->first_free = sizeof(
|
106
|
+
lmc_mem_descriptor_t *md = ptr;
|
107
|
+
size_t s = size - sizeof(lmc_mem_descriptor_t);
|
108
|
+
// size: enough space for lmc_mem_descriptor_t + lmc_mem_chunk_descriptor_t
|
109
|
+
md->first_free = sizeof(lmc_mem_descriptor_t);
|
112
110
|
md->magic = 0xF00D;
|
113
111
|
md->locked = 0;
|
114
112
|
md->total_size = s;
|
115
|
-
|
113
|
+
lmc_mem_chunk_descriptor_t *c = ptr + sizeof(lmc_mem_descriptor_t);
|
116
114
|
c->next = 0;
|
117
115
|
c->size = s;
|
118
116
|
}
|
@@ -121,7 +119,7 @@ size_t lmc_max(size_t a, size_t b) {
|
|
121
119
|
return a > b ? a : b;
|
122
120
|
}
|
123
121
|
|
124
|
-
size_t __s(char *where,
|
122
|
+
size_t __s(char *where, lmc_mem_status_t ms, size_t mem_before, size_t expected_diff) {
|
125
123
|
size_t free = ms.total_free_mem;
|
126
124
|
printf("(%s) ", where);
|
127
125
|
if (mem_before) { printf("[%ld:%zd] ", free - mem_before, expected_diff); }
|
@@ -135,15 +133,15 @@ size_t __s(char *where, mem_status_t ms, size_t mem_before, size_t expected_diff
|
|
135
133
|
}
|
136
134
|
|
137
135
|
size_t lmc_valloc(void *base, size_t size) {
|
138
|
-
|
139
|
-
// MOD by power of 2
|
136
|
+
lmc_mem_descriptor_t *md = base;
|
137
|
+
// idea: MOD by power of 2
|
140
138
|
size_t s = lmc_max(size + sizeof(size_t),
|
141
|
-
sizeof(
|
139
|
+
sizeof(lmc_mem_chunk_descriptor_t) + sizeof(size_t));
|
142
140
|
// larger than available space?
|
143
|
-
|
144
|
-
|
141
|
+
lmc_mem_chunk_descriptor_t *c = md_first_free(base);
|
142
|
+
lmc_mem_chunk_descriptor_t *p = NULL;
|
145
143
|
if (size == 0) { return 0; }
|
146
|
-
while (c && c->size <s ) {
|
144
|
+
while (c && c->size < s ) {
|
147
145
|
p = c;
|
148
146
|
if (c->next == 0) {
|
149
147
|
c = 0;
|
@@ -156,13 +154,14 @@ size_t lmc_valloc(void *base, size_t size) {
|
|
156
154
|
return 0;
|
157
155
|
}
|
158
156
|
size_t r = 0;
|
159
|
-
if (c->size - s < sizeof(
|
157
|
+
if (c->size - s < sizeof(lmc_mem_chunk_descriptor_t)) { s = c->size; }
|
160
158
|
// ----------------- -------------------
|
161
159
|
// | chunk | wanted: | |
|
162
160
|
// ----------------- -------------------
|
163
161
|
if (c->size == s) {
|
164
162
|
if (p) { p->next = c->next; }
|
165
163
|
else {md->first_free = c->next; }
|
164
|
+
LMC_TEST_CRASH
|
166
165
|
r = (size_t)((void*)c - (void*)base);
|
167
166
|
} else {
|
168
167
|
// ----------------- -------------------
|
@@ -170,6 +169,7 @@ size_t lmc_valloc(void *base, size_t size) {
|
|
170
169
|
// | | -------------------
|
171
170
|
// -----------------
|
172
171
|
c->size -= s;
|
172
|
+
LMC_TEST_CRASH
|
173
173
|
r = (size_t)((void*)c - base) + c->size;
|
174
174
|
}
|
175
175
|
*(size_t *)(r + base) = s;
|
@@ -178,12 +178,12 @@ size_t lmc_valloc(void *base, size_t size) {
|
|
178
178
|
|
179
179
|
// compact_chunks,
|
180
180
|
void lmc_check_coalesce(void *base, size_t va_chunk) {
|
181
|
-
|
182
|
-
|
181
|
+
lmc_mem_descriptor_t *md = base;
|
182
|
+
lmc_mem_chunk_descriptor_t *chunk = base + va_chunk;
|
183
183
|
size_t c_size = chunk->size;
|
184
184
|
size_t va_chunk_p = 0;
|
185
185
|
size_t va_c_free_chunk = 0;
|
186
|
-
|
186
|
+
lmc_mem_chunk_descriptor_t* c_free_chunk = base + va_c_free_chunk;
|
187
187
|
size_t va_previous = 0;
|
188
188
|
size_t merge1_chunk = 0;
|
189
189
|
int merge1 = 0;
|
@@ -208,9 +208,13 @@ void lmc_check_coalesce(void *base, size_t va_chunk) {
|
|
208
208
|
// ----------------------
|
209
209
|
if (va_chunk + c_size == va_c_free_chunk) {
|
210
210
|
chunk->size += c_free_chunk->size;
|
211
|
+
LMC_TEST_CRASH
|
211
212
|
if (chunk->next == va_c_free_chunk) { va_previous = va_chunk; }
|
212
|
-
|
213
|
+
LMC_TEST_CRASH
|
214
|
+
lmc_mem_chunk_descriptor_t *p = va_previous ? base + va_previous : 0;
|
215
|
+
LMC_TEST_CRASH
|
213
216
|
if (p) { p->next = c_free_chunk->next; }
|
217
|
+
LMC_TEST_CRASH
|
214
218
|
break;
|
215
219
|
}
|
216
220
|
}
|
@@ -226,42 +230,33 @@ void lmc_check_coalesce(void *base, size_t va_chunk) {
|
|
226
230
|
// | chunk |
|
227
231
|
// ----------------------
|
228
232
|
if (merge1) {
|
229
|
-
|
230
|
-
|
231
|
-
|
233
|
+
lmc_mem_chunk_descriptor_t *cd = base + merge1_chunk;
|
234
|
+
lmc_mem_chunk_descriptor_t *p = va_chunk_p ? base + va_chunk_p : 0;
|
235
|
+
lmc_mem_chunk_descriptor_t *vacd = va_chunk? base + va_chunk : 0;
|
236
|
+
LMC_TEST_CRASH
|
232
237
|
if (p) { p->next = vacd->next; }
|
238
|
+
LMC_TEST_CRASH
|
233
239
|
if (md->first_free == va_chunk) { md->first_free = chunk->next; }
|
240
|
+
LMC_TEST_CRASH
|
234
241
|
cd->size += c_size;
|
235
242
|
}
|
236
243
|
}
|
237
244
|
|
238
|
-
|
239
|
-
void lmc_free(void *base, size_t chunk) {
|
240
|
-
#ifdef LMC_DEBUG_ALLOC
|
241
|
-
size_t mb = __s("free1", lmc_status(base, "lmc_free1"), 0, 0);
|
242
|
-
#endif
|
243
|
-
if (chunk == 0) { return; }
|
244
|
-
mem_descriptor_t *md = base;
|
245
|
-
size_t va_used_chunk = chunk - sizeof(size_t);
|
245
|
+
void __lmc_free(void *base, size_t va_used_chunk, size_t uc_size) {
|
246
246
|
void *used_chunk_p = base + va_used_chunk;
|
247
|
-
|
248
|
-
|
247
|
+
lmc_mem_descriptor_t *md = base;
|
248
|
+
lmc_mem_chunk_descriptor_t *mcd_used_chunk = used_chunk_p;
|
249
249
|
size_t va_c_free_chunk = 0;
|
250
|
-
|
250
|
+
lmc_mem_chunk_descriptor_t* c_free_chunk = base + va_c_free_chunk;
|
251
251
|
size_t va_previous = 0;
|
252
252
|
size_t va_c_free_end = 0;
|
253
|
-
if (!(chunk >= sizeof(mem_descriptor_t) + sizeof(size_t)) ||
|
254
|
-
!is_va_valid(base, chunk)) {
|
255
|
-
printf("lmc_free: Invalid pointer: %zd\n", chunk);
|
256
|
-
return;
|
257
|
-
}
|
258
253
|
#ifdef LMC_DEBUG_ALLOC
|
259
254
|
if (uc_size == 0) {
|
260
255
|
printf("SIZE is 0!\n");
|
261
256
|
lmc_dump(base);
|
262
257
|
abort();
|
263
258
|
}
|
264
|
-
memset(base +
|
259
|
+
memset(base + va_used_chunk - sizeof(size_t), 0xF9, uc_size - sizeof(size_t));
|
265
260
|
#endif
|
266
261
|
int freed = 0;
|
267
262
|
while (c_free_chunk) {
|
@@ -274,7 +269,9 @@ void lmc_free(void *base, size_t chunk) {
|
|
274
269
|
// ----------------------
|
275
270
|
if (va_c_free_end == va_used_chunk) {
|
276
271
|
freed = 1;
|
272
|
+
LMC_TEST_CRASH
|
277
273
|
c_free_chunk->size += uc_size;
|
274
|
+
LMC_TEST_CRASH
|
278
275
|
lmc_check_coalesce(base, va_c_free_chunk);
|
279
276
|
break;
|
280
277
|
} else
|
@@ -285,7 +282,7 @@ void lmc_free(void *base, size_t chunk) {
|
|
285
282
|
// ----------------------
|
286
283
|
if (va_used_chunk + uc_size == va_c_free_chunk) {
|
287
284
|
freed = 1;
|
288
|
-
|
285
|
+
lmc_mem_chunk_descriptor_t *p = base + va_previous;
|
289
286
|
mcd_used_chunk->next = c_free_chunk->next;
|
290
287
|
mcd_used_chunk->size = uc_size + c_free_chunk->size;
|
291
288
|
p->next = va_used_chunk;
|
@@ -318,7 +315,162 @@ void lmc_free(void *base, size_t chunk) {
|
|
318
315
|
#endif
|
319
316
|
}
|
320
317
|
|
318
|
+
void lmc_free(void *base, size_t chunk) {
|
319
|
+
#ifdef LMC_DEBUG_ALLOC
|
320
|
+
size_t mb = __s("free1", lmc_status(base, "lmc_free1"), 0, 0);
|
321
|
+
#endif
|
322
|
+
if (chunk == 0) { return; }
|
323
|
+
if (!(chunk >= sizeof(lmc_mem_descriptor_t) + sizeof(size_t)) ||
|
324
|
+
!lmc_is_va_valid(base, chunk)) {
|
325
|
+
printf("lmc_free: Invalid pointer: %zd\n", chunk);
|
326
|
+
return;
|
327
|
+
}
|
328
|
+
size_t va_used_chunk = chunk - sizeof(size_t);
|
329
|
+
void *used_chunk_p = base + va_used_chunk;
|
330
|
+
size_t uc_size = *(size_t *)used_chunk_p;
|
331
|
+
__lmc_free(base, va_used_chunk, uc_size);
|
332
|
+
}
|
333
|
+
|
321
334
|
void lmc_realloc(void *base, size_t chunk) {
|
322
335
|
// check if enough reserved space, true: resize; otherwise: alloc new and
|
323
336
|
// then free
|
324
337
|
}
|
338
|
+
|
339
|
+
int lmc_um_getbit(char *bf, int i) {
|
340
|
+
bf += i / 8; return (*bf & (1 << (i % 8))) != 0;
|
341
|
+
}
|
342
|
+
|
343
|
+
void lmc_um_setbit(char *bf, int i, int v) {
|
344
|
+
bf += i / 8;
|
345
|
+
if (v) *bf |= 1 << (i % 8);
|
346
|
+
else *bf &= ~(1 << (i % 8));
|
347
|
+
}
|
348
|
+
|
349
|
+
int lmc_um_find_leaks(void *base, char *bf) {
|
350
|
+
lmc_mem_descriptor_t *md = base;
|
351
|
+
size_t i;
|
352
|
+
// check if gap size if smaller than sizeof(free_chunk_t)
|
353
|
+
int gap = 0;
|
354
|
+
size_t gs = 0;
|
355
|
+
size_t m;
|
356
|
+
size_t gap_count = 0;
|
357
|
+
size_t space = 0;
|
358
|
+
memset(&m, 0xFF, sizeof(m));
|
359
|
+
for (i = 0; i < md->total_size; ++i) {
|
360
|
+
if (!gap) {
|
361
|
+
size_t *b = (void *)bf + i / 8;
|
362
|
+
while (*b == m && i < md->total_size - sizeof(size_t)) {
|
363
|
+
i += sizeof(size_t) * 8; b++;
|
364
|
+
}
|
365
|
+
}
|
366
|
+
if (lmc_um_getbit(bf, i) == 0) {
|
367
|
+
if (!gap) {
|
368
|
+
gs = i;
|
369
|
+
gap = 1;
|
370
|
+
gap_count++;
|
371
|
+
}
|
372
|
+
} else {
|
373
|
+
if (gap) {
|
374
|
+
gap = 0;
|
375
|
+
space += i - gs;
|
376
|
+
__lmc_free(base, gs, i - gs);
|
377
|
+
}
|
378
|
+
}
|
379
|
+
}
|
380
|
+
if (gap) {
|
381
|
+
gap = 0;
|
382
|
+
space += i - gs;
|
383
|
+
__lmc_free(base, gs, i - gs);
|
384
|
+
}
|
385
|
+
//printf("total leaks: %zd block, %zd bytes total\n", gap_count, space);
|
386
|
+
return 1;
|
387
|
+
}
|
388
|
+
|
389
|
+
int lmc_um_check_unmarked(void *base, char *bf, size_t va, size_t size) {
|
390
|
+
size_t i;
|
391
|
+
size_t n;
|
392
|
+
memset(&n, 0x0, sizeof(n));
|
393
|
+
size_t end = va + size;
|
394
|
+
for (i = va; i < va + size; ++i) {
|
395
|
+
size_t *b = (void *)bf + i / 8;
|
396
|
+
while (*b == n && i < end - sizeof(size_t)) {
|
397
|
+
i += sizeof(size_t) * 8; b++;
|
398
|
+
}
|
399
|
+
if (lmc_um_getbit(bf, i) != 0) {
|
400
|
+
//printf("umarked2: FAILED at: %zd\n", i);
|
401
|
+
//printf("umarked2: FAILED start: %zd\n", va);
|
402
|
+
//size_t d = i;
|
403
|
+
//while (lmc_um_getbit(bf, d) != 0) { --d; }
|
404
|
+
//printf("area starts at: %zd\n", d);
|
405
|
+
//size_t e = i;
|
406
|
+
//while (lmc_um_getbit(bf, e) != 0) { ++e; }
|
407
|
+
//printf("area ends at: %zd\n", e);
|
408
|
+
return 0;
|
409
|
+
}
|
410
|
+
}
|
411
|
+
return 1;
|
412
|
+
}
|
413
|
+
|
414
|
+
int lmc_um_mark(void *base, char *bf, size_t va, size_t size) {
|
415
|
+
size_t i;
|
416
|
+
lmc_mem_descriptor_t *md = base;
|
417
|
+
if ((va > sizeof(lmc_mem_descriptor_t)) &&
|
418
|
+
(!lmc_is_va_valid(base, va) || !lmc_is_va_valid(base, va + size))) {
|
419
|
+
printf("Error: VA start out of range: va: %zd - %zd max %zd!\n",
|
420
|
+
va, va + size, md->total_size);
|
421
|
+
return 0;
|
422
|
+
}
|
423
|
+
if (!lmc_um_check_unmarked(base, bf, va, size)) return 0;
|
424
|
+
for (i = va; i < va + size; ++i) {
|
425
|
+
if (i % 8 == 0) {
|
426
|
+
size_t b_start = i / 8;
|
427
|
+
size_t b_end = (va + size - 1) / 8;
|
428
|
+
if (b_start != b_end) {
|
429
|
+
memset(bf + b_start, 0xFF, b_end - b_start);
|
430
|
+
i += (b_end * 8) - va;
|
431
|
+
}
|
432
|
+
}
|
433
|
+
lmc_um_setbit(bf, i, 1);
|
434
|
+
}
|
435
|
+
return 1;
|
436
|
+
}
|
437
|
+
|
438
|
+
int lmc_um_mark_allocated(void *base, char *bf, size_t va) {
|
439
|
+
size_t real_va = va - sizeof(size_t);
|
440
|
+
size_t s = *(size_t *)(base + real_va);
|
441
|
+
return lmc_um_mark(base, bf, real_va, s);
|
442
|
+
}
|
443
|
+
|
444
|
+
char *lmc_um_new_mem_usage_bitmap(void *base) {
|
445
|
+
lmc_mem_descriptor_t *md = base;
|
446
|
+
size_t ts = ((md->total_size + 7) / 8);
|
447
|
+
char *bf = calloc(1, ts);
|
448
|
+
size_t va = md->first_free;
|
449
|
+
if (!lmc_um_mark(base, bf, 0, sizeof(lmc_mem_descriptor_t))) goto failed;
|
450
|
+
lmc_mem_chunk_descriptor_t *c;
|
451
|
+
while (va) {
|
452
|
+
c = base + va;
|
453
|
+
if (!lmc_um_mark(base, bf, va, c->size)) goto failed;
|
454
|
+
va = c->next;
|
455
|
+
}
|
456
|
+
return bf;
|
457
|
+
|
458
|
+
failed:
|
459
|
+
free(bf);
|
460
|
+
return 0;
|
461
|
+
}
|
462
|
+
|
463
|
+
lmc_log_descriptor_t *lmc_log_op(void *base, int opid) {
|
464
|
+
lmc_mem_descriptor_t *md = base;
|
465
|
+
lmc_log_descriptor_t *l = &md->log;
|
466
|
+
l->op_id = opid;
|
467
|
+
l->p1 = l->p2 = 0x0;
|
468
|
+
return l;
|
469
|
+
}
|
470
|
+
|
471
|
+
void lmc_log_finish(void *base) {
|
472
|
+
lmc_mem_descriptor_t *md = base;
|
473
|
+
lmc_log_descriptor_t *l = &md->log;
|
474
|
+
l->op_id = 0;
|
475
|
+
l->p1 = l->p2 = 0x0;
|
476
|
+
}
|