xref: /linux/tools/perf/util/fncache.c (revision c95baf12f5077419db01313ab61c2aac007d40cd)
1*d9664582SAndi Kleen // SPDX-License-Identifier: GPL-2.0-only
2*d9664582SAndi Kleen /* Manage a cache of file names' existence */
3*d9664582SAndi Kleen #include <stdlib.h>
4*d9664582SAndi Kleen #include <unistd.h>
5*d9664582SAndi Kleen #include <string.h>
6*d9664582SAndi Kleen #include <linux/list.h>
7*d9664582SAndi Kleen #include "fncache.h"
8*d9664582SAndi Kleen 
9*d9664582SAndi Kleen struct fncache {
10*d9664582SAndi Kleen 	struct hlist_node nd;
11*d9664582SAndi Kleen 	bool res;
12*d9664582SAndi Kleen 	char name[];
13*d9664582SAndi Kleen };
14*d9664582SAndi Kleen 
15*d9664582SAndi Kleen #define FNHSIZE 61
16*d9664582SAndi Kleen 
17*d9664582SAndi Kleen static struct hlist_head fncache_hash[FNHSIZE];
18*d9664582SAndi Kleen 
shash(const unsigned char * s)19*d9664582SAndi Kleen unsigned shash(const unsigned char *s)
20*d9664582SAndi Kleen {
21*d9664582SAndi Kleen 	unsigned h = 0;
22*d9664582SAndi Kleen 	while (*s)
23*d9664582SAndi Kleen 		h = 65599 * h + *s++;
24*d9664582SAndi Kleen 	return h ^ (h >> 16);
25*d9664582SAndi Kleen }
26*d9664582SAndi Kleen 
lookup_fncache(const char * name,bool * res)27*d9664582SAndi Kleen static bool lookup_fncache(const char *name, bool *res)
28*d9664582SAndi Kleen {
29*d9664582SAndi Kleen 	int h = shash((const unsigned char *)name) % FNHSIZE;
30*d9664582SAndi Kleen 	struct fncache *n;
31*d9664582SAndi Kleen 
32*d9664582SAndi Kleen 	hlist_for_each_entry(n, &fncache_hash[h], nd) {
33*d9664582SAndi Kleen 		if (!strcmp(n->name, name)) {
34*d9664582SAndi Kleen 			*res = n->res;
35*d9664582SAndi Kleen 			return true;
36*d9664582SAndi Kleen 		}
37*d9664582SAndi Kleen 	}
38*d9664582SAndi Kleen 	return false;
39*d9664582SAndi Kleen }
40*d9664582SAndi Kleen 
update_fncache(const char * name,bool res)41*d9664582SAndi Kleen static void update_fncache(const char *name, bool res)
42*d9664582SAndi Kleen {
43*d9664582SAndi Kleen 	struct fncache *n = malloc(sizeof(struct fncache) + strlen(name) + 1);
44*d9664582SAndi Kleen 	int h = shash((const unsigned char *)name) % FNHSIZE;
45*d9664582SAndi Kleen 
46*d9664582SAndi Kleen 	if (!n)
47*d9664582SAndi Kleen 		return;
48*d9664582SAndi Kleen 	strcpy(n->name, name);
49*d9664582SAndi Kleen 	n->res = res;
50*d9664582SAndi Kleen 	hlist_add_head(&n->nd, &fncache_hash[h]);
51*d9664582SAndi Kleen }
52*d9664582SAndi Kleen 
53*d9664582SAndi Kleen /* No LRU, only use when bounded in some other way. */
file_available(const char * name)54*d9664582SAndi Kleen bool file_available(const char *name)
55*d9664582SAndi Kleen {
56*d9664582SAndi Kleen 	bool res;
57*d9664582SAndi Kleen 
58*d9664582SAndi Kleen 	if (lookup_fncache(name, &res))
59*d9664582SAndi Kleen 		return res;
60*d9664582SAndi Kleen 	res = access(name, R_OK) == 0;
61*d9664582SAndi Kleen 	update_fncache(name, res);
62*d9664582SAndi Kleen 	return res;
63*d9664582SAndi Kleen }
64