CUBRID Engine  latest
api_util.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 
20 /*
21  * api_util.h -
22  */
23 
24 #include "config.h"
25 
26 #include <stdlib.h>
27 #include <pthread.h>
28 #include <assert.h>
29 #include <string.h>
30 #include "api_util.h"
31 #include "error_code.h"
32 
33 typedef struct ht_elem_s ht_elem;
34 typedef struct ht_bucket_s ht_bucket;
36 
37 /* static hash table entry. linked via doubly linked list header */
38 struct ht_elem_s
39 {
40  dlisth head; /* must be the first member */
41  void *elem;
42 };
43 
45 {
46  dlisth head; /* must be the first member */
47 };
48 
50 {
51  int bucket_sz;
55  ht_bucket buckets[1];
56 };
57 
58 /* malloc debug header */
60 {
62  int line;
63  char file[12];
64 };
65 #define MALLOC_HEADER_SZ 32
66 
67 static void once_function ();
68 static void make_debug_h (debug_malloc_h * mh, const char *file, int line);
69 static void dump_debug_h (debug_malloc_h * mh, FILE * fp);
70 
71 /* lock */
73 static int malloc_count;
74 static int free_count;
77 
78 /* global variable */
80 
81 /*
82  * once_function - initialize api_malloc/free/calloc debug information
83  * return: void
84  */
85 static void
87 {
89  dlisth_init (&malloc_list);
90  malloc_count = 0;
91  free_count = 0;
92 }
93 
94 /*
95  * make_debug_h - initialize debug malloc header with given file and line
96  * return: void
97  * mh(in): malloc debug header
98  * file(in): file name
99  * line(in): line number
100  */
101 static void
102 make_debug_h (debug_malloc_h * mh, const char *file, int line)
103 {
104  int file_len;
105  char *bp;
106 
107  dlisth_init (&mh->head);
108  mh->line = line;
109  file_len = strlen (file);
110  bp = file_len < 11 ? (char *) file : (char *) file + file_len - 11;
111  strncpy (mh->file, bp, 11);
112  mh->file[11] = 0;
113 }
114 
115 /*
116  * dump_debug_h - print debug malloc header information to given out fp
117  * return:
118  * mh(in): malloc debug header
119  * fp(in): FILE pointer
120  */
121 static void
122 dump_debug_h (debug_malloc_h * mh, FILE * fp)
123 {
124  fprintf (fp, "file: %s, line %d\n", mh->file, mh->line);
125 }
126 
127 
128 /*
129  * dlisth_map - map over dlist and call map function
130  * return: NO_ERROR if successful, error code otherwise
131  * h(in): doubly linked list header
132  * func(in): map function
133  * arg(in): argument for the map function
134  *
135  * NOTE: traverse stops when map function set continue out parameter to 0
136  */
137 int
138 dlisth_map (dlisth * h, dlist_map_func func, void *arg)
139 {
140  dlisth *tmp;
141  int cont;
142  assert (h != NULL);
143  assert (func != NULL);
144  cont = 0;
145  for (tmp = h->next; tmp != h; tmp = tmp->next)
146  {
147  int r = func (tmp, arg, &cont);
148  if (r != NO_ERROR)
149  return r;
150  else if (cont == 0)
151  break;
152  }
153  return NO_ERROR;
154 }
155 
156 /*
157  * hash_new - create new static hash table
158  * return: NO_ERROR if successful, error code otherwise
159  * bucket_sz(in): hash table bucket size
160  * hashf(in): hash function
161  * keyf(in): key function
162  * comparef(in): compare function
163  * rht(out): hash table
164  */
165 int
166 hash_new (int bucket_sz, ht_hashf hashf, ht_keyf keyf, ht_comparef comparef, hash_table ** rht)
167 {
168  int sz, i;
169  hash_table *ht;
170 
171  assert (bucket_sz > 0);
172  assert (hashf != NULL);
173  assert (comparef != NULL);
174 
175  sz = sizeof (*ht) + (bucket_sz - 1) * sizeof (ht_bucket);
176  ht = (hash_table *) API_MALLOC (sz);
177  if (ht == NULL)
179 
180  ht->bucket_sz = bucket_sz;
181  ht->hashf = hashf;
182  ht->keyf = keyf;
183  ht->comparef = comparef;
184  for (i = 0; i < bucket_sz; i++)
185  dlisth_init ((dlisth *) (&ht->buckets[i].head));
186 
187  *rht = ht;
188  return NO_ERROR;
189 }
190 
191 /*
192  * hash_destroy - destroy static hash table
193  * return: void
194  * ht(in): hash table
195  * dtor(in): element destructor function
196  */
197 void
199 {
200  int i;
201 
202  assert (ht != NULL);
203  if (ht == NULL)
204  return;
205 
206  for (i = 0; i < ht->bucket_sz; i++)
207  {
208  dlisth *h, *header;
209  h = header = &ht->buckets[i].head;
210  h = h->next;
211  while (h != header)
212  {
213  ht_elem *hte = (ht_elem *) h;
214  h = h->next;
215 
216  dlisth_delete ((dlisth *) hte);
217  if (dtor)
218  dtor (hte->elem);
219  API_FREE (hte);
220  }
221  }
222  API_FREE (ht);
223 }
224 
225 /*
226  * hash_lookup - lookup element
227  * return: NO_ERROR if successful, error code otherwise
228  * ht(in): hash table
229  * key(in): pointer to the key
230  * relem(out): element found
231  */
232 int
233 hash_lookup (hash_table * ht, void *key, void **relem)
234 {
235  int rc;
236  unsigned int hcode;
237  dlisth *h, *header;
238 
239  assert (ht != NULL);
240  assert (relem != NULL);
241 
242  rc = ht->hashf (key, &hcode);
243  if (rc != NO_ERROR)
244  return rc;
245  hcode = hcode % ht->bucket_sz;
246 
247  header = &ht->buckets[(size_t) hcode].head;
248  for (h = header->next; h != header; h = h->next)
249  {
250  ht_elem *hte = (ht_elem *) h;
251  void *ekey;
252  int r;
253 
254  if ((rc = ht->keyf (hte->elem, &ekey)) != NO_ERROR)
255  return rc;
256  if ((rc = ht->comparef (key, ekey, &r)) == NO_ERROR && r == 0)
257  {
258  *relem = hte->elem;
259  return NO_ERROR;
260  }
261  else if (rc != NO_ERROR)
262  return rc;
263  }
264  *relem = NULL;
265  return NO_ERROR;
266 }
267 
268 /*
269  * hash_insert - insert element to the hash table
270  * return: NO_ERROR if successful, error code otherwise
271  * ht(in): hash table
272  * elem(in): element to insert
273  */
274 int
276 {
277  int rc;
278  void *key;
279  dlisth *header;
280  ht_elem *hte;
281  unsigned int hcode;
282 
283  assert (ht != NULL && elem != NULL);
284 
285  rc = ht->keyf (elem, &key);
286  if (rc != NO_ERROR)
287  return rc;
288 
289  rc = ht->hashf (key, &hcode);
290  if (rc != NO_ERROR)
291  return rc;
292 
293  hcode = hcode % ht->bucket_sz;
294  header = &ht->buckets[(size_t) hcode].head;
295 
296  hte = API_MALLOC (sizeof (ht_elem));
297  if (hte == NULL)
299 
300  hte->elem = elem;
301 
302  dlisth_insert_after ((dlisth *) hte, header);
303  return NO_ERROR;
304 }
305 
306 
307 /*
308  * hash_delete - delete hash entry from hash table and return element found
309  * return: NO_ERROR if successful, error_code otherwise
310  * ht(in): hash table
311  * key(in): pointer to the key
312  * relem(out): element found, or set to NULL
313  *
314  * NOTE
315  * When element is not found then NO_ERROR returned with NULL relem value
316  */
317 int
318 hash_delete (hash_table * ht, void *key, void **relem)
319 {
320  int rc;
321  unsigned int hcode;
322  dlisth *h, *header;
323 
324  assert (ht != NULL);
325  assert (relem != NULL);
326  *relem = NULL;
327 
328  rc = ht->hashf (key, &hcode);
329  if (rc != NO_ERROR)
330  return rc;
331 
332  hcode = hcode % ht->bucket_sz;
333  header = &ht->buckets[(size_t) hcode].head;
334  for (h = header->next; h != header; h = h->next)
335  {
336  int r;
337  ht_elem *hte = (ht_elem *) h;
338  void *ekey;
339 
340  if ((rc = ht->keyf (hte->elem, &ekey)) != NO_ERROR)
341  return rc;
342 
343  if ((rc = ht->comparef (key, ekey, &r)) == NO_ERROR && r == 0)
344  {
345  *relem = hte->elem;
346  dlisth_delete (h);
347  API_FREE (hte);
348  return NO_ERROR;
349  }
350  else if (rc != NO_ERROR)
351  return rc;
352  }
353  return NO_ERROR;
354 }
355 
356 
357 /*
358  * api_calloc - calloc() debug version
359  * return: pointer to the allocated memory
360  * nmemb(in): number of elem
361  * size(in): size of elem
362  * file(in): file name
363  * line(in): line number
364  */
365 void *
366 api_calloc (size_t nmemb, size_t size, const char *file, int line)
367 {
368  void *ptr;
369  size_t sz;
370 
371  if (api_malloc_dhook_flag_set == 0)
372  return calloc (nmemb, size);
373 
375 
376  sz = MALLOC_HEADER_SZ + nmemb * size;
377  assert (sizeof (debug_malloc_h) <= MALLOC_HEADER_SZ);
378  ptr = malloc (sz);
379  if (ptr)
380  {
381  make_debug_h ((debug_malloc_h *) ptr, file, line);
382  memset ((char *) ptr + MALLOC_HEADER_SZ, 0, nmemb * size);
383  API_LOCK (&mutex);
384  dlisth_insert_after ((dlisth *) ptr, &malloc_list);
385  malloc_count++;
386  API_UNLOCK (&mutex);
387  }
388  return (char *) ptr + MALLOC_HEADER_SZ;
389 }
390 
391 /*
392  * api_malloc - malloc() debug version
393  * return: pointer to allcated memory
394  * size(in): allcation size
395  * file(in): file name
396  * line(in): line number
397  */
398 void *
399 api_malloc (size_t size, const char *file, int line)
400 {
401  void *ptr;
402  size_t sz;
403 
404  if (api_malloc_dhook_flag_set == 0)
405  return malloc (size);
406 
408 
409  sz = MALLOC_HEADER_SZ + size;
410  assert (sizeof (debug_malloc_h) <= MALLOC_HEADER_SZ);
411  ptr = malloc (sz);
412  if (ptr)
413  {
414  make_debug_h ((debug_malloc_h *) ptr, file, line);
415  API_LOCK (&mutex);
416  dlisth_insert_after ((dlisth *) ptr, &malloc_list);
417  malloc_count++;
418  API_UNLOCK (&mutex);
419  }
420  return (char *) ptr + MALLOC_HEADER_SZ;
421 }
422 
423 /*
424  * api_free - free() debug version
425  * return: void
426  * ptr(in): pointer to allcated memory via api_malloc(), api_calloc()
427  * file(in): file name
428  * line(in): line number
429  */
430 void
431 api_free (void *ptr, const char *file, int line)
432 {
433  char *p = NULL;
434 
435  if (api_malloc_dhook_flag_set == 0)
436  return free (ptr);
437 
439  if (ptr)
440  {
441  p = (char *) ptr - MALLOC_HEADER_SZ;
442  API_LOCK (&mutex);
443  dlisth_delete ((dlisth *) p);
444  free_count++;
445  API_UNLOCK (&mutex);
446  }
447  free (p);
448 }
449 
450 /*
451  * api_check_memory - check memory
452  * return: 0 if successful, count of failure otherwise
453  * fp(in): FILE * to print check message
454  * NOTE : this function checks malloc/free pair match and
455  * dump debug debug information of malloc/calloced but not freeed.
456  */
457 int
458 api_check_memory (FILE * fp)
459 {
460  int res = 0;
461 
462  if (api_malloc_dhook_flag_set == 0)
463  return 0;
464 
466  API_LOCK (&mutex);
467  if (malloc_count != free_count)
468  {
469  fprintf (fp, "malloc/free count mismatch (%d/%d)\n", malloc_count, free_count);
470  res++;
471  }
472  if (!dlisth_is_empty (&malloc_list))
473  {
474  dlisth *h;
475  fprintf (fp, "malloc list not empty (memory leak)\n");
476  for (h = malloc_list.next; h != &malloc_list; h = h->next)
477  {
478  fprintf (fp, "\t");
479  dump_debug_h ((debug_malloc_h *) h, fp);
480  fprintf (fp, "\n");
481  }
482  res++;
483  }
484  API_UNLOCK (&mutex);
485  return res;
486 }
int api_check_memory(FILE *fp)
Definition: api_util.c:458
#define dlisth_insert_after(ih, bh)
Definition: api_util.h:68
#define MALLOC_HEADER_SZ
Definition: api_util.c:65
dlisth * next
Definition: api_util.h:33
#define NO_ERROR
Definition: error_code.h:46
int hash_insert(hash_table *ht, void *elem)
Definition: api_util.c:275
void hash_destroy(hash_table *ht, ht_destroyf dtor)
Definition: api_util.c:198
int hash_lookup(hash_table *ht, void *key, void **relem)
Definition: api_util.c:233
int hash_delete(hash_table *ht, void *key, void **relem)
Definition: api_util.c:318
static API_MUTEX mutex
Definition: api_util.c:72
static API_ONCE_TYPE once
Definition: api_util.c:76
ht_hashf hashf
Definition: api_util.c:52
static int malloc_count
Definition: api_util.c:73
ht_bucket buckets[1]
Definition: api_util.c:55
#define API_MUTEX
Definition: api_util.h:97
static void dump_debug_h(debug_malloc_h *mh, FILE *fp)
Definition: api_util.c:122
int(* ht_hashf)(void *key, unsigned int *rv)
Definition: api_util.h:84
static void once_function()
Definition: api_util.c:86
ht_keyf keyf
Definition: api_util.c:53
#define API_UNLOCK(m)
Definition: api_util.h:101
int(* ht_comparef)(void *key1, void *key2, int *r)
Definition: api_util.h:82
#define assert(x)
void * api_malloc(size_t size, const char *file, int line)
Definition: api_util.c:399
#define dlisth_delete(h_)
Definition: api_util.h:50
dlisth head
Definition: api_util.c:46
#define NULL
Definition: freelistheap.h:34
#define API_LOCK(m)
Definition: api_util.h:100
int(* ht_keyf)(void *elem, void **rk)
Definition: api_util.h:86
#define API_FREE(p)
Definition: api_util.h:112
int dlisth_map(dlisth *h, dlist_map_func func, void *arg)
Definition: api_util.c:138
void * elem
Definition: api_util.c:41
void * api_calloc(size_t nmemb, size_t size, const char *file, int line)
Definition: api_util.c:366
static int free_count
Definition: api_util.c:74
static int rc
Definition: serial.c:50
#define API_ONCE_TYPE
Definition: api_util.h:104
int api_malloc_dhook_flag_set
Definition: api_util.c:79
int(* dlist_map_func)(dlisth *h, void *arg, int *cont)
Definition: api_util.h:38
#define API_ONCE_INIT
Definition: api_util.h:105
#define strlen(s1)
Definition: intl_support.c:43
int bucket_sz
Definition: api_util.c:51
#define API_ONCE_FUNC(t, r)
Definition: api_util.h:106
static void make_debug_h(debug_malloc_h *mh, const char *file, int line)
Definition: api_util.c:102
int i
Definition: dynamic_load.c:954
#define API_MALLOC(s)
Definition: api_util.h:111
static dlisth malloc_list
Definition: api_util.c:75
#define dlisth_is_empty(h)
Definition: api_util.h:48
#define API_MUTEX_INIT(m)
Definition: api_util.h:98
#define dlisth_init(h)
Definition: api_util.h:42
char file[12]
Definition: api_util.c:63
void api_free(void *ptr, const char *file, int line)
Definition: api_util.c:431
void(* ht_destroyf)(void *elem)
Definition: api_util.h:88
const char ** p
Definition: dynamic_load.c:945
dlisth head
Definition: api_util.c:40
int hash_new(int bucket_sz, ht_hashf hashf, ht_keyf keyf, ht_comparef comparef, hash_table **rht)
Definition: api_util.c:166
#define ER_INTERFACE_NO_MORE_MEMORY
Definition: error_code.h:1198
ht_comparef comparef
Definition: api_util.c:54