this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "os.h"
3
4#include <fcntl.h>
5#include <sys/mman.h>
6#include <sys/stat.h>
7#include <time.h>
8#include <unistd.h>
9
10#include <cerrno>
11#include <csignal>
12#include <cstdio>
13#include <cstdlib>
14#include <cstring>
15
16#include "globals.h"
17#include "utils.h"
18
19namespace py {
20
21// clang-format off
22#define V(SIGNAL) { #SIGNAL, SIGNAL }
23const OS::Signal OS::kStandardSignals[] = {
24 V(SIGABRT),
25 V(SIGALRM),
26 V(SIGBUS),
27 V(SIGCHLD),
28 V(SIGCONT),
29 V(SIGFPE),
30 V(SIGHUP),
31 V(SIGILL),
32 V(SIGINT),
33 V(SIGKILL),
34 V(SIGPIPE),
35 V(SIGQUIT),
36 V(SIGSEGV),
37 V(SIGSTOP),
38 V(SIGTERM),
39 V(SIGTRAP),
40 V(SIGTSTP),
41 V(SIGTTIN),
42 V(SIGTTOU),
43 V(SIGURG),
44 V(SIGUSR1),
45 V(SIGUSR2),
46 V(SIGXCPU),
47 V(SIGXFSZ),
48 { nullptr, 0 },
49};
50#undef V
51// clang-format on
52
53byte* OS::allocateMemory(word size, word* allocated_size) {
54 size = Utils::roundUp(size, kPageSize);
55 if (allocated_size != nullptr) *allocated_size = size;
56 int prot = PROT_READ | PROT_WRITE;
57 int flags = MAP_PRIVATE | MAP_ANONYMOUS;
58 void* result = ::mmap(nullptr, size, prot, flags, -1, 0);
59 CHECK(result != MAP_FAILED, "mmap failure");
60 return static_cast<byte*>(result);
61}
62
63bool OS::access(const char* path, int mode) {
64 return ::access(path, mode) == 0;
65}
66
67int OS::pageSize() { return ::sysconf(_SC_PAGESIZE); }
68
69bool OS::protectMemory(byte* address, word size, Protection mode) {
70 DCHECK(size >= 0, "invalid size %ld", size);
71 int prot;
72 switch (mode) {
73 case kNoAccess:
74 prot = PROT_NONE;
75 break;
76 case kReadWrite:
77 prot = PROT_READ | PROT_WRITE;
78 break;
79 case kReadExecute:
80 prot = PROT_READ | PROT_EXEC;
81 break;
82 case kReadWriteExecute:
83 prot = PROT_READ | PROT_WRITE | PROT_EXEC;
84 break;
85 default:
86 std::abort();
87 }
88 int result = mprotect(address, size, prot);
89 CHECK(result == 0, "mprotect failure");
90 return result == 0;
91}
92
93bool OS::freeMemory(byte* ptr, word size) {
94 DCHECK(size >= 0, "invalid size %ld", size);
95 int result = ::munmap(ptr, size);
96 CHECK(result != -1, "munmap failure");
97 return result == 0;
98}
99
100class ScopedFd {
101 public:
102 explicit ScopedFd(int fd) : fd_(fd) {}
103
104 ~ScopedFd() {
105 if (fd_ != -1) {
106 close(fd_);
107 }
108 }
109
110 int get() const { return fd_; }
111
112 private:
113 int fd_;
114 DISALLOW_COPY_AND_ASSIGN(ScopedFd);
115};
116
117bool OS::secureRandom(byte* ptr, word size) {
118 DCHECK(size >= 0, "invalid size %ld", size);
119 ScopedFd fd(::open("/dev/urandom", O_RDONLY));
120 if (fd.get() == -1) {
121 return false;
122 }
123 do {
124 word result;
125 do {
126 result = ::read(fd.get(), ptr, size);
127 } while (result == -1 && errno == EINTR);
128 if (result == -1) {
129 break;
130 }
131 size -= result;
132 ptr += result;
133 } while (size > 0);
134 return size == 0;
135}
136
137byte* OS::readFile(FILE* fp, word* len_out) {
138 std::fseek(fp, 0, SEEK_END);
139 word length = std::ftell(fp);
140 std::fseek(fp, 0, SEEK_SET);
141
142 word capacity = length <= 0 ? 4096 : length;
143 byte* buffer = reinterpret_cast<byte*>(std::malloc(capacity));
144 CHECK(buffer != nullptr, "out of memory");
145
146 length = 0;
147 do {
148 if (length == capacity) {
149 capacity *= 2;
150 buffer = reinterpret_cast<byte*>(std::realloc(buffer, capacity));
151 CHECK(buffer != nullptr, "out of memory");
152 }
153 length += std::fread(buffer + length, 1, capacity - length, fp);
154 } while (capacity > 0 && length >= capacity);
155 if (ferror(fp)) {
156 fprintf(stderr, "file read error: %s\n", std::strerror(errno));
157 std::free(buffer);
158 return nullptr;
159 }
160 *len_out = length;
161 return buffer;
162}
163
164bool OS::dirExists(const char* dir) {
165 struct stat st;
166 int err = ::stat(dir, &st);
167 if (err == 0 && (st.st_mode & S_IFDIR)) {
168 return true;
169 }
170 if (errno != 0 && errno != ENOENT) {
171 std::fprintf(stderr, "stat error: %s %s\n", dir, std::strerror(errno));
172 }
173 return false;
174}
175
176bool OS::fileExists(const char* file) {
177 struct stat st;
178 int err = ::stat(file, &st);
179 if (err == 0 && S_ISREG(st.st_mode)) {
180 return true;
181 }
182 if (errno != 0 && errno != ENOENT) {
183 std::fprintf(stderr, "stat error: %s %s\n", file, std::strerror(errno));
184 }
185 return false;
186}
187
188char* OS::readLink(const char* path) {
189 char* buffer = nullptr;
190 for (ssize_t size = 64;; size *= 2) {
191 buffer = reinterpret_cast<char*>(std::realloc(buffer, size));
192 CHECK(buffer != nullptr, "out of memory");
193 ssize_t res = ::readlink(path, buffer, size);
194 if (res == -1) {
195 std::free(buffer);
196 return nullptr;
197 }
198 if (res < size - 1) {
199 buffer[res] = '\0';
200 return buffer;
201 }
202 }
203}
204
205double OS::currentTime() {
206 timespec ts;
207 int err = clock_gettime(CLOCK_REALTIME, &ts);
208 CHECK(!err, "clock_gettime failure");
209
210 if (ts.tv_nsec == 0) {
211 return static_cast<double>(ts.tv_sec);
212 }
213
214 int64_t nanoseconds = ts.tv_sec * kNanosecondsPerSecond;
215 nanoseconds += ts.tv_nsec;
216 double result = static_cast<double>(nanoseconds);
217 result /= kNanosecondsPerSecond;
218 return result;
219}
220
221} // namespace py