Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | /* |
michael@0 | 7 | * This is a test for the io continuation thread machinery |
michael@0 | 8 | * in pthreads. |
michael@0 | 9 | */ |
michael@0 | 10 | |
michael@0 | 11 | #include "nspr.h" |
michael@0 | 12 | #include <stdio.h> |
michael@0 | 13 | |
michael@0 | 14 | int num_threads = 10; /* must be an even number */ |
michael@0 | 15 | PRThreadScope thread_scope = PR_GLOBAL_THREAD; |
michael@0 | 16 | |
michael@0 | 17 | void ThreadFunc(void *arg) |
michael@0 | 18 | { |
michael@0 | 19 | PRFileDesc *fd = (PRFileDesc *) arg; |
michael@0 | 20 | char buf[1024]; |
michael@0 | 21 | PRInt32 nbytes; |
michael@0 | 22 | PRErrorCode err; |
michael@0 | 23 | |
michael@0 | 24 | nbytes = PR_Recv(fd, buf, sizeof(buf), 0, PR_SecondsToInterval(20)); |
michael@0 | 25 | if (nbytes == -1) { |
michael@0 | 26 | err = PR_GetError(); |
michael@0 | 27 | if (err != PR_PENDING_INTERRUPT_ERROR) { |
michael@0 | 28 | fprintf(stderr, "PR_Recv failed: (%d, %d)\n", |
michael@0 | 29 | err, PR_GetOSError()); |
michael@0 | 30 | PR_ProcessExit(1); |
michael@0 | 31 | } |
michael@0 | 32 | /* |
michael@0 | 33 | * After getting an I/O interrupt, this thread must |
michael@0 | 34 | * close the fd before it exits due to a limitation |
michael@0 | 35 | * of our NT implementation. |
michael@0 | 36 | */ |
michael@0 | 37 | if (PR_Close(fd) == PR_FAILURE) { |
michael@0 | 38 | fprintf(stderr, "PR_Close failed\n"); |
michael@0 | 39 | PR_ProcessExit(1); |
michael@0 | 40 | } |
michael@0 | 41 | } else { |
michael@0 | 42 | fprintf(stderr, "PR_Recv received %d bytes!?\n", nbytes); |
michael@0 | 43 | PR_ProcessExit(1); |
michael@0 | 44 | } |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | int main(int argc, char **argv) |
michael@0 | 48 | { |
michael@0 | 49 | PRFileDesc **fds; |
michael@0 | 50 | PRThread **threads; |
michael@0 | 51 | PRIntervalTime start, elapsed; |
michael@0 | 52 | int index; |
michael@0 | 53 | |
michael@0 | 54 | fds = (PRFileDesc **) PR_MALLOC(2 * num_threads * sizeof(PRFileDesc *)); |
michael@0 | 55 | PR_ASSERT(fds != NULL); |
michael@0 | 56 | threads = (PRThread **) PR_MALLOC(num_threads * sizeof(PRThread *)); |
michael@0 | 57 | PR_ASSERT(threads != NULL); |
michael@0 | 58 | |
michael@0 | 59 | for (index = 0; index < num_threads; index++) { |
michael@0 | 60 | if (PR_NewTCPSocketPair(&fds[2 * index]) == PR_FAILURE) { |
michael@0 | 61 | fprintf(stderr, "PR_NewTCPSocket failed\n"); |
michael@0 | 62 | PR_ProcessExit(1); |
michael@0 | 63 | } |
michael@0 | 64 | threads[index] = PR_CreateThread( |
michael@0 | 65 | PR_USER_THREAD, ThreadFunc, fds[2 * index], |
michael@0 | 66 | PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0); |
michael@0 | 67 | if (NULL == threads[index]) { |
michael@0 | 68 | fprintf(stderr, "PR_CreateThread failed\n"); |
michael@0 | 69 | PR_ProcessExit(1); |
michael@0 | 70 | } |
michael@0 | 71 | } |
michael@0 | 72 | |
michael@0 | 73 | /* Let the threads block in PR_Recv */ |
michael@0 | 74 | PR_Sleep(PR_SecondsToInterval(2)); |
michael@0 | 75 | |
michael@0 | 76 | printf("Interrupting the threads\n"); |
michael@0 | 77 | fflush(stdout); |
michael@0 | 78 | start = PR_IntervalNow(); |
michael@0 | 79 | for (index = 0; index < num_threads; index++) { |
michael@0 | 80 | if (PR_Interrupt(threads[index]) == PR_FAILURE) { |
michael@0 | 81 | fprintf(stderr, "PR_Interrupt failed\n"); |
michael@0 | 82 | PR_ProcessExit(1); |
michael@0 | 83 | } |
michael@0 | 84 | } |
michael@0 | 85 | for (index = 0; index < num_threads; index++) { |
michael@0 | 86 | if (PR_JoinThread(threads[index]) == PR_FAILURE) { |
michael@0 | 87 | fprintf(stderr, "PR_JoinThread failed\n"); |
michael@0 | 88 | PR_ProcessExit(1); |
michael@0 | 89 | } |
michael@0 | 90 | } |
michael@0 | 91 | elapsed = (PRIntervalTime)(PR_IntervalNow() - start); |
michael@0 | 92 | printf("Threads terminated in %d milliseconds\n", |
michael@0 | 93 | PR_IntervalToMilliseconds(elapsed)); |
michael@0 | 94 | fflush(stdout); |
michael@0 | 95 | |
michael@0 | 96 | /* We are being very generous and allow 10 seconds. */ |
michael@0 | 97 | if (elapsed >= PR_SecondsToInterval(10)) { |
michael@0 | 98 | fprintf(stderr, "Interrupting threads took longer than 10 seconds!!\n"); |
michael@0 | 99 | PR_ProcessExit(1); |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | for (index = 0; index < num_threads; index++) { |
michael@0 | 103 | /* fds[2 * index] was passed to and closed by threads[index]. */ |
michael@0 | 104 | if (PR_Close(fds[2 * index + 1]) == PR_FAILURE) { |
michael@0 | 105 | fprintf(stderr, "PR_Close failed\n"); |
michael@0 | 106 | PR_ProcessExit(1); |
michael@0 | 107 | } |
michael@0 | 108 | } |
michael@0 | 109 | PR_DELETE(threads); |
michael@0 | 110 | PR_DELETE(fds); |
michael@0 | 111 | printf("PASS\n"); |
michael@0 | 112 | PR_Cleanup(); |
michael@0 | 113 | return 0; |
michael@0 | 114 | } |