blob: 22f2245f487bd9787bc1e97012f0e2fbf393914d [file] [log] [blame]
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000028// Platform specific code for Linux goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
31#include <pthread.h>
32#include <semaphore.h>
33#include <signal.h>
lrn@chromium.org5d00b602011-01-05 09:51:43 +000034#include <sys/prctl.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include <sys/time.h>
36#include <sys/resource.h>
lrn@chromium.org303ada72010-10-27 09:33:13 +000037#include <sys/syscall.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000038#include <sys/types.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include <stdlib.h>
40
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000041#if defined(__GLIBC__) && !defined(__UCLIBC__)
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000042#include <execinfo.h>
43#include <cxxabi.h>
44#endif
45
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046// Ubuntu Dapper requires memory pages to be marked as
47// executable. Otherwise, OS raises an exception when executing code
48// in that page.
49#include <sys/types.h> // mmap & munmap
ager@chromium.org236ad962008-09-25 09:45:57 +000050#include <sys/mman.h> // mmap & munmap
51#include <sys/stat.h> // open
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000052#include <fcntl.h> // open
53#include <unistd.h> // sysconf
ager@chromium.org236ad962008-09-25 09:45:57 +000054#include <strings.h> // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include <errno.h>
56#include <stdarg.h>
57
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000058// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
59// Old versions of the C library <signal.h> didn't define the type.
60#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
61 defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
62#include <asm/sigcontext.h>
63#endif
64
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065#undef MAP_TYPE
66
67#include "v8.h"
68
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000069#include "platform-posix.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000070#include "platform.h"
ager@chromium.orga1645e22009-09-09 19:27:10 +000071#include "v8threads.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000072#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073
74
kasperl@chromium.org71affb52009-05-26 05:44:31 +000075namespace v8 {
76namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077
78// 0 is never a valid thread id on Linux since tids and pids share a
79// name space and pid 0 is reserved (see man 2 kill).
80static const pthread_t kNoThread = (pthread_t) 0;
81
82
83double ceiling(double x) {
84 return ceil(x);
85}
86
87
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000088static Mutex* limit_mutex = NULL;
89
90
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000091void OS::PostSetUp() {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000092 POSIXPostSetUp();
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000093}
94
95
ager@chromium.orgc4c92722009-11-18 14:12:51 +000096uint64_t OS::CpuFeaturesImpliedByPlatform() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000097 return 0; // Linux runs on anything.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000098}
99
100
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000101#ifdef __arm__
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000102static bool CPUInfoContainsString(const char * search_string) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000103 const char* file_name = "/proc/cpuinfo";
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000104 // This is written as a straight shot one pass parser
105 // and not using STL string and ifstream because,
106 // on Linux, it's reading from a (non-mmap-able)
107 // character special device.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000108 FILE* f = NULL;
109 const char* what = search_string;
110
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000111 if (NULL == (f = fopen(file_name, "r"))) {
112 OS::PrintError("Failed to open /proc/cpuinfo\n");
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000113 return false;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000114 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000115
116 int k;
117 while (EOF != (k = fgetc(f))) {
118 if (k == *what) {
119 ++what;
120 while ((*what != '\0') && (*what == fgetc(f))) {
121 ++what;
122 }
123 if (*what == '\0') {
124 fclose(f);
125 return true;
126 } else {
127 what = search_string;
128 }
129 }
130 }
131 fclose(f);
132
133 // Did not find string in the proc file.
134 return false;
135}
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000136
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000137
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000138bool OS::ArmCpuHasFeature(CpuFeature feature) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000139 const char* search_string = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000140 // Simple detection of VFP at runtime for Linux.
141 // It is based on /proc/cpuinfo, which reveals hardware configuration
142 // to user-space applications. According to ARM (mid 2009), no similar
143 // facility is universally available on the ARM architectures,
144 // so it's up to individual OSes to provide such.
145 switch (feature) {
146 case VFP3:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000147 search_string = "vfpv3";
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000148 break;
149 case ARMv7:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000150 search_string = "ARMv7";
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000151 break;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000152 case SUDIV:
153 search_string = "idiva";
154 break;
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000155 case VFP32DREGS:
156 // This case is handled specially below.
157 break;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000158 default:
159 UNREACHABLE();
160 }
161
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000162 if (feature == VFP32DREGS) {
163 return ArmCpuHasFeature(VFP3) && !CPUInfoContainsString("d16");
164 }
165
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000166 if (CPUInfoContainsString(search_string)) {
167 return true;
168 }
169
170 if (feature == VFP3) {
171 // Some old kernels will report vfp not vfpv3. Here we make a last attempt
172 // to detect vfpv3 by checking for vfp *and* neon, since neon is only
173 // available on architectures with vfpv3.
174 // Checking neon on its own is not enough as it is possible to have neon
175 // without vfp.
176 if (CPUInfoContainsString("vfp") && CPUInfoContainsString("neon")) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000177 return true;
178 }
179 }
180
181 return false;
182}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000183
184
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000185CpuImplementer OS::GetCpuImplementer() {
186 static bool use_cached_value = false;
187 static CpuImplementer cached_value = UNKNOWN_IMPLEMENTER;
188 if (use_cached_value) {
189 return cached_value;
190 }
191 if (CPUInfoContainsString("CPU implementer\t: 0x41")) {
192 cached_value = ARM_IMPLEMENTER;
193 } else if (CPUInfoContainsString("CPU implementer\t: 0x51")) {
194 cached_value = QUALCOMM_IMPLEMENTER;
195 } else {
196 cached_value = UNKNOWN_IMPLEMENTER;
197 }
198 use_cached_value = true;
199 return cached_value;
200}
201
202
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000203bool OS::ArmUsingHardFloat() {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000204 // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
205 // the Floating Point ABI used (PCS stands for Procedure Call Standard).
206 // We use these as well as a couple of other defines to statically determine
207 // what FP ABI used.
208 // GCC versions 4.4 and below don't support hard-fp.
209 // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
210 // __ARM_PCS_VFP.
211
212#define GCC_VERSION (__GNUC__ * 10000 \
213 + __GNUC_MINOR__ * 100 \
214 + __GNUC_PATCHLEVEL__)
215#if GCC_VERSION >= 40600
216#if defined(__ARM_PCS_VFP)
217 return true;
218#else
219 return false;
220#endif
221
222#elif GCC_VERSION < 40500
223 return false;
224
225#else
226#if defined(__ARM_PCS_VFP)
227 return true;
228#elif defined(__ARM_PCS) || defined(__SOFTFP) || !defined(__VFP_FP__)
229 return false;
230#else
231#error "Your version of GCC does not report the FP ABI compiled for." \
232 "Please report it on this issue" \
233 "http://code.google.com/p/v8/issues/detail?id=2140"
234
235#endif
236#endif
237#undef GCC_VERSION
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000238}
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000239
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000240#endif // def __arm__
241
242
lrn@chromium.org7516f052011-03-30 08:52:27 +0000243#ifdef __mips__
244bool OS::MipsCpuHasFeature(CpuFeature feature) {
245 const char* search_string = NULL;
246 const char* file_name = "/proc/cpuinfo";
247 // Simple detection of FPU at runtime for Linux.
248 // It is based on /proc/cpuinfo, which reveals hardware configuration
249 // to user-space applications. According to MIPS (early 2010), no similar
250 // facility is universally available on the MIPS architectures,
251 // so it's up to individual OSes to provide such.
252 //
253 // This is written as a straight shot one pass parser
254 // and not using STL string and ifstream because,
255 // on Linux, it's reading from a (non-mmap-able)
256 // character special device.
257
258 switch (feature) {
259 case FPU:
260 search_string = "FPU";
261 break;
262 default:
263 UNREACHABLE();
264 }
265
266 FILE* f = NULL;
267 const char* what = search_string;
268
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000269 if (NULL == (f = fopen(file_name, "r"))) {
270 OS::PrintError("Failed to open /proc/cpuinfo\n");
lrn@chromium.org7516f052011-03-30 08:52:27 +0000271 return false;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000272 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000273
274 int k;
275 while (EOF != (k = fgetc(f))) {
276 if (k == *what) {
277 ++what;
278 while ((*what != '\0') && (*what == fgetc(f))) {
279 ++what;
280 }
281 if (*what == '\0') {
282 fclose(f);
283 return true;
284 } else {
285 what = search_string;
286 }
287 }
288 }
289 fclose(f);
290
291 // Did not find string in the proc file.
292 return false;
293}
294#endif // def __mips__
295
296
ager@chromium.org236ad962008-09-25 09:45:57 +0000297int OS::ActivationFrameAlignment() {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000298#ifdef V8_TARGET_ARCH_ARM
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000299 // On EABI ARM targets this is required for fp correctness in the
300 // runtime system.
ager@chromium.org3a6061e2009-03-12 14:24:36 +0000301 return 8;
ager@chromium.org5c838252010-02-19 08:53:10 +0000302#elif V8_TARGET_ARCH_MIPS
303 return 8;
304#endif
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000305 // With gcc 4.4 the tree vectorization optimizer can generate code
ager@chromium.orge2902be2009-06-08 12:21:35 +0000306 // that requires 16 byte alignment such as movdqa on x86.
307 return 16;
ager@chromium.org236ad962008-09-25 09:45:57 +0000308}
309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000310
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000311void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000312#if (defined(V8_TARGET_ARCH_ARM) && defined(__arm__)) || \
313 (defined(V8_TARGET_ARCH_MIPS) && defined(__mips__))
314 // Only use on ARM or MIPS hardware.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000315 MemoryBarrier();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000316#else
317 __asm__ __volatile__("" : : : "memory");
318 // An x86 store acts as a release barrier.
319#endif
320 *ptr = value;
321}
322
323
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000324const char* OS::LocalTimezone(double time) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000325 if (std::isnan(time)) return "";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000326 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
327 struct tm* t = localtime(&tv);
328 if (NULL == t) return "";
329 return t->tm_zone;
330}
331
332
333double OS::LocalTimeOffset() {
334 time_t tv = time(NULL);
335 struct tm* t = localtime(&tv);
336 // tm_gmtoff includes any daylight savings offset, so subtract it.
337 return static_cast<double>(t->tm_gmtoff * msPerSecond -
338 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
339}
340
341
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000342// We keep the lowest and highest addresses mapped as a quick way of
343// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000344// and verification). The estimate is conservative, i.e., not all addresses in
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345// 'allocated' space are actually allocated to our heap. The range is
346// [lowest, highest), inclusive on the low and and exclusive on the high end.
347static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
348static void* highest_ever_allocated = reinterpret_cast<void*>(0);
349
350
351static void UpdateAllocatedSpaceLimits(void* address, int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000352 ASSERT(limit_mutex != NULL);
353 ScopedLock lock(limit_mutex);
354
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 lowest_ever_allocated = Min(lowest_ever_allocated, address);
356 highest_ever_allocated =
357 Max(highest_ever_allocated,
358 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
359}
360
361
362bool OS::IsOutsideAllocatedSpace(void* address) {
363 return address < lowest_ever_allocated || address >= highest_ever_allocated;
364}
365
366
367size_t OS::AllocateAlignment() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000368 return sysconf(_SC_PAGESIZE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369}
370
371
kasper.lund7276f142008-07-30 08:49:36 +0000372void* OS::Allocate(const size_t requested,
373 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000374 bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000375 const size_t msize = RoundUp(requested, AllocateAlignment());
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000376 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000377 void* addr = OS::GetRandomMmapAddr();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000378 void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000379 if (mbase == MAP_FAILED) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000380 LOG(i::Isolate::Current(),
381 StringEvent("OS::Allocate", "mmap failed"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000382 return NULL;
383 }
384 *allocated = msize;
385 UpdateAllocatedSpaceLimits(mbase, msize);
386 return mbase;
387}
388
389
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000390void OS::Free(void* address, const size_t size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 // TODO(1240712): munmap has a return value which is ignored here.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000392 int result = munmap(address, size);
393 USE(result);
394 ASSERT(result == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395}
396
397
398void OS::Sleep(int milliseconds) {
399 unsigned int ms = static_cast<unsigned int>(milliseconds);
400 usleep(1000 * ms);
401}
402
403
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000404int OS::NumberOfCores() {
405 return sysconf(_SC_NPROCESSORS_ONLN);
406}
407
408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409void OS::Abort() {
410 // Redirect to std abort to signal abnormal program termination.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000411 if (FLAG_break_on_abort) {
412 DebugBreak();
413 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 abort();
415}
416
417
kasper.lund7276f142008-07-30 08:49:36 +0000418void OS::DebugBreak() {
ager@chromium.org5ec48922009-05-05 07:25:34 +0000419// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x,
420// which is the architecture of generated code).
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000421#if (defined(__arm__) || defined(__thumb__))
kasper.lund7276f142008-07-30 08:49:36 +0000422 asm("bkpt 0");
ager@chromium.org5c838252010-02-19 08:53:10 +0000423#elif defined(__mips__)
424 asm("break");
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000425#elif defined(__native_client__)
426 asm("hlt");
kasper.lund7276f142008-07-30 08:49:36 +0000427#else
428 asm("int $3");
429#endif
430}
431
432
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000433void OS::DumpBacktrace() {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000434#if defined(__GLIBC__) && !defined(__UCLIBC__)
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000435 void* trace[100];
436 int size = backtrace(trace, ARRAY_SIZE(trace));
437 char** symbols = backtrace_symbols(trace, size);
438 fprintf(stderr, "\n==== C stack trace ===============================\n\n");
439 if (size == 0) {
440 fprintf(stderr, "(empty)\n");
441 } else if (symbols == NULL) {
442 fprintf(stderr, "(no symbols)\n");
443 } else {
444 for (int i = 1; i < size; ++i) {
445 fprintf(stderr, "%2d: ", i);
446 char mangled[201];
447 if (sscanf(symbols[i], "%*[^(]%*[(]%200[^)+]", mangled) == 1) { // NOLINT
448 int status;
449 size_t length;
450 char* demangled = abi::__cxa_demangle(mangled, NULL, &length, &status);
451 fprintf(stderr, "%s\n", demangled ? demangled : mangled);
452 free(demangled);
453 } else {
454 fprintf(stderr, "??\n");
455 }
456 }
457 }
458 fflush(stderr);
459 free(symbols);
460#endif
461}
462
463
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000464class PosixMemoryMappedFile : public OS::MemoryMappedFile {
465 public:
466 PosixMemoryMappedFile(FILE* file, void* memory, int size)
467 : file_(file), memory_(memory), size_(size) { }
468 virtual ~PosixMemoryMappedFile();
469 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000470 virtual int size() { return size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471 private:
472 FILE* file_;
473 void* memory_;
474 int size_;
475};
476
477
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000478OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000479 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000480 if (file == NULL) return NULL;
481
482 fseek(file, 0, SEEK_END);
483 int size = ftell(file);
484
485 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000486 mmap(OS::GetRandomMmapAddr(),
487 size,
488 PROT_READ | PROT_WRITE,
489 MAP_SHARED,
490 fileno(file),
491 0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000492 return new PosixMemoryMappedFile(file, memory, size);
493}
494
495
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
497 void* initial) {
498 FILE* file = fopen(name, "w+");
499 if (file == NULL) return NULL;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000500 int result = fwrite(initial, size, 1, file);
501 if (result < 1) {
502 fclose(file);
503 return NULL;
504 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000506 mmap(OS::GetRandomMmapAddr(),
507 size,
508 PROT_READ | PROT_WRITE,
509 MAP_SHARED,
510 fileno(file),
511 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 return new PosixMemoryMappedFile(file, memory, size);
513}
514
515
516PosixMemoryMappedFile::~PosixMemoryMappedFile() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000517 if (memory_) OS::Free(memory_, size_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518 fclose(file_);
519}
520
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000521
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522void OS::LogSharedLibraryAddresses() {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000523 // This function assumes that the layout of the file is as follows:
524 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
525 // If we encounter an unexpected situation we abort scanning further entries.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000526 FILE* fp = fopen("/proc/self/maps", "r");
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000527 if (fp == NULL) return;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000528
529 // Allocate enough room to be able to store a full file name.
530 const int kLibNameLen = FILENAME_MAX + 1;
531 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 i::Isolate* isolate = ISOLATE;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000534 // This loop will terminate once the scanning hits an EOF.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535 while (true) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000536 uintptr_t start, end;
537 char attr_r, attr_w, attr_x, attr_p;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000538 // Parse the addresses and permission bits at the beginning of the line.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000539 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
540 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000541
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000542 int c;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000543 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
544 // Found a read-only executable entry. Skip characters until we reach
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000545 // the beginning of the filename or the end of the line.
546 do {
547 c = getc(fp);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000548 } while ((c != EOF) && (c != '\n') && (c != '/') && (c != '['));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000549 if (c == EOF) break; // EOF: Was unexpected, just exit.
550
551 // Process the filename if found.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000552 if ((c == '/') || (c == '[')) {
553 // Push the '/' or '[' back into the stream to be read below.
554 ungetc(c, fp);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000555
556 // Read to the end of the line. Exit if the read fails.
557 if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
558
559 // Drop the newline character read by fgets. We do not need to check
560 // for a zero-length string because we know that we at least read the
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000561 // '/' or '[' character.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000562 lib_name[strlen(lib_name) - 1] = '\0';
563 } else {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000564 // No library name found, just record the raw address range.
565 snprintf(lib_name, kLibNameLen,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000566 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
567 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 LOG(isolate, SharedLibraryEvent(lib_name, start, end));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000569 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000570 // Entry not describing executable data. Skip to end of line to set up
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000571 // reading the next entry.
572 do {
573 c = getc(fp);
574 } while ((c != EOF) && (c != '\n'));
575 if (c == EOF) break;
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577 }
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000578 free(lib_name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000579 fclose(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580}
581
582
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000583void OS::SignalCodeMovingGC() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000584 // Support for ll_prof.py.
585 //
586 // The Linux profiler built into the kernel logs all mmap's with
587 // PROT_EXEC so that analysis tools can properly attribute ticks. We
588 // do a mmap with a name known by ll_prof.py and immediately munmap
589 // it. This injects a GC marker into the stream of events generated
590 // by the kernel and allows us to synchronize V8 code log and the
591 // kernel log.
592 int size = sysconf(_SC_PAGESIZE);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000593 FILE* f = fopen(FLAG_gc_fake_mmap, "w+");
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000594 if (f == NULL) {
595 OS::PrintError("Failed to open %s\n", FLAG_gc_fake_mmap);
596 OS::Abort();
597 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000598 void* addr = mmap(OS::GetRandomMmapAddr(),
599 size,
600 PROT_READ | PROT_EXEC,
601 MAP_PRIVATE,
602 fileno(f),
603 0);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000604 ASSERT(addr != MAP_FAILED);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000605 OS::Free(addr, size);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000606 fclose(f);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000607}
608
609
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000610int OS::StackWalk(Vector<OS::StackFrame> frames) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000611 // backtrace is a glibc extension.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000612#if defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000613 int frames_size = frames.length();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000614 ScopedVector<void*> addresses(frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000616 int frames_count = backtrace(addresses.start(), frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000618 char** symbols = backtrace_symbols(addresses.start(), frames_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 if (symbols == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 return kStackWalkError;
621 }
622
623 for (int i = 0; i < frames_count; i++) {
624 frames[i].address = addresses[i];
625 // Format a text representation of the frame based on the information
626 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000627 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
628 "%s",
629 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 // Make sure line termination is in place.
631 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
632 }
633
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 free(symbols);
635
636 return frames_count;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000637#else // defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000638 return 0;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000639#endif // defined(__GLIBC__) && !defined(__UCLIBC__)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640}
641
642
643// Constants used for mmap.
644static const int kMmapFd = -1;
645static const int kMmapFdOffset = 0;
646
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000647
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000648VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000650
651VirtualMemory::VirtualMemory(size_t size)
652 : address_(ReserveRegion(size)), size_(size) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653
654
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000655VirtualMemory::VirtualMemory(size_t size, size_t alignment)
656 : address_(NULL), size_(0) {
657 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
658 size_t request_size = RoundUp(size + alignment,
659 static_cast<intptr_t>(OS::AllocateAlignment()));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000660 void* reservation = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000661 request_size,
662 PROT_NONE,
663 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
664 kMmapFd,
665 kMmapFdOffset);
666 if (reservation == MAP_FAILED) return;
667
668 Address base = static_cast<Address>(reservation);
669 Address aligned_base = RoundUp(base, alignment);
670 ASSERT_LE(base, aligned_base);
671
672 // Unmap extra memory reserved before and after the desired block.
673 if (aligned_base != base) {
674 size_t prefix_size = static_cast<size_t>(aligned_base - base);
675 OS::Free(base, prefix_size);
676 request_size -= prefix_size;
677 }
678
679 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
680 ASSERT_LE(aligned_size, request_size);
681
682 if (aligned_size != request_size) {
683 size_t suffix_size = request_size - aligned_size;
684 OS::Free(aligned_base + aligned_size, suffix_size);
685 request_size -= suffix_size;
686 }
687
688 ASSERT(aligned_size == request_size);
689
690 address_ = static_cast<void*>(aligned_base);
691 size_ = aligned_size;
692}
693
694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695VirtualMemory::~VirtualMemory() {
696 if (IsReserved()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000697 bool result = ReleaseRegion(address(), size());
698 ASSERT(result);
699 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700 }
701}
702
703
704bool VirtualMemory::IsReserved() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000705 return address_ != NULL;
706}
707
708
709void VirtualMemory::Reset() {
710 address_ = NULL;
711 size_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712}
713
714
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000715bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000716 return CommitRegion(address, size, is_executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717}
718
719
720bool VirtualMemory::Uncommit(void* address, size_t size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000721 return UncommitRegion(address, size);
722}
723
724
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000725bool VirtualMemory::Guard(void* address) {
726 OS::Guard(address, OS::CommitPageSize());
727 return true;
728}
729
730
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000731void* VirtualMemory::ReserveRegion(size_t size) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000732 void* result = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000733 size,
734 PROT_NONE,
735 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
736 kMmapFd,
737 kMmapFdOffset);
738
739 if (result == MAP_FAILED) return NULL;
740
741 return result;
742}
743
744
745bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
746 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
747 if (MAP_FAILED == mmap(base,
748 size,
749 prot,
750 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
751 kMmapFd,
752 kMmapFdOffset)) {
753 return false;
754 }
755
756 UpdateAllocatedSpaceLimits(base, size);
757 return true;
758}
759
760
761bool VirtualMemory::UncommitRegion(void* base, size_t size) {
762 return mmap(base,
763 size,
764 PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000765 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000766 kMmapFd,
767 kMmapFdOffset) != MAP_FAILED;
768}
769
770
771bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
772 return munmap(base, size) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773}
774
775
danno@chromium.org72204d52012-10-31 10:02:10 +0000776bool VirtualMemory::HasLazyCommits() {
777 return true;
778}
779
780
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000781class Thread::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782 public:
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000783 PlatformData() : thread_(kNoThread) {}
ager@chromium.org41826e72009-03-30 13:30:57 +0000784
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000785 pthread_t thread_; // Thread handle for pthread.
786};
787
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000788Thread::Thread(const Options& options)
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000789 : data_(new PlatformData()),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000790 stack_size_(options.stack_size()),
791 start_semaphore_(NULL) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000792 set_name(options.name());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793}
794
795
796Thread::~Thread() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000797 delete data_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798}
799
800
801static void* ThreadEntry(void* arg) {
802 Thread* thread = reinterpret_cast<Thread*>(arg);
803 // This is also initialized by the first argument to pthread_create() but we
804 // don't know which thread will run first (the original thread or the new
805 // one) so we initialize it here too.
danno@chromium.orgb6451162011-08-17 14:33:23 +0000806#ifdef PR_SET_NAME
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000807 prctl(PR_SET_NAME,
808 reinterpret_cast<unsigned long>(thread->name()), // NOLINT
809 0, 0, 0);
danno@chromium.orgb6451162011-08-17 14:33:23 +0000810#endif
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000811 thread->data()->thread_ = pthread_self();
812 ASSERT(thread->data()->thread_ != kNoThread);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000813 thread->NotifyStartedAndRun();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814 return NULL;
815}
816
817
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000818void Thread::set_name(const char* name) {
819 strncpy(name_, name, sizeof(name_));
820 name_[sizeof(name_) - 1] = '\0';
821}
822
823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824void Thread::Start() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 pthread_attr_t* attr_ptr = NULL;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000826#if defined(__native_client__)
827 // use default stack size.
828#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000829 pthread_attr_t attr;
830 if (stack_size_ > 0) {
831 pthread_attr_init(&attr);
832 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
833 attr_ptr = &attr;
834 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000835#endif
danno@chromium.orgc612e022011-11-10 11:38:15 +0000836 int result = pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
837 CHECK_EQ(0, result);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000838 ASSERT(data_->thread_ != kNoThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839}
840
841
842void Thread::Join() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000843 pthread_join(data_->thread_, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844}
845
846
847Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
848 pthread_key_t key;
849 int result = pthread_key_create(&key, NULL);
850 USE(result);
851 ASSERT(result == 0);
852 return static_cast<LocalStorageKey>(key);
853}
854
855
856void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
857 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
858 int result = pthread_key_delete(pthread_key);
859 USE(result);
860 ASSERT(result == 0);
861}
862
863
864void* Thread::GetThreadLocal(LocalStorageKey key) {
865 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
866 return pthread_getspecific(pthread_key);
867}
868
869
870void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
871 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
872 pthread_setspecific(pthread_key, value);
873}
874
875
876void Thread::YieldCPU() {
877 sched_yield();
878}
879
880
881class LinuxMutex : public Mutex {
882 public:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883 LinuxMutex() {
884 pthread_mutexattr_t attrs;
885 int result = pthread_mutexattr_init(&attrs);
886 ASSERT(result == 0);
887 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
888 ASSERT(result == 0);
889 result = pthread_mutex_init(&mutex_, &attrs);
890 ASSERT(result == 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000891 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892 }
893
894 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
895
896 virtual int Lock() {
897 int result = pthread_mutex_lock(&mutex_);
898 return result;
899 }
900
901 virtual int Unlock() {
902 int result = pthread_mutex_unlock(&mutex_);
903 return result;
904 }
905
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000906 virtual bool TryLock() {
907 int result = pthread_mutex_trylock(&mutex_);
908 // Return false if the lock is busy and locking failed.
909 if (result == EBUSY) {
910 return false;
911 }
912 ASSERT(result == 0); // Verify no other errors.
913 return true;
914 }
915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916 private:
917 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
918};
919
920
921Mutex* OS::CreateMutex() {
922 return new LinuxMutex();
923}
924
925
926class LinuxSemaphore : public Semaphore {
927 public:
928 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
929 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
930
kasper.lund7276f142008-07-30 08:49:36 +0000931 virtual void Wait();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000932 virtual bool Wait(int timeout);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 virtual void Signal() { sem_post(&sem_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 private:
935 sem_t sem_;
936};
937
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000938
kasper.lund7276f142008-07-30 08:49:36 +0000939void LinuxSemaphore::Wait() {
940 while (true) {
941 int result = sem_wait(&sem_);
942 if (result == 0) return; // Successfully got semaphore.
943 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
944 }
945}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000947
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000948#ifndef TIMEVAL_TO_TIMESPEC
949#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
950 (ts)->tv_sec = (tv)->tv_sec; \
951 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
952} while (false)
953#endif
954
955
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000956bool LinuxSemaphore::Wait(int timeout) {
957 const long kOneSecondMicros = 1000000; // NOLINT
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000958
959 // Split timeout into second and nanosecond parts.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000960 struct timeval delta;
961 delta.tv_usec = timeout % kOneSecondMicros;
962 delta.tv_sec = timeout / kOneSecondMicros;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000963
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000964 struct timeval current_time;
965 // Get the current time.
966 if (gettimeofday(&current_time, NULL) == -1) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000967 return false;
968 }
969
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000970 // Calculate time for end of timeout.
971 struct timeval end_time;
972 timeradd(&current_time, &delta, &end_time);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000973
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000974 struct timespec ts;
975 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000976 // Wait for semaphore signalled or timeout.
977 while (true) {
978 int result = sem_timedwait(&sem_, &ts);
979 if (result == 0) return true; // Successfully got semaphore.
980 if (result > 0) {
981 // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
982 errno = result;
983 result = -1;
984 }
985 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
986 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
987 }
988}
989
990
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991Semaphore* OS::CreateSemaphore(int count) {
992 return new LinuxSemaphore(count);
993}
994
ager@chromium.org381abbb2009-02-25 13:23:22 +0000995
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000996void OS::SetUp() {
997 // Seed the random number generator. We preserve microsecond resolution.
998 uint64_t seed = Ticks() ^ (getpid() << 16);
999 srandom(static_cast<unsigned int>(seed));
1000 limit_mutex = CreateMutex();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001001}
1002
1003
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001004void OS::TearDown() {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001005 delete limit_mutex;
1006}
1007
1008
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009} } // namespace v8::internal