mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / ut / ut0mem.c
blob55f1c8593b89b531862b9d7703bece073a0719cb
1 /************************************************************************
2 Memory primitives
4 (c) 1994, 1995 Innobase Oy
6 Created 5/11/1994 Heikki Tuuri
7 *************************************************************************/
9 #include "ut0mem.h"
11 #ifdef UNIV_NONINL
12 #include "ut0mem.ic"
13 #endif
15 #include "mem0mem.h"
16 #include "os0sync.h"
17 #include "os0thread.h"
19 /* This struct is placed first in every allocated memory block */
20 typedef struct ut_mem_block_struct ut_mem_block_t;
22 /* The total amount of memory currently allocated from the OS with malloc */
23 ulint ut_total_allocated_memory = 0;
25 struct ut_mem_block_struct{
26 UT_LIST_NODE_T(ut_mem_block_t) mem_block_list;
27 /* mem block list node */
28 ulint size; /* size of allocated memory */
29 ulint magic_n;
32 #define UT_MEM_MAGIC_N 1601650166
34 /* List of all memory blocks allocated from the operating system
35 with malloc */
36 UT_LIST_BASE_NODE_T(ut_mem_block_t) ut_mem_block_list;
38 os_fast_mutex_t ut_list_mutex; /* this protects the list */
40 ibool ut_mem_block_list_inited = FALSE;
42 ulint* ut_mem_null_ptr = NULL;
44 /**************************************************************************
45 Initializes the mem block list at database startup. */
46 static
47 void
48 ut_mem_block_list_init(void)
49 /*========================*/
51 os_fast_mutex_init(&ut_list_mutex);
52 UT_LIST_INIT(ut_mem_block_list);
53 ut_mem_block_list_inited = TRUE;
56 /**************************************************************************
57 Allocates memory. */
59 void*
60 ut_malloc_low(
61 /*==========*/
62 /* out, own: allocated memory */
63 ulint n, /* in: number of bytes to allocate */
64 ibool assert_on_error)/* in: if TRUE, we crash mysqld if the
65 memory cannot be allocated */
67 ulint retry_count = 0;
68 void* ret;
70 ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
72 if (!ut_mem_block_list_inited) {
73 ut_mem_block_list_init();
75 retry:
76 os_fast_mutex_lock(&ut_list_mutex);
78 ret = malloc(n + sizeof(ut_mem_block_t));
80 if (ret == NULL && retry_count < 60) {
81 if (retry_count == 0) {
82 ut_print_timestamp(stderr);
84 fprintf(stderr,
85 " InnoDB: Error: cannot allocate"
86 " %lu bytes of\n"
87 "InnoDB: memory with malloc!"
88 " Total allocated memory\n"
89 "InnoDB: by InnoDB %lu bytes."
90 " Operating system errno: %lu\n"
91 "InnoDB: Check if you should"
92 " increase the swap file or\n"
93 "InnoDB: ulimits of your operating system.\n"
94 "InnoDB: On FreeBSD check you"
95 " have compiled the OS with\n"
96 "InnoDB: a big enough maximum process size.\n"
97 "InnoDB: Note that in most 32-bit"
98 " computers the process\n"
99 "InnoDB: memory space is limited"
100 " to 2 GB or 4 GB.\n"
101 "InnoDB: We keep retrying"
102 " the allocation for 60 seconds...\n",
103 (ulong) n, (ulong) ut_total_allocated_memory,
104 #ifdef __WIN__
105 (ulong) GetLastError()
106 #else
107 (ulong) errno
108 #endif
112 os_fast_mutex_unlock(&ut_list_mutex);
114 /* Sleep for a second and retry the allocation; maybe this is
115 just a temporary shortage of memory */
117 os_thread_sleep(1000000);
119 retry_count++;
121 goto retry;
124 if (ret == NULL) {
125 /* Flush stderr to make more probable that the error
126 message gets in the error file before we generate a seg
127 fault */
129 fflush(stderr);
131 os_fast_mutex_unlock(&ut_list_mutex);
133 /* Make an intentional seg fault so that we get a stack
134 trace */
135 /* Intentional segfault on NetWare causes an abend. Avoid this
136 by graceful exit handling in ut_a(). */
137 #if (!defined __NETWARE__)
138 if (assert_on_error) {
139 ut_print_timestamp(stderr);
141 fprintf(stderr,
142 " InnoDB: We now intentionally"
143 " generate a seg fault so that\n"
144 "InnoDB: on Linux we get a stack trace.\n");
146 if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
147 } else {
148 return(NULL);
150 #else
151 ut_a(0);
152 #endif
155 UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t));
157 ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t);
158 ((ut_mem_block_t*)ret)->magic_n = UT_MEM_MAGIC_N;
160 ut_total_allocated_memory += n + sizeof(ut_mem_block_t);
162 UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list,
163 ((ut_mem_block_t*)ret));
164 os_fast_mutex_unlock(&ut_list_mutex);
166 return((void*)((byte*)ret + sizeof(ut_mem_block_t)));
169 /**************************************************************************
170 Frees a memory block allocated with ut_malloc. */
172 void
173 ut_free(
174 /*====*/
175 void* ptr) /* in, own: memory block */
177 ut_mem_block_t* block;
179 block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
181 os_fast_mutex_lock(&ut_list_mutex);
183 ut_a(block->magic_n == UT_MEM_MAGIC_N);
184 ut_a(ut_total_allocated_memory >= block->size);
186 ut_total_allocated_memory -= block->size;
188 UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
189 free(block);
191 os_fast_mutex_unlock(&ut_list_mutex);
194 /**************************************************************************
195 Implements realloc. This is needed by /pars/lexyy.c. Otherwise, you should not
196 use this function because the allocation functions in mem0mem.h are the
197 recommended ones in InnoDB.
199 man realloc in Linux, 2004:
201 realloc() changes the size of the memory block pointed to
202 by ptr to size bytes. The contents will be unchanged to
203 the minimum of the old and new sizes; newly allocated memĀ­
204 ory will be uninitialized. If ptr is NULL, the call is
205 equivalent to malloc(size); if size is equal to zero, the
206 call is equivalent to free(ptr). Unless ptr is NULL, it
207 must have been returned by an earlier call to malloc(),
208 calloc() or realloc().
210 RETURN VALUE
211 realloc() returns a pointer to the newly allocated memory,
212 which is suitably aligned for any kind of variable and may
213 be different from ptr, or NULL if the request fails. If
214 size was equal to 0, either NULL or a pointer suitable to
215 be passed to free() is returned. If realloc() fails the
216 original block is left untouched - it is not freed or
217 moved. */
219 void*
220 ut_realloc(
221 /*=======*/
222 /* out, own: pointer to new mem block or NULL */
223 void* ptr, /* in: pointer to old block or NULL */
224 ulint size) /* in: desired size */
226 ut_mem_block_t* block;
227 ulint old_size;
228 ulint min_size;
229 void* new_ptr;
231 if (ptr == NULL) {
233 return(ut_malloc(size));
236 if (size == 0) {
237 ut_free(ptr);
239 return(NULL);
242 block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
244 ut_a(block->magic_n == UT_MEM_MAGIC_N);
246 old_size = block->size - sizeof(ut_mem_block_t);
248 if (size < old_size) {
249 min_size = size;
250 } else {
251 min_size = old_size;
254 new_ptr = ut_malloc(size);
256 if (new_ptr == NULL) {
258 return(NULL);
261 /* Copy the old data from ptr */
262 ut_memcpy(new_ptr, ptr, min_size);
264 ut_free(ptr);
266 return(new_ptr);
269 /**************************************************************************
270 Frees in shutdown all allocated memory not freed yet. */
272 void
273 ut_free_all_mem(void)
274 /*=================*/
276 ut_mem_block_t* block;
278 os_fast_mutex_free(&ut_list_mutex);
280 while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) {
282 ut_a(block->magic_n == UT_MEM_MAGIC_N);
283 ut_a(ut_total_allocated_memory >= block->size);
285 ut_total_allocated_memory -= block->size;
287 UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
288 free(block);
291 if (ut_total_allocated_memory != 0) {
292 fprintf(stderr,
293 "InnoDB: Warning: after shutdown"
294 " total allocated memory is %lu\n",
295 (ulong) ut_total_allocated_memory);
299 /**************************************************************************
300 Copies up to size - 1 characters from the NUL-terminated string src to
301 dst, NUL-terminating the result. Returns strlen(src), so truncation
302 occurred if the return value >= size. */
304 ulint
305 ut_strlcpy(
306 /*=======*/
307 /* out: strlen(src) */
308 char* dst, /* in: destination buffer */
309 const char* src, /* in: source buffer */
310 ulint size) /* in: size of destination buffer */
312 ulint src_size = strlen(src);
314 if (size != 0) {
315 ulint n = ut_min(src_size, size - 1);
317 memcpy(dst, src, n);
318 dst[n] = '\0';
321 return(src_size);
324 /**************************************************************************
325 Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
326 (size - 1) bytes of src, not the first. */
328 ulint
329 ut_strlcpy_rev(
330 /*===========*/
331 /* out: strlen(src) */
332 char* dst, /* in: destination buffer */
333 const char* src, /* in: source buffer */
334 ulint size) /* in: size of destination buffer */
336 ulint src_size = strlen(src);
338 if (size != 0) {
339 ulint n = ut_min(src_size, size - 1);
341 memcpy(dst, src + src_size - n, n + 1);
344 return(src_size);
347 /**************************************************************************
348 Return the number of times s2 occurs in s1. Overlapping instances of s2
349 are only counted once. */
351 ulint
352 ut_strcount(
353 /*========*/
354 /* out: the number of times s2 occurs in s1 */
355 const char* s1, /* in: string to search in */
356 const char* s2) /* in: string to search for */
358 ulint count = 0;
359 ulint len = strlen(s2);
361 if (len == 0) {
363 return(0);
366 for (;;) {
367 s1 = strstr(s1, s2);
369 if (!s1) {
371 break;
374 count++;
375 s1 += len;
378 return(count);
381 /**************************************************************************
382 Replace every occurrence of s1 in str with s2. Overlapping instances of s1
383 are only replaced once. */
385 char *
386 ut_strreplace(
387 /*==========*/
388 /* out, own: modified string, must be
389 freed with mem_free() */
390 const char* str, /* in: string to operate on */
391 const char* s1, /* in: string to replace */
392 const char* s2) /* in: string to replace s1 with */
394 char* new_str;
395 char* ptr;
396 const char* str_end;
397 ulint str_len = strlen(str);
398 ulint s1_len = strlen(s1);
399 ulint s2_len = strlen(s2);
400 ulint count = 0;
401 int len_delta = (int)s2_len - (int)s1_len;
403 str_end = str + str_len;
405 if (len_delta <= 0) {
406 len_delta = 0;
407 } else {
408 count = ut_strcount(str, s1);
411 new_str = mem_alloc(str_len + count * len_delta + 1);
412 ptr = new_str;
414 while (str) {
415 const char* next = strstr(str, s1);
417 if (!next) {
418 next = str_end;
421 memcpy(ptr, str, next - str);
422 ptr += next - str;
424 if (next == str_end) {
426 break;
429 memcpy(ptr, s2, s2_len);
430 ptr += s2_len;
432 str = next + s1_len;
435 *ptr = '\0';
437 return(new_str);