zephyr/include/sys/libc-hooks.h
Yasushi SHOJI b2fde24c4c 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>
2021-07-20 13:32:36 -04:00

91 lines
2.9 KiB
C

/*
* Copyright (c) 2018, Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_SYS_LIBC_HOOKS_H_
#define ZEPHYR_INCLUDE_SYS_LIBC_HOOKS_H_
#include <toolchain.h>
#include <stdio.h>
#include <stddef.h>
/*
* Private header for specifying accessory functions to the C library internals
* that need to call into the kernel as system calls
*/
#ifdef CONFIG_NEWLIB_LIBC
/* syscall generation ignores preprocessor, ensure this is defined to ensure
* we don't have compile errors
*/
#define _MLIBC_RESTRICT
__syscall int z_zephyr_read_stdin(char *buf, int nbytes);
__syscall int z_zephyr_write_stdout(const void *buf, int nbytes);
#else
/* Minimal libc */
__syscall int zephyr_fputc(int c, FILE * stream);
__syscall size_t zephyr_fwrite(const void *_MLIBC_RESTRICT ptr, size_t size,
size_t nitems, FILE *_MLIBC_RESTRICT stream);
#endif /* CONFIG_NEWLIB_LIBC */
#ifdef CONFIG_USERSPACE
#if defined(CONFIG_NEWLIB_LIBC)
/* If we are using newlib, the heap arena is in one of two areas:
* - If we have an MPU that requires power of two alignment, the heap bounds
* must be specified in Kconfig via CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE.
* - Otherwise, the heap arena on most arches starts at a suitably
* aligned base addreess after the `_end` linker symbol, through to the end
* of system RAM.
*/
#if (!defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) || \
(defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) && \
CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE))
#define Z_MALLOC_PARTITION_EXISTS 1
extern struct k_mem_partition z_malloc_partition;
#endif
#elif defined(CONFIG_MINIMAL_LIBC)
#if (CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE > 0)
/* Minimal libc by default has no malloc arena, its size must be set in
* Kconfig via CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE
*/
#define Z_MALLOC_PARTITION_EXISTS 1
#endif /* CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE > 0 */
#endif /* CONFIG_MINIMAL_LIBC */
#ifdef Z_MALLOC_PARTITION_EXISTS
/* Memory partition containing the libc malloc arena. Configuration controls
* whether this is available, and an arena size may need to be set.
*/
extern struct k_mem_partition z_malloc_partition;
#endif
#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_STACK_CANARIES) || \
defined(CONFIG_NEED_LIBC_MEM_PARTITION)
/* - All newlib globals will be placed into z_libc_partition.
* - Minimal C library globals, if any, will be placed into
* z_libc_partition.
* - Stack canary globals will be placed into z_libc_partition since
* 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
/* C library globals, except the malloc arena */
extern struct k_mem_partition z_libc_partition;
#endif
#endif /* CONFIG_USERSPACE */
#include <syscalls/libc-hooks.h>
#endif /* ZEPHYR_INCLUDE_SYS_LIBC_HOOKS_H_ */