Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #include "cpr.h" |
michael@0 | 6 | #include "cpr_stdlib.h" |
michael@0 | 7 | #include "cpr_stdio.h" |
michael@0 | 8 | #include <pthread.h> |
michael@0 | 9 | #include <errno.h> |
michael@0 | 10 | #include <unistd.h> |
michael@0 | 11 | #include <sys/resource.h> |
michael@0 | 12 | #include "thread_monitor.h" |
michael@0 | 13 | #include "prtypes.h" |
michael@0 | 14 | #include "mozilla/Assertions.h" |
michael@0 | 15 | |
michael@0 | 16 | #define ANDROID_MIN_THREAD_PRIORITY (-20) /* tbd: check MV linux: current val from Larry port */ |
michael@0 | 17 | #define ANDROID_MAX_THREAD_PRIORITY (+19) /* tbd: check MV linux. current val from Larry port */ |
michael@0 | 18 | |
michael@0 | 19 | void CSFLogRegisterThread(const cprThread_t thread); |
michael@0 | 20 | |
michael@0 | 21 | /** |
michael@0 | 22 | * cprCreateThread |
michael@0 | 23 | * |
michael@0 | 24 | * @brief Create a thread |
michael@0 | 25 | * |
michael@0 | 26 | * The cprCreateThread function creates another execution thread within the |
michael@0 | 27 | * current process. If the input parameter "name" is present, then this is used |
michael@0 | 28 | * for debugging purposes. The startRoutine is the address of the function where |
michael@0 | 29 | * the thread execution begins. The start routine prototype is defined as |
michael@0 | 30 | * follows |
michael@0 | 31 | * @code |
michael@0 | 32 | * int32_t (*cprThreadStartRoutine)(void* data) |
michael@0 | 33 | * @endcode |
michael@0 | 34 | * |
michael@0 | 35 | * @param[in] name - name of the thread created (optional) |
michael@0 | 36 | * @param[in] startRoutine - function where thread execution begins |
michael@0 | 37 | * @param[in] stackSize - size of the thread's stack |
michael@0 | 38 | * @param[in] priority - thread's execution priority |
michael@0 | 39 | * @param[in] data - parameter to pass to startRoutine |
michael@0 | 40 | * |
michael@0 | 41 | * Return Value: Thread handle or NULL if creation failed. |
michael@0 | 42 | */ |
michael@0 | 43 | cprThread_t |
michael@0 | 44 | cprCreateThread (const char *name, |
michael@0 | 45 | cprThreadStartRoutine startRoutine, |
michael@0 | 46 | uint16_t stackSize, |
michael@0 | 47 | uint16_t priority, |
michael@0 | 48 | void *data) |
michael@0 | 49 | { |
michael@0 | 50 | static const char fname[] = "cprCreateThread"; |
michael@0 | 51 | static uint16_t id = 0; |
michael@0 | 52 | cpr_thread_t *threadPtr; |
michael@0 | 53 | pthread_t threadId; |
michael@0 | 54 | pthread_attr_t attr; |
michael@0 | 55 | |
michael@0 | 56 | CPR_INFO("%s: creating '%s' thread\n", fname, name); |
michael@0 | 57 | |
michael@0 | 58 | /* Malloc memory for a new thread */ |
michael@0 | 59 | threadPtr = (cpr_thread_t *)cpr_malloc(sizeof(cpr_thread_t)); |
michael@0 | 60 | if (threadPtr != NULL) { |
michael@0 | 61 | if (pthread_attr_init(&attr) != 0) { |
michael@0 | 62 | |
michael@0 | 63 | CPR_ERROR("%s - Failed to init attribute for thread %s\n", |
michael@0 | 64 | fname, name); |
michael@0 | 65 | cpr_free(threadPtr); |
michael@0 | 66 | return (cprThread_t)NULL; |
michael@0 | 67 | } |
michael@0 | 68 | |
michael@0 | 69 | if (pthread_attr_setstacksize(&attr, stackSize) != 0) { |
michael@0 | 70 | CPR_ERROR("%s - Invalid stacksize %d specified for thread %s\n", |
michael@0 | 71 | fname, stackSize, name); |
michael@0 | 72 | cpr_free(threadPtr); |
michael@0 | 73 | return (cprThread_t)NULL; |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | if (pthread_create(&threadId, &attr, startRoutine, data) != 0) { |
michael@0 | 77 | CPR_ERROR("%s - Creation of thread %s failed: %d\n", |
michael@0 | 78 | fname, name, errno); |
michael@0 | 79 | cpr_free(threadPtr); |
michael@0 | 80 | return (cprThread_t)NULL; |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | /* Assign name to CPR if one was passed in */ |
michael@0 | 84 | if (name != NULL) { |
michael@0 | 85 | threadPtr->name = name; |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | /* |
michael@0 | 89 | * TODO - It would be nice for CPR to keep a linked |
michael@0 | 90 | * list of running threads for debugging purposes |
michael@0 | 91 | * such as a show command or walking the list to ensure |
michael@0 | 92 | * that an application does not attempt to create |
michael@0 | 93 | * the same thread twice. |
michael@0 | 94 | */ |
michael@0 | 95 | threadPtr->u.handleInt = threadId; |
michael@0 | 96 | threadPtr->threadId = ++id; |
michael@0 | 97 | CSFLogRegisterThread(threadPtr); |
michael@0 | 98 | return (cprThread_t)threadPtr; |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | /* Malloc failed */ |
michael@0 | 102 | CPR_ERROR("%s - Malloc for thread %s failed.\n", fname, name); |
michael@0 | 103 | errno = ENOMEM; |
michael@0 | 104 | return (cprThread_t)NULL; |
michael@0 | 105 | } |
michael@0 | 106 | |
michael@0 | 107 | /* |
michael@0 | 108 | * cprJoinThread |
michael@0 | 109 | * |
michael@0 | 110 | * wait for thread termination |
michael@0 | 111 | */ |
michael@0 | 112 | void cprJoinThread(cprThread_t thread) |
michael@0 | 113 | { |
michael@0 | 114 | cpr_thread_t *cprThreadPtr; |
michael@0 | 115 | |
michael@0 | 116 | cprThreadPtr = (cpr_thread_t *) thread; |
michael@0 | 117 | MOZ_ASSERT(cprThreadPtr); |
michael@0 | 118 | pthread_join(cprThreadPtr->u.handleInt, NULL); |
michael@0 | 119 | } |
michael@0 | 120 | |
michael@0 | 121 | /** |
michael@0 | 122 | * cprDestroyThread |
michael@0 | 123 | * |
michael@0 | 124 | * @brief Destroys the thread passed in. |
michael@0 | 125 | * |
michael@0 | 126 | * The cprDestroyThread function is called to destroy a thread. The thread |
michael@0 | 127 | * parameter may be any valid thread including the calling thread itself. |
michael@0 | 128 | * |
michael@0 | 129 | * @param[in] thread - thread to destroy. |
michael@0 | 130 | * |
michael@0 | 131 | * @return CPR_SUCCESS or CPR_FAILURE. errno should be set for FAILURE case. |
michael@0 | 132 | * |
michael@0 | 133 | * @note In Linux there will never be a success indication as the |
michael@0 | 134 | * calling thread will have been terminated. |
michael@0 | 135 | */ |
michael@0 | 136 | cprRC_t |
michael@0 | 137 | cprDestroyThread (cprThread_t thread) |
michael@0 | 138 | { |
michael@0 | 139 | cpr_thread_t *cprThreadPtr; |
michael@0 | 140 | |
michael@0 | 141 | cprThreadPtr = (cpr_thread_t *) thread; |
michael@0 | 142 | if (cprThreadPtr) { |
michael@0 | 143 | /* |
michael@0 | 144 | * Make sure thread is trying to destroy itself. |
michael@0 | 145 | */ |
michael@0 | 146 | if ((pthread_t) cprThreadPtr->u.handleInt == pthread_self()) { |
michael@0 | 147 | CPR_INFO("%s: Destroying Thread %d", __FUNCTION__, cprThreadPtr->threadId); |
michael@0 | 148 | pthread_exit(NULL); |
michael@0 | 149 | return CPR_SUCCESS; |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | CPR_ERROR("%s: Thread attempted to destroy another thread, not itself.", |
michael@0 | 153 | __FUNCTION__); |
michael@0 | 154 | MOZ_ASSERT(PR_FALSE); |
michael@0 | 155 | errno = EINVAL; |
michael@0 | 156 | return CPR_FAILURE; |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | CPR_ERROR("%s - NULL pointer passed in.", __FUNCTION__); |
michael@0 | 160 | MOZ_ASSERT(PR_FALSE); |
michael@0 | 161 | errno = EINVAL; |
michael@0 | 162 | return CPR_FAILURE; |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | /** |
michael@0 | 166 | * cprAdjustRelativeThreadPriority |
michael@0 | 167 | * |
michael@0 | 168 | * @brief The function sets the relative thread priority up or down by the given value. |
michael@0 | 169 | * |
michael@0 | 170 | * This function is used pSIPCC to set up the thread priority. The values of the |
michael@0 | 171 | * priority range from -20 (Maximum priority) to +19 (Minimum priority). |
michael@0 | 172 | * |
michael@0 | 173 | * @param[in] relPri - nice value of the thread -20 is MAX and 19 is MIN |
michael@0 | 174 | * |
michael@0 | 175 | * @return CPR_SUCCESS or CPR_FAILURE |
michael@0 | 176 | */ |
michael@0 | 177 | cprRC_t |
michael@0 | 178 | cprAdjustRelativeThreadPriority (int relPri) |
michael@0 | 179 | { |
michael@0 | 180 | const char *fname = "cprAdjustRelativeThreadPriority"; |
michael@0 | 181 | |
michael@0 | 182 | if (setpriority(PRIO_PROCESS, 0, relPri) == -1) { |
michael@0 | 183 | CPR_ERROR("%s: could not set the nice..err=%d\n", |
michael@0 | 184 | fname, errno); |
michael@0 | 185 | return CPR_FAILURE; |
michael@0 | 186 | } |
michael@0 | 187 | return CPR_SUCCESS; |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | /** |
michael@0 | 191 | * @} |
michael@0 | 192 | * @addtogroup ThreadInternal Helper functions for implementing threads in CPR |
michael@0 | 193 | * @ingroup Threads |
michael@0 | 194 | * @brief Helper functions used by CPR for thread implementation |
michael@0 | 195 | * |
michael@0 | 196 | * @{ |
michael@0 | 197 | */ |
michael@0 | 198 | |
michael@0 | 199 | /** |
michael@0 | 200 | * cprGetThreadId |
michael@0 | 201 | * |
michael@0 | 202 | * @brief Return the pthread ID for the given CPR thread. |
michael@0 | 203 | * |
michael@0 | 204 | * @param[in] thread - thread to query |
michael@0 | 205 | * |
michael@0 | 206 | * @return Thread's Id or zero(0) |
michael@0 | 207 | * |
michael@0 | 208 | */ |
michael@0 | 209 | pthread_t |
michael@0 | 210 | cprGetThreadId (cprThread_t thread) |
michael@0 | 211 | { |
michael@0 | 212 | if (thread) { |
michael@0 | 213 | return ((cpr_thread_t *)thread)->u.handleInt; |
michael@0 | 214 | } |
michael@0 | 215 | return 0; |
michael@0 | 216 | } |
michael@0 | 217 | /** |
michael@0 | 218 | * @} |
michael@0 | 219 | */ |