x86_cpu_features.c: cpuid fix for x86_32 PIC with old GCC versions
[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(alignment != 0 && is_power_of_2(alignment) &&
109                       alignment <= 4096);
110
111         const uintptr_t mask = alignment - 1;
112         char *ptr = NULL;
113         char *raw_ptr;
114
115         raw_ptr = MALLOC(mask + sizeof(size_t) + size);
116         if (raw_ptr) {
117                 ptr = (char *)raw_ptr + sizeof(size_t);
118                 ptr = (void *)(((uintptr_t)ptr + mask) & ~mask);
119                 *((size_t *)ptr - 1) = ptr - raw_ptr;
120         }
121         return ptr;
122 }
123
124 void
125 wimlib_aligned_free(void *ptr)
126 {
127         if (ptr)
128                 FREE((char *)ptr - *((size_t *)ptr - 1));
129 }
130
131 void *
132 memdup(const void *mem, size_t size)
133 {
134         void *ptr = MALLOC(size);
135         if (ptr)
136                 ptr = memcpy(ptr, mem, size);
137         return ptr;
138 }
139
140 /* API function documented in wimlib.h  */
141 WIMLIBAPI int
142 wimlib_set_memory_allocator(void *(*malloc_func)(size_t),
143                             void (*free_func)(void *),
144                             void *(*realloc_func)(void *, size_t))
145 {
146         wimlib_malloc_func  = malloc_func  ? malloc_func  : malloc;
147         wimlib_free_func    = free_func    ? free_func    : free;
148         wimlib_realloc_func = realloc_func ? realloc_func : realloc;
149
150         xml_set_memory_allocator(wimlib_malloc_func, wimlib_free_func,
151                                  wimlib_realloc_func);
152         return 0;
153 }
154
155 /*******************
156  * String utilities
157  *******************/
158
159 #ifndef HAVE_MEMPCPY
160 void *mempcpy(void *dst, const void *src, size_t n)
161 {
162         return memcpy(dst, src, n) + n;
163 }
164 #endif
165
166 static bool seeded = false;
167
168 static void
169 seed_random(void)
170 {
171         srand(now_as_wim_timestamp());
172         seeded = true;
173 }
174
175 /* Fills @n characters pointed to by @p with random alphanumeric characters. */
176 void
177 randomize_char_array_with_alnum(tchar *p, size_t n)
178 {
179         if (!seeded)
180                 seed_random();
181         while (n--) {
182                 int r = rand() % 62;
183                 if (r < 26)
184                         *p++ = r + 'a';
185                 else if (r < 52)
186                         *p++ = r - 26 + 'A';
187                 else
188                         *p++ = r - 52 + '0';
189         }
190 }
191
192 /* Fills @n bytes pointer to by @p with random numbers. */
193 void
194 randomize_byte_array(u8 *p, size_t n)
195 {
196         if (!seeded)
197                 seed_random();
198         while (n--)
199                 *p++ = rand();
200 }
201
202 #ifndef __WIN32__
203 unsigned
204 get_available_cpus(void)
205 {
206         long n = sysconf(_SC_NPROCESSORS_ONLN);
207         if (n < 1 || n >= UINT_MAX) {
208                 WARNING("Failed to determine number of processors; assuming 1.");
209                 return 1;
210         }
211         return n;
212 }
213 #endif /* !__WIN32__ */
214
215 #ifndef __WIN32__
216 u64
217 get_available_memory(void)
218 {
219 #if defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
220         long page_size = sysconf(_SC_PAGESIZE);
221         long num_pages = sysconf(_SC_PHYS_PAGES);
222         if (page_size <= 0 || num_pages <= 0)
223                 goto default_size;
224         return ((u64)page_size * (u64)num_pages);
225 #else
226         int mib[2] = {CTL_HW, HW_MEMSIZE};
227         u64 memsize;
228         size_t len = sizeof(memsize);
229         if (sysctl(mib, ARRAY_LEN(mib), &memsize, &len, NULL, 0) < 0 || len != 8)
230                 goto default_size;
231         return memsize;
232 #endif
233
234 default_size:
235         WARNING("Failed to determine available memory; assuming 1 GiB");
236         return (u64)1 << 30;
237 }
238 #endif /* !__WIN32__ */