]> wimlib.net Git - wimlib/blob - src/util.c
util.c: for aligned_malloc, store original pointer directly
[wimlib] / src / util.c
1 /*
2  * util.c - utility functions
3  */
4
5 /*
6  * Copyright (C) 2012, 2013, 2014 Eric Biggers
7  *
8  * This file is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License as published by the Free
10  * Software Foundation; either version 3 of the License, or (at your option) any
11  * later version.
12  *
13  * This file is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this file; if not, see http://www.gnu.org/licenses/.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #ifdef HAVE_SYS_SYSCTL_H
31 #  include <sys/types.h>
32 #  include <sys/sysctl.h>
33 #endif
34 #include <unistd.h>
35
36 #include "wimlib.h"
37 #include "wimlib/assert.h"
38 #include "wimlib/error.h"
39 #include "wimlib/timestamp.h"
40 #include "wimlib/util.h"
41 #include "wimlib/xml.h"
42
43 /*******************
44  * Memory allocation
45  *******************/
46
47 static void *(*wimlib_malloc_func) (size_t)         = malloc;
48 static void  (*wimlib_free_func)   (void *)         = free;
49 static void *(*wimlib_realloc_func)(void *, size_t) = realloc;
50
51 void *
52 wimlib_malloc(size_t size)
53 {
54         void *ptr;
55
56 retry:
57         ptr = (*wimlib_malloc_func)(size);
58         if (unlikely(!ptr)) {
59                 if (size == 0) {
60                         size = 1;
61                         goto retry;
62                 }
63         }
64         return ptr;
65 }
66
67 void
68 wimlib_free_memory(void *ptr)
69 {
70         (*wimlib_free_func)(ptr);
71 }
72
73 void *
74 wimlib_realloc(void *ptr, size_t size)
75 {
76         if (size == 0)
77                 size = 1;
78         return (*wimlib_realloc_func)(ptr, size);
79 }
80
81 void *
82 wimlib_calloc(size_t nmemb, size_t size)
83 {
84         size_t total_size = nmemb * size;
85         void *p = MALLOC(total_size);
86         if (p)
87                 p = memset(p, 0, total_size);
88         return p;
89 }
90
91 char *
92 wimlib_strdup(const char *str)
93 {
94         return memdup(str, strlen(str) + 1);
95 }
96
97 #ifdef __WIN32__
98 wchar_t *
99 wimlib_wcsdup(const wchar_t *str)
100 {
101         return memdup(str, (wcslen(str) + 1) * sizeof(wchar_t));
102 }
103 #endif
104
105 void *
106 wimlib_aligned_malloc(size_t size, size_t alignment)
107 {
108         wimlib_assert(is_power_of_2(alignment));
109
110         void *ptr = MALLOC(sizeof(void *) + alignment - 1 + size);
111         if (ptr) {
112                 void *orig_ptr = ptr;
113                 ptr = (void *)ALIGN((uintptr_t)ptr + sizeof(void *), alignment);
114                 ((void **)ptr)[-1] = orig_ptr;
115         }
116         return ptr;
117 }
118
119 void
120 wimlib_aligned_free(void *ptr)
121 {
122         if (ptr)
123                 FREE(((void **)ptr)[-1]);
124 }
125
126 void *
127 memdup(const void *mem, size_t size)
128 {
129         void *ptr = MALLOC(size);
130         if (ptr)
131                 ptr = memcpy(ptr, mem, size);
132         return ptr;
133 }
134
135 /* API function documented in wimlib.h  */
136 WIMLIBAPI int
137 wimlib_set_memory_allocator(void *(*malloc_func)(size_t),
138                             void (*free_func)(void *),
139                             void *(*realloc_func)(void *, size_t))
140 {
141         wimlib_malloc_func  = malloc_func  ? malloc_func  : malloc;
142         wimlib_free_func    = free_func    ? free_func    : free;
143         wimlib_realloc_func = realloc_func ? realloc_func : realloc;
144
145         xml_set_memory_allocator(wimlib_malloc_func, wimlib_free_func,
146                                  wimlib_realloc_func);
147         return 0;
148 }
149
150 /*******************
151  * String utilities
152  *******************/
153
154 #ifndef HAVE_MEMPCPY
155 void *mempcpy(void *dst, const void *src, size_t n)
156 {
157         return memcpy(dst, src, n) + n;
158 }
159 #endif
160
161 static bool seeded = false;
162
163 static void
164 seed_random(void)
165 {
166         srand(now_as_wim_timestamp());
167         seeded = true;
168 }
169
170 /* Fills @n characters pointed to by @p with random alphanumeric characters. */
171 void
172 randomize_char_array_with_alnum(tchar *p, size_t n)
173 {
174         if (!seeded)
175                 seed_random();
176         while (n--) {
177                 int r = rand() % 62;
178                 if (r < 26)
179                         *p++ = r + 'a';
180                 else if (r < 52)
181                         *p++ = r - 26 + 'A';
182                 else
183                         *p++ = r - 52 + '0';
184         }
185 }
186
187 /* Fills @n bytes pointer to by @p with random numbers. */
188 void
189 randomize_byte_array(u8 *p, size_t n)
190 {
191         if (!seeded)
192                 seed_random();
193         while (n--)
194                 *p++ = rand();
195 }
196
197 #ifndef __WIN32__
198 unsigned
199 get_available_cpus(void)
200 {
201         long n = sysconf(_SC_NPROCESSORS_ONLN);
202         if (n < 1 || n >= UINT_MAX) {
203                 WARNING("Failed to determine number of processors; assuming 1.");
204                 return 1;
205         }
206         return n;
207 }
208 #endif /* !__WIN32__ */
209
210 #ifndef __WIN32__
211 u64
212 get_available_memory(void)
213 {
214 #if defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
215         long page_size = sysconf(_SC_PAGESIZE);
216         long num_pages = sysconf(_SC_PHYS_PAGES);
217         if (page_size <= 0 || num_pages <= 0)
218                 goto default_size;
219         return ((u64)page_size * (u64)num_pages);
220 #else
221         int mib[2] = {CTL_HW, HW_MEMSIZE};
222         u64 memsize;
223         size_t len = sizeof(memsize);
224         if (sysctl(mib, ARRAY_LEN(mib), &memsize, &len, NULL, 0) < 0 || len != 8)
225                 goto default_size;
226         return memsize;
227 #endif
228
229 default_size:
230         WARNING("Failed to determine available memory; assuming 1 GiB");
231         return (u64)1 << 30;
232 }
233 #endif /* !__WIN32__ */