1
by brian
clean slate |
1 |
/************************************************************************
|
2 |
The memory management |
|
3 |
||
4 |
(c) 1994, 1995 Innobase Oy |
|
5 |
||
6 |
Created 6/8/1994 Heikki Tuuri |
|
7 |
*************************************************************************/
|
|
8 |
||
9 |
#include "mem0dbg.ic"
|
|
10 |
||
11 |
#include "mem0pool.h"
|
|
12 |
||
13 |
/*******************************************************************
|
|
14 |
Creates a memory heap block where data can be allocated. */ |
|
15 |
||
16 |
mem_block_t* |
|
17 |
mem_heap_create_block( |
|
18 |
/*==================*/
|
|
19 |
/* out, own: memory heap block, NULL if |
|
20 |
did not succeed (only possible for |
|
21 |
MEM_HEAP_BTR_SEARCH type heaps) */ |
|
22 |
mem_heap_t* heap, /* in: memory heap or NULL if first block |
|
23 |
should be created */ |
|
24 |
ulint n, /* in: number of bytes needed for user data, or |
|
25 |
if init_block is not NULL, its size in bytes */ |
|
26 |
void* init_block, /* in: init block in fast create, |
|
27 |
type must be MEM_HEAP_DYNAMIC */ |
|
28 |
ulint type, /* in: type of heap: MEM_HEAP_DYNAMIC or |
|
29 |
MEM_HEAP_BUFFER */ |
|
30 |
const char* file_name,/* in: file name where created */ |
|
31 |
ulint line); /* in: line where created */ |
|
32 |
/**********************************************************************
|
|
33 |
Frees a block from a memory heap. */ |
|
34 |
||
35 |
void
|
|
36 |
mem_heap_block_free( |
|
37 |
/*================*/
|
|
38 |
mem_heap_t* heap, /* in: heap */ |
|
39 |
mem_block_t* block); /* in: block to free */ |
|
40 |
/**********************************************************************
|
|
41 |
Frees the free_block field from a memory heap. */ |
|
42 |
||
43 |
void
|
|
44 |
mem_heap_free_block_free( |
|
45 |
/*=====================*/
|
|
46 |
mem_heap_t* heap); /* in: heap */ |
|
47 |
/*******************************************************************
|
|
48 |
Adds a new block to a memory heap. */ |
|
49 |
||
50 |
mem_block_t* |
|
51 |
mem_heap_add_block( |
|
52 |
/*===============*/
|
|
53 |
/* out: created block, NULL if did not |
|
54 |
succeed (only possible for |
|
55 |
MEM_HEAP_BTR_SEARCH type heaps)*/ |
|
56 |
mem_heap_t* heap, /* in: memory heap */ |
|
57 |
ulint n); /* in: number of bytes user needs */ |
|
58 |
||
59 |
UNIV_INLINE
|
|
60 |
void
|
|
61 |
mem_block_set_len(mem_block_t* block, ulint len) |
|
62 |
{
|
|
63 |
ut_ad(len > 0); |
|
64 |
||
65 |
block->len = len; |
|
66 |
}
|
|
67 |
||
68 |
UNIV_INLINE
|
|
69 |
ulint
|
|
70 |
mem_block_get_len(mem_block_t* block) |
|
71 |
{
|
|
72 |
return(block->len); |
|
73 |
}
|
|
74 |
||
75 |
UNIV_INLINE
|
|
76 |
void
|
|
77 |
mem_block_set_type(mem_block_t* block, ulint type) |
|
78 |
{
|
|
79 |
ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER) |
|
80 |
|| (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH)); |
|
81 |
||
82 |
block->type = type; |
|
83 |
}
|
|
84 |
||
85 |
UNIV_INLINE
|
|
86 |
ulint
|
|
87 |
mem_block_get_type(mem_block_t* block) |
|
88 |
{
|
|
89 |
return(block->type); |
|
90 |
}
|
|
91 |
||
92 |
UNIV_INLINE
|
|
93 |
void
|
|
94 |
mem_block_set_free(mem_block_t* block, ulint free) |
|
95 |
{
|
|
96 |
ut_ad(free > 0); |
|
97 |
ut_ad(free <= mem_block_get_len(block)); |
|
98 |
||
99 |
block->free = free; |
|
100 |
}
|
|
101 |
||
102 |
UNIV_INLINE
|
|
103 |
ulint
|
|
104 |
mem_block_get_free(mem_block_t* block) |
|
105 |
{
|
|
106 |
return(block->free); |
|
107 |
}
|
|
108 |
||
109 |
UNIV_INLINE
|
|
110 |
void
|
|
111 |
mem_block_set_start(mem_block_t* block, ulint start) |
|
112 |
{
|
|
113 |
ut_ad(start > 0); |
|
114 |
||
115 |
block->start = start; |
|
116 |
}
|
|
117 |
||
118 |
UNIV_INLINE
|
|
119 |
ulint
|
|
120 |
mem_block_get_start(mem_block_t* block) |
|
121 |
{
|
|
122 |
return(block->start); |
|
123 |
}
|
|
124 |
||
125 |
/*******************************************************************
|
|
126 |
Allocates n bytes of memory from a memory heap. */ |
|
127 |
UNIV_INLINE
|
|
128 |
void* |
|
129 |
mem_heap_alloc( |
|
130 |
/*===========*/
|
|
131 |
/* out: allocated storage, NULL if did not |
|
132 |
succeed (only possible for |
|
133 |
MEM_HEAP_BTR_SEARCH type heaps) */ |
|
134 |
mem_heap_t* heap, /* in: memory heap */ |
|
135 |
ulint n) /* in: number of bytes; if the heap is allowed |
|
136 |
to grow into the buffer pool, this must be |
|
137 |
<= MEM_MAX_ALLOC_IN_BUF */ |
|
138 |
{
|
|
139 |
mem_block_t* block; |
|
140 |
void* buf; |
|
141 |
ulint free; |
|
142 |
||
143 |
ut_ad(mem_heap_check(heap)); |
|
144 |
||
145 |
block = UT_LIST_GET_LAST(heap->base); |
|
146 |
||
147 |
ut_ad(!(block->type & MEM_HEAP_BUFFER) || (n <= MEM_MAX_ALLOC_IN_BUF)); |
|
148 |
||
149 |
/* Check if there is enough space in block. If not, create a new |
|
150 |
block to the heap */ |
|
151 |
||
152 |
if (mem_block_get_len(block) |
|
153 |
< mem_block_get_free(block) + MEM_SPACE_NEEDED(n)) { |
|
154 |
||
155 |
block = mem_heap_add_block(heap, n); |
|
156 |
||
157 |
if (block == NULL) { |
|
158 |
||
159 |
return(NULL); |
|
160 |
}
|
|
161 |
}
|
|
162 |
||
163 |
free = mem_block_get_free(block); |
|
164 |
||
165 |
buf = (byte*)block + free; |
|
166 |
||
167 |
mem_block_set_free(block, free + MEM_SPACE_NEEDED(n)); |
|
168 |
||
169 |
#ifdef UNIV_MEM_DEBUG
|
|
170 |
UNIV_MEM_ALLOC(buf, |
|
171 |
n + MEM_FIELD_HEADER_SIZE + MEM_FIELD_TRAILER_SIZE); |
|
172 |
||
173 |
/* In the debug version write debugging info to the field */ |
|
174 |
mem_field_init((byte*)buf, n); |
|
175 |
||
176 |
/* Advance buf to point at the storage which will be given to the |
|
177 |
caller */ |
|
178 |
buf = (byte*)buf + MEM_FIELD_HEADER_SIZE; |
|
179 |
||
180 |
#endif
|
|
181 |
#ifdef UNIV_SET_MEM_TO_ZERO
|
|
182 |
UNIV_MEM_ALLOC(buf, n); |
|
183 |
memset(buf, '\0', n); |
|
184 |
#endif
|
|
185 |
UNIV_MEM_ALLOC(buf, n); |
|
186 |
return(buf); |
|
187 |
}
|
|
188 |
||
189 |
/*********************************************************************
|
|
190 |
Returns a pointer to the heap top. */ |
|
191 |
UNIV_INLINE
|
|
192 |
byte* |
|
193 |
mem_heap_get_heap_top( |
|
194 |
/*==================*/
|
|
195 |
/* out: pointer to the heap top */ |
|
196 |
mem_heap_t* heap) /* in: memory heap */ |
|
197 |
{
|
|
198 |
mem_block_t* block; |
|
199 |
byte* buf; |
|
200 |
||
201 |
ut_ad(mem_heap_check(heap)); |
|
202 |
||
203 |
block = UT_LIST_GET_LAST(heap->base); |
|
204 |
||
205 |
buf = (byte*)block + mem_block_get_free(block); |
|
206 |
||
207 |
return(buf); |
|
208 |
}
|
|
209 |
||
210 |
/*********************************************************************
|
|
211 |
Frees the space in a memory heap exceeding the pointer given. The |
|
212 |
pointer must have been acquired from mem_heap_get_heap_top. The first |
|
213 |
memory block of the heap is not freed. */ |
|
214 |
UNIV_INLINE
|
|
215 |
void
|
|
216 |
mem_heap_free_heap_top( |
|
217 |
/*===================*/
|
|
218 |
mem_heap_t* heap, /* in: heap from which to free */ |
|
219 |
byte* old_top)/* in: pointer to old top of heap */ |
|
220 |
{
|
|
221 |
mem_block_t* block; |
|
222 |
mem_block_t* prev_block; |
|
223 |
#ifdef UNIV_MEM_DEBUG
|
|
224 |
ibool error; |
|
225 |
ulint total_size; |
|
226 |
ulint size; |
|
227 |
#endif
|
|
228 |
||
229 |
ut_ad(mem_heap_check(heap)); |
|
230 |
||
231 |
#ifdef UNIV_MEM_DEBUG
|
|
232 |
||
233 |
/* Validate the heap and get its total allocated size */ |
|
234 |
mem_heap_validate_or_print(heap, NULL, FALSE, &error, &total_size, |
|
235 |
NULL, NULL); |
|
236 |
ut_a(!error); |
|
237 |
||
238 |
/* Get the size below top pointer */ |
|
239 |
mem_heap_validate_or_print(heap, old_top, FALSE, &error, &size, NULL, |
|
240 |
NULL); |
|
241 |
ut_a(!error); |
|
242 |
||
243 |
#endif
|
|
244 |
||
245 |
block = UT_LIST_GET_LAST(heap->base); |
|
246 |
||
247 |
while (block != NULL) { |
|
248 |
if (((byte*)block + mem_block_get_free(block) >= old_top) |
|
249 |
&& ((byte*)block <= old_top)) { |
|
250 |
/* Found the right block */ |
|
251 |
||
252 |
break; |
|
253 |
}
|
|
254 |
||
255 |
/* Store prev_block value before freeing the current block |
|
256 |
(the current block will be erased in freeing) */ |
|
257 |
||
258 |
prev_block = UT_LIST_GET_PREV(list, block); |
|
259 |
||
260 |
mem_heap_block_free(heap, block); |
|
261 |
||
262 |
block = prev_block; |
|
263 |
}
|
|
264 |
||
265 |
ut_ad(block); |
|
266 |
||
267 |
/* Set the free field of block */ |
|
268 |
mem_block_set_free(block, old_top - (byte*)block); |
|
269 |
||
270 |
#ifdef UNIV_MEM_DEBUG
|
|
271 |
ut_ad(mem_block_get_start(block) <= mem_block_get_free(block)); |
|
272 |
||
273 |
/* In the debug version erase block from top up */ |
|
274 |
mem_erase_buf(old_top, (byte*)block + block->len - old_top); |
|
275 |
||
276 |
/* Update allocated memory count */ |
|
277 |
mutex_enter(&mem_hash_mutex); |
|
278 |
mem_current_allocated_memory -= (total_size - size); |
|
279 |
mutex_exit(&mem_hash_mutex); |
|
280 |
#else /* UNIV_MEM_DEBUG */
|
|
281 |
UNIV_MEM_ASSERT_W(old_top, (byte*)block + block->len - old_top); |
|
282 |
#endif /* UNIV_MEM_DEBUG */
|
|
283 |
UNIV_MEM_ALLOC(old_top, (byte*)block + block->len - old_top); |
|
284 |
||
285 |
/* If free == start, we may free the block if it is not the first |
|
286 |
one */ |
|
287 |
||
288 |
if ((heap != block) && (mem_block_get_free(block) |
|
289 |
== mem_block_get_start(block))) { |
|
290 |
mem_heap_block_free(heap, block); |
|
291 |
}
|
|
292 |
}
|
|
293 |
||
294 |
/*********************************************************************
|
|
295 |
Empties a memory heap. The first memory block of the heap is not freed. */ |
|
296 |
UNIV_INLINE
|
|
297 |
void
|
|
298 |
mem_heap_empty( |
|
299 |
/*===========*/
|
|
300 |
mem_heap_t* heap) /* in: heap to empty */ |
|
301 |
{
|
|
302 |
mem_heap_free_heap_top(heap, (byte*)heap + mem_block_get_start(heap)); |
|
303 |
||
304 |
if (heap->free_block) { |
|
305 |
mem_heap_free_block_free(heap); |
|
306 |
}
|
|
307 |
}
|
|
308 |
||
309 |
/*********************************************************************
|
|
310 |
Returns a pointer to the topmost element in a memory heap. The size of the |
|
311 |
element must be given. */ |
|
312 |
UNIV_INLINE
|
|
313 |
void* |
|
314 |
mem_heap_get_top( |
|
315 |
/*=============*/
|
|
316 |
/* out: pointer to the topmost element */ |
|
317 |
mem_heap_t* heap, /* in: memory heap */ |
|
318 |
ulint n) /* in: size of the topmost element */ |
|
319 |
{
|
|
320 |
mem_block_t* block; |
|
321 |
void* buf; |
|
322 |
||
323 |
ut_ad(mem_heap_check(heap)); |
|
324 |
||
325 |
block = UT_LIST_GET_LAST(heap->base); |
|
326 |
||
327 |
buf = (byte*)block + mem_block_get_free(block) - MEM_SPACE_NEEDED(n); |
|
328 |
||
329 |
#ifdef UNIV_MEM_DEBUG
|
|
330 |
ut_ad(mem_block_get_start(block) <=(ulint)((byte*)buf - (byte*)block)); |
|
331 |
||
332 |
/* In the debug version, advance buf to point at the storage which |
|
333 |
was given to the caller in the allocation*/ |
|
334 |
||
335 |
buf = (byte*)buf + MEM_FIELD_HEADER_SIZE; |
|
336 |
||
337 |
/* Check that the field lengths agree */ |
|
338 |
ut_ad(n == (ulint)mem_field_header_get_len(buf)); |
|
339 |
#endif
|
|
340 |
||
341 |
return(buf); |
|
342 |
}
|
|
343 |
||
344 |
/*********************************************************************
|
|
345 |
Frees the topmost element in a memory heap. The size of the element must be |
|
346 |
given. */ |
|
347 |
UNIV_INLINE
|
|
348 |
void
|
|
349 |
mem_heap_free_top( |
|
350 |
/*==============*/
|
|
351 |
mem_heap_t* heap, /* in: memory heap */ |
|
352 |
ulint n) /* in: size of the topmost element */ |
|
353 |
{
|
|
354 |
mem_block_t* block; |
|
355 |
||
356 |
ut_ad(mem_heap_check(heap)); |
|
357 |
||
358 |
block = UT_LIST_GET_LAST(heap->base); |
|
359 |
||
360 |
/* Subtract the free field of block */ |
|
361 |
mem_block_set_free(block, mem_block_get_free(block) |
|
362 |
- MEM_SPACE_NEEDED(n)); |
|
363 |
UNIV_MEM_ASSERT_W((byte*) block + mem_block_get_free(block), n); |
|
364 |
#ifdef UNIV_MEM_DEBUG
|
|
365 |
||
366 |
ut_ad(mem_block_get_start(block) <= mem_block_get_free(block)); |
|
367 |
||
368 |
/* In the debug version check the consistency, and erase field */ |
|
369 |
mem_field_erase((byte*)block + mem_block_get_free(block), n); |
|
370 |
#endif
|
|
371 |
||
372 |
/* If free == start, we may free the block if it is not the first |
|
373 |
one */ |
|
374 |
||
375 |
if ((heap != block) && (mem_block_get_free(block) |
|
376 |
== mem_block_get_start(block))) { |
|
377 |
mem_heap_block_free(heap, block); |
|
378 |
} else { |
|
379 |
/* Avoid a bogus UNIV_MEM_ASSERT_W() warning in a |
|
380 |
subsequent invocation of mem_heap_free_top(). |
|
381 |
Originally, this was UNIV_MEM_FREE(), to catch writes |
|
382 |
to freed memory. */ |
|
383 |
UNIV_MEM_ALLOC((byte*) block + mem_block_get_free(block), n); |
|
384 |
}
|
|
385 |
}
|
|
386 |
||
387 |
/*********************************************************************
|
|
388 |
NOTE: Use the corresponding macros instead of this function. Creates a |
|
389 |
memory heap. For debugging purposes, takes also the file name and line as |
|
390 |
argument. */ |
|
391 |
UNIV_INLINE
|
|
392 |
mem_heap_t* |
|
393 |
mem_heap_create_func( |
|
394 |
/*=================*/
|
|
395 |
/* out, own: memory heap, NULL if |
|
396 |
did not succeed (only possible for |
|
397 |
MEM_HEAP_BTR_SEARCH type heaps)*/ |
|
398 |
ulint n, /* in: desired start block size, |
|
399 |
this means that a single user buffer |
|
400 |
of size n will fit in the block, |
|
401 |
0 creates a default size block; |
|
402 |
if init_block is not NULL, n tells |
|
403 |
its size in bytes */ |
|
404 |
void* init_block, /* in: if very fast creation is |
|
405 |
wanted, the caller can reserve some |
|
406 |
memory from its stack, for example, |
|
407 |
and pass it as the the initial block |
|
408 |
to the heap: then no OS call of malloc |
|
409 |
is needed at the creation. CAUTION: |
|
410 |
the caller must make sure the initial |
|
411 |
block is not unintentionally erased |
|
412 |
(if allocated in the stack), before |
|
413 |
the memory heap is explicitly freed. */ |
|
414 |
ulint type, /* in: heap type */ |
|
415 |
const char* file_name, /* in: file name where created */ |
|
416 |
ulint line) /* in: line where created */ |
|
417 |
{
|
|
418 |
mem_block_t* block; |
|
419 |
||
420 |
if (n > 0) { |
|
421 |
block = mem_heap_create_block(NULL, n, init_block, type, |
|
422 |
file_name, line); |
|
423 |
} else { |
|
424 |
block = mem_heap_create_block(NULL, MEM_BLOCK_START_SIZE, |
|
425 |
init_block, type, |
|
426 |
file_name, line); |
|
427 |
}
|
|
428 |
||
429 |
if (block == NULL) { |
|
430 |
||
431 |
return(NULL); |
|
432 |
}
|
|
433 |
||
434 |
UT_LIST_INIT(block->base); |
|
435 |
||
436 |
/* Add the created block itself as the first block in the list */ |
|
437 |
UT_LIST_ADD_FIRST(list, block->base, block); |
|
438 |
||
439 |
#ifdef UNIV_MEM_DEBUG
|
|
440 |
||
441 |
mem_hash_insert(block, file_name, line); |
|
442 |
||
443 |
#endif
|
|
444 |
||
445 |
return(block); |
|
446 |
}
|
|
447 |
||
448 |
/*********************************************************************
|
|
449 |
NOTE: Use the corresponding macro instead of this function. Frees the space |
|
450 |
occupied by a memory heap. In the debug version erases the heap memory |
|
451 |
blocks. */ |
|
452 |
UNIV_INLINE
|
|
453 |
void
|
|
454 |
mem_heap_free_func( |
|
455 |
/*===============*/
|
|
456 |
mem_heap_t* heap, /* in, own: heap to be freed */ |
|
457 |
const char* file_name __attribute__((unused)), |
|
458 |
/* in: file name where freed */ |
|
459 |
ulint line __attribute__((unused))) |
|
460 |
{
|
|
461 |
mem_block_t* block; |
|
462 |
mem_block_t* prev_block; |
|
463 |
||
464 |
ut_ad(mem_heap_check(heap)); |
|
465 |
||
466 |
block = UT_LIST_GET_LAST(heap->base); |
|
467 |
||
468 |
#ifdef UNIV_MEM_DEBUG
|
|
469 |
||
470 |
/* In the debug version remove the heap from the hash table of heaps |
|
471 |
and check its consistency */ |
|
472 |
||
473 |
mem_hash_remove(heap, file_name, line); |
|
474 |
||
475 |
#endif
|
|
476 |
||
477 |
if (heap->free_block) { |
|
478 |
mem_heap_free_block_free(heap); |
|
479 |
}
|
|
480 |
||
481 |
while (block != NULL) { |
|
482 |
/* Store the contents of info before freeing current block |
|
483 |
(it is erased in freeing) */ |
|
484 |
||
485 |
prev_block = UT_LIST_GET_PREV(list, block); |
|
486 |
||
487 |
mem_heap_block_free(heap, block); |
|
488 |
||
489 |
block = prev_block; |
|
490 |
}
|
|
491 |
}
|
|
492 |
||
493 |
/*******************************************************************
|
|
494 |
NOTE: Use the corresponding macro instead of this function. |
|
495 |
Allocates a single buffer of memory from the dynamic memory of |
|
496 |
the C compiler. Is like malloc of C. The buffer must be freed |
|
497 |
with mem_free. */ |
|
498 |
UNIV_INLINE
|
|
499 |
void* |
|
500 |
mem_alloc_func( |
|
501 |
/*===========*/
|
|
502 |
/* out, own: free storage */ |
|
503 |
ulint n, /* in: desired number of bytes */ |
|
504 |
const char* file_name, /* in: file name where created */ |
|
505 |
ulint line /* in: line where created */ |
|
506 |
)
|
|
507 |
{
|
|
508 |
mem_heap_t* heap; |
|
509 |
void* buf; |
|
510 |
||
511 |
heap = mem_heap_create_func(n, NULL, MEM_HEAP_DYNAMIC, file_name, |
|
512 |
line); |
|
513 |
||
514 |
/* Note that as we created the first block in the heap big enough |
|
515 |
for the buffer requested by the caller, the buffer will be in the |
|
516 |
first block and thus we can calculate the pointer to the heap from |
|
517 |
the pointer to the buffer when we free the memory buffer. */ |
|
518 |
||
519 |
buf = mem_heap_alloc(heap, n); |
|
520 |
||
521 |
ut_a((byte*)heap == (byte*)buf - MEM_BLOCK_HEADER_SIZE |
|
522 |
- MEM_FIELD_HEADER_SIZE); |
|
523 |
return(buf); |
|
524 |
}
|
|
525 |
||
526 |
/*******************************************************************
|
|
527 |
NOTE: Use the corresponding macro instead of this function. Frees a single |
|
528 |
buffer of storage from the dynamic memory of the C compiler. Similar to the |
|
529 |
free of C. */ |
|
530 |
UNIV_INLINE
|
|
531 |
void
|
|
532 |
mem_free_func( |
|
533 |
/*==========*/
|
|
534 |
void* ptr, /* in, own: buffer to be freed */ |
|
535 |
const char* file_name, /* in: file name where created */ |
|
536 |
ulint line /* in: line where created */ |
|
537 |
)
|
|
538 |
{
|
|
539 |
mem_heap_t* heap; |
|
540 |
||
541 |
heap = (mem_heap_t*)((byte*)ptr - MEM_BLOCK_HEADER_SIZE |
|
542 |
- MEM_FIELD_HEADER_SIZE); |
|
543 |
mem_heap_free_func(heap, file_name, line); |
|
544 |
}
|
|
545 |
||
546 |
/*********************************************************************
|
|
547 |
Returns the space in bytes occupied by a memory heap. */ |
|
548 |
UNIV_INLINE
|
|
549 |
ulint
|
|
550 |
mem_heap_get_size( |
|
551 |
/*==============*/
|
|
552 |
mem_heap_t* heap) /* in: heap */ |
|
553 |
{
|
|
554 |
mem_block_t* block; |
|
555 |
ulint size = 0; |
|
556 |
||
557 |
ut_ad(mem_heap_check(heap)); |
|
558 |
||
559 |
block = heap; |
|
560 |
||
561 |
while (block != NULL) { |
|
562 |
||
563 |
size += mem_block_get_len(block); |
|
564 |
block = UT_LIST_GET_NEXT(list, block); |
|
565 |
}
|
|
566 |
||
567 |
if (heap->free_block) { |
|
568 |
size += UNIV_PAGE_SIZE; |
|
569 |
}
|
|
570 |
||
571 |
return(size); |
|
572 |
}
|
|
573 |
||
574 |
/**************************************************************************
|
|
575 |
Duplicates a NUL-terminated string. */ |
|
576 |
UNIV_INLINE
|
|
577 |
char* |
|
578 |
mem_strdup( |
|
579 |
/*=======*/
|
|
580 |
/* out, own: a copy of the string, |
|
581 |
must be deallocated with mem_free */ |
|
582 |
const char* str) /* in: string to be copied */ |
|
583 |
{
|
|
584 |
ulint len = strlen(str) + 1; |
|
585 |
return(memcpy(mem_alloc(len), str, len)); |
|
586 |
}
|
|
587 |
||
588 |
/**************************************************************************
|
|
589 |
Makes a NUL-terminated copy of a nonterminated string. */ |
|
590 |
UNIV_INLINE
|
|
591 |
char* |
|
592 |
mem_strdupl( |
|
593 |
/*========*/
|
|
594 |
/* out, own: a copy of the string, |
|
595 |
must be deallocated with mem_free */ |
|
596 |
const char* str, /* in: string to be copied */ |
|
597 |
ulint len) /* in: length of str, in bytes */ |
|
598 |
{
|
|
599 |
char* s = mem_alloc(len + 1); |
|
600 |
s[len] = 0; |
|
601 |
return(memcpy(s, str, len)); |
|
602 |
}
|
|
603 |
||
604 |
/**************************************************************************
|
|
605 |
Makes a NUL-terminated copy of a nonterminated string, |
|
606 |
allocated from a memory heap. */ |
|
607 |
UNIV_INLINE
|
|
608 |
char* |
|
609 |
mem_heap_strdupl( |
|
610 |
/*=============*/
|
|
611 |
/* out, own: a copy of the string */ |
|
612 |
mem_heap_t* heap, /* in: memory heap where string is allocated */ |
|
613 |
const char* str, /* in: string to be copied */ |
|
614 |
ulint len) /* in: length of str, in bytes */ |
|
615 |
{
|
|
616 |
char* s = mem_heap_alloc(heap, len + 1); |
|
617 |
s[len] = 0; |
|
618 |
return(memcpy(s, str, len)); |
|
619 |
}
|