Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "vm/PosixNSPR.h"
9 #include "js/Utility.h"
11 #ifdef JS_POSIX_NSPR
13 #include <errno.h>
14 #include <sys/time.h>
15 #include <time.h>
17 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
18 #include <pthread_np.h>
19 #endif
21 class nspr::Thread
22 {
23 pthread_t pthread_;
24 void (*start)(void *arg);
25 void *arg;
26 bool joinable;
28 public:
29 Thread(void (*start)(void *arg), void *arg, bool joinable)
30 : start(start), arg(arg), joinable(joinable) {}
32 static void *ThreadRoutine(void *arg);
34 pthread_t &pthread() { return pthread_; }
35 };
37 static pthread_key_t gSelfThreadIndex;
38 static nspr::Thread gMainThread(nullptr, nullptr, false);
40 void *
41 nspr::Thread::ThreadRoutine(void *arg)
42 {
43 Thread *self = static_cast<Thread *>(arg);
44 pthread_setspecific(gSelfThreadIndex, self);
45 self->start(self->arg);
46 if (!self->joinable)
47 js_delete(self);
48 return nullptr;
49 }
51 static bool gInitialized;
53 void
54 DummyDestructor(void *)
55 {
56 }
58 /* Should be called from the main thread. */
59 static void
60 Initialize()
61 {
62 gInitialized = true;
64 if (pthread_key_create(&gSelfThreadIndex, DummyDestructor)) {
65 MOZ_CRASH();
66 return;
67 }
69 pthread_setspecific(gSelfThreadIndex, &gMainThread);
70 }
72 PRThread *
73 PR_CreateThread(PRThreadType type,
74 void (*start)(void *arg),
75 void *arg,
76 PRThreadPriority priority,
77 PRThreadScope scope,
78 PRThreadState state,
79 uint32_t stackSize)
80 {
81 JS_ASSERT(type == PR_USER_THREAD);
82 JS_ASSERT(priority == PR_PRIORITY_NORMAL);
84 if (!gInitialized) {
85 /*
86 * We assume that the first call to PR_CreateThread happens on the main
87 * thread.
88 */
89 Initialize();
90 }
92 pthread_attr_t attr;
93 if (pthread_attr_init(&attr))
94 return nullptr;
96 if (stackSize && pthread_attr_setstacksize(&attr, stackSize)) {
97 pthread_attr_destroy(&attr);
98 return nullptr;
99 }
101 nspr::Thread *t = js_new<nspr::Thread>(start, arg,
102 state != PR_UNJOINABLE_THREAD);
103 if (!t) {
104 pthread_attr_destroy(&attr);
105 return nullptr;
106 }
108 if (pthread_create(&t->pthread(), &attr, &nspr::Thread::ThreadRoutine, t)) {
109 pthread_attr_destroy(&attr);
110 js_delete(t);
111 return nullptr;
112 }
114 if (state == PR_UNJOINABLE_THREAD) {
115 if (pthread_detach(t->pthread())) {
116 pthread_attr_destroy(&attr);
117 js_delete(t);
118 return nullptr;
119 }
120 }
122 pthread_attr_destroy(&attr);
124 return t;
125 }
127 PRStatus
128 PR_JoinThread(PRThread *thread)
129 {
130 if (pthread_join(thread->pthread(), nullptr))
131 return PR_FAILURE;
133 js_delete(thread);
135 return PR_SUCCESS;
136 }
138 PRThread *
139 PR_GetCurrentThread()
140 {
141 if (!gInitialized)
142 Initialize();
144 return (PRThread *)pthread_getspecific(gSelfThreadIndex);
145 }
147 PRStatus
148 PR_SetCurrentThreadName(const char *name)
149 {
150 int result;
151 #ifdef XP_MACOSX
152 result = pthread_setname_np(name);
153 #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
154 pthread_set_name_np(pthread_self(), name);
155 result = 0;
156 #elif defined(__NetBSD__)
157 result = pthread_setname_np(pthread_self(), "%s", (void *)name);
158 #else
159 result = pthread_setname_np(pthread_self(), name);
160 #endif
161 if (result)
162 return PR_FAILURE;
163 return PR_SUCCESS;
164 }
166 static const size_t MaxTLSKeyCount = 32;
167 static size_t gTLSKeyCount;
168 static pthread_key_t gTLSKeys[MaxTLSKeyCount];
170 PRStatus
171 PR_NewThreadPrivateIndex(unsigned *newIndex, PRThreadPrivateDTOR destructor)
172 {
173 /*
174 * We only call PR_NewThreadPrivateIndex from the main thread, so there's no
175 * need to lock the table of TLS keys.
176 */
177 JS_ASSERT(PR_GetCurrentThread() == &gMainThread);
179 pthread_key_t key;
180 if (pthread_key_create(&key, destructor))
181 return PR_FAILURE;
183 JS_ASSERT(gTLSKeyCount + 1 < MaxTLSKeyCount);
185 gTLSKeys[gTLSKeyCount] = key;
186 *newIndex = gTLSKeyCount;
187 gTLSKeyCount++;
189 return PR_SUCCESS;
190 }
192 PRStatus
193 PR_SetThreadPrivate(unsigned index, void *priv)
194 {
195 if (index >= gTLSKeyCount)
196 return PR_FAILURE;
197 if (pthread_setspecific(gTLSKeys[index], priv))
198 return PR_FAILURE;
199 return PR_SUCCESS;
200 }
202 void *
203 PR_GetThreadPrivate(unsigned index)
204 {
205 if (index >= gTLSKeyCount)
206 return nullptr;
207 return pthread_getspecific(gTLSKeys[index]);
208 }
210 PRStatus
211 PR_CallOnce(PRCallOnceType *once, PRCallOnceFN func)
212 {
213 MOZ_ASSUME_UNREACHABLE("PR_CallOnce unimplemented");
214 }
216 PRStatus
217 PR_CallOnceWithArg(PRCallOnceType *once, PRCallOnceWithArgFN func, void *arg)
218 {
219 MOZ_ASSUME_UNREACHABLE("PR_CallOnceWithArg unimplemented");
220 }
222 class nspr::Lock
223 {
224 pthread_mutex_t mutex_;
226 public:
227 Lock() {}
228 pthread_mutex_t &mutex() { return mutex_; }
229 };
231 PRLock *
232 PR_NewLock()
233 {
234 nspr::Lock *lock = js_new<nspr::Lock>();
235 if (!lock)
236 return nullptr;
238 if (pthread_mutex_init(&lock->mutex(), nullptr)) {
239 js_delete(lock);
240 return nullptr;
241 }
243 return lock;
244 }
246 void
247 PR_DestroyLock(PRLock *lock)
248 {
249 pthread_mutex_destroy(&lock->mutex());
250 js_delete(lock);
251 }
253 void
254 PR_Lock(PRLock *lock)
255 {
256 pthread_mutex_lock(&lock->mutex());
257 }
259 PRStatus
260 PR_Unlock(PRLock *lock)
261 {
262 if (pthread_mutex_unlock(&lock->mutex()))
263 return PR_FAILURE;
264 return PR_SUCCESS;
265 }
267 class nspr::CondVar
268 {
269 pthread_cond_t cond_;
270 nspr::Lock *lock_;
272 public:
273 CondVar(nspr::Lock *lock) : lock_(lock) {}
274 pthread_cond_t &cond() { return cond_; }
275 nspr::Lock *lock() { return lock_; }
276 };
278 PRCondVar *
279 PR_NewCondVar(PRLock *lock)
280 {
281 nspr::CondVar *cvar = js_new<nspr::CondVar>(lock);
282 if (!cvar)
283 return nullptr;
285 if (pthread_cond_init(&cvar->cond(), nullptr)) {
286 js_delete(cvar);
287 return nullptr;
288 }
290 return cvar;
291 }
293 void
294 PR_DestroyCondVar(PRCondVar *cvar)
295 {
296 pthread_cond_destroy(&cvar->cond());
297 js_delete(cvar);
298 }
300 PRStatus
301 PR_NotifyCondVar(PRCondVar *cvar)
302 {
303 if (pthread_cond_signal(&cvar->cond()))
304 return PR_FAILURE;
305 return PR_SUCCESS;
306 }
308 PRStatus
309 PR_NotifyAllCondVar(PRCondVar *cvar)
310 {
311 if (pthread_cond_broadcast(&cvar->cond()))
312 return PR_FAILURE;
313 return PR_SUCCESS;
314 }
316 uint32_t
317 PR_MillisecondsToInterval(uint32_t milli)
318 {
319 return milli;
320 }
322 static const uint64_t TicksPerSecond = 1000;
323 static const uint64_t NanoSecondsInSeconds = 1000000000;
324 static const uint64_t MicroSecondsInSeconds = 1000000;
326 uint32_t
327 PR_TicksPerSecond()
328 {
329 return TicksPerSecond;
330 }
332 PRStatus
333 PR_WaitCondVar(PRCondVar *cvar, uint32_t timeout)
334 {
335 if (timeout == PR_INTERVAL_NO_TIMEOUT) {
336 if (pthread_cond_wait(&cvar->cond(), &cvar->lock()->mutex()))
337 return PR_FAILURE;
338 return PR_SUCCESS;
339 } else {
340 struct timespec ts;
341 struct timeval tv;
343 gettimeofday(&tv, nullptr);
344 ts.tv_sec = tv.tv_sec;
345 ts.tv_nsec = tv.tv_usec * (NanoSecondsInSeconds / MicroSecondsInSeconds);
347 ts.tv_nsec += timeout * (NanoSecondsInSeconds / TicksPerSecond);
348 while (uint64_t(ts.tv_nsec) >= NanoSecondsInSeconds) {
349 ts.tv_nsec -= NanoSecondsInSeconds;
350 ts.tv_sec++;
351 }
353 int result = pthread_cond_timedwait(&cvar->cond(), &cvar->lock()->mutex(), &ts);
354 if (result == 0 || result == ETIMEDOUT)
355 return PR_SUCCESS;
356 return PR_FAILURE;
357 }
358 }
360 #endif /* JS_POSIX_NSPR */