~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/include/mem0mem.ic

  • Committer: Monty Taylor
  • Date: 2008-10-30 19:42:06 UTC
  • mto: (520.4.38 devel)
  • mto: This revision was merged to the branch mainline in revision 572.
  • Revision ID: monty@inaugust.com-20081030194206-fzus6yqlw1ekru65
Removed handler from common_includes.

Show diffs side-by-side

added added

removed removed

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