blob: c4b0fb8226e79e98d2a1d30a4dd565b56b569e53 [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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
28// Platform specific code for POSIX goes here. This is not a platform on its
29// own but contains the parts which are the same across POSIX platforms Linux,
Steve Blockd0582a62009-12-15 09:54:21 +000030// Mac OS, FreeBSD and OpenBSD.
Steve Blocka7e24c12009-10-30 11:49:00 +000031
32#include <unistd.h>
33#include <errno.h>
34#include <time.h>
35
36#include <sys/socket.h>
37#include <sys/resource.h>
38#include <sys/time.h>
39#include <sys/types.h>
40
41#include <arpa/inet.h>
42#include <netinet/in.h>
43#include <netdb.h>
44
45#if defined(ANDROID)
46#define LOG_TAG "v8"
47#include <utils/Log.h> // LOG_PRI_VA
48#endif
49
50#include "v8.h"
51
52#include "platform.h"
53
54namespace v8 {
55namespace internal {
56
Steve Block3ce2e202009-11-05 08:53:23 +000057// ----------------------------------------------------------------------------
58// Math functions
59
60double modulo(double x, double y) {
61 return fmod(x, y);
62}
Steve Blocka7e24c12009-10-30 11:49:00 +000063
Steve Blockd0582a62009-12-15 09:54:21 +000064
65double OS::nan_value() {
66 // NAN from math.h is defined in C99 and not in POSIX.
67 return NAN;
68}
69
70
Steve Blocka7e24c12009-10-30 11:49:00 +000071// ----------------------------------------------------------------------------
72// POSIX date/time support.
73//
74
75int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
76 struct rusage usage;
77
78 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
79 *secs = usage.ru_utime.tv_sec;
80 *usecs = usage.ru_utime.tv_usec;
81 return 0;
82}
83
84
85double OS::TimeCurrentMillis() {
86 struct timeval tv;
87 if (gettimeofday(&tv, NULL) < 0) return 0.0;
88 return (static_cast<double>(tv.tv_sec) * 1000) +
89 (static_cast<double>(tv.tv_usec) / 1000);
90}
91
92
93int64_t OS::Ticks() {
94 // gettimeofday has microsecond resolution.
95 struct timeval tv;
96 if (gettimeofday(&tv, NULL) < 0)
97 return 0;
98 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
99}
100
101
Steve Blocka7e24c12009-10-30 11:49:00 +0000102double OS::DaylightSavingsOffset(double time) {
103 if (isnan(time)) return nan_value();
104 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
105 struct tm* t = localtime(&tv);
106 if (NULL == t) return nan_value();
107 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
108}
109
110
Iain Merrick75681382010-08-19 15:07:18 +0100111int OS::GetLastError() {
112 return errno;
113}
114
115
Steve Blocka7e24c12009-10-30 11:49:00 +0000116// ----------------------------------------------------------------------------
117// POSIX stdio support.
118//
119
120FILE* OS::FOpen(const char* path, const char* mode) {
121 return fopen(path, mode);
122}
123
124
Steve Block1e0659c2011-05-24 12:43:12 +0100125bool OS::Remove(const char* path) {
126 return (remove(path) == 0);
127}
128
129
Steve Block44f0eee2011-05-26 01:26:41 +0100130const char* const OS::LogFileOpenMode = "w";
Steve Blocka7e24c12009-10-30 11:49:00 +0000131
132
133void OS::Print(const char* format, ...) {
134 va_list args;
135 va_start(args, format);
136 VPrint(format, args);
137 va_end(args);
138}
139
140
141void OS::VPrint(const char* format, va_list args) {
Steve Block44f0eee2011-05-26 01:26:41 +0100142#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
Steve Blocka7e24c12009-10-30 11:49:00 +0000143 LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, format, args);
144#else
145 vprintf(format, args);
146#endif
147}
148
149
Ben Murdochb0fe1622011-05-05 13:52:32 +0100150void OS::FPrint(FILE* out, const char* format, ...) {
151 va_list args;
152 va_start(args, format);
153 VFPrint(out, format, args);
154 va_end(args);
155}
156
157
158void OS::VFPrint(FILE* out, const char* format, va_list args) {
Steve Block44f0eee2011-05-26 01:26:41 +0100159#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
Ben Murdochb0fe1622011-05-05 13:52:32 +0100160 LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, format, args);
161#else
162 vfprintf(out, format, args);
163#endif
164}
165
166
Steve Blocka7e24c12009-10-30 11:49:00 +0000167void OS::PrintError(const char* format, ...) {
168 va_list args;
169 va_start(args, format);
170 VPrintError(format, args);
171 va_end(args);
172}
173
174
175void OS::VPrintError(const char* format, va_list args) {
Steve Block44f0eee2011-05-26 01:26:41 +0100176#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 LOG_PRI_VA(ANDROID_LOG_ERROR, LOG_TAG, format, args);
178#else
179 vfprintf(stderr, format, args);
180#endif
181}
182
183
184int OS::SNPrintF(Vector<char> str, const char* format, ...) {
185 va_list args;
186 va_start(args, format);
187 int result = VSNPrintF(str, format, args);
188 va_end(args);
189 return result;
190}
191
192
193int OS::VSNPrintF(Vector<char> str,
194 const char* format,
195 va_list args) {
196 int n = vsnprintf(str.start(), str.length(), format, args);
197 if (n < 0 || n >= str.length()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100198 // If the length is zero, the assignment fails.
199 if (str.length() > 0)
200 str[str.length() - 1] = '\0';
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 return -1;
202 } else {
203 return n;
204 }
205}
206
207
Ben Murdoch8b112d22011-06-08 16:22:53 +0100208#if defined(V8_TARGET_ARCH_IA32)
209static OS::MemCopyFunction memcopy_function = NULL;
210static Mutex* memcopy_function_mutex = OS::CreateMutex();
211// Defined in codegen-ia32.cc.
212OS::MemCopyFunction CreateMemCopyFunction();
213
214// Copy memory area to disjoint memory area.
215void OS::MemCopy(void* dest, const void* src, size_t size) {
216 if (memcopy_function == NULL) {
217 ScopedLock lock(memcopy_function_mutex);
218 if (memcopy_function == NULL) {
219 OS::MemCopyFunction temp = CreateMemCopyFunction();
220 MemoryBarrier();
221 memcopy_function = temp;
222 }
223 }
224 // Note: here we rely on dependent reads being ordered. This is true
225 // on all architectures we currently support.
226 (*memcopy_function)(dest, src, size);
227#ifdef DEBUG
228 CHECK_EQ(0, memcmp(dest, src, size));
229#endif
230}
231#endif // V8_TARGET_ARCH_IA32
232
Steve Blocka7e24c12009-10-30 11:49:00 +0000233// ----------------------------------------------------------------------------
234// POSIX string support.
235//
236
237char* OS::StrChr(char* str, int c) {
238 return strchr(str, c);
239}
240
241
242void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
243 strncpy(dest.start(), src, n);
244}
245
246
247// ----------------------------------------------------------------------------
248// POSIX socket support.
249//
250
251class POSIXSocket : public Socket {
252 public:
253 explicit POSIXSocket() {
254 // Create the socket.
255 socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100256 if (IsValid()) {
257 // Allow rapid reuse.
258 static const int kOn = 1;
259 int ret = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
260 &kOn, sizeof(kOn));
261 ASSERT(ret == 0);
262 USE(ret);
263 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000264 }
265 explicit POSIXSocket(int socket): socket_(socket) { }
266 virtual ~POSIXSocket() { Shutdown(); }
267
268 // Server initialization.
269 bool Bind(const int port);
270 bool Listen(int backlog) const;
271 Socket* Accept() const;
272
273 // Client initialization.
274 bool Connect(const char* host, const char* port);
275
276 // Shutdown socket for both read and write.
277 bool Shutdown();
278
279 // Data Transimission
280 int Send(const char* data, int len) const;
281 int Receive(char* data, int len) const;
282
283 bool SetReuseAddress(bool reuse_address);
284
285 bool IsValid() const { return socket_ != -1; }
286
287 private:
288 int socket_;
289};
290
291
292bool POSIXSocket::Bind(const int port) {
293 if (!IsValid()) {
294 return false;
295 }
296
297 sockaddr_in addr;
298 memset(&addr, 0, sizeof(addr));
299 addr.sin_family = AF_INET;
300 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
301 addr.sin_port = htons(port);
302 int status = bind(socket_,
Iain Merrick75681382010-08-19 15:07:18 +0100303 BitCast<struct sockaddr *>(&addr),
Steve Blocka7e24c12009-10-30 11:49:00 +0000304 sizeof(addr));
305 return status == 0;
306}
307
308
309bool POSIXSocket::Listen(int backlog) const {
310 if (!IsValid()) {
311 return false;
312 }
313
314 int status = listen(socket_, backlog);
315 return status == 0;
316}
317
318
319Socket* POSIXSocket::Accept() const {
320 if (!IsValid()) {
321 return NULL;
322 }
323
324 int socket = accept(socket_, NULL, NULL);
325 if (socket == -1) {
326 return NULL;
327 } else {
328 return new POSIXSocket(socket);
329 }
330}
331
332
333bool POSIXSocket::Connect(const char* host, const char* port) {
334 if (!IsValid()) {
335 return false;
336 }
337
338 // Lookup host and port.
339 struct addrinfo *result = NULL;
340 struct addrinfo hints;
341 memset(&hints, 0, sizeof(addrinfo));
342 hints.ai_family = AF_INET;
343 hints.ai_socktype = SOCK_STREAM;
344 hints.ai_protocol = IPPROTO_TCP;
345 int status = getaddrinfo(host, port, &hints, &result);
346 if (status != 0) {
347 return false;
348 }
349
350 // Connect.
351 status = connect(socket_, result->ai_addr, result->ai_addrlen);
352 freeaddrinfo(result);
353 return status == 0;
354}
355
356
357bool POSIXSocket::Shutdown() {
358 if (IsValid()) {
359 // Shutdown socket for both read and write.
360 int status = shutdown(socket_, SHUT_RDWR);
361 close(socket_);
362 socket_ = -1;
363 return status == 0;
364 }
365 return true;
366}
367
368
369int POSIXSocket::Send(const char* data, int len) const {
370 int status = send(socket_, data, len, 0);
371 return status;
372}
373
374
375int POSIXSocket::Receive(char* data, int len) const {
376 int status = recv(socket_, data, len, 0);
377 return status;
378}
379
380
381bool POSIXSocket::SetReuseAddress(bool reuse_address) {
382 int on = reuse_address ? 1 : 0;
383 int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
384 return status == 0;
385}
386
387
388bool Socket::Setup() {
389 // Nothing to do on POSIX.
390 return true;
391}
392
393
394int Socket::LastError() {
395 return errno;
396}
397
398
399uint16_t Socket::HToN(uint16_t value) {
400 return htons(value);
401}
402
403
404uint16_t Socket::NToH(uint16_t value) {
405 return ntohs(value);
406}
407
408
409uint32_t Socket::HToN(uint32_t value) {
410 return htonl(value);
411}
412
413
414uint32_t Socket::NToH(uint32_t value) {
415 return ntohl(value);
416}
417
418
419Socket* OS::CreateSocket() {
420 return new POSIXSocket();
421}
422
423
424} } // namespace v8::internal