|
1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | 2 | /* Manage a cache of file names' existence */ |
| 3 | +#include <pthread.h> |
3 | 4 | #include <stdlib.h> |
4 | | -#include <unistd.h> |
5 | 5 | #include <string.h> |
6 | | -#include <linux/list.h> |
| 6 | +#include <unistd.h> |
| 7 | +#include <linux/compiler.h> |
7 | 8 | #include "fncache.h" |
| 9 | +#include "hashmap.h" |
8 | 10 |
|
9 | | -struct fncache { |
10 | | - struct hlist_node nd; |
11 | | - bool res; |
12 | | - char name[]; |
13 | | -}; |
| 11 | +static struct hashmap *fncache; |
14 | 12 |
|
15 | | -#define FNHSIZE 61 |
| 13 | +static size_t fncache__hash(long key, void *ctx __maybe_unused) |
| 14 | +{ |
| 15 | + return str_hash((const char *)key); |
| 16 | +} |
16 | 17 |
|
17 | | -static struct hlist_head fncache_hash[FNHSIZE]; |
| 18 | +static bool fncache__equal(long key1, long key2, void *ctx __maybe_unused) |
| 19 | +{ |
| 20 | + return strcmp((const char *)key1, (const char *)key2) == 0; |
| 21 | +} |
18 | 22 |
|
19 | | -unsigned shash(const unsigned char *s) |
| 23 | +static void fncache__init(void) |
20 | 24 | { |
21 | | - unsigned h = 0; |
22 | | - while (*s) |
23 | | - h = 65599 * h + *s++; |
24 | | - return h ^ (h >> 16); |
| 25 | + fncache = hashmap__new(fncache__hash, fncache__equal, /*ctx=*/NULL); |
| 26 | +} |
| 27 | + |
| 28 | +static struct hashmap *fncache__get(void) |
| 29 | +{ |
| 30 | + static pthread_once_t fncache_once = PTHREAD_ONCE_INIT; |
| 31 | + |
| 32 | + pthread_once(&fncache_once, fncache__init); |
| 33 | + |
| 34 | + return fncache; |
25 | 35 | } |
26 | 36 |
|
27 | 37 | static bool lookup_fncache(const char *name, bool *res) |
28 | 38 | { |
29 | | - int h = shash((const unsigned char *)name) % FNHSIZE; |
30 | | - struct fncache *n; |
31 | | - |
32 | | - hlist_for_each_entry(n, &fncache_hash[h], nd) { |
33 | | - if (!strcmp(n->name, name)) { |
34 | | - *res = n->res; |
35 | | - return true; |
36 | | - } |
37 | | - } |
38 | | - return false; |
| 39 | + long val; |
| 40 | + |
| 41 | + if (!hashmap__find(fncache__get(), name, &val)) |
| 42 | + return false; |
| 43 | + |
| 44 | + *res = (val != 0); |
| 45 | + return true; |
39 | 46 | } |
40 | 47 |
|
41 | 48 | static void update_fncache(const char *name, bool res) |
42 | 49 | { |
43 | | - struct fncache *n = malloc(sizeof(struct fncache) + strlen(name) + 1); |
44 | | - int h = shash((const unsigned char *)name) % FNHSIZE; |
45 | | - |
46 | | - if (!n) |
47 | | - return; |
48 | | - strcpy(n->name, name); |
49 | | - n->res = res; |
50 | | - hlist_add_head(&n->nd, &fncache_hash[h]); |
| 50 | + char *old_key = NULL, *key = strdup(name); |
| 51 | + |
| 52 | + if (key) { |
| 53 | + hashmap__set(fncache__get(), key, res, &old_key, /*old_value*/NULL); |
| 54 | + free(old_key); |
| 55 | + } |
51 | 56 | } |
52 | 57 |
|
53 | 58 | /* No LRU, only use when bounded in some other way. */ |
|
0 commit comments