1 /*@ Memory: tools like copy, move etc., and a heap allocation interface.
2  *
3  * Copyright (c) 2001 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
4  * SPDX-License-Identifier: ISC
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #ifndef su_MEM_H
19 #define su_MEM_H
20 #include <su/code.h>
21 #define su_HEADER
22 #include <su/code-in.h>
23 C_DECL_BEGIN
24 /* A memset that is not optimized away */
25 EXPORT_DATA void * (* volatile su_mem_set_volatile)(void*, int, uz);
26 EXPORT sz su_mem_cmp(void const *vpa, void const *vpb, uz len);
27 EXPORT void *su_mem_copy(void *vp, void const *src, uz len);
28 EXPORT void *su_mem_find(void const *vp, s32 what, uz len);
29 EXPORT void *su_mem_rfind(void const *vp, s32 what, uz len);
30 EXPORT void *su_mem_move(void *vp, void const *src, uz len);
31 EXPORT void *su_mem_set(void *vp, s32 what, uz len);
32 #if (defined su_HAVE_DEBUG && !defined su_HAVE_MEM_CANARIES_DISABLE) ||\
33       defined DOXYGEN
34 # define su_MEM_ALLOC_DEBUG
35 #endif
36 enum su_mem_alloc_flags{
37    su_MEM_ALLOC_NONE,
38    su_MEM_ALLOC_CLEAR = 1u<<1,
39    su_MEM_ALLOC_32BIT_OVERFLOW = 1u<<2,
40    su_MEM_ALLOC_31BIT_OVERFLOW = 1u<<3,
41    su_MEM_ALLOC_OVERFLOW_OK = su_STATE_ERR_OVERFLOW,
42    su_MEM_ALLOC_NOMEM_OK = su_STATE_ERR_NOMEM,
43    su_MEM_ALLOC_MAYFAIL = su_STATE_ERR_PASS,
44    su_MEM_ALLOC_MUSTFAIL = su_STATE_ERR_NOPASS,
45    su__MEM_ALLOC_MARK_SHIFT = 16u,
46    su_MEM_ALLOC_MARK_0 = 0u<<su__MEM_ALLOC_MARK_SHIFT,
47    su_MEM_ALLOC_MARK_1 = 1u<<su__MEM_ALLOC_MARK_SHIFT,
48    su_MEM_ALLOC_MARK_2 = 2u<<su__MEM_ALLOC_MARK_SHIFT,
49    su_MEM_ALLOC_MARK_3 = 3u<<su__MEM_ALLOC_MARK_SHIFT,
50    su_MEM_ALLOC_MARK_AUTO = su_MEM_ALLOC_MARK_1,
51    su_MEM_ALLOC_MARK_AUTO_HUGE = su_MEM_ALLOC_MARK_2,
52    su_MEM_ALLOC_MARK_LOFI = su_MEM_ALLOC_MARK_3,
53    su__MEM_ALLOC_MARK_MAX = 3u,
54    su__MEM_ALLOC_MARK_MASK = 3u,
55    su__MEM_ALLOC_USER_MASK = 0xFF | su_STATE_ERR_MASK |
56          (su__MEM_ALLOC_MARK_MASK << su__MEM_ALLOC_MARK_SHIFT)
57 };
58 #ifdef su_SOURCE_MEM_ALLOC
59 CTA((su_STATE_ERR_MASK & ~0xFF00u) == 0,
60    "Reuse of low order bits impossible, or mask excesses storage");
61 #endif
62 enum{
63    su_MEM_ALLOC_MIN = Z_ALIGN(1)
64 };
65 enum su_mem_conf_option{
66    su_MEM_CONF_NONE,
67    /* su_MEM_ALLOC_DEBUG only: booleans */
68    su_MEM_CONF_DEBUG = 1u<<0,
69    su_MEM_CONF_ON_ERROR_EMERG = 1u<<1,
70    su_MEM_CONF_LINGER_FREE = 1u<<2,
71    su_MEM_CONF_LINGER_FREE_RELEASE = 1u<<3,
72 /*madvise,free area count*/
73 /*say_if_empty_on_exit,statistics*/
74    su__MEM_CONF_MAX = su_MEM_CONF_LINGER_FREE_RELEASE
75 };
76 #ifdef su_MEM_ALLOC_DEBUG
77 EXPORT boole su__mem_get_can_book(uz size, uz no);
78 EXPORT boole su__mem_check(su_DBG_LOC_ARGS_DECL_SOLE);
79 EXPORT boole su__mem_trace(su_DBG_LOC_ARGS_DECL_SOLE);
80 #endif
81 EXPORT void *su_mem_allocate(uz size, uz no, u32 maf  su_DBG_LOC_ARGS_DECL);
82 EXPORT void *su_mem_reallocate(void *ovp, uz size, uz no, u32 maf
83       su_DBG_LOC_ARGS_DECL);
84 EXPORT void su_mem_free(void *ovp  su_DBG_LOC_ARGS_DECL);
85 #define su_MEM_ALLOCATE(SZ,NO,F) \
86       su_mem_allocate(SZ, NO, F  su_DBG_LOC_ARGS_INJ)
87 #define su_MEM_REALLOCATE(OVP,SZ,NO,F) \
88       su_mem_reallocate(OVP, SZ, NO, F  su_DBG_LOC_ARGS_INJ)
89 #ifdef su_HAVE_DBG_LOC_ARGS
90 # define su_MEM_ALLOCATE_LOC(SZ,NO,F,FNAME,LNNO) \
91       su_mem_allocate(SZ, NO, F, FNAME, LNNO)
92 # define su_MEM_REALLOCATE_LOC(OVP,SZ,NO,F,FNAME,LNNO) \
93       su_mem_reallocate(OVP, SZ, NO, F, FNAME, LNNO)
94 #else
95 # define su_MEM_ALLOCATE_LOC(SZ,NO,F,FNAME,LNNO) \
96       su_mem_allocate(SZ, NO, F)
97 # define su_MEM_REALLOCATE_LOC(OVP,SZ,NO,F,FNAME,LNNO) \
98       su_mem_reallocate(OVP, SZ, NO, F)
99 #endif
100 /* The "normal" interface; there X, X_LOC, and X_LOCOR */
101 #define su_MEM_ALLOC(SZ) su_MEM_ALLOCATE(SZ, 1, su_MEM_ALLOC_NONE)
102 #define su_MEM_ALLOC_LOC(SZ,FNAME,LNNO) \
103       su_MEM_ALLOCATE_LOC(SZ, 1, su_MEM_ALLOC_NONE, FNAME, LNNO)
104 #define su_MEM_ALLOC_N(SZ,NO) su_MEM_ALLOCATE(SZ, NO, su_MEM_ALLOC_NONE)
105 #define su_MEM_ALLOC_N_LOC(SZ,NO,FNAME,LNNO) \
106       su_MEM_ALLOCATE_LOC(SZ, NO, su_MEM_ALLOC_NONE, FNAME, LNNO)
107 #define su_MEM_CALLOC(SZ) su_MEM_ALLOCATE(SZ, 1, su_MEM_ALLOC_CLEAR)
108 #define su_MEM_CALLOC_LOC(SZ,FNAME,LNNO) \
109       su_MEM_ALLOCATE_LOC(SZ, 1, su_MEM_ALLOC_CLEAR, FNAME, LNNO)
110 #define su_MEM_CALLOC_N(SZ,NO) su_MEM_ALLOCATE(SZ, NO, su_MEM_ALLOC_CLEAR)
111 #define su_MEM_CALLOC_N_LOC(SZ,NO,FNAME,LNNO) \
112       su_MEM_ALLOCATE_LOC(SZ, NO, su_MEM_ALLOC_CLEAR, FNAME, LNNO)
113 #define su_MEM_REALLOC(OVP,SZ) su_MEM_REALLOCATE(OVP, SZ, 1, su_MEM_ALLOC_NONE)
114 #define su_MEM_REALLOC_LOC(OVP,SZ,FNAME,LNNO) \
115       su_MEM_REALLOCATE_LOC(OVP, SZ, 1, su_MEM_ALLOC_NONE, FNAME, LNNO)
116 #define su_MEM_REALLOC_N(OVP,SZ,NO) \
117       su_MEM_REALLOCATE(OVP, SZ, NO, su_MEM_ALLOC_NONE)
118 #define su_MEM_REALLOC_N_LOC(OVP,SZ,NO,FNAME,LNNO) \
119       su_MEM_REALLOCATE_LOC(OVP, SZ, NO, su_MEM_ALLOC_NONE, FNAME, LNNO)
120 #define su_MEM_TALLOC(T,NO) su_S(T *,su_MEM_ALLOC_N(sizeof(T), NO))
121 #define su_MEM_TALLOC_LOC(T,NO,FNAME,LNNO) \
122       su_S(T *,su_MEM_ALLOC_N_LOC(sizeof(T), NO, FNAME, LNNO))
123 #define su_MEM_TCALLOC(T,NO) su_S(T *,su_MEM_CALLOC_N(sizeof(T), NO))
124 #define su_MEM_TCALLOC_LOC(T,NO,FNAME,LNNO) \
125       su_S(T *,su_MEM_CALLOC_N_LOC(sizeof(T), NO, FNAME, LNNO))
126 #define su_MEM_TREALLOC(T,OVP,NO) \
127       su_S(T *,su_MEM_REALLOC_N(OVP, sizeof(T), NO))
128 #define su_MEM_TREALLOC_LOC(T,OVP,NO,FNAME,LNNO) \
129       su_S(T *,su_MEM_REALLOC_N_LOC(OVP, sizeof(T), NO, FNAME, LNNO))
130 #define su_MEM_TALLOCF(T,NO,F) su_S(T *,su_MEM_ALLOCATE(sizeof(T), NO, F))
131 #define su_MEM_TALLOCF_LOC(T,NO,F,FNAME,LNNO) \
132       su_S(T *,su_MEM_ALLOCATE_LOC(sizeof(T), NO, F, FNAME, LNNO))
133 #define su_MEM_TCALLOCF(T,NO,F) \
134    su_S(T *,su_MEM_ALLOCATE(sizeof(T), NO, su_MEM_ALLOC_CLEAR | (F)))
135 #define su_MEM_TCALLOCF_LOC(T,NO,F,FNAME,LNNO) \
136    su_S(T *,su_MEM_ALLOCATE_LOC(sizeof(T), NO, su_MEM_ALLOC_CLEAR | (F)),\
137       FNAME, LNNO)
138 #define su_MEM_TREALLOCF(T,OVP,NO,F) \
139       su_S(T *,su_MEM_REALLOCATE(OVP, sizeof(T), NO, F))
140 #define su_MEM_TREALLOCF_LOC(T,OVP,NO,F,FNAME,LNNO) \
141       su_S(T *,su_MEM_REALLOCATE_LOC(OVP, sizeof(T), NO, F, FNAME, LNNO))
142 #define su_MEM_FREE(OVP) su_mem_free(OVP  su_DBG_LOC_ARGS_INJ)
143 #ifdef su_HAVE_DBG_LOC_ARGS
144 # define su_MEM_FREE_LOC(OVP,FNAME,LNNO) su_mem_free(OVP, FNAME, LNNO)
145 #else
146 # define su_MEM_FREE_LOC(OVP,FNAME,LNNO) su_mem_free(OVP)
147 #endif
148 /* (The painful _LOCOR series) */
149 #ifdef su_HAVE_DBG_LOC_ARGS
150 # define su_MEM_ALLOC_LOCOR(SZ,ORARGS) su_MEM_ALLOC_LOC(SZ, ORARGS)
151 # define su_MEM_ALLOC_N_LOCOR(SZ,NO,ORARGS) su_MEM_ALLOC_N_LOC(SZ, NO, ORARGS)
152 # define su_MEM_CALLOC_LOCOR(SZ,ORARGS) su_MEM_CALLOC_LOC(SZ, ORGARGS)
153 # define su_MEM_CALLOC_N_LOCOR(SZ,NO,ORARGS) \
154       su_MEM_CALLOC_N_LOC(SZ, NO, ORARGS)
155 # define su_MEM_REALLOC_LOCOR(OVP,SZ,ORARGS) \
156       su_MEM_REALLOC_LOC(OVP, SZ, ORARGS)
157 # define su_MEM_REALLOC_N_LOCOR(OVP,SZ,NO,ORARGS) \
158       su_MEM_REALLOC_N_LOC(OVP, SZ, NO, ORARGS)
159 # define su_MEM_TALLOC_LOCOR(T,NO,ORARGS) su_MEM_TALLOC_LOC(T, NO, ORARGS)
160 # define su_MEM_TCALLOC_LOCOR(T,NO,ORARGS) su_MEM_TCALLOC_LOC(T, NO, ORARGS)
161 # define su_MEM_TREALLOC_LOCOR(T,OVP,NO,ORARGS) \
162       su_MEM_TREALLOC_LOC(T, OVP, NO, ORARGS)
163 # define su_MEM_TALLOCF_LOCOR(T,NO,F,ORARGS) \
164    su_MEM_TALLOCF_LOC(T, NO, F, ORARGS)
165 # define su_MEM_TCALLOCF_LOCOR(T,NO,F,ORARGS) \
166    su_MEM_TCALLOCF_LOC(T, NO, F, ORARGS)
167 # define su_MEM_TREALLOCF_LOCOR(T,OVP,NO,F,ORARGS) \
168       su_MEM_TREALLOCF_LOC(T, OVP, NO, F, ORARGS)
169 # define su_MEM_FREE_LOCOR(OVP,ORARGS) su_MEM_FREE_LOC(OVP, ORARGS)
170 #else
171 # define su_MEM_ALLOC_LOCOR(SZ,ORARGS) su_MEM_ALLOC(SZ)
172 # define su_MEM_ALLOC_N_LOCOR(SZ,NO,ORARGS) su_MEM_ALLOC_N(SZ, NO)
173 # define su_MEM_CALLOC_LOCOR(SZ,ORARGS) su_MEM_CALLOC(SZ)
174 # define su_MEM_CALLOC_N_LOCOR(SZ,NO,ORARGS) su_MEM_CALLOC_N(SZ, NO)
175 # define su_MEM_REALLOC_LOCOR(OVP,SZ,ORARGS) su_MEM_REALLOC(OVP, SZ)
176 # define su_MEM_REALLOC_N_LOCOR(OVP,SZ,NO,ORARGS) su_MEM_REALLOC_N(OVP, SZ, NO)
177 # define su_MEM_TALLOC_LOCOR(T,NO,ORARGS) su_MEM_TALLOC(T, NO)
178 # define su_MEM_TCALLOC_LOCOR(T,NO,ORARGS) su_MEM_TCALLOC(T, NO)
179 # define su_MEM_TREALLOC_LOCOR(T,OVP,NO) su_MEM_TREALLOC(T, OVP, NO)
180 # define su_MEM_TALLOCF_LOCOR(T,NO,F,ORARGS) su_MEM_TALLOCF(T, NO, F)
181 # define su_MEM_TCALLOCF_LOCOR(T,NO,F,ORARGS) su_MEM_TCALLOCF(T, NO, F)
182 # define su_MEM_TREALLOCF_LOCOR(T,OVP,F,NO) su_MEM_TREALLOCF(T, OVP, NO, F)
183 # define su_MEM_FREE_LOCOR(OVP,ORARGS) su_MEM_FREE_LOC(OVP, ORARGS)
184 #endif /* !su_HAVE_DBG_LOC_ARGS */
su_mem_get_can_book(uz size,uz no,uz notoadd)185 INLINE boole su_mem_get_can_book(uz size, uz no, uz notoadd){
186    if(UZ_MAX - no <= notoadd)
187       return FAL0;
188    no += notoadd;
189    if(no == 0)
190       return TRU1;
191    no = UZ_MAX / no;
192    if(no < size || (size != 1 && no == size))
193       return FAL0;
194 #ifdef su_MEM_ALLOC_DEBUG
195    if(!su__mem_get_can_book(size, no))
196       return FAL0;
197 #endif
198    return TRU1;
199 }
200 #define su_mem_get_usable_size(SZ) su_Z_ALIGN(SZ) /* XXX fake */
201 #define su_mem_get_usable_size_32(SZ) su_S(su_u32,su_Z_ALIGN(SZ)) /*XXX*/
202 /* XXX get_usable_size_ptr(), get_memory_usage()  */
203 EXPORT void su_mem_set_conf(u32 mco, uz val);
su_mem_check(void)204 INLINE boole su_mem_check(void){
205 #ifdef su_MEM_ALLOC_DEBUG
206    return su__mem_check(su_DBG_LOC_ARGS_INJ_SOLE);
207 #else
208    return FAL0;
209 #endif
210 }
211 /* XXX mem_check_ptr()  */
212 /* XXX mem_[usage_]info(); opt: output channel, thread ptr */
su_mem_trace(void)213 INLINE boole su_mem_trace(void){ /* XXX ochannel, thrptr*/
214 #ifdef su_MEM_ALLOC_DEBUG
215    return su__mem_trace(su_DBG_LOC_ARGS_INJ_SOLE);
216 #else
217    return FAL0;
218 #endif
219 }
220 C_DECL_END
221 #include <su/code-ou.h>
222 #endif /* !su_MEM_H */
223 /* s-it-mode */
224