1 /*
2  * Copyright (c) 2014, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include <stdlib.h>
28 #include <string.h>
29 #include "handle.h"
30 
31 /*
32  * Define the initial capacity of the database. It should be a low number
33  * multiple of 2 since some databases a likely to only use a few handles.
34  * Since the algorithm is to doubles up when growing it shouldn't cause a
35  * noticable overhead on large databases.
36  */
37 #define HANDLE_DB_INITIAL_MAX_PTRS	4
38 
mutex_lock(struct handle_db * db)39 static void mutex_lock(struct handle_db *db)
40 {
41 	if (db->mu)
42 		pthread_mutex_lock(db->mu);
43 }
44 
mutex_unlock(struct handle_db * db)45 static void mutex_unlock(struct handle_db *db)
46 {
47 	if (db->mu)
48 		pthread_mutex_unlock(db->mu);
49 }
50 
51 
handle_db_set_mutex(struct handle_db * db,pthread_mutex_t * mu)52 void handle_db_set_mutex(struct handle_db *db, pthread_mutex_t *mu)
53 {
54 	db->mu = mu;
55 }
56 
handle_db_destroy(struct handle_db * db)57 void handle_db_destroy(struct handle_db *db)
58 {
59 	if (db) {
60 		mutex_lock(db);
61 		free(db->ptrs);
62 		db->ptrs = NULL;
63 		db->max_ptrs = 0;
64 		mutex_unlock(db);
65 	}
66 }
67 
handle_get(struct handle_db * db,void * ptr)68 int handle_get(struct handle_db *db, void *ptr)
69 {
70 	size_t n = 0;
71 	void *p = NULL;
72 	size_t new_max_ptrs = 0;
73 	int ret = 0;
74 
75 	if (!db || !ptr)
76 		return -1;
77 
78 	mutex_lock(db);
79 
80 	/* Try to find an empty location */
81 	for (n = 0; n < db->max_ptrs; n++) {
82 		if (!db->ptrs[n]) {
83 			db->ptrs[n] = ptr;
84 			ret = n;
85 			goto out;
86 		}
87 	}
88 
89 	/* No location available, grow the ptrs array */
90 	if (db->max_ptrs)
91 		new_max_ptrs = db->max_ptrs * 2;
92 	else
93 		new_max_ptrs = HANDLE_DB_INITIAL_MAX_PTRS;
94 	p = realloc(db->ptrs, new_max_ptrs * sizeof(void *));
95 	if (!p) {
96 		ret = -1;
97 		goto out;
98 	}
99 	db->ptrs = p;
100 	memset(db->ptrs + db->max_ptrs, 0,
101 	       (new_max_ptrs - db->max_ptrs) * sizeof(void *));
102 	db->max_ptrs = new_max_ptrs;
103 
104 	/* Since n stopped at db->max_ptrs there is an empty location there */
105 	db->ptrs[n] = ptr;
106 	ret = n;
107 
108 out:
109 	mutex_unlock(db);
110 	return ret;
111 }
112 
handle_put(struct handle_db * db,int handle)113 void *handle_put(struct handle_db *db, int handle)
114 {
115 	void *p = NULL;
116 
117 	if (!db || handle < 0)
118 		return NULL;
119 
120 	mutex_lock(db);
121 
122 	if ((size_t)handle >= db->max_ptrs) {
123 		p = NULL;
124 		goto out;
125 	}
126 
127 	p = db->ptrs[handle];
128 	db->ptrs[handle] = NULL;
129 
130 out:
131 	mutex_unlock(db);
132 	return p;
133 }
134 
handle_lookup(struct handle_db * db,int handle)135 void *handle_lookup(struct handle_db *db, int handle)
136 {
137 	void *p = NULL;
138 
139 	if (!db || handle < 0)
140 		return NULL;
141 
142 	mutex_lock(db);
143 
144 	if ((size_t)handle >= db->max_ptrs) {
145 		p = NULL;
146 		goto out;
147 	}
148 
149 	p = db->ptrs[handle];
150 
151 out:
152 	mutex_unlock(db);
153 	return p;
154 }
155 
handle_foreach_put(struct handle_db * db,void (* cb)(int handle,void * ptr,void * arg),void * arg)156 void handle_foreach_put(struct handle_db *db,
157 			void (*cb)(int handle, void *ptr, void *arg),
158 			void *arg)
159 {
160 	size_t n = 0;
161 
162 	if (!db || !cb)
163 		return;
164 
165 	mutex_lock(db);
166 
167 	for (n = 0; n < db->max_ptrs; n++) {
168 		if (db->ptrs[n]) {
169 			cb(n, db->ptrs[n], arg);
170 			db->ptrs[n] = NULL;
171 		}
172 	}
173 
174 	mutex_unlock(db);
175 }
176