YAZ  5.34.0
nmem.c
Go to the documentation of this file.
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 
14 #if HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17 
18 #include <assert.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <stddef.h>
23 #include <yaz/xmalloc.h>
24 #include <yaz/nmem.h>
25 #include <yaz/log.h>
26 #include <yaz/snprintf.h>
27 
28 #if YAZ_POSIX_THREADS
29 #include <pthread.h>
30 #endif
31 
32 #if YAZ_POSIX_THREADS
33 static pthread_mutex_t nmem_mutex = PTHREAD_MUTEX_INITIALIZER;
34 #endif
35 static size_t no_nmem_handles = 0;
36 static size_t no_nmem_blocks = 0;
37 static size_t nmem_allocated = 0;
38 
39 #define NMEM_CHUNK (4*1024)
40 
41 struct nmem_block
42 {
43  char *buf; /* memory allocated in this block */
44  size_t size; /* size of buf */
45  size_t top; /* top of buffer */
46  struct nmem_block *next;
47 };
48 
50 {
51  size_t total;
52  struct nmem_block *blocks;
53  struct nmem_control *next;
54 };
55 
56 struct align {
57  char x;
58  union {
59  char c;
60  short s;
61  int i;
62  long l;
63 #if HAVE_LONG_LONG
64  long long ll;
65 #endif
66  float f;
67  double d;
68  } u;
69 };
70 
71 #define NMEM_ALIGN (offsetof(struct align, u))
72 
73 static int log_level = 0;
74 static int log_level_initialized = 0;
75 
76 static void nmem_lock(void)
77 {
78 #if YAZ_POSIX_THREADS
79  pthread_mutex_lock(&nmem_mutex);
80 #endif
81 }
82 
83 static void nmem_unlock(void)
84 {
85 #if YAZ_POSIX_THREADS
86  pthread_mutex_unlock(&nmem_mutex);
87 #endif
88 }
89 
90 static void free_block(struct nmem_block *p)
91 {
92  nmem_lock();
94  nmem_allocated -= p->size;
95  nmem_unlock();
96  xfree(p->buf);
97  xfree(p);
98  if (log_level)
99  yaz_log(log_level, "nmem free_block p=%p", p);
100 }
101 
102 /*
103  * acquire a block with a minimum of size free bytes.
104  */
105 static struct nmem_block *get_block(size_t size)
106 {
107  struct nmem_block *r;
108  size_t get = NMEM_CHUNK;
109 
110  if (log_level)
111  yaz_log(log_level, "nmem get_block size=%ld", (long) size);
112 
113  if (get < size)
114  get = size;
115  if (log_level)
116  yaz_log(log_level, "nmem get_block alloc new block size=%ld",
117  (long) get);
118 
119  r = (struct nmem_block *) xmalloc(sizeof(*r));
120  r->buf = (char *)xmalloc(r->size = get);
121  r->top = 0;
122  nmem_lock();
123  no_nmem_blocks++;
124  nmem_allocated += r->size;
125  nmem_unlock();
126  return r;
127 }
128 
130 {
131  struct nmem_block *t;
132 
133  yaz_log(log_level, "nmem_reset p=%p", n);
134  if (!n)
135  return;
136  while (n->blocks)
137  {
138  t = n->blocks;
139  n->blocks = n->blocks->next;
140  free_block(t);
141  }
142  n->total = 0;
143 }
144 
145 void *nmem_malloc(NMEM n, size_t size)
146 {
147  struct nmem_block *p;
148  char *r;
149 
150  if (!n)
151  {
152  yaz_log(YLOG_FATAL, "calling nmem_malloc with an null pointer");
153  abort();
154  }
155  p = n->blocks;
156  if (!p || p->size < size + p->top)
157  {
158  p = get_block(size);
159  p->next = n->blocks;
160  n->blocks = p;
161  }
162  r = p->buf + p->top;
163  /* align size */
164  p->top += (size + (NMEM_ALIGN - 1)) & ~(NMEM_ALIGN - 1);
165  n->total += size;
166  return r;
167 }
168 
169 size_t nmem_total(NMEM n)
170 {
171  return n->total;
172 }
173 
175 {
176 #if YAZ_POSIX_THREADS
177  pthread_atfork(nmem_lock, nmem_unlock, nmem_unlock);
178 #endif
179 }
180 
182 {
183  NMEM r;
184 
185  nmem_lock();
186  no_nmem_handles++;
187  nmem_unlock();
189  {
190  /* below will call nmem_init_globals once */
193  }
194 
195  r = (struct nmem_control *)xmalloc(sizeof(*r));
196 
197  r->blocks = 0;
198  r->total = 0;
199  r->next = 0;
200 
201  return r;
202 }
203 
205 {
206  if (!n)
207  return;
208 
209  nmem_reset(n);
210  xfree(n);
211  nmem_lock();
212  no_nmem_handles--;
213  nmem_unlock();
214 }
215 
216 void nmem_transfer(NMEM dst, NMEM src)
217 {
218  struct nmem_block *t;
219  while ((t = src->blocks))
220  {
221  src->blocks = t->next;
222  t->next = dst->blocks;
223  dst->blocks = t;
224  }
225  dst->total += src->total;
226  src->total = 0;
227 }
228 
229 int nmem_get_status(char *dst, size_t l)
230 {
231  size_t handles, blocks, allocated;
232 
233  nmem_lock();
234  handles = no_nmem_handles;
235  blocks = no_nmem_blocks;
236  allocated = nmem_allocated;
237  nmem_unlock();
238  yaz_snprintf(dst, l,
239  "<nmem>\n"
240  " <handles>%zd</handles>\n"
241  " <blocks>%zd</blocks>\n"
242  " <allocated>%zd</allocated>\n"
243  "</nmem>\n", handles, blocks, allocated);
244  return 0;
245 }
246 /*
247  * Local variables:
248  * c-basic-offset: 4
249  * c-file-style: "Stroustrup"
250  * indent-tabs-mode: nil
251  * End:
252  * vim: shiftwidth=4 tabstop=8 expandtab
253  */
254 
Header for errno utilities.
void yaz_log(int level, const char *fmt,...)
Writes log message.
Definition: log.c:487
int yaz_log_module_level(const char *name)
returns level for module
Definition: log.c:586
Logging utility.
#define YLOG_FATAL
log level: fatal
Definition: log.h:42
void nmem_init_globals(void)
Definition: nmem.c:174
void nmem_transfer(NMEM dst, NMEM src)
transfers memory from one NMEM handle to another
Definition: nmem.c:216
static void free_block(struct nmem_block *p)
Definition: nmem.c:90
static size_t no_nmem_blocks
Definition: nmem.c:36
static void nmem_lock(void)
Definition: nmem.c:76
static size_t nmem_allocated
Definition: nmem.c:37
static size_t no_nmem_handles
Definition: nmem.c:35
void nmem_reset(NMEM n)
releases memory associaged with an NMEM handle
Definition: nmem.c:129
int nmem_get_status(char *dst, size_t l)
returns memory status for NMEM - as XML
Definition: nmem.c:229
#define NMEM_CHUNK
Definition: nmem.c:39
static void nmem_unlock(void)
Definition: nmem.c:83
static int log_level
Definition: nmem.c:73
NMEM nmem_create(void)
returns new NMEM handle
Definition: nmem.c:181
static struct nmem_block * get_block(size_t size)
Definition: nmem.c:105
void * nmem_malloc(NMEM n, size_t size)
allocates memory block on NMEM handle
Definition: nmem.c:145
size_t nmem_total(NMEM n)
returns size in bytes of memory for NMEM handle
Definition: nmem.c:169
static int log_level_initialized
Definition: nmem.c:74
#define NMEM_ALIGN
Definition: nmem.c:71
void nmem_destroy(NMEM n)
destroys NMEM handle and memory associated with it
Definition: nmem.c:204
Header for Nibble Memory functions.
void yaz_snprintf(char *buf, size_t size, const char *fmt,...)
Definition: snprintf.c:31
Header for config file reading utilities.
Definition: nmem.c:56
double d
Definition: nmem.c:67
float f
Definition: nmem.c:66
long l
Definition: nmem.c:62
union align::@6 u
int i
Definition: nmem.c:61
char c
Definition: nmem.c:59
char x
Definition: nmem.c:57
short s
Definition: nmem.c:60
size_t top
Definition: nmem.c:45
size_t size
Definition: nmem.c:44
struct nmem_block * next
Definition: nmem.c:46
char * buf
Definition: nmem.c:43
struct nmem_control * next
Definition: nmem.c:53
struct nmem_block * blocks
Definition: nmem.c:52
size_t total
Definition: nmem.c:51
Header for memory handling functions.
#define xfree(x)
utility macro which calls xfree_f
Definition: xmalloc.h:53
#define xmalloc(x)
utility macro which calls malloc_f
Definition: xmalloc.h:49