libc: minimal: Add rand() and srand()
rand() and srand() are pseudo-random number generator functions defined in ISO C. This implementation uses the Linear Congruential Generator (LCG) algorithm with the following parameters, which are the same as used in GNU Libc "TYPE_0" algorithm. Modulus 2^31 Multiplier 1103515245 Increment 12345 Output Bits 30..0 Note that the default algorithm used by GNU Libc is not TYPE_0, and TYPE_0 should be selected first by an initstate() call as shown below. All global variables in a C library must be routed to a memory partition in order to be used by user-mode applications when CONFIG_USERSPACE is enabled. Thus, srand_seed is marked as such. z_libc_partition is originally used by the Newlib C library but it's generic enough to be used by either the minimal libc or the newlib. All other functions in the Minimal C library, however, don't require global variables/states. Unconditionally using z_libc_partition with the minimal libc might be a problem for applications utilizing many custom memory partitions on platforms with a limited number of MPU regions (eg. Cortex M0/M3). This commit introduces a kconfig option CONFIG_MINIMAL_LIBC_RAND so that applications can enable the functions if needed. The option is disabled by default. Because this commit _does_ implement rand() and srand(), our coding guideline check on GitHub Action finds it as a violation. Error: lib/libc/minimal/include/stdlib.h:45:WARNING: Violation to rule 21.2 (Should not used a reserved identifier) - srand But this is false positive. The following is a simple test program for LCG with GNU Libc. #include <stdio.h> #include <stdlib.h> int main() { static char state[8]; /* Switch GLIBC to use LCG/TYPE_0 generator type. */ initstate(0, state, sizeof(state)); srand(1); /* Or any other value. */ printf("%d\n", rand()); printf("%d\n", rand()); return 0; } See initstate(3p) for more detail about how to use LCG in GLIBC. Signed-off-by: Yasushi SHOJI <yashi@spacecubics.com>
This commit is contained in:
parent
244f69d1df
commit
b2fde24c4c
5 changed files with 57 additions and 5 deletions
|
@ -69,11 +69,14 @@ extern struct k_mem_partition z_malloc_partition;
|
||||||
|
|
||||||
#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_STACK_CANARIES) || \
|
#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_STACK_CANARIES) || \
|
||||||
defined(CONFIG_NEED_LIBC_MEM_PARTITION)
|
defined(CONFIG_NEED_LIBC_MEM_PARTITION)
|
||||||
/* Minimal libc has no globals. We do put the stack canary global in the
|
/* - All newlib globals will be placed into z_libc_partition.
|
||||||
* libc partition since it is not worth placing in a partition of its own.
|
* - Minimal C library globals, if any, will be placed into
|
||||||
*
|
* z_libc_partition.
|
||||||
* Some architectures require a global pointer for thread local storage,
|
* - Stack canary globals will be placed into z_libc_partition since
|
||||||
* which is placed inside the libc partition.
|
* it is not worth placing in its own partition.
|
||||||
|
* - Some architectures may place the global pointer to the thread local
|
||||||
|
* storage in z_libc_partition since it is not worth placing in its
|
||||||
|
* own partition.
|
||||||
*/
|
*/
|
||||||
#define Z_LIBC_PARTITION_EXISTS 1
|
#define Z_LIBC_PARTITION_EXISTS 1
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,19 @@ config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE
|
||||||
Enable smaller but potentially slower implementations of memcpy and
|
Enable smaller but potentially slower implementations of memcpy and
|
||||||
memset. On the Cortex-M0+ this reduces the total code size by 120 bytes.
|
memset. On the Cortex-M0+ this reduces the total code size by 120 bytes.
|
||||||
|
|
||||||
|
config MINIMAL_LIBC_RAND
|
||||||
|
bool "Enables rand and srand functions"
|
||||||
|
select NEED_LIBC_MEM_PARTITION
|
||||||
|
help
|
||||||
|
Enable rand() and srand() for the minimal libc. The
|
||||||
|
functions implicitly access global/static data. Such data
|
||||||
|
must be put into a memory partition if CONFIG_USERSPACE=y,
|
||||||
|
and disabling this option may save an entry for application
|
||||||
|
defining many custom partitions.
|
||||||
|
|
||||||
|
Say 'Y' here if you need rand() and srand(). This might require
|
||||||
|
an additional memory partition.
|
||||||
|
|
||||||
endif # MINIMAL_LIBC
|
endif # MINIMAL_LIBC
|
||||||
|
|
||||||
config STDOUT_CONSOLE
|
config STDOUT_CONSOLE
|
||||||
|
|
|
@ -22,3 +22,4 @@ zephyr_library_sources(
|
||||||
)
|
)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK source/time/time.c)
|
zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK source/time/time.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_MINIMAL_LIBC_RAND source/stdlib/rand.c)
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#define ZEPHYR_LIB_LIBC_MINIMAL_INCLUDE_STDLIB_H_
|
#define ZEPHYR_LIB_LIBC_MINIMAL_INCLUDE_STDLIB_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,7 +39,11 @@ static inline void exit(int status)
|
||||||
}
|
}
|
||||||
void abort(void);
|
void abort(void);
|
||||||
|
|
||||||
|
#ifdef CONFIG_MINIMAL_LIBC_RAND
|
||||||
|
#define RAND_MAX INT_MAX
|
||||||
int rand(void);
|
int rand(void);
|
||||||
|
void srand(unsigned int seed);
|
||||||
|
#endif /* CONFIG_MINIMAL_LIBC_RAND */
|
||||||
|
|
||||||
static inline int abs(int __n)
|
static inline int abs(int __n)
|
||||||
{
|
{
|
||||||
|
|
29
lib/libc/minimal/source/stdlib/rand.c
Normal file
29
lib/libc/minimal/source/stdlib/rand.c
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Space Cubics, LLC.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/libc-hooks.h>
|
||||||
|
#include <app_memory/app_memdomain.h>
|
||||||
|
|
||||||
|
#define LIBC_DATA K_APP_DMEM(z_libc_partition)
|
||||||
|
|
||||||
|
#define OUTPUT_BITS (0x7fffffffU)
|
||||||
|
#define MULTIPLIER (1103515245U)
|
||||||
|
#define INCREMENT (12345U)
|
||||||
|
|
||||||
|
static LIBC_DATA unsigned long srand_seed = 1;
|
||||||
|
|
||||||
|
void srand(unsigned int s)
|
||||||
|
{
|
||||||
|
srand_seed = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rand(void)
|
||||||
|
{
|
||||||
|
srand_seed = (MULTIPLIER * srand_seed + INCREMENT) & OUTPUT_BITS;
|
||||||
|
|
||||||
|
return srand_seed;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue