OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/os_compat_android.h" | 5 #include "base/os_compat_android.h" |
6 | 6 |
7 #include <errno.h> | |
8 #include <math.h> | |
9 #include <sys/stat.h> | |
7 #include <time64.h> | 10 #include <time64.h> |
8 | 11 |
9 #include "base/stringprintf.h" | 12 #include "base/stringprintf.h" |
10 | 13 |
11 // There is no futimes() avaiable in Bionic, so we provide our own | 14 // There is no futimes() avaiable in Bionic, so we provide our own |
12 // implementation until it is there. | 15 // implementation until it is there. |
13 extern "C" { | 16 extern "C" { |
14 | 17 |
15 int futimes(int fd, const struct timeval tv[2]) { | 18 int futimes(int fd, const struct timeval tv[2]) { |
16 const std::string fd_path = StringPrintf("/proc/self/fd/%d", fd); | 19 const std::string fd_path = StringPrintf("/proc/self/fd/%d", fd); |
17 return utimes(fd_path.c_str(), tv); | 20 return utimes(fd_path.c_str(), tv); |
18 } | 21 } |
19 | 22 |
20 // Android has only timegm64() and no timegm(). | 23 // Android has only timegm64() and no timegm(). |
21 // We replicate the behaviour of timegm() when the result overflows time_t. | 24 // We replicate the behaviour of timegm() when the result overflows time_t. |
22 time_t timegm(struct tm* const t) { | 25 time_t timegm(struct tm* const t) { |
23 // time_t is signed on Android. | 26 // time_t is signed on Android. |
24 static const time_t kTimeMax = ~(1 << (sizeof(time_t) * CHAR_BIT - 1)); | 27 static const time_t kTimeMax = ~(1 << (sizeof(time_t) * CHAR_BIT - 1)); |
25 static const time_t kTimeMin = (1 << (sizeof(time_t) * CHAR_BIT - 1)); | 28 static const time_t kTimeMin = (1 << (sizeof(time_t) * CHAR_BIT - 1)); |
26 time64_t result = timegm64(t); | 29 time64_t result = timegm64(t); |
27 if (result < kTimeMin || result > kTimeMax) | 30 if (result < kTimeMin || result > kTimeMax) |
28 return -1; | 31 return -1; |
29 return result; | 32 return result; |
30 } | 33 } |
31 | 34 |
35 // The following is only needed when building with GCC 4.6 or higher | |
36 // (i.e. not with Android GCC 4.4.3, nor with Clang). | |
37 // | |
38 // GCC is now capable of optimizing successive calls to sin() and cos() into | |
39 // a single call to sincos(). This means that source code that looks like: | |
40 // | |
41 // double c, s; | |
42 // c = cos(angle); | |
43 // s = sin(angle); | |
44 // | |
45 // Will generate machine code that looks like: | |
46 // | |
47 // double c, s; | |
48 // sincos(angle, &s, &c); | |
49 // | |
50 // Unfortunately, sincos() and friends are not part of the Android libm.so | |
51 // library provided by the NDK for API level 9. When the optimization kicks | |
52 // in, it makes the final build fail with a puzzling message (puzzling | |
53 // because 'sincos' doesn't appear anywhere in the sources!). | |
54 // | |
55 // To solve this, we provide our own implementation of the sincos() function | |
56 // and related friends. Note that we must also explicitely tell GCC to disable | |
57 // optimizations when generating these. Otherwise, the generated machine code | |
58 // for each function would simply end up calling itself, resulting in a | |
59 // runtime crash due to stack overflow. | |
60 // | |
61 #if defined(__GNUC__) && !defined(__clang__) | |
62 | |
63 // For the record, Clang does not support the 'optimize' attribute. | |
64 // In the unlikely event that it begins performing this optimization too, | |
65 // we'll have to find a different way to achieve this. NOTE: Tested with O1 | |
66 // which still performs the optimization. | |
67 // | |
68 #define GCC_NO_OPTIMIZE __attribute__((optimize("O0"))) | |
69 | |
70 GCC_NO_OPTIMIZE | |
71 void sincos(double angle, double* s, double *c) | |
72 { | |
brettw
2012/07/10 20:56:04
Style: Check placement of { throughout this patch
felipeg
2012/07/11 15:26:24
Done.
| |
73 *c = cos(angle); | |
74 *s = sin(angle); | |
75 } | |
76 | |
77 GCC_NO_OPTIMIZE | |
78 void sincosf(float angle, float* s, float* c) | |
79 { | |
80 *c = cosf(angle); | |
81 *s = sinf(angle); | |
82 } | |
83 | |
84 #endif // __GNUC__ && !__clang__ | |
85 | |
86 // An implementation of mkdtemp, since it is not exposed by the NDK | |
87 // for native API level 9 that we target. | |
88 char* mkdtemp(char* path) | |
89 { | |
90 if (path == NULL) { | |
91 errno = EINVAL; | |
92 return NULL; | |
93 } | |
94 | |
95 int len = strlen(path); | |
96 int suffix = len; | |
97 | |
98 // The last six characters of 'path' must be XXXXXX, but the string | |
99 // can be terminated by a longer string of 'X'. Find its start at | |
100 // 'suffix'. | |
101 while (suffix > 0 && path[suffix-1] == 'X') | |
102 suffix--; | |
103 | |
104 // Error if there aren't at least 6 'X' characters at the end | |
105 if (len - suffix < 6) { | |
106 errno = EINVAL; | |
107 return NULL; | |
108 } | |
109 | |
110 // If the path contains a directory, as in /tmp/foo/XXXXXXXX, make sure | |
111 // that /tmp/foo exists, otherwise we're going to loop a really long | |
112 // time for nothing below | |
113 char* dirsep = strrchr(path, '/'); | |
114 if (dirsep != NULL) { | |
115 struct stat st; | |
116 int ret; | |
117 | |
118 *dirsep = '\0'; // Terminating directory path temporarily | |
brettw
2012/07/10 20:56:04
Style: two spaces before end-of-line comments. Che
felipeg
2012/07/11 15:26:24
Done.
| |
119 | |
120 ret = stat(path, &st); | |
121 | |
122 *dirsep = '/'; // Restoring directory separator | |
123 if (ret < 0) { // Directory probably does not exist | |
124 return NULL; | |
125 } | |
brettw
2012/07/10 20:56:04
Don't use {} here since you don't elsewhere.
felipeg
2012/07/11 15:26:24
Done.
| |
126 if (!S_ISDIR(st.st_mode)) { // Not a directory | |
127 errno = ENOTDIR; | |
128 return NULL; | |
129 } | |
130 } | |
131 | |
132 // Now replace all the XXXXXs with a random alphanumerical string. We're | |
133 // going to use something like <randomchars><pid>, where <randomchars> is | |
134 // a string of random alphabetical characters, and <pid> is the decimal | |
135 // pid string. This matches the BSD implementation. | |
brettw
2012/07/10 20:56:04
I wonder if all of this is necessary. The man page
digit1
2012/07/11 15:40:48
First, for the record, this code is taken from rec
| |
136 pid_t pid = gettid(); | |
137 int pos = len - 1; | |
138 | |
139 // First, write the pid from last to first digit | |
140 while (pos >= suffix && pid != 0) { | |
141 path[pos--] = '0' + (pid % 10); | |
142 pid /= 10; | |
143 } | |
144 | |
145 // Then, add some random chars until we cover all the XXXXs | |
146 while (pos >= suffix) { | |
147 int ch = (arc4random() & 0xffff) % (26+26); | |
148 if (ch < 26) | |
149 ch = 'A' + ch; | |
150 else | |
151 ch = 'a' + (ch - 26); | |
152 | |
153 path[pos--] = (char)ch; | |
brettw
2012/07/10 20:56:04
Don't use C casts, use static_cast.
felipeg
2012/07/11 15:26:24
Done.
| |
154 } | |
155 | |
156 // Now loop until we CAN create a directory by that name. Otherwise, | |
157 // 'increment' the characters after suffix to find a free one. | |
158 for (;;) { | |
159 | |
160 if (mkdir(path, 0700) == 0) { | |
brettw
2012/07/10 20:56:04
I'd skip the blank line above here.
felipeg
2012/07/11 15:26:24
Done.
| |
161 // We just created the directory succesfully. | |
162 return path; | |
163 } | |
164 | |
165 if (errno != EEXIST) { | |
166 // The directory doesn't exist, but an error occured | |
167 return NULL; | |
168 } | |
169 | |
170 // The directory does exist, find a new name by 'incrementing' from | |
171 // left to right, the rules are: | |
172 // A -> B | |
173 // B -> C | |
174 // ... | |
175 // Z -> a | |
176 // a -> b | |
177 // b -> c | |
178 // ... | |
179 // z -> A + increment the next character | |
180 // | |
181 // 0..9 -> A | |
182 pos = suffix; | |
183 for (;;) { | |
184 int ch = path[pos]; | |
185 if (ch == 'Z') { // Z -> a | |
186 path[pos] = 'a'; | |
187 break; | |
188 } | |
189 if (ch == 'z') { // z -> A + increment the next character | |
190 path[pos++] = 'A'; | |
191 if (pos == len) { | |
192 // uh-oh, we're out of candidates here | |
193 return 0; | |
194 } | |
195 continue; | |
196 } | |
197 if (ch >= '0' && ch <= '9') { // 0...9 -> A | |
198 path[pos] = 'A'; | |
199 break; | |
200 } | |
201 path[pos] += 1; // otherwise: $ch -> $ch + 1 | |
202 break; | |
203 } | |
204 } | |
205 } | |
206 | |
32 } // extern "C" | 207 } // extern "C" |
OLD | NEW |