merged volatile memory barriers
[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 #if defined(__DARWIN__)
30 # include <mach/mach.h>
31 # include <mach/mach_host.h>
32 # include <mach/host_info.h>
33 #endif
34
35 /* this should work on BSD */
36 /* #include <sys/sysctl.h> */
37
38 #include "mm/memory.hpp"
39
40 #include "vm/os.hpp"
41 #include "vm/vm.hpp"
42
43
44 /**
45  * Prints an error message and aborts the VM.
46  *
47  * @param text Error message to print.
48  */
49 void os::abort(const char* text, ...)
50 {
51         va_list ap;
52
53         // Print the log message.
54         log_start();
55
56         va_start(ap, text);
57         log_vprint(text, ap);
58         va_end(ap);
59
60         log_finish();
61
62         // Print a backtrace.
63         os::print_backtrace();
64
65         // Now abort the VM.
66         os::abort();
67 }
68
69
70 /**
71  * Common code for both os::abort_errnum and os::abort_errno.
72  */
73 static void abort_verrnum(int errnum, const char* text, va_list ap)
74 {
75         // Print the log message.
76         log_start();
77
78         log_vprint(text, ap);
79
80         // Print the strerror-message of errnum.
81         log_print(": %s", os::strerror(errnum));
82
83         log_finish();
84
85         // Print a backtrace.
86         os::print_backtrace();
87
88         // Now abort the VM.
89         os::abort();
90 }
91
92 /**
93  * Prints an error message, appends ":" plus the strerror-message of
94  * errnum and aborts the VM.
95  *
96  * @param errnum Error number.
97  * @param text   Error message to print.
98  */
99 void os::abort_errnum(int errnum, const char* text, ...)
100 {
101         va_list ap;
102
103         va_start(ap, text);
104         abort_verrnum(errnum, text, ap);
105         va_end(ap);
106 }
107
108
109 /**
110  * Equal to abort_errnum, but uses errno to get the error number.
111  *
112  * @param text Error message to print.
113  */
114 void os::abort_errno(const char* text, ...)
115 {
116         va_list ap;
117
118         va_start(ap, text);
119         abort_verrnum(errno, text, ap);
120         va_end(ap);
121 }
122
123
124 /**
125  * Return the current working directory.
126  *
127  * @return Pointer to a char array allocated by MNEW, or
128  *         NULL if memory could not be allocated.
129  */
130 char* os::getcwd(void)
131 {
132         int32_t size = 1024;
133
134         char* buf = MNEW(char, size);
135
136         while (buf != NULL) {
137                 if (getcwd(buf, size) != NULL)
138                         return buf;
139
140                 MFREE(buf, char, size);
141
142                 /* too small buffer or a more serious problem */
143
144                 if (errno != ERANGE)
145                         abort_errno("os::getcwd: getcwd failed");
146
147                 /* double the buffer size */
148
149                 size *= 2;
150
151                 buf = MNEW(char, size);
152         }
153
154         return NULL;
155 }
156
157
158 /**
159  * Maps anonymous memory, even on systems not defining
160  * MAP_ANON(YMOUS).
161  *
162  * @param ...
163  */
164 void* os::mmap_anonymous(void *addr, size_t len, int prot, int flags)
165 {
166         void* p;
167
168 #if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
169         p = mmap(addr, len, prot,
170 # if defined(MAP_ANON)
171                          MAP_ANON | flags,
172 # else
173                          MAP_ANONYMOUS | flags,
174 # endif
175                          -1, 0);
176 #else
177         int fd;
178
179         fd = open("/dev/zero", O_RDONLY, 0);
180
181         if (fd == -1)
182                 os::abort_errno("os::mmap_anonymous: open failed");
183
184         p = mmap(addr, len, prot, flags, fd, 0);
185 #endif
186
187 #if defined(MAP_FAILED)
188         if (p == MAP_FAILED)
189 #else
190         if (p == (void *) -1)
191 #endif
192                 os::abort_errno("os::mmap_anonymous: mmap failed");
193
194         return p;
195 }
196
197
198 /**
199  * Print a C backtrace.
200  */
201 void os::print_backtrace()
202 {
203 #define BACKTRACE_SIZE 100
204         void** array = new void*[SIZEOF_VOID_P * BACKTRACE_SIZE];
205
206         // Get the backtrace.
207         int size = backtrace(array, BACKTRACE_SIZE);
208
209         // Resolve the symbols.
210         char** strings = backtrace_symbols(array, size);
211
212         log_println("Backtrace (%d stack frames):", size);
213
214         for (int i = 0; i < size; i++)
215                 log_println("%s", strings[i]);
216
217         // We have to free the strings.
218         free(strings);
219 }
220
221
222 /**
223  * Returns the number of online processors in the system.
224  *
225  * @return Number of online processors.
226  */
227 int os::processors_online(void)
228 {
229 #if defined(_SC_NPROC_ONLN)
230
231         return (int) sysconf(_SC_NPROC_ONLN);
232
233 #elif defined(_SC_NPROCESSORS_ONLN)
234
235         return (int) sysconf(_SC_NPROCESSORS_ONLN);
236
237 #elif defined(__DARWIN__)
238
239         host_basic_info_data_t hinfo;
240         mach_msg_type_number_t hinfo_count = HOST_BASIC_INFO_COUNT;
241         kern_return_t rc;
242
243         rc = host_info(mach_host_self(), HOST_BASIC_INFO,
244                                    (host_info_t) &hinfo, &hinfo_count);
245  
246         if (rc != KERN_SUCCESS) {
247                 return -1;
248         }
249
250         /* XXX michi: according to my infos this should be
251            hinfo.max_cpus, can someone please confirm or deny that? */
252         return (int) hinfo.avail_cpus;
253
254 #elif defined(__FREEBSD__)
255 # error IMPLEMENT ME!
256
257         /* this should work in BSD */
258         /*
259         int ncpu, mib[2], rc;
260         size_t len;
261
262         mib[0] = CTL_HW;
263         mib[1] = HW_NCPU;
264         len = sizeof(ncpu);
265         rc = sysctl(mib, 2, &ncpu, &len, NULL, 0);
266
267         return (int32_t) ncpu;
268         */
269
270 #else
271
272         return 1;
273
274 #endif
275 }
276
277
278 // Legacy C interface.
279
280 extern "C" {
281         void*  os_mmap_anonymous(void *addr, size_t len, int prot, int flags) { return os::mmap_anonymous(addr, len, prot, flags); }
282
283         int    os_atoi(const char* nptr) { return os::atoi(nptr); }
284         int    os_getpagesize(void) { return os::getpagesize(); }
285         void*  os_memcpy(void* dest, const void* src, size_t n) { return os::memcpy(dest, src, n); }
286         void*  os_memset(void* s, int c, size_t n) { return os::memset(s, c, n); }
287         char*  os_strdup(const char* s) { return os::strdup(s); }
288         int    os_strlen(const char* s) { return os::strlen(s); }
289
290 }
291
292
293 /*
294  * These are local overrides for various environment variables in Emacs.
295  * Please do not remove this and leave it at the end of the file, where
296  * Emacs will automagically detect them.
297  * ---------------------------------------------------------------------
298  * Local variables:
299  * mode: c++
300  * indent-tabs-mode: t
301  * c-basic-offset: 4
302  * tab-width: 4
303  * End:
304  * vim:noexpandtab:sw=4:ts=4:
305  */