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