mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
newlib: implement posix_memalign, sysconf, realpath
Closes https://github.com/espressif/esp-idf/issues/6119 Closes https://github.com/espressif/esp-idf/issues/7798
This commit is contained in:
parent
8d329951c3
commit
d83ce227aa
@ -17,7 +17,9 @@ set(srcs
|
||||
"syscalls.c"
|
||||
"termios.c"
|
||||
"stdatomic.c"
|
||||
"time.c")
|
||||
"time.c"
|
||||
"sysconf.c"
|
||||
"realpath.c")
|
||||
set(include_dirs platform_include)
|
||||
|
||||
if(CONFIG_SPIRAM_CACHE_WORKAROUND)
|
||||
|
@ -1,20 +1,13 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/reent.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
@ -81,6 +74,23 @@ void* memalign(size_t alignment, size_t n)
|
||||
return heap_caps_aligned_alloc(alignment, n, MALLOC_CAP_DEFAULT);
|
||||
}
|
||||
|
||||
int posix_memalign(void **out_ptr, size_t alignment, size_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
/* returning NULL for zero size is allowed, don't treat this as an error */
|
||||
*out_ptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
void *result = heap_caps_aligned_alloc(alignment, size, MALLOC_CAP_DEFAULT);
|
||||
if (result != NULL) {
|
||||
/* Modify output pointer only on success */
|
||||
*out_ptr = result;
|
||||
return 0;
|
||||
}
|
||||
/* Note: error returned, not set via errno! */
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* No-op function, used to force linking this file,
|
||||
instead of the heap implementation from newlib.
|
||||
*/
|
||||
|
125
components/newlib/realpath.c
Normal file
125
components/newlib/realpath.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
/* realpath logic:
|
||||
* 1. prepend CWD (/)
|
||||
* 2. iterate over components (search until next '/' or end of line)
|
||||
* - empty, skip the component
|
||||
* - if it is '.', skip the component
|
||||
* - if it is '..'
|
||||
* - and out_level == 0, ??? ('/..')
|
||||
* - otherwise, reverse-search for '/', set out_pos to that - 1, decrement out_level
|
||||
* - otherwise, add the component to output, increment out_level
|
||||
*/
|
||||
|
||||
char * realpath(const char *file_name, char *resolved_name)
|
||||
{
|
||||
char * out_path = resolved_name;
|
||||
if (out_path == NULL) {
|
||||
/* allowed as an extension, allocate memory for the output path */
|
||||
out_path = malloc(PATH_MAX);
|
||||
if (out_path == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* canonical path starts with / */
|
||||
strlcpy(out_path, "/", PATH_MAX);
|
||||
|
||||
/* pointers moving over the input and output path buffers */
|
||||
const char* in_ptr = file_name;
|
||||
char* out_ptr = out_path + 1;
|
||||
/* number of path components in the output buffer */
|
||||
size_t out_depth = 0;
|
||||
|
||||
|
||||
while (*in_ptr) {
|
||||
/* "path component" is the part between two '/' path separators.
|
||||
* locate the next path component in the input path:
|
||||
*/
|
||||
const char* end_of_path_component = strchrnul(in_ptr, '/');
|
||||
size_t path_component_len = end_of_path_component - in_ptr;
|
||||
|
||||
if (path_component_len == 0 ||
|
||||
(path_component_len == 1 && in_ptr[0] == '.')) {
|
||||
/* empty path component or '.' - nothing to do */
|
||||
} else if (path_component_len == 2 && in_ptr[0] == '.' && in_ptr[1] == '.') {
|
||||
/* '..' - remove one path component from the output */
|
||||
if (out_depth == 0) {
|
||||
/* nothing to remove */
|
||||
} else if (out_depth == 1) {
|
||||
/* there is only one path component in output;
|
||||
* remove it, but keep the leading separator
|
||||
*/
|
||||
out_ptr = out_path + 1;
|
||||
*out_ptr = '\0';
|
||||
out_depth = 0;
|
||||
} else {
|
||||
/* remove last path component and the separator preceding it */
|
||||
char * prev_sep = strrchr(out_path, '/');
|
||||
assert(prev_sep > out_path); /* this shouldn't be the leading separator */
|
||||
out_ptr = prev_sep;
|
||||
*out_ptr = '\0';
|
||||
--out_depth;
|
||||
}
|
||||
} else {
|
||||
/* copy path component to output; +1 is for the separator */
|
||||
if (out_ptr - out_path + 1 + path_component_len > PATH_MAX - 1) {
|
||||
/* output buffer insufficient */
|
||||
errno = E2BIG;
|
||||
goto fail;
|
||||
} else {
|
||||
/* add separator if necessary */
|
||||
if (out_depth > 0) {
|
||||
*out_ptr = '/';
|
||||
++out_ptr;
|
||||
}
|
||||
memcpy(out_ptr, in_ptr, path_component_len);
|
||||
out_ptr += path_component_len;
|
||||
*out_ptr = '\0';
|
||||
++out_depth;
|
||||
}
|
||||
}
|
||||
/* move input pointer to separator right after this path component */
|
||||
in_ptr += path_component_len;
|
||||
if (*in_ptr != '\0') {
|
||||
/* move past it unless already at the end of the input string */
|
||||
++in_ptr;
|
||||
}
|
||||
}
|
||||
return out_path;
|
||||
|
||||
fail:
|
||||
if (resolved_name == NULL) {
|
||||
/* out_path was allocated, free it */
|
||||
free(out_path);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char * getcwd(char *buf, size_t size)
|
||||
{
|
||||
if (buf == NULL) {
|
||||
return strdup("/");
|
||||
}
|
||||
strlcpy(buf, "/", size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int chdir(const char *path)
|
||||
{
|
||||
(void) path;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
27
components/newlib/sysconf.c
Normal file
27
components/newlib/sysconf.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_FREERTOS_UNICORE
|
||||
#define CPU_NUM 1
|
||||
#else
|
||||
#define CPU_NUM CONFIG_SOC_CPU_CORES_NUM
|
||||
#endif
|
||||
|
||||
long sysconf(int arg)
|
||||
{
|
||||
switch (arg) {
|
||||
case _SC_NPROCESSORS_CONF:
|
||||
case _SC_NPROCESSORS_ONLN:
|
||||
return CPU_NUM;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
idf_component_register(SRCS
|
||||
"test_newlib_main.c"
|
||||
"test_stdatomic.c"
|
||||
"test_misc.c"
|
||||
REQUIRES test_utils
|
||||
PRIV_REQUIRES unity)
|
||||
|
95
components/newlib/test_apps/main/test_misc.c
Normal file
95
components/newlib/test_apps/main/test_misc.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdlib.h>
|
||||
#include "unity.h"
|
||||
#include "unity_fixture.h"
|
||||
|
||||
// unity_fixture_malloc_overrides.h defines 'free' as 'unity_free',
|
||||
// which can only handle pointers allocated with 'unity_malloc'.
|
||||
// This test allocates memory via 'posix_memalign' so calling 'free'
|
||||
// for these pointers causes the heap guards check to fail.
|
||||
#undef free
|
||||
|
||||
TEST_GROUP(misc);
|
||||
|
||||
TEST_SETUP(misc)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_TEAR_DOWN(misc)
|
||||
{
|
||||
}
|
||||
|
||||
TEST(misc, posix_memalign)
|
||||
{
|
||||
void* outptr;
|
||||
int ret;
|
||||
|
||||
ret = posix_memalign(&outptr, 4, 0);
|
||||
TEST_ASSERT_EQUAL_PTR(NULL, outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
|
||||
void* magic = (void*) 0xEFEFEFEF;
|
||||
outptr = magic;
|
||||
ret = posix_memalign(&outptr, 0x10000000, 64); // too big alignment - should fail on all targets
|
||||
TEST_ASSERT_EQUAL_INT(ret, ENOMEM);
|
||||
TEST_ASSERT_EQUAL_PTR(magic, outptr); // was not modified
|
||||
|
||||
outptr = magic;
|
||||
ret = posix_memalign(&outptr, 16, 0x10000000); // too big size - should fail on all targets
|
||||
TEST_ASSERT_EQUAL_INT(ret, ENOMEM);
|
||||
TEST_ASSERT_EQUAL_PTR(magic, outptr); // was not modified
|
||||
|
||||
outptr = magic;
|
||||
ret = posix_memalign(&outptr, 16, 64);
|
||||
TEST_ASSERT_TRUE(outptr != magic);
|
||||
TEST_ASSERT_NOT_NULL(outptr);
|
||||
TEST_ASSERT_EQUAL_INT(ret, 0);
|
||||
free(outptr);
|
||||
}
|
||||
|
||||
TEST(misc, sysconf)
|
||||
{
|
||||
TEST_ASSERT_NOT_EQUAL(-1, sysconf(_SC_NPROCESSORS_ONLN));
|
||||
}
|
||||
|
||||
TEST(misc, realpath)
|
||||
{
|
||||
char out[PATH_MAX];
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("//", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath(".", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("./", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/.", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("./.", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("../..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/a", realpath("/a/", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/a/..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/", realpath("/a/../..", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/c", realpath("/a/../b/../c", out));
|
||||
TEST_ASSERT_EQUAL_STRING("/abc/def", realpath("/abc/./def/ghi/..", out));
|
||||
char* out_new = realpath("/abc/./def/ghi/..", NULL);
|
||||
TEST_ASSERT_NOT_NULL(out_new);
|
||||
TEST_ASSERT_EQUAL_STRING("/abc/def", out_new);
|
||||
free(out_new);
|
||||
}
|
||||
|
||||
TEST_GROUP_RUNNER(misc)
|
||||
{
|
||||
RUN_TEST_CASE(misc, posix_memalign)
|
||||
RUN_TEST_CASE(misc, sysconf)
|
||||
RUN_TEST_CASE(misc, realpath)
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
static void run_all_tests(void)
|
||||
{
|
||||
RUN_TEST_GROUP(stdatomic);
|
||||
RUN_TEST_GROUP(misc);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
|
@ -1421,7 +1421,6 @@ components/mqtt/host_test/mocks/include/machine/endian.h
|
||||
components/mqtt/host_test/mocks/include/sys/queue.h
|
||||
components/newlib/abort.c
|
||||
components/newlib/assert.c
|
||||
components/newlib/heap.c
|
||||
components/newlib/platform_include/assert.h
|
||||
components/newlib/platform_include/errno.h
|
||||
components/newlib/platform_include/esp_newlib.h
|
||||
|
Loading…
Reference in New Issue
Block a user