From 61b1791584c85cba45a29e59940338445037cefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Wed, 31 Aug 2022 16:23:48 +0200 Subject: [PATCH] libs/libc: add obstack --- include/obstack.h | 479 ++++++++++++++++++++ libs/libc/Makefile | 1 + libs/libc/obstack/Make.defs | 29 ++ libs/libc/obstack/lib_obstack_alloc.c | 68 +++ libs/libc/obstack/lib_obstack_blank.c | 47 ++ libs/libc/obstack/lib_obstack_copy.c | 78 ++++ libs/libc/obstack/lib_obstack_finish.c | 98 ++++ libs/libc/obstack/lib_obstack_free.c | 76 ++++ libs/libc/obstack/lib_obstack_grow.c | 93 ++++ libs/libc/obstack/lib_obstack_init.c | 53 +++ libs/libc/obstack/lib_obstack_make_room.c | 105 +++++ libs/libc/obstack/lib_obstack_malloc.c | 81 ++++ libs/libc/obstack/lib_obstack_malloc.h | 53 +++ libs/libc/obstack/lib_obstack_object_size.c | 48 ++ libs/libc/obstack/lib_obstack_printf.c | 64 +++ libs/libc/obstack/lib_obstack_room.c | 51 +++ libs/libc/obstack/lib_obstack_vprintf.c | 97 ++++ 17 files changed, 1521 insertions(+) create mode 100644 include/obstack.h create mode 100644 libs/libc/obstack/Make.defs create mode 100644 libs/libc/obstack/lib_obstack_alloc.c create mode 100644 libs/libc/obstack/lib_obstack_blank.c create mode 100644 libs/libc/obstack/lib_obstack_copy.c create mode 100644 libs/libc/obstack/lib_obstack_finish.c create mode 100644 libs/libc/obstack/lib_obstack_free.c create mode 100644 libs/libc/obstack/lib_obstack_grow.c create mode 100644 libs/libc/obstack/lib_obstack_init.c create mode 100644 libs/libc/obstack/lib_obstack_make_room.c create mode 100644 libs/libc/obstack/lib_obstack_malloc.c create mode 100644 libs/libc/obstack/lib_obstack_malloc.h create mode 100644 libs/libc/obstack/lib_obstack_object_size.c create mode 100644 libs/libc/obstack/lib_obstack_printf.c create mode 100644 libs/libc/obstack/lib_obstack_room.c create mode 100644 libs/libc/obstack/lib_obstack_vprintf.c diff --git a/include/obstack.h b/include/obstack.h new file mode 100644 index 0000000000..97b2364df1 --- /dev/null +++ b/include/obstack.h @@ -0,0 +1,479 @@ +/**************************************************************************** + * include/obstack.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This is based on the GlibC API but the implementation is not exactly same. + * The major difference is how required memory is allocated. The GlibC + * implementation starts with 4KB of allocated space. That would make it + * impossible to use this on MCUs. This implementation rather tries to + * allocated only required amount of space and it won't allocate chunk unless + * grow functions are used and even then it uses realloc to release unused + * space. It also in default won't use 4KB per chunk but rather just BUFSIZ. + * + * Not implemented interface: + * obstack_alignment_mask: + * The current implementation does not provide any alignment guaranties. + * obstack_chunk_alloc and obstack_chunk_free: + * Internal implementation uses not only alloc and free but also realloc + * and thus standard implementations are used unconditionally instead of + * requiring users to provide declaration for these functions. + */ + +#ifndef __INCLUDE_OBSTACK_H +#define __INCLUDE_OBSTACK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_chunk_size + * + * Description: + * The access to the obstack configuration specifying the size of the + * single chunk used when growing object. + * It is documented t hat this is macro and that it is possible to use + * assignment to change the chunk size (eq.: obstack_chunk_size(h) = 1024). + * + * The default chunk size is set to BUFSIZ. + * + * The chunks size has to be always power of two due to the limitations of + * the obstack_make_room implementation! + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Size of the single chunk. + * + ****************************************************************************/ +#define obstack_chunk_size(h) ((h)->chunk_size) + +/**************************************************************************** + * Name: obstack_base + * + * Description: + * Provides access to the tentative starting address of the + * currently growing object. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Tentative starting address of the currently growing object. + * + ****************************************************************************/ +#define obstack_base(h) ((h)->object_base) + +/**************************************************************************** + * Name: obstack_next_free + * + * Description: + * Provides access to the tentative address just after the end of the + * currently growing object. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Address just after the end of the currently growing object. + * + ****************************************************************************/ +#define obstack_next_free(h) ((h)->next_free) + +/**************************************************************************** + * Name: obstack_blank_fast + * + * Description: + * Moves the end of the currently growing object by given size and thus + * adding given number of uninitialized bytes to the growing object. + * There is no check if there is enough room and thus it is easy to cause + * buffer overrun. Use only when you are sure that there is enough room! + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * size: number of bytes + * + * Returned Value: + * The new address just after the end of the currently growing object. + * + ****************************************************************************/ +#define obstack_blank_fast(h, size) ((h)->next_free += (size)) + +/**************************************************************************** + * Name: obstack_1grow_fast + * + * Description: + * Adds one byte to the currently growing object. + * There is no check if there is enough room and thus it is easy to cause + * buffer overrun. Use only when you are sure that there is enough room! + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * data: byte to be added + * + * Returned Value: + * Added byte. + * + ****************************************************************************/ +#define obstack_1grow_fast(h, data) (*((h)->next_free++) = (data)) + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +struct _obstack_chunk /* Chunk head. */ +{ + FAR char *limit; /* Address of char after this chunk */ + FAR struct _obstack_chunk *prev; /* Address of prior chunk or NULL */ +}; + +struct obstack +{ + size_t chunk_size; /* Preferred size to allocate chunks in */ + FAR struct _obstack_chunk *chunk; /* Address of current struct _obstack_chunk */ + FAR char *object_base; /* Address of object we are building */ + FAR char *next_free; /* Where to add next char to current object */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: obstack_init + * + * Description: + * Initialize obstack for allocation of objects. + * Compared to the GlibC version this won't initialize a first chunk. + * + * Input Parameters: + * h: pointer to the handle to initialize + * + ****************************************************************************/ + +void obstack_init(FAR struct obstack *h); + +/**************************************************************************** + * Name: obstack_alloc + * + * Description: + * Allocate an object of given size with uninitialized bytes. + * Compared to the GlibC version this uses malloc to allocate exactly + * required space (plus overhead) and nothing more. + * + * Input Parameters: + * h: pointer to the handle to allocate an object in + * size: number of bytes to allocate + * + ****************************************************************************/ + +FAR void *obstack_alloc(FAR struct obstack *h, size_t size); + +/**************************************************************************** + * Name: obstack_copy + * + * Description: + * Allocate an object of given size with contents copied from address. + * The same remarks regarding the allocation apply here as for + * obstack_alloc. + * + * Input Parameters: + * h: pointer to the handle to allocate an object in + * address: pointer to the bytes to be used to initialize new object + * size: number of bytes to allocate + * + ****************************************************************************/ + +FAR void *obstack_copy(FAR struct obstack *h, + FAR const void *address, size_t size); + +/**************************************************************************** + * Name: obstack_copy0 + * + * Description: + * Allocate an object of given size+1 with contents copied from address and + * append null byte at the end. + * The same remarks regarding the allocation apply here as for + * obstack_alloc. + * + * Input Parameters: + * h: pointer to the handle to allocate an object in + * address: pointer to the bytes to be used to initialize new object + * size: number of bytes to allocate (excluding the null byte) + * + ****************************************************************************/ + +FAR void *obstack_copy0(FAR struct obstack *h, + FAR const void *address, size_t size); + +/**************************************************************************** + * Name: obstack_free + * + * Description: + * Free objects (and everything allocated in the specified obstack more + * recently than object). You can pass NULL to free everything. + * The buffer the allocated object was preset is kept and thus can be + * immediately reused for growing. The only exception for this is when NULL + * is passed as in such case even the last buffer is freed. + * + * Input Parameters: + * h: pointer to the handle object belongs to + * object: the pointer to the object or NULL + * + ****************************************************************************/ + +void obstack_free(FAR struct obstack *h, FAR void *object); + +/**************************************************************************** + * Name: obstack_make_room + * + * Description: + * This is non-standard function that is probably available only on NuttX! + * Make sure that there is room in the buffer to fit object with given + * size. The allocation performed is in multiples of chunk_size specified + * for the obstack. + * + * Input Parameters: + * h: pointer to the handle where room should be made + * size: number of bytes to be free for growth + * + * Assumptions/Limitations: + * The obstack's chunk_size is expected to be power of two. This helps to + * eliminate division that might not be implemented in the HW and thus + * inefficient. + * + ****************************************************************************/ + +void obstack_make_room(struct obstack *h, size_t size); + +/**************************************************************************** + * Name: obstack_blank + * + * Description: + * Grow object by given size. The bytes are uninitialized. + * + * Input Parameters: + * h: pointer to the handle to allocated object to + * size: number of bytes to grow object + * + ****************************************************************************/ + +void obstack_blank(FAR struct obstack *h, size_t size); + +/**************************************************************************** + * Name: obstack_grow + * + * Description: + * Grow object by given size and allocated it with bytes from address. + * + * Input Parameters: + * h: pointer to the handle to allocated object to + * address: pointer to the bytes to be used to initialize the new object + * size: number of bytes to grow object + * + ****************************************************************************/ + +void obstack_grow(FAR struct obstack *h, + FAR const void *address, size_t size); + +/**************************************************************************** + * Name: obstack_grow0 + * + * Description: + * Grow object by given size+1 and allocated it with bytes from address + * plus null byte at the end. + * + * Input Parameters: + * h: pointer to the handle to allocated object to + * address: pointer to the bytes to be used to initialize the new object + * size: number of bytes to grow object (excluding the null byte) + * + ****************************************************************************/ + +void obstack_grow0(FAR struct obstack *h, + FAR const void *address, size_t size); + +/**************************************************************************** + * Name: obstack_1grow + * + * Description: + * Grow object by single data byte. + * + * Input Parameters: + * h: pointer to the handle to allocated object to + * data: byte to be added to the growing object + * + ****************************************************************************/ + +void obstack_1grow(FAR struct obstack *h, char data); + +/**************************************************************************** + * Name: obstack_finish + * + * Description: + * Finish growing object and receive address to it. + * Compared to the GlibC version this uses realloc to reduce buffer size to + * only allocated amount. The non-standard obstack_finish_norealloc can be + * used if you want the standard behavior for ever reason. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Permanent address to the object. + * + ****************************************************************************/ + +FAR void *obstack_finish(FAR struct obstack *h); + +/**************************************************************************** + * Name: obstack_finish_norealloc + * + * Description: + * Finish growing object and receive address to it without reallocating + * buffer to fit the object (keeping space for more growth). + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Permanent address to the object. + * + ****************************************************************************/ + +FAR void *obstack_finish_norealloc(FAR struct obstack *h); + +/**************************************************************************** + * Name: obstack_object_size + * + * Description: + * Calculate the size of the currently growing object. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Size of the object. + * + ****************************************************************************/ + +size_t obstack_object_size(FAR struct obstack *h); + +/**************************************************************************** + * Name: obstack_room + * + * Description: + * Calculate the number of bytes available for growth before reallocation + * is required. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Number of free bytes. + * + ****************************************************************************/ + +size_t obstack_room(FAR struct obstack *h); + +/**************************************************************************** + * Name: obstack_printf + * + * Description: + * This is similar to the asprintf except it uses obstack to allocate + * string on. The characters are written onto the end of the currently + * growing object and terminated by null byte. + * + * This function is defined in stdio.h in GlibC. There is no definition + * that would be in stdio.h required for these here and thus it is easier + * to just keep these functions here as user has to include obstack anyway + * to get the full functionality. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * fmt: format string with its format inputs followed. + * + * Returned Value: + * Number of characters added to the obstack excluding the null byte. + * + ****************************************************************************/ + +int obstack_printf(FAR struct obstack *h, FAR const char *fmt, ...) + printflike(2, 3); + +/**************************************************************************** + * Name: obstack_vprintf + * + * Description: + * This is similar to the vasprintf except it uses obstack to allocate + * string on. The characters are written onto the end of the currently + * growing object and terminated by null byte. + * + * The same remarks are applied here as for obstack_printf regarding the + * definition location in GlibC. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * fmt: format string + * ap: format string input as a variable argument list + * + * Returned Value: + * Number of characters added to the obstack excluding the null byte. + * + ****************************************************************************/ + +int obstack_vprintf(FAR struct obstack *h, FAR const char *fmt, va_list ap) + printflike(2, 0); + +/**************************************************************************** + * Name: obstack_alloc_failed_handler + * + * Description: + * Error handler called when 'obstack_chunk_alloc' failed to allocate more + * memory. This can be set to a user defined function which should either + * abort gracefully or use longjump - but shouldn't return. The default + * action is to print a message and abort. + * + ****************************************************************************/ + +extern void (*obstack_alloc_failed_handler) (void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_OBSTACK_H */ diff --git a/libs/libc/Makefile b/libs/libc/Makefile index 3b9258efa7..e69d32323d 100644 --- a/libs/libc/Makefile +++ b/libs/libc/Makefile @@ -42,6 +42,7 @@ include misc/Make.defs include modlib/Make.defs include net/Make.defs include netdb/Make.defs +include obstack/Make.defs include pthread/Make.defs include pwd/Make.defs include queue/Make.defs diff --git a/libs/libc/obstack/Make.defs b/libs/libc/obstack/Make.defs new file mode 100644 index 0000000000..c163af8989 --- /dev/null +++ b/libs/libc/obstack/Make.defs @@ -0,0 +1,29 @@ +############################################################################ +# libs/libc/obstack/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +CSRCS += lib_obstack_init.c lib_obstack_alloc.c lib_obstack_copy.c +CSRCS += lib_obstack_free.c lib_obstack_make_room.c lib_obstack_blank.c +CSRCS += lib_obstack_grow.c lib_obstack_finish.c +CSRCS += lib_obstack_object_size.c lib_obstack_room.c +CSRCS += lib_obstack_printf.c lib_obstack_vprintf.c +CSRCS += lib_obstack_malloc.c + +DEPPATH += --dep-path obstack +VPATH += :obstack diff --git a/libs/libc/obstack/lib_obstack_alloc.c b/libs/libc/obstack/lib_obstack_alloc.c new file mode 100644 index 0000000000..928526f74f --- /dev/null +++ b/libs/libc/obstack/lib_obstack_alloc.c @@ -0,0 +1,68 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_alloc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "lib_obstack_malloc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_alloc + * + * Description: + * Allocate an object of given size with uninitialized bytes. + * Compared to the GlibC version this uses malloc to allocate exactly + * required space (plus overhead) and nothing more. + * + * Input Parameters: + * h: pointer to the handle to allocate an object in + * size: number of bytes to allocate + * + ****************************************************************************/ + +FAR void *obstack_alloc(FAR struct obstack *h, size_t size) +{ + FAR struct _obstack_chunk *prev; + FAR void *res; + + if (h->chunk == NULL || (h->chunk->limit - h->object_base) < size) + { + /* TODO: could we just expand current allocation? */ + + prev = h->chunk; + h->chunk = lib_obstack_malloc(size + sizeof(struct _obstack_chunk)); + h->chunk->limit = + (FAR char *)h->chunk + sizeof(struct _obstack_chunk) + size; + h->chunk->prev = prev; + h->object_base = (FAR char *)h->chunk + sizeof(struct _obstack_chunk); + } + + res = h->object_base; + h->object_base += size; + h->next_free = h->object_base; + + return res; +} diff --git a/libs/libc/obstack/lib_obstack_blank.c b/libs/libc/obstack/lib_obstack_blank.c new file mode 100644 index 0000000000..407b3880af --- /dev/null +++ b/libs/libc/obstack/lib_obstack_blank.c @@ -0,0 +1,47 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_blank.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_blank + * + * Description: + * Grow object by given size. The bytes are uninitialized. + * + * Input Parameters: + * h: pointer to the handle to allocated object to + * size: number of bytes to grow object + * + ****************************************************************************/ + +void obstack_blank(FAR struct obstack *h, size_t size) +{ + obstack_make_room(h, size); + obstack_blank_fast(h, size); +} diff --git a/libs/libc/obstack/lib_obstack_copy.c b/libs/libc/obstack/lib_obstack_copy.c new file mode 100644 index 0000000000..18f7254899 --- /dev/null +++ b/libs/libc/obstack/lib_obstack_copy.c @@ -0,0 +1,78 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_copy.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_copy + * + * Description: + * Allocate an object of given size with contents copied from address. + * The same remarks regarding the allocation apply here as for + * obstack_alloc. + * + * Input Parameters: + * h: pointer to the handle to allocate an object in + * address: pointer to the bytes to be used to initialize new object + * size: number of bytes to allocate + * + ****************************************************************************/ + +FAR void *obstack_copy(FAR struct obstack *h, + FAR const void *address, size_t size) +{ + FAR void *res = obstack_alloc(h, size); + memcpy(res, address, size); + return res; +} + +/**************************************************************************** + * Name: obstack_copy0 + * + * Description: + * Allocate an object of given size+1 with contents copied from address and + * append null byte at the end. + * The same remarks regarding the allocation apply here as for + * obstack_alloc. + * + * Input Parameters: + * h: pointer to the handle to allocate an object in + * address: pointer to the bytes to be used to initialize new object + * size: number of bytes to allocate (excluding the null byte) + * + ****************************************************************************/ + +FAR void *obstack_copy0(FAR struct obstack *h, + FAR const void *address, size_t size) +{ + FAR char *res = obstack_alloc(h, size + 1); + memcpy(res, address, size); + res[size] = '\0'; + return res; +} diff --git a/libs/libc/obstack/lib_obstack_finish.c b/libs/libc/obstack/lib_obstack_finish.c new file mode 100644 index 0000000000..6c5fbcfc56 --- /dev/null +++ b/libs/libc/obstack/lib_obstack_finish.c @@ -0,0 +1,98 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_finish.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "lib_obstack_malloc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_finish + * + * Description: + * Finish growing object and receive address to it. + * Compared to the GlibC version this uses realloc to reduce buffer size to + * only allocated amount. The non-standard obstack_finish_norealloc can be + * used if you want the standard behavior for ever reason. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Permanent address to the object. + * + ****************************************************************************/ + +FAR void *obstack_finish(FAR struct obstack *h) +{ + size_t chsize; + void *chbase; + + /* To reduce memory used by allocation we reallocate the chunk to fit + * exactly data it contains. + * This can be performed only if there is no other object preset in the + * chunk already as we can't ensure that realloc won't move the data and + * thus invalidate already returned address to the existing object. + * The object can be there if called uses obstack_finish alongside with + * obstack_finish_norealloc. + */ + + chbase = (FAR char *)h->chunk + sizeof(struct _obstack_chunk); + if (chbase == h->object_base) + { + chsize = h->next_free - (FAR char *)h->chunk; + h->chunk = lib_obstack_realloc(h->chunk, chsize); + h->chunk->limit = (FAR void *)h->chunk + chsize; + h->object_base = h->chunk->limit; + h->next_free = h->chunk->limit; + return (FAR void *)h->chunk + sizeof(struct _obstack_chunk); + } + + return obstack_finish_norealloc(h); +} + +/**************************************************************************** + * Name: obstack_finish_norealloc + * + * Description: + * Finish growing object and receive address to it without reallocating + * buffer to fit the object (keeping space for more growth). + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Permanent address to the object. + * + ****************************************************************************/ + +FAR void *obstack_finish_norealloc(FAR struct obstack *h) +{ + FAR char *res = h->object_base; + h->object_base = h->next_free; + return res; +} diff --git a/libs/libc/obstack/lib_obstack_free.c b/libs/libc/obstack/lib_obstack_free.c new file mode 100644 index 0000000000..460e27f054 --- /dev/null +++ b/libs/libc/obstack/lib_obstack_free.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_free.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_free + * + * Description: + * Free objects (and everything allocated in the specified obstack more + * recently than object). You can pass NULL to free everything. + * The buffer the allocated object was preset is kept and thus can be + * immediately reused for growing. The only exception for this is when NULL + * is passed as in such case even the last buffer is freed. + * + * Input Parameters: + * h: pointer to the handle object belongs to + * object: the pointer to the object or NULL + * + ****************************************************************************/ + +void obstack_free(FAR struct obstack *h, FAR void *object) +{ + FAR struct _obstack_chunk *prev; + + while (h->chunk) + { + if (object >= (FAR void *)&h->chunk + sizeof(struct _obstack_chunk) + && object < (FAR void *)h->chunk->limit) + { + /* The object is in this chunk so just move object base. + * Note: this keeps the last chunk allocated. This is desirable + * behavior as we can decide if we want to reuse it by either + * passing NULL to free everything or the first returned object to + * keep the chunk allocated. + */ + + h->object_base = object; + h->next_free = object; + return; + } + + prev = h->chunk->prev; + lib_free(h->chunk); + h->chunk = prev; + } + + h->object_base = NULL; + h->next_free = NULL; +} diff --git a/libs/libc/obstack/lib_obstack_grow.c b/libs/libc/obstack/lib_obstack_grow.c new file mode 100644 index 0000000000..9574d29851 --- /dev/null +++ b/libs/libc/obstack/lib_obstack_grow.c @@ -0,0 +1,93 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_grow.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_grow + * + * Description: + * Grow object by given size and allocated it with bytes from address. + * + * Input Parameters: + * h: pointer to the handle to allocated object to + * address: pointer to the bytes to be used to initialize the new object + * size: number of bytes to grow object + * + ****************************************************************************/ + +void obstack_grow(FAR struct obstack *h, + FAR const void *address, size_t size) +{ + obstack_make_room(h, size); + memcpy(h->next_free, address, size); + h->next_free += size; +} + +/**************************************************************************** + * Name: obstack_grow0 + * + * Description: + * Grow object by given size+1 and allocated it with bytes from address + * plus null byte at the end. + * + * Input Parameters: + * h: pointer to the handle to allocated object to + * address: pointer to the bytes to be used to initialize the new object + * size: number of bytes to grow object (excluding the null byte) + * + ****************************************************************************/ + +void obstack_grow0(FAR struct obstack *h, + FAR const void *address, size_t size) +{ + obstack_make_room(h, size + 1); + memcpy(h->next_free, address, size); + h->next_free += size; + *h->next_free = '\0'; + h->next_free++; +} + +/**************************************************************************** + * Name: obstack_1grow + * + * Description: + * Grow object by single data byte. + * + * Input Parameters: + * h: pointer to the handle to allocated object to + * data: byte to be added to the growing object + * + ****************************************************************************/ + +void obstack_1grow(FAR struct obstack *h, char data) +{ + obstack_make_room(h, 1); + obstack_1grow_fast(h, data); +} diff --git a/libs/libc/obstack/lib_obstack_init.c b/libs/libc/obstack/lib_obstack_init.c new file mode 100644 index 0000000000..369fe476d4 --- /dev/null +++ b/libs/libc/obstack/lib_obstack_init.c @@ -0,0 +1,53 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_init.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_init + * + * Description: + * Initialize obstack for allocation of objects. + * Compared to the GlibC version this won't initialize a first chunk. + * + * Input Parameters: + * h: pointer to the handle to initialize + * + ****************************************************************************/ + +void obstack_init(FAR struct obstack *h) +{ + DEBUGASSERT(h != NULL); + + h->chunk_size = BUFSIZ; + h->chunk = NULL; + h->object_base = NULL; + h->next_free = NULL; +} diff --git a/libs/libc/obstack/lib_obstack_make_room.c b/libs/libc/obstack/lib_obstack_make_room.c new file mode 100644 index 0000000000..673fc22b3d --- /dev/null +++ b/libs/libc/obstack/lib_obstack_make_room.c @@ -0,0 +1,105 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_make_room.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include "lib_obstack_malloc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_make_room + * + * Description: + * This is non-standard function that is probably available only on NuttX! + * Make sure that there is room in the buffer to fit object with given + * size. The allocation performed is in multiples of chunk_size specified + * for the obstack. + * + * Input Parameters: + * h: pointer to the handle where room should be made + * size: number of bytes to be free for growth + * + * Assumptions/Limitations: + * The obstack's chunk_size is expected to be power of two. This helps to + * eliminate division that might not be implemented in the HW and thus + * inefficient. + * + ****************************************************************************/ + +void obstack_make_room(FAR struct obstack *h, size_t size) +{ + unsigned i; + size_t mask; + + DEBUGASSERT(h); + + if (obstack_room(h) >= size) + { + return; /* No need to allocate anything */ + } + + size_t object_size = obstack_object_size(h); + + size += object_size + sizeof(struct _obstack_chunk); + + /* Note: this is rounding up to the multiple of chunk size that is power of + * two. Thus this creates limitation that chunks can be only power of two. + */ + + mask = h->chunk_size; + for (i = 1; i < sizeof(size_t); i <<= 1) + mask |= mask >> i; + size = (size + mask) & ~mask; + + if (h->chunk == NULL || + h->object_base != (FAR char *)h->chunk + sizeof(struct _obstack_chunk)) + { + /* Allocate new chunk if there is something in the chunk already or if + * there is no chunk yet. + */ + + FAR struct _obstack_chunk *prev = h->chunk; + h->chunk = lib_obstack_malloc(size); + h->chunk->prev = prev; + + /* Move growing object to the new chunk */ + + memcpy((FAR char *)h->chunk + sizeof(struct _obstack_chunk), + h->object_base, object_size); + } + + else + { + h->chunk = lib_obstack_realloc(h->chunk, size); + } + + h->chunk->limit = + (FAR char *)h->chunk + sizeof(struct _obstack_chunk) + size; + h->object_base = (FAR char *)h->chunk + sizeof(struct _obstack_chunk); + h->next_free = h->object_base + object_size; +} diff --git a/libs/libc/obstack/lib_obstack_malloc.c b/libs/libc/obstack/lib_obstack_malloc.c new file mode 100644 index 0000000000..9ff028b575 --- /dev/null +++ b/libs/libc/obstack/lib_obstack_malloc.c @@ -0,0 +1,81 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_malloc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "lib_obstack_malloc.h" +#include +#include +#include +#include + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void default_alloc_failed_handler(void); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +void (*obstack_alloc_failed_handler)(void) = default_alloc_failed_handler; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void default_alloc_failed_handler(void) +{ + lerr("Failed to allocate to grow obstack"); + abort(); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +FAR void *lib_obstack_malloc(size_t size) +{ + FAR void *res; + + res = lib_malloc(size); + + if (res) + return res; + + obstack_alloc_failed_handler(); + PANIC(); +} + +FAR void *lib_obstack_realloc(FAR void *ptr, size_t size) +{ + FAR void *res; + + res = lib_realloc(ptr, size); + + if (res) + return res; + + obstack_alloc_failed_handler(); + PANIC(); +} diff --git a/libs/libc/obstack/lib_obstack_malloc.h b/libs/libc/obstack/lib_obstack_malloc.h new file mode 100644 index 0000000000..1906856fd7 --- /dev/null +++ b/libs/libc/obstack/lib_obstack_malloc.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_malloc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __LIBS_LIBC_OBSTACK_MALLOC_H +#define __LIBS_LIBC_OBSTACK_MALLOC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +FAR void *lib_obstack_malloc(size_t size); + +FAR void *lib_obstack_realloc(FAR void *ptr, size_t size); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __LIBS_LIBC_OBSTACK_MALLOC_H */ diff --git a/libs/libc/obstack/lib_obstack_object_size.c b/libs/libc/obstack/lib_obstack_object_size.c new file mode 100644 index 0000000000..c8bf13ad2f --- /dev/null +++ b/libs/libc/obstack/lib_obstack_object_size.c @@ -0,0 +1,48 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_object_size.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_object_size + * + * Description: + * Calculate the size of the currently growing object. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Size of the object. + * + ****************************************************************************/ + +size_t obstack_object_size(FAR struct obstack *h) +{ + return h->next_free - h->object_base; +} diff --git a/libs/libc/obstack/lib_obstack_printf.c b/libs/libc/obstack/lib_obstack_printf.c new file mode 100644 index 0000000000..74cfcc804a --- /dev/null +++ b/libs/libc/obstack/lib_obstack_printf.c @@ -0,0 +1,64 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_printf.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_printf + * + * Description: + * This is similar to the asprintf except it uses obstack to allocate + * string on. The characters are written onto the end of the currently + * growing object and terminated by null byte. + * + * This function is defined in stdio.h in GlibC. There is no definition + * that would be in stdio.h required for these here and thus it is easier + * to just keep these functions here as user has to include obstack anyway + * to get the full functionality. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * fmt: format string with its format inputs followed. + * + * Returned Value: + * Number of characters added to the obstack excluding the null byte. + * + ****************************************************************************/ + +int obstack_printf(FAR struct obstack *h, FAR const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = obstack_vprintf(h, fmt, ap); + va_end(ap); + + return res; +} diff --git a/libs/libc/obstack/lib_obstack_room.c b/libs/libc/obstack/lib_obstack_room.c new file mode 100644 index 0000000000..1afc308964 --- /dev/null +++ b/libs/libc/obstack/lib_obstack_room.c @@ -0,0 +1,51 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_room.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_room + * + * Description: + * Calculate the number of bytes available for growth before reallocation + * is required. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * + * Returned Value: + * Number of free bytes. + * + ****************************************************************************/ + +size_t obstack_room(FAR struct obstack *h) +{ + DEBUGASSERT(h); + return h->chunk != NULL ? h->chunk->limit - h->next_free : 0; +} diff --git a/libs/libc/obstack/lib_obstack_vprintf.c b/libs/libc/obstack/lib_obstack_vprintf.c new file mode 100644 index 0000000000..89d67318a4 --- /dev/null +++ b/libs/libc/obstack/lib_obstack_vprintf.c @@ -0,0 +1,97 @@ +/**************************************************************************** + * libs/libc/obstack/lib_obstack_vprintf.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct obstack_stream +{ + struct lib_outstream_s public; + FAR struct obstack *h; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int obstack_puts(FAR struct lib_outstream_s *this, + FAR const void *buf, int len) +{ + FAR struct obstack_stream *mthis = (FAR struct obstack_stream *)this; + + DEBUGASSERT(this); + + obstack_grow(mthis->h, buf, len); + + return len; +} + +static void obstack_putc(FAR struct lib_outstream_s *this, int ch) +{ + char tmp = ch; + obstack_puts(this, &tmp, 1); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: obstack_vprintf + * + * Description: + * This is similar to the vasprintf except it uses obstack to allocate + * string on. The characters are written onto the end of the currently + * growing object and terminated by null byte. + * + * The same remarks are applied here as for obstack_printf regarding the + * definition location in GlibC. + * + * Input Parameters: + * h: pointer to the handle used to grow the object. + * fmt: format string + * ap: format string input as a variable argument list + * + * Returned Value: + * Number of characters added to the obstack excluding the null byte. + * + ****************************************************************************/ + +int obstack_vprintf(FAR struct obstack *h, FAR const char *fmt, va_list ap) +{ + struct obstack_stream outstream; + + outstream.public.put = obstack_putc; + outstream.public.puts = obstack_puts; + outstream.public.flush = lib_noflush; + outstream.public.nput = 0; + outstream.h = h; + + return lib_vsprintf(&outstream.public, fmt, ap); +}