xref: /third_party/mesa3d/src/util/ralloc.c (revision bf215546)
1/*
2 * Copyright © 2010 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#include <assert.h>
25#include <stdarg.h>
26#include <stdint.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "util/macros.h"
32#include "util/u_math.h"
33#include "util/u_printf.h"
34
35#include "ralloc.h"
36
37#define CANARY 0x5A1106
38
39/* Align the header's size so that ralloc() allocations will return with the
40 * same alignment as a libc malloc would have (8 on 32-bit GLIBC, 16 on
41 * 64-bit), avoiding performance penalities on x86 and alignment faults on
42 * ARM.
43 */
44struct ralloc_header
45{
46#if defined(__LP64__) || defined(_WIN64)
47   alignas(16)
48#else
49   alignas(8)
50#endif
51
52#ifndef NDEBUG
53   /* A canary value used to determine whether a pointer is ralloc'd. */
54   unsigned canary;
55#endif
56
57   struct ralloc_header *parent;
58
59   /* The first child (head of a linked list) */
60   struct ralloc_header *child;
61
62   /* Linked list of siblings */
63   struct ralloc_header *prev;
64   struct ralloc_header *next;
65
66   void (*destructor)(void *);
67};
68
69typedef struct ralloc_header ralloc_header;
70
71static void unlink_block(ralloc_header *info);
72static void unsafe_free(ralloc_header *info);
73
74static ralloc_header *
75get_header(const void *ptr)
76{
77   ralloc_header *info = (ralloc_header *) (((char *) ptr) -
78					    sizeof(ralloc_header));
79   assert(info->canary == CANARY);
80   return info;
81}
82
83#define PTR_FROM_HEADER(info) (((char *) info) + sizeof(ralloc_header))
84
85static void
86add_child(ralloc_header *parent, ralloc_header *info)
87{
88   if (parent != NULL) {
89      info->parent = parent;
90      info->next = parent->child;
91      parent->child = info;
92
93      if (info->next != NULL)
94	 info->next->prev = info;
95   }
96}
97
98void *
99ralloc_context(const void *ctx)
100{
101   return ralloc_size(ctx, 0);
102}
103
104void *
105ralloc_size(const void *ctx, size_t size)
106{
107   /* Some malloc allocation doesn't always align to 16 bytes even on 64 bits
108    * system, from Android bionic/tests/malloc_test.cpp:
109    *  - Allocations of a size that rounds up to a multiple of 16 bytes
110    *    must have at least 16 byte alignment.
111    *  - Allocations of a size that rounds up to a multiple of 8 bytes and
112    *    not 16 bytes, are only required to have at least 8 byte alignment.
113    */
114   void *block = malloc(align64(size + sizeof(ralloc_header),
115                                alignof(ralloc_header)));
116   ralloc_header *info;
117   ralloc_header *parent;
118
119   if (unlikely(block == NULL))
120      return NULL;
121
122   info = (ralloc_header *) block;
123   /* measurements have shown that calloc is slower (because of
124    * the multiplication overflow checking?), so clear things
125    * manually
126    */
127   info->parent = NULL;
128   info->child = NULL;
129   info->prev = NULL;
130   info->next = NULL;
131   info->destructor = NULL;
132
133   parent = ctx != NULL ? get_header(ctx) : NULL;
134
135   add_child(parent, info);
136
137#ifndef NDEBUG
138   info->canary = CANARY;
139#endif
140
141   return PTR_FROM_HEADER(info);
142}
143
144void *
145rzalloc_size(const void *ctx, size_t size)
146{
147   void *ptr = ralloc_size(ctx, size);
148
149   if (likely(ptr))
150      memset(ptr, 0, size);
151
152   return ptr;
153}
154
155/* helper function - assumes ptr != NULL */
156static void *
157resize(void *ptr, size_t size)
158{
159   ralloc_header *child, *old, *info;
160
161   old = get_header(ptr);
162   info = realloc(old, align64(size + sizeof(ralloc_header),
163                               alignof(ralloc_header)));
164
165   if (info == NULL)
166      return NULL;
167
168   /* Update parent and sibling's links to the reallocated node. */
169   if (info != old && info->parent != NULL) {
170      if (info->parent->child == old)
171	 info->parent->child = info;
172
173      if (info->prev != NULL)
174	 info->prev->next = info;
175
176      if (info->next != NULL)
177	 info->next->prev = info;
178   }
179
180   /* Update child->parent links for all children */
181   for (child = info->child; child != NULL; child = child->next)
182      child->parent = info;
183
184   return PTR_FROM_HEADER(info);
185}
186
187void *
188reralloc_size(const void *ctx, void *ptr, size_t size)
189{
190   if (unlikely(ptr == NULL))
191      return ralloc_size(ctx, size);
192
193   assert(ralloc_parent(ptr) == ctx);
194   return resize(ptr, size);
195}
196
197void *
198rerzalloc_size(const void *ctx, void *ptr, size_t old_size, size_t new_size)
199{
200   if (unlikely(ptr == NULL))
201      return rzalloc_size(ctx, new_size);
202
203   assert(ralloc_parent(ptr) == ctx);
204   ptr = resize(ptr, new_size);
205
206   if (new_size > old_size)
207      memset((char *)ptr + old_size, 0, new_size - old_size);
208
209   return ptr;
210}
211
212void *
213ralloc_array_size(const void *ctx, size_t size, unsigned count)
214{
215   if (count > SIZE_MAX/size)
216      return NULL;
217
218   return ralloc_size(ctx, size * count);
219}
220
221void *
222rzalloc_array_size(const void *ctx, size_t size, unsigned count)
223{
224   if (count > SIZE_MAX/size)
225      return NULL;
226
227   return rzalloc_size(ctx, size * count);
228}
229
230void *
231reralloc_array_size(const void *ctx, void *ptr, size_t size, unsigned count)
232{
233   if (count > SIZE_MAX/size)
234      return NULL;
235
236   return reralloc_size(ctx, ptr, size * count);
237}
238
239void *
240rerzalloc_array_size(const void *ctx, void *ptr, size_t size,
241                     unsigned old_count, unsigned new_count)
242{
243   if (new_count > SIZE_MAX/size)
244      return NULL;
245
246   return rerzalloc_size(ctx, ptr, size * old_count, size * new_count);
247}
248
249void
250ralloc_free(void *ptr)
251{
252   ralloc_header *info;
253
254   if (ptr == NULL)
255      return;
256
257   info = get_header(ptr);
258   unlink_block(info);
259   unsafe_free(info);
260}
261
262static void
263unlink_block(ralloc_header *info)
264{
265   /* Unlink from parent & siblings */
266   if (info->parent != NULL) {
267      if (info->parent->child == info)
268	 info->parent->child = info->next;
269
270      if (info->prev != NULL)
271	 info->prev->next = info->next;
272
273      if (info->next != NULL)
274	 info->next->prev = info->prev;
275   }
276   info->parent = NULL;
277   info->prev = NULL;
278   info->next = NULL;
279}
280
281static void
282unsafe_free(ralloc_header *info)
283{
284   /* Recursively free any children...don't waste time unlinking them. */
285   ralloc_header *temp;
286   while (info->child != NULL) {
287      temp = info->child;
288      info->child = temp->next;
289      unsafe_free(temp);
290   }
291
292   /* Free the block itself.  Call the destructor first, if any. */
293   if (info->destructor != NULL)
294      info->destructor(PTR_FROM_HEADER(info));
295
296   free(info);
297}
298
299void
300ralloc_steal(const void *new_ctx, void *ptr)
301{
302   ralloc_header *info, *parent;
303
304   if (unlikely(ptr == NULL))
305      return;
306
307   info = get_header(ptr);
308   parent = new_ctx ? get_header(new_ctx) : NULL;
309
310   unlink_block(info);
311
312   add_child(parent, info);
313}
314
315void
316ralloc_adopt(const void *new_ctx, void *old_ctx)
317{
318   ralloc_header *new_info, *old_info, *child;
319
320   if (unlikely(old_ctx == NULL))
321      return;
322
323   old_info = get_header(old_ctx);
324   new_info = get_header(new_ctx);
325
326   /* If there are no children, bail. */
327   if (unlikely(old_info->child == NULL))
328      return;
329
330   /* Set all the children's parent to new_ctx; get a pointer to the last child. */
331   for (child = old_info->child; child->next != NULL; child = child->next) {
332      child->parent = new_info;
333   }
334   child->parent = new_info;
335
336   /* Connect the two lists together; parent them to new_ctx; make old_ctx empty. */
337   child->next = new_info->child;
338   if (child->next)
339      child->next->prev = child;
340   new_info->child = old_info->child;
341   old_info->child = NULL;
342}
343
344void *
345ralloc_parent(const void *ptr)
346{
347   ralloc_header *info;
348
349   if (unlikely(ptr == NULL))
350      return NULL;
351
352   info = get_header(ptr);
353   return info->parent ? PTR_FROM_HEADER(info->parent) : NULL;
354}
355
356void
357ralloc_set_destructor(const void *ptr, void(*destructor)(void *))
358{
359   ralloc_header *info = get_header(ptr);
360   info->destructor = destructor;
361}
362
363char *
364ralloc_strdup(const void *ctx, const char *str)
365{
366   size_t n;
367   char *ptr;
368
369   if (unlikely(str == NULL))
370      return NULL;
371
372   n = strlen(str);
373   ptr = ralloc_array(ctx, char, n + 1);
374   memcpy(ptr, str, n);
375   ptr[n] = '\0';
376   return ptr;
377}
378
379char *
380ralloc_strndup(const void *ctx, const char *str, size_t max)
381{
382   size_t n;
383   char *ptr;
384
385   if (unlikely(str == NULL))
386      return NULL;
387
388   n = strnlen(str, max);
389   ptr = ralloc_array(ctx, char, n + 1);
390   memcpy(ptr, str, n);
391   ptr[n] = '\0';
392   return ptr;
393}
394
395/* helper routine for strcat/strncat - n is the exact amount to copy */
396static bool
397cat(char **dest, const char *str, size_t n)
398{
399   char *both;
400   size_t existing_length;
401   assert(dest != NULL && *dest != NULL);
402
403   existing_length = strlen(*dest);
404   both = resize(*dest, existing_length + n + 1);
405   if (unlikely(both == NULL))
406      return false;
407
408   memcpy(both + existing_length, str, n);
409   both[existing_length + n] = '\0';
410
411   *dest = both;
412   return true;
413}
414
415
416bool
417ralloc_strcat(char **dest, const char *str)
418{
419   return cat(dest, str, strlen(str));
420}
421
422bool
423ralloc_strncat(char **dest, const char *str, size_t n)
424{
425   return cat(dest, str, strnlen(str, n));
426}
427
428bool
429ralloc_str_append(char **dest, const char *str,
430                  size_t existing_length, size_t str_size)
431{
432   char *both;
433   assert(dest != NULL && *dest != NULL);
434
435   both = resize(*dest, existing_length + str_size + 1);
436   if (unlikely(both == NULL))
437      return false;
438
439   memcpy(both + existing_length, str, str_size);
440   both[existing_length + str_size] = '\0';
441
442   *dest = both;
443
444   return true;
445}
446
447char *
448ralloc_asprintf(const void *ctx, const char *fmt, ...)
449{
450   char *ptr;
451   va_list args;
452   va_start(args, fmt);
453   ptr = ralloc_vasprintf(ctx, fmt, args);
454   va_end(args);
455   return ptr;
456}
457
458char *
459ralloc_vasprintf(const void *ctx, const char *fmt, va_list args)
460{
461   size_t size = u_printf_length(fmt, args) + 1;
462
463   char *ptr = ralloc_size(ctx, size);
464   if (ptr != NULL)
465      vsnprintf(ptr, size, fmt, args);
466
467   return ptr;
468}
469
470bool
471ralloc_asprintf_append(char **str, const char *fmt, ...)
472{
473   bool success;
474   va_list args;
475   va_start(args, fmt);
476   success = ralloc_vasprintf_append(str, fmt, args);
477   va_end(args);
478   return success;
479}
480
481bool
482ralloc_vasprintf_append(char **str, const char *fmt, va_list args)
483{
484   size_t existing_length;
485   assert(str != NULL);
486   existing_length = *str ? strlen(*str) : 0;
487   return ralloc_vasprintf_rewrite_tail(str, &existing_length, fmt, args);
488}
489
490bool
491ralloc_asprintf_rewrite_tail(char **str, size_t *start, const char *fmt, ...)
492{
493   bool success;
494   va_list args;
495   va_start(args, fmt);
496   success = ralloc_vasprintf_rewrite_tail(str, start, fmt, args);
497   va_end(args);
498   return success;
499}
500
501bool
502ralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt,
503			      va_list args)
504{
505   size_t new_length;
506   char *ptr;
507
508   assert(str != NULL);
509
510   if (unlikely(*str == NULL)) {
511      // Assuming a NULL context is probably bad, but it's expected behavior.
512      *str = ralloc_vasprintf(NULL, fmt, args);
513      *start = strlen(*str);
514      return true;
515   }
516
517   new_length = u_printf_length(fmt, args);
518
519   ptr = resize(*str, *start + new_length + 1);
520   if (unlikely(ptr == NULL))
521      return false;
522
523   vsnprintf(ptr + *start, new_length + 1, fmt, args);
524   *str = ptr;
525   *start += new_length;
526   return true;
527}
528
529/***************************************************************************
530 * Linear allocator for short-lived allocations.
531 ***************************************************************************
532 *
533 * The allocator consists of a parent node (2K buffer), which requires
534 * a ralloc parent, and child nodes (allocations). Child nodes can't be freed
535 * directly, because the parent doesn't track them. You have to release
536 * the parent node in order to release all its children.
537 *
538 * The allocator uses a fixed-sized buffer with a monotonically increasing
539 * offset after each allocation. If the buffer is all used, another buffer
540 * is allocated, sharing the same ralloc parent, so all buffers are at
541 * the same level in the ralloc hierarchy.
542 *
543 * The linear parent node is always the first buffer and keeps track of all
544 * other buffers.
545 */
546
547#define MIN_LINEAR_BUFSIZE 2048
548#define SUBALLOC_ALIGNMENT 8
549#define LMAGIC 0x87b9c7d3
550
551struct linear_header {
552
553   /* align first member to align struct */
554#if defined(__LP64__) || defined(_WIN64)
555   alignas(16)
556#else
557   alignas(8)
558#endif
559
560#ifndef NDEBUG
561   unsigned magic;   /* for debugging */
562#endif
563   unsigned offset;  /* points to the first unused byte in the buffer */
564   unsigned size;    /* size of the buffer */
565   void *ralloc_parent;          /* new buffers will use this */
566   struct linear_header *next;   /* next buffer if we have more */
567   struct linear_header *latest; /* the only buffer that has free space */
568
569   /* After this structure, the buffer begins.
570    * Each suballocation consists of linear_size_chunk as its header followed
571    * by the suballocation, so it goes:
572    *
573    * - linear_size_chunk
574    * - allocated space
575    * - linear_size_chunk
576    * - allocated space
577    * etc.
578    *
579    * linear_size_chunk is only needed by linear_realloc.
580    */
581};
582
583struct linear_size_chunk {
584   unsigned size; /* for realloc */
585   unsigned _padding;
586};
587
588typedef struct linear_header linear_header;
589typedef struct linear_size_chunk linear_size_chunk;
590
591#define LINEAR_PARENT_TO_HEADER(parent) \
592   (linear_header*) \
593   ((char*)(parent) - sizeof(linear_size_chunk) - sizeof(linear_header))
594
595/* Allocate the linear buffer with its header. */
596static linear_header *
597create_linear_node(void *ralloc_ctx, unsigned min_size)
598{
599   linear_header *node;
600
601   min_size += sizeof(linear_size_chunk);
602
603   if (likely(min_size < MIN_LINEAR_BUFSIZE))
604      min_size = MIN_LINEAR_BUFSIZE;
605
606   node = ralloc_size(ralloc_ctx, sizeof(linear_header) + min_size);
607   if (unlikely(!node))
608      return NULL;
609
610#ifndef NDEBUG
611   node->magic = LMAGIC;
612#endif
613   node->offset = 0;
614   node->size = min_size;
615   node->ralloc_parent = ralloc_ctx;
616   node->next = NULL;
617   node->latest = node;
618   return node;
619}
620
621void *
622linear_alloc_child(void *parent, unsigned size)
623{
624   linear_header *first = LINEAR_PARENT_TO_HEADER(parent);
625   linear_header *latest = first->latest;
626   linear_header *new_node;
627   linear_size_chunk *ptr;
628   unsigned full_size;
629
630   assert(first->magic == LMAGIC);
631   assert(!latest->next);
632
633   size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
634   full_size = sizeof(linear_size_chunk) + size;
635
636   if (unlikely(latest->offset + full_size > latest->size)) {
637      /* allocate a new node */
638      new_node = create_linear_node(latest->ralloc_parent, size);
639      if (unlikely(!new_node))
640         return NULL;
641
642      first->latest = new_node;
643      latest->latest = new_node;
644      latest->next = new_node;
645      latest = new_node;
646   }
647
648   ptr = (linear_size_chunk *)((char*)&latest[1] + latest->offset);
649   ptr->size = size;
650   latest->offset += full_size;
651
652   assert((uintptr_t)&ptr[1] % SUBALLOC_ALIGNMENT == 0);
653   return &ptr[1];
654}
655
656void *
657linear_alloc_parent(void *ralloc_ctx, unsigned size)
658{
659   linear_header *node;
660
661   if (unlikely(!ralloc_ctx))
662      return NULL;
663
664   size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
665
666   node = create_linear_node(ralloc_ctx, size);
667   if (unlikely(!node))
668      return NULL;
669
670   return linear_alloc_child((char*)node +
671                             sizeof(linear_header) +
672                             sizeof(linear_size_chunk), size);
673}
674
675void *
676linear_zalloc_child(void *parent, unsigned size)
677{
678   void *ptr = linear_alloc_child(parent, size);
679
680   if (likely(ptr))
681      memset(ptr, 0, size);
682   return ptr;
683}
684
685void *
686linear_zalloc_parent(void *parent, unsigned size)
687{
688   void *ptr = linear_alloc_parent(parent, size);
689
690   if (likely(ptr))
691      memset(ptr, 0, size);
692   return ptr;
693}
694
695void
696linear_free_parent(void *ptr)
697{
698   linear_header *node;
699
700   if (unlikely(!ptr))
701      return;
702
703   node = LINEAR_PARENT_TO_HEADER(ptr);
704   assert(node->magic == LMAGIC);
705
706   while (node) {
707      void *ptr = node;
708
709      node = node->next;
710      ralloc_free(ptr);
711   }
712}
713
714void
715ralloc_steal_linear_parent(void *new_ralloc_ctx, void *ptr)
716{
717   linear_header *node;
718
719   if (unlikely(!ptr))
720      return;
721
722   node = LINEAR_PARENT_TO_HEADER(ptr);
723   assert(node->magic == LMAGIC);
724
725   while (node) {
726      ralloc_steal(new_ralloc_ctx, node);
727      node->ralloc_parent = new_ralloc_ctx;
728      node = node->next;
729   }
730}
731
732void *
733ralloc_parent_of_linear_parent(void *ptr)
734{
735   linear_header *node = LINEAR_PARENT_TO_HEADER(ptr);
736   assert(node->magic == LMAGIC);
737   return node->ralloc_parent;
738}
739
740void *
741linear_realloc(void *parent, void *old, unsigned new_size)
742{
743   unsigned old_size = 0;
744   ralloc_header *new_ptr;
745
746   new_ptr = linear_alloc_child(parent, new_size);
747
748   if (unlikely(!old))
749      return new_ptr;
750
751   old_size = ((linear_size_chunk*)old)[-1].size;
752
753   if (likely(new_ptr && old_size))
754      memcpy(new_ptr, old, MIN2(old_size, new_size));
755
756   return new_ptr;
757}
758
759/* All code below is pretty much copied from ralloc and only the alloc
760 * calls are different.
761 */
762
763char *
764linear_strdup(void *parent, const char *str)
765{
766   unsigned n;
767   char *ptr;
768
769   if (unlikely(!str))
770      return NULL;
771
772   n = strlen(str);
773   ptr = linear_alloc_child(parent, n + 1);
774   if (unlikely(!ptr))
775      return NULL;
776
777   memcpy(ptr, str, n);
778   ptr[n] = '\0';
779   return ptr;
780}
781
782char *
783linear_asprintf(void *parent, const char *fmt, ...)
784{
785   char *ptr;
786   va_list args;
787   va_start(args, fmt);
788   ptr = linear_vasprintf(parent, fmt, args);
789   va_end(args);
790   return ptr;
791}
792
793char *
794linear_vasprintf(void *parent, const char *fmt, va_list args)
795{
796   unsigned size = u_printf_length(fmt, args) + 1;
797
798   char *ptr = linear_alloc_child(parent, size);
799   if (ptr != NULL)
800      vsnprintf(ptr, size, fmt, args);
801
802   return ptr;
803}
804
805bool
806linear_asprintf_append(void *parent, char **str, const char *fmt, ...)
807{
808   bool success;
809   va_list args;
810   va_start(args, fmt);
811   success = linear_vasprintf_append(parent, str, fmt, args);
812   va_end(args);
813   return success;
814}
815
816bool
817linear_vasprintf_append(void *parent, char **str, const char *fmt, va_list args)
818{
819   size_t existing_length;
820   assert(str != NULL);
821   existing_length = *str ? strlen(*str) : 0;
822   return linear_vasprintf_rewrite_tail(parent, str, &existing_length, fmt, args);
823}
824
825bool
826linear_asprintf_rewrite_tail(void *parent, char **str, size_t *start,
827                             const char *fmt, ...)
828{
829   bool success;
830   va_list args;
831   va_start(args, fmt);
832   success = linear_vasprintf_rewrite_tail(parent, str, start, fmt, args);
833   va_end(args);
834   return success;
835}
836
837bool
838linear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start,
839                              const char *fmt, va_list args)
840{
841   size_t new_length;
842   char *ptr;
843
844   assert(str != NULL);
845
846   if (unlikely(*str == NULL)) {
847      *str = linear_vasprintf(parent, fmt, args);
848      *start = strlen(*str);
849      return true;
850   }
851
852   new_length = u_printf_length(fmt, args);
853
854   ptr = linear_realloc(parent, *str, *start + new_length + 1);
855   if (unlikely(ptr == NULL))
856      return false;
857
858   vsnprintf(ptr + *start, new_length + 1, fmt, args);
859   *str = ptr;
860   *start += new_length;
861   return true;
862}
863
864/* helper routine for strcat/strncat - n is the exact amount to copy */
865static bool
866linear_cat(void *parent, char **dest, const char *str, unsigned n)
867{
868   char *both;
869   unsigned existing_length;
870   assert(dest != NULL && *dest != NULL);
871
872   existing_length = strlen(*dest);
873   both = linear_realloc(parent, *dest, existing_length + n + 1);
874   if (unlikely(both == NULL))
875      return false;
876
877   memcpy(both + existing_length, str, n);
878   both[existing_length + n] = '\0';
879
880   *dest = both;
881   return true;
882}
883
884bool
885linear_strcat(void *parent, char **dest, const char *str)
886{
887   return linear_cat(parent, dest, str, strlen(str));
888}
889