| OLD | NEW |
| 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 /* This Source Code Form is subject to the terms of the Mozilla Public | 2 /* This Source Code Form is subject to the terms of the Mozilla Public |
| 3 * License, v. 2.0. If a copy of the MPL was not distributed with this | 3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 5 | 5 |
| 6 /* | 6 /* |
| 7 ** File: ptthread.c | 7 ** File: ptthread.c |
| 8 ** Descritpion: Implemenation for threds using pthreds | 8 ** Descritpion: Implemenation for threds using pthreds |
| 9 ** Exports: ptthread.h | 9 ** Exports: ptthread.h |
| 10 */ | 10 */ |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 ts->stackBottom = ts->allocBase - ts->stackSize; | 115 ts->stackBottom = ts->allocBase - ts->stackSize; |
| 116 #endif | 116 #endif |
| 117 } | 117 } |
| 118 } | 118 } |
| 119 | 119 |
| 120 static void *_pt_root(void *arg) | 120 static void *_pt_root(void *arg) |
| 121 { | 121 { |
| 122 PRIntn rv; | 122 PRIntn rv; |
| 123 PRThread *thred = (PRThread*)arg; | 123 PRThread *thred = (PRThread*)arg; |
| 124 PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE; | 124 PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE; |
| 125 pthread_t id = pthread_self(); |
| 125 #ifdef _PR_NICE_PRIORITY_SCHEDULING | 126 #ifdef _PR_NICE_PRIORITY_SCHEDULING |
| 126 pid_t tid; | 127 pid_t tid; |
| 127 #endif | 128 #endif |
| 128 | 129 |
| 129 /* | |
| 130 * Both the parent thread and this new thread set thred->id. | |
| 131 * The new thread must ensure that thred->id is set before | |
| 132 * it executes its startFunc. The parent thread must ensure | |
| 133 * that thred->id is set before PR_CreateThread() returns. | |
| 134 * Both threads set thred->id without holding a lock. Since | |
| 135 * they are writing the same value, this unprotected double | |
| 136 * write should be safe. | |
| 137 */ | |
| 138 thred->id = pthread_self(); | |
| 139 | |
| 140 #ifdef _PR_NICE_PRIORITY_SCHEDULING | 130 #ifdef _PR_NICE_PRIORITY_SCHEDULING |
| 141 /* | 131 /* |
| 142 * We need to know the kernel thread ID of each thread in order to | 132 * We need to know the kernel thread ID of each thread in order to |
| 143 * set its nice value hence we do it here instead of at creation time. | 133 * set its nice value hence we do it here instead of at creation time. |
| 144 */ | 134 */ |
| 145 tid = gettid(); | 135 tid = gettid(); |
| 146 errno = 0; | 136 errno = 0; |
| 147 rv = getpriority(PRIO_PROCESS, 0); | 137 rv = getpriority(PRIO_PROCESS, 0); |
| 148 | 138 |
| 149 /* If we cannot read the main thread's nice value don't try to change the | 139 /* If we cannot read the main thread's nice value don't try to change the |
| 150 * new thread's nice value. */ | 140 * new thread's nice value. */ |
| 151 if (errno == 0) { | 141 if (errno == 0) { |
| 152 setpriority(PRIO_PROCESS, tid, | 142 setpriority(PRIO_PROCESS, tid, |
| 153 pt_RelativePriority(rv, thred->priority)); | 143 pt_RelativePriority(rv, thred->priority)); |
| 154 } | 144 } |
| 155 | |
| 156 PR_Lock(pt_book.ml); | |
| 157 thred->tid = tid; | |
| 158 PR_NotifyAllCondVar(pt_book.cv); | |
| 159 PR_Unlock(pt_book.ml); | |
| 160 #endif | 145 #endif |
| 161 | 146 |
| 162 /* | 147 /* |
| 163 ** DCE Threads can't detach during creation, so do it late. | 148 ** DCE Threads can't detach during creation, so do it late. |
| 164 ** I would like to do it only here, but that doesn't seem | 149 ** I would like to do it only here, but that doesn't seem |
| 165 ** to work. | 150 ** to work. |
| 166 */ | 151 */ |
| 167 #if defined(_PR_DCETHREADS) | 152 #if defined(_PR_DCETHREADS) |
| 168 if (detached) | 153 if (detached) |
| 169 { | 154 { |
| 170 /* pthread_detach() modifies its argument, so we must pass a copy */ | 155 /* pthread_detach() modifies its argument, so we must pass a copy */ |
| 171 pthread_t self = thred->id; | 156 pthread_t self = id; |
| 172 rv = pthread_detach(&self); | 157 rv = pthread_detach(&self); |
| 173 PR_ASSERT(0 == rv); | 158 PR_ASSERT(0 == rv); |
| 174 } | 159 } |
| 175 #endif /* defined(_PR_DCETHREADS) */ | 160 #endif /* defined(_PR_DCETHREADS) */ |
| 176 | 161 |
| 177 /* Set up the thread stack information */ | 162 /* Set up the thread stack information */ |
| 178 _PR_InitializeStack(thred->stack); | 163 _PR_InitializeStack(thred->stack); |
| 179 | 164 |
| 180 /* | 165 /* |
| 181 * Set within the current thread the pointer to our object. | 166 * Set within the current thread the pointer to our object. |
| 182 * This object will be deleted when the thread termintates, | 167 * This object will be deleted when the thread termintates, |
| 183 * whether in a join or detached (see _PR_InitThreads()). | 168 * whether in a join or detached (see _PR_InitThreads()). |
| 184 */ | 169 */ |
| 185 rv = pthread_setspecific(pt_book.key, thred); | 170 rv = pthread_setspecific(pt_book.key, thred); |
| 186 PR_ASSERT(0 == rv); | 171 PR_ASSERT(0 == rv); |
| 187 | 172 |
| 188 /* make the thread visible to the rest of the runtime */ | 173 /* make the thread visible to the rest of the runtime */ |
| 189 PR_Lock(pt_book.ml); | 174 PR_Lock(pt_book.ml); |
| 175 /* |
| 176 * Both the parent thread and this new thread set thred->id. |
| 177 * The new thread must ensure that thred->id is set before |
| 178 * it executes its startFunc. The parent thread must ensure |
| 179 * that thred->id is set before PR_CreateThread() returns. |
| 180 * Both threads set thred->id while holding pt_book.ml and |
| 181 * use thred->idSet to ensure thred->id is written only once. |
| 182 */ |
| 183 if (!thred->idSet) |
| 184 { |
| 185 thred->id = id; |
| 186 thred->idSet = PR_TRUE; |
| 187 } |
| 188 else |
| 189 { |
| 190 PR_ASSERT(pthread_equal(thred->id, id)); |
| 191 } |
| 192 |
| 193 #ifdef _PR_NICE_PRIORITY_SCHEDULING |
| 194 thred->tid = tid; |
| 195 PR_NotifyAllCondVar(pt_book.cv); |
| 196 #endif |
| 190 | 197 |
| 191 /* If this is a GCABLE thread, set its state appropriately */ | 198 /* If this is a GCABLE thread, set its state appropriately */ |
| 192 if (thred->suspend & PT_THREAD_SETGCABLE) | 199 if (thred->suspend & PT_THREAD_SETGCABLE) |
| 193 thred->state |= PT_THREAD_GCABLE; | 200 thred->state |= PT_THREAD_GCABLE; |
| 194 thred->suspend = 0; | 201 thred->suspend = 0; |
| 195 | 202 |
| 196 thred->prev = pt_book.last; | 203 thred->prev = pt_book.last; |
| 197 if (pt_book.last) | 204 if (pt_book.last) |
| 198 pt_book.last->next = thred; | 205 pt_book.last->next = thred; |
| 199 else | 206 else |
| 200 pt_book.first = thred; | 207 pt_book.first = thred; |
| 201 thred->next = NULL; | 208 thred->next = NULL; |
| 202 pt_book.last = thred; | 209 pt_book.last = thred; |
| 203 PR_Unlock(pt_book.ml); | 210 PR_Unlock(pt_book.ml); |
| 204 | 211 |
| 205 thred->startFunc(thred->arg); /* make visible to the client */ | 212 thred->startFunc(thred->arg); /* make visible to the client */ |
| 206 | 213 |
| 207 /* unhook the thread from the runtime */ | 214 /* unhook the thread from the runtime */ |
| 208 PR_Lock(pt_book.ml); | 215 PR_Lock(pt_book.ml); |
| 209 /* | 216 /* |
| 210 * At this moment, PR_CreateThread() may not have set thred->id yet. | 217 * At this moment, PR_CreateThread() may not have set thred->id yet. |
| 211 * It is safe for a detached thread to free thred only after | 218 * It is safe for a detached thread to free thred only after |
| 212 * PR_CreateThread() has set thred->id. | 219 * PR_CreateThread() has accessed thred->id and thred->idSet. |
| 213 */ | 220 */ |
| 214 if (detached) | 221 if (detached) |
| 215 { | 222 { |
| 216 while (!thred->okToDelete) | 223 while (!thred->okToDelete) |
| 217 PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); | 224 PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); |
| 218 } | 225 } |
| 219 | 226 |
| 220 if (thred->state & PT_THREAD_SYSTEM) | 227 if (thred->state & PT_THREAD_SYSTEM) |
| 221 pt_book.system -= 1; | 228 pt_book.system -= 1; |
| 222 else if (--pt_book.user == pt_book.this_many) | 229 else if (--pt_book.user == pt_book.this_many) |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 if (!_pr_initialized) return NULL; | 273 if (!_pr_initialized) return NULL; |
| 267 | 274 |
| 268 /* PR_NEWZAP must not call PR_GetCurrentThread() */ | 275 /* PR_NEWZAP must not call PR_GetCurrentThread() */ |
| 269 thred = PR_NEWZAP(PRThread); | 276 thred = PR_NEWZAP(PRThread); |
| 270 if (NULL != thred) | 277 if (NULL != thred) |
| 271 { | 278 { |
| 272 int rv; | 279 int rv; |
| 273 | 280 |
| 274 thred->priority = PR_PRIORITY_NORMAL; | 281 thred->priority = PR_PRIORITY_NORMAL; |
| 275 thred->id = pthread_self(); | 282 thred->id = pthread_self(); |
| 283 thred->idSet = PR_TRUE; |
| 276 #ifdef _PR_NICE_PRIORITY_SCHEDULING | 284 #ifdef _PR_NICE_PRIORITY_SCHEDULING |
| 277 thred->tid = gettid(); | 285 thred->tid = gettid(); |
| 278 #endif | 286 #endif |
| 279 rv = pthread_setspecific(pt_book.key, thred); | 287 rv = pthread_setspecific(pt_book.key, thred); |
| 280 PR_ASSERT(0 == rv); | 288 PR_ASSERT(0 == rv); |
| 281 | 289 |
| 282 thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN; | 290 thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN; |
| 283 PR_Lock(pt_book.ml); | 291 PR_Lock(pt_book.ml); |
| 284 | 292 |
| 285 /* then put it into the list */ | 293 /* then put it into the list */ |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 486 PR_NotifyAllCondVar(pt_book.cv); | 494 PR_NotifyAllCondVar(pt_book.cv); |
| 487 PR_Unlock(pt_book.ml); | 495 PR_Unlock(pt_book.ml); |
| 488 | 496 |
| 489 PR_Free(thred->stack); | 497 PR_Free(thred->stack); |
| 490 PR_Free(thred); /* all that work ... poof! */ | 498 PR_Free(thred); /* all that work ... poof! */ |
| 491 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr); | 499 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr); |
| 492 thred = NULL; /* and for what? */ | 500 thred = NULL; /* and for what? */ |
| 493 goto done; | 501 goto done; |
| 494 } | 502 } |
| 495 | 503 |
| 504 PR_Lock(pt_book.ml); |
| 496 /* | 505 /* |
| 497 * Both the parent thread and this new thread set thred->id. | 506 * Both the parent thread and this new thread set thred->id. |
| 498 * The parent thread must ensure that thred->id is set before | 507 * The parent thread must ensure that thred->id is set before |
| 499 * PR_CreateThread() returns. (See comments in _pt_root().) | 508 * PR_CreateThread() returns. (See comments in _pt_root().) |
| 500 */ | 509 */ |
| 501 thred->id = id; | 510 if (!thred->idSet) |
| 511 { |
| 512 thred->id = id; |
| 513 thred->idSet = PR_TRUE; |
| 514 } |
| 515 else |
| 516 { |
| 517 PR_ASSERT(pthread_equal(thred->id, id)); |
| 518 } |
| 502 | 519 |
| 503 /* | 520 /* |
| 504 * If the new thread is detached, tell it that PR_CreateThread() | 521 * If the new thread is detached, tell it that PR_CreateThread() has |
| 505 * has set thred->id so it's ok to delete thred. | 522 * accessed thred->id and thred->idSet so it's ok to delete thred. |
| 506 */ | 523 */ |
| 507 if (PR_UNJOINABLE_THREAD == state) | 524 if (PR_UNJOINABLE_THREAD == state) |
| 508 { | 525 { |
| 509 PR_Lock(pt_book.ml); | |
| 510 thred->okToDelete = PR_TRUE; | 526 thred->okToDelete = PR_TRUE; |
| 511 PR_NotifyAllCondVar(pt_book.cv); | 527 PR_NotifyAllCondVar(pt_book.cv); |
| 512 PR_Unlock(pt_book.ml); | |
| 513 } | 528 } |
| 529 PR_Unlock(pt_book.ml); |
| 514 } | 530 } |
| 515 | 531 |
| 516 done: | 532 done: |
| 517 rv = _PT_PTHREAD_ATTR_DESTROY(&tattr); | 533 rv = _PT_PTHREAD_ATTR_DESTROY(&tattr); |
| 518 PR_ASSERT(0 == rv); | 534 PR_ASSERT(0 == rv); |
| 519 | 535 |
| 520 return thred; | 536 return thred; |
| 521 } /* _PR_CreateThread */ | 537 } /* _PR_CreateThread */ |
| 522 | 538 |
| 523 PR_IMPLEMENT(PRThread*) PR_CreateThread( | 539 PR_IMPLEMENT(PRThread*) PR_CreateThread( |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 933 pt_book.ml = PR_NewLock(); | 949 pt_book.ml = PR_NewLock(); |
| 934 PR_ASSERT(NULL != pt_book.ml); | 950 PR_ASSERT(NULL != pt_book.ml); |
| 935 pt_book.cv = PR_NewCondVar(pt_book.ml); | 951 pt_book.cv = PR_NewCondVar(pt_book.ml); |
| 936 PR_ASSERT(NULL != pt_book.cv); | 952 PR_ASSERT(NULL != pt_book.cv); |
| 937 thred = PR_NEWZAP(PRThread); | 953 thred = PR_NEWZAP(PRThread); |
| 938 PR_ASSERT(NULL != thred); | 954 PR_ASSERT(NULL != thred); |
| 939 thred->arg = NULL; | 955 thred->arg = NULL; |
| 940 thred->startFunc = NULL; | 956 thred->startFunc = NULL; |
| 941 thred->priority = priority; | 957 thred->priority = priority; |
| 942 thred->id = pthread_self(); | 958 thred->id = pthread_self(); |
| 959 thred->idSet = PR_TRUE; |
| 943 #ifdef _PR_NICE_PRIORITY_SCHEDULING | 960 #ifdef _PR_NICE_PRIORITY_SCHEDULING |
| 944 thred->tid = gettid(); | 961 thred->tid = gettid(); |
| 945 #endif | 962 #endif |
| 946 | 963 |
| 947 thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); | 964 thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); |
| 948 if (PR_SYSTEM_THREAD == type) | 965 if (PR_SYSTEM_THREAD == type) |
| 949 { | 966 { |
| 950 thred->state |= PT_THREAD_SYSTEM; | 967 thred->state |= PT_THREAD_SYSTEM; |
| 951 pt_book.system += 1; | 968 pt_book.system += 1; |
| 952 pt_book.this_many = 0; | 969 pt_book.this_many = 0; |
| (...skipping 835 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1788 PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread) | 1805 PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread) |
| 1789 { | 1806 { |
| 1790 if (!thread) | 1807 if (!thread) |
| 1791 return NULL; | 1808 return NULL; |
| 1792 return thread->name; | 1809 return thread->name; |
| 1793 } | 1810 } |
| 1794 | 1811 |
| 1795 #endif /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */ | 1812 #endif /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */ |
| 1796 | 1813 |
| 1797 /* ptthread.c */ | 1814 /* ptthread.c */ |
| OLD | NEW |