* src/toolbox/util.c (_Jv_getcwd): Moved convenience function to os wrapper.
[cacao.git] / src / vm / os.cpp
1 /* src/vm/os.cpp - system (OS) functions
2
3    Copyright (C) 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5    Copyright (C) 2008 Theobroma Systems Ltd.
6
7    This file is part of CACAO.
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22    02110-1301, USA.
23
24 */
25
26
27 #include "config.h"
28
29 /* NOTE: In this file we check for all system headers, because we wrap
30    all system calls into functions for better portability. */
31
32 #if defined(HAVE_ERRNO_H)
33 # include <errno.h>
34 #endif
35
36 #if defined(HAVE_STDINT_H)
37 # include <stdint.h>
38 #endif
39
40 #if defined(HAVE_STRING_H)
41 # include <string.h>
42 #endif
43
44 #if defined(HAVE_UNISTD_H)
45 # include <unistd.h>
46 #endif
47
48 #if defined(HAVE_SYS_MMAN_H)
49 # include <sys/mman.h>
50 #endif
51
52 #if defined(__DARWIN__)
53 # include <mach/mach.h>
54 # include <mach/mach_host.h>
55 # include <mach/host_info.h>
56 #endif
57
58 /* this should work on BSD */
59 /* #include <sys/sysctl.h> */
60
61 #include "mm/memory.hpp"
62
63 #include "vm/vm.hpp"
64
65
66 /**
67  * Prints an error message and aborts the VM.
68  *
69  * @param text Error message to print.
70  */
71 void os::abort(const char* text, ...)
72 {
73         va_list ap;
74
75         // Print the log message.
76         log_start();
77
78         va_start(ap, text);
79         log_vprint(text, ap);
80         va_end(ap);
81
82         log_finish();
83
84         // Print a backtrace.
85         os::print_backtrace();
86
87         // Now abort the VM.
88         os::abort();
89 }
90
91
92 /**
93  * Common code for both os::abort_errnum and os::abort_errno.
94  */
95 static void abort_verrnum(int errnum, const char* text, va_list ap)
96 {
97         // Print the log message.
98         log_start();
99
100         log_vprint(text, ap);
101
102         // Print the strerror-message of errnum.
103         log_print(": %s", os::strerror(errnum));
104
105         log_finish();
106
107         // Print a backtrace.
108         os::print_backtrace();
109
110         // Now abort the VM.
111         os::abort();
112 }
113
114 /**
115  * Prints an error message, appends ":" plus the strerror-message of
116  * errnum and aborts the VM.
117  *
118  * @param errnum Error number.
119  * @param text   Error message to print.
120  */
121 void os::abort_errnum(int errnum, const char* text, ...)
122 {
123         va_list ap;
124
125         va_start(ap, text);
126         abort_verrnum(errnum, text, ap);
127         va_end(ap);
128 }
129
130
131 /**
132  * Equal to abort_errnum, but uses errno to get the error number.
133  *
134  * @param text Error message to print.
135  */
136 void os::abort_errno(const char* text, ...)
137 {
138         va_list ap;
139
140         va_start(ap, text);
141         abort_verrnum(errno, text, ap);
142         va_end(ap);
143 }
144
145
146 /**
147  * Return the current working directory.
148  *
149  * @return Pointer to a char array allocated by MNEW, or
150  *         NULL if memory could not be allocated.
151  */
152 char* os::getcwd(void)
153 {
154         int32_t size = 1024;
155
156         char* buf = MNEW(char, size);
157
158         while (buf != NULL) {
159                 if (getcwd(buf, size) != NULL)
160                         return buf;
161
162                 MFREE(buf, char, size);
163
164                 /* too small buffer or a more serious problem */
165
166                 if (errno != ERANGE)
167                         abort_errno("os::getcwd: getcwd failed");
168
169                 /* double the buffer size */
170
171                 size *= 2;
172
173                 buf = MNEW(char, size);
174         }
175
176         return NULL;
177 }
178
179
180 /**
181  * Maps anonymous memory, even on systems not defining
182  * MAP_ANON(YMOUS).
183  *
184  * @param ...
185  */
186 void* os::mmap_anonymous(void *addr, size_t len, int prot, int flags)
187 {
188         void* p;
189
190 #if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
191         p = mmap(addr, len, prot,
192 # if defined(MAP_ANON)
193                          MAP_ANON | flags,
194 # else
195                          MAP_ANONYMOUS | flags,
196 # endif
197                          -1, 0);
198 #else
199         int fd;
200
201         fd = open("/dev/zero", O_RDONLY, 0);
202
203         if (fd == -1)
204                 os::abort_errno("os::mmap_anonymous: open failed");
205
206         p = mmap(addr, len, prot, flags, fd, 0);
207 #endif
208
209 #if defined(MAP_FAILED)
210         if (p == MAP_FAILED)
211 #else
212         if (p == (void *) -1)
213 #endif
214                 os::abort_errno("os::mmap_anonymous: mmap failed");
215
216         return p;
217 }
218
219
220 /**
221  * Print a C backtrace.
222  */
223 void os::print_backtrace()
224 {
225 #define BACKTRACE_SIZE 100
226         void** array = new void*[SIZEOF_VOID_P * BACKTRACE_SIZE];
227
228         // Get the backtrace.
229         int size = backtrace(array, BACKTRACE_SIZE);
230
231         // Resolve the symbols.
232         char** strings = backtrace_symbols(array, size);
233
234         log_println("Backtrace (%d stack frames):", size);
235
236         for (int i = 0; i < size; i++)
237                 log_println("%s", strings[i]);
238
239         // We have to free the strings.
240         free(strings);
241 }
242
243
244 /**
245  * Returns the number of online processors in the system.
246  *
247  * @return Number of online processors.
248  */
249 int os::processors_online(void)
250 {
251 #if defined(_SC_NPROC_ONLN)
252
253         return (int) sysconf(_SC_NPROC_ONLN);
254
255 #elif defined(_SC_NPROCESSORS_ONLN)
256
257         return (int) sysconf(_SC_NPROCESSORS_ONLN);
258
259 #elif defined(__DARWIN__)
260
261         host_basic_info_data_t hinfo;
262         mach_msg_type_number_t hinfo_count = HOST_BASIC_INFO_COUNT;
263         kern_return_t rc;
264
265         rc = host_info(mach_host_self(), HOST_BASIC_INFO,
266                                    (host_info_t) &hinfo, &hinfo_count);
267  
268         if (rc != KERN_SUCCESS) {
269                 return -1;
270         }
271
272         /* XXX michi: according to my infos this should be
273            hinfo.max_cpus, can someone please confirm or deny that? */
274         return (int) hinfo.avail_cpus;
275
276 #elif defined(__FREEBSD__)
277 # error IMPLEMENT ME!
278
279         /* this should work in BSD */
280         /*
281         int ncpu, mib[2], rc;
282         size_t len;
283
284         mib[0] = CTL_HW;
285         mib[1] = HW_NCPU;
286         len = sizeof(ncpu);
287         rc = sysctl(mib, 2, &ncpu, &len, NULL, 0);
288
289         return (int32_t) ncpu;
290         */
291
292 #else
293
294         return 1;
295
296 #endif
297 }
298
299
300 // Legacy C interface.
301
302 extern "C" {
303         void*  os_mmap_anonymous(void *addr, size_t len, int prot, int flags) { return os::mmap_anonymous(addr, len, prot, flags); }
304
305         void   os_abort(void) { os::abort(); }
306         int    os_access(const char* pathname, int mode) { return os::access(pathname, mode); }
307         int    os_atoi(const char* nptr) { return os::atoi(nptr); }
308         void*  os_calloc(size_t nmemb, size_t size) { return os::calloc(nmemb, size); }
309 #if defined(ENABLE_JRE_LAYOUT)
310         char*  os_dirname(char* path) { return os::dirname(path); }
311 #endif
312         char*  os_dlerror(void) { return os::dlerror(); }
313         void*  os_dlsym(void* handle, const char* symbol) { return os::dlsym(handle, symbol); }
314         int    os_fclose(FILE* fp) { return os::fclose(fp); }
315         FILE*  os_fopen(const char* path, const char* mode) { return os::fopen(path, mode); }
316         size_t os_fread(void* ptr, size_t size, size_t nmemb, FILE* stream) { return os::fread(ptr, size, nmemb, stream); }
317         void   os_free(void* ptr) { os::free(ptr); }
318         int    os_getpagesize(void) { return os::getpagesize(); }
319         void*  os_memcpy(void* dest, const void* src, size_t n) { return os::memcpy(dest, src, n); }
320         void*  os_memset(void* s, int c, size_t n) { return os::memset(s, c, n); }
321         int    os_mprotect(void* addr, size_t len, int prot) { return os::mprotect(addr, len, prot); }
322         int    os_scandir(const char* dir, struct dirent*** namelist, int(*filter)(const struct dirent*), int(*compar)(const void*, const void*)) { return os::scandir(dir, namelist, filter, compar); }
323         int    os_stat(const char* path, struct stat* buf) { return os::stat(path, buf); }
324         char*  os_strcat(char* dest, const char* src) { return os::strcat(dest, src); }
325         char*  os_strcpy(char* dest, const char* src) { return os::strcpy(dest, src); }
326         char*  os_strdup(const char* s) { return os::strdup(s); }
327         int    os_strlen(const char* s) { return os::strlen(s); }
328
329 }
330
331
332 /*
333  * These are local overrides for various environment variables in Emacs.
334  * Please do not remove this and leave it at the end of the file, where
335  * Emacs will automagically detect them.
336  * ---------------------------------------------------------------------
337  * Local variables:
338  * mode: c++
339  * indent-tabs-mode: t
340  * c-basic-offset: 4
341  * tab-width: 4
342  * End:
343  * vim:noexpandtab:sw=4:ts=4:
344  */