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 |