1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 #include <stdbool.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <sys/reent.h>
12 #include "esp_attr.h"
13 
14 /**
15  * This is the replacement for newlib's _REENT_INIT_PTR and __sinit.
16  * The problem with __sinit is that it allocates three FILE structures
17  * (stdin, stdout, stderr). Having individual standard streams for each task
18  * is a bit too much on a small embedded system. So we point streams
19  * to the streams of the global struct _reent, which are initialized in
20  * startup code.
21  */
esp_reent_init(struct _reent * r)22 void IRAM_ATTR esp_reent_init(struct _reent* r)
23 {
24     memset(r, 0, sizeof(*r));
25     r->_stdout = _GLOBAL_REENT->_stdout;
26     r->_stderr = _GLOBAL_REENT->_stderr;
27     r->_stdin  = _GLOBAL_REENT->_stdin;
28     r->__cleanup = &_cleanup_r;
29     r->__sdidinit = 1;
30     r->__sglue._next = NULL;
31     r->__sglue._niobs = 0;
32     r->__sglue._iobs = NULL;
33 }
34 
35 /* only declared in private stdio header file, local.h */
36 extern void __sfp_lock_acquire(void);
37 extern void __sfp_lock_release(void);
38 
esp_reent_cleanup(void)39 void esp_reent_cleanup(void)
40 {
41     struct _reent* r = __getreent();
42     /* Clean up storage used by mprec functions */
43     if (r->_mp) {
44         if (_REENT_MP_FREELIST(r)) {
45             for (unsigned int i = 0; i < _Kmax; ++i) {
46                 struct _Bigint *cur, *next;
47                 next = _REENT_MP_FREELIST(r)[i];
48                 while (next) {
49                     cur = next;
50                     next = next->_next;
51                     free(cur);
52                 }
53             }
54         }
55         free(_REENT_MP_FREELIST(r));
56         free(_REENT_MP_RESULT(r));
57     }
58 
59     /* Clean up "glue" (lazily-allocated FILE objects) */
60     struct _glue* prev = &_GLOBAL_REENT->__sglue;
61     for (struct _glue* cur = _GLOBAL_REENT->__sglue._next; cur != NULL;) {
62         if (cur->_niobs == 0) {
63             cur = cur->_next;
64             continue;
65         }
66         bool has_open_files = false;
67         for (int i = 0; i < cur->_niobs; ++i) {
68             FILE* fp = &cur->_iobs[i];
69             if (fp->_flags != 0) {
70                 has_open_files = true;
71                 break;
72             }
73         }
74         if (has_open_files) {
75             prev = cur;
76             cur = cur->_next;
77             continue;
78         }
79         struct _glue* next = cur->_next;
80         prev->_next = next;
81         free(cur);
82         cur = next;
83     }
84 
85     /* Clean up various other buffers */
86     free(r->_mp);
87     r->_mp = NULL;
88     free(r->_r48);
89     r->_r48 = NULL;
90     free(r->_localtime_buf);
91     r->_localtime_buf = NULL;
92     free(r->_asctime_buf);
93     r->_asctime_buf = NULL;
94 }
95