|
40 | 40 | static inline BOOL ThreadNotStarted(Thread *t)
|
41 | 41 | {
|
42 | 42 | WRAPPER_NO_CONTRACT;
|
43 |
| - return (t && t->IsUnstarted() && !t->HasValidThreadHandle()); |
44 |
| -} |
45 |
| - |
46 |
| -static inline BOOL ThreadIsRunning(Thread *t) |
47 |
| -{ |
48 |
| - WRAPPER_NO_CONTRACT; |
49 |
| - return (t && |
50 |
| - (t->m_State & (Thread::TS_ReportDead|Thread::TS_Dead)) == 0 && |
51 |
| - (t->HasValidThreadHandle())); |
| 43 | + return (t && t->IsUnstarted()); |
52 | 44 | }
|
53 | 45 |
|
54 | 46 | static inline BOOL ThreadIsDead(Thread *t)
|
@@ -255,10 +247,10 @@ void ThreadNative::Start(Thread* pNewThread, int threadStackSize, int priority,
|
255 | 247 |
|
256 | 248 | #ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
|
257 | 249 | // Attempt to eagerly set the apartment state during thread startup.
|
258 |
| - Thread::ApartmentState as = pNewThread->GetExplicitApartment(); |
| 250 | + Thread::ApartmentState as = pNewThread->GetApartmentOfUnstartedThread(); |
259 | 251 | if (as == Thread::AS_Unknown)
|
260 | 252 | {
|
261 |
| - pNewThread->SetApartment(Thread::AS_InMTA); |
| 253 | + pNewThread->SetApartmentOfUnstartedThread(Thread::AS_InMTA); |
262 | 254 | }
|
263 | 255 | #endif
|
264 | 256 |
|
@@ -553,13 +545,23 @@ extern "C" INT32 QCALLTYPE ThreadNative_SetApartmentState(QCall::ObjectHandleOnS
|
553 | 545 | // We can only change the apartment if the thread is unstarted or
|
554 | 546 | // running, and if it's running we have to be in the thread's
|
555 | 547 | // context.
|
556 |
| - if (!ThreadNotStarted(thread) |
557 |
| - && (!ThreadIsRunning(thread) || (GetThread() != thread))) |
| 548 | + if (ThreadNotStarted(thread)) |
558 | 549 | {
|
559 |
| - COMPlusThrow(kThreadStateException); |
| 550 | + // Compat: Disallow resetting the initial apartment state |
| 551 | + if (thread->GetApartmentOfUnstartedThread() == Thread::AS_Unknown) |
| 552 | + thread->SetApartmentOfUnstartedThread((Thread::ApartmentState)iState); |
| 553 | + |
| 554 | + retVal = thread->GetApartmentOfUnstartedThread(); |
560 | 555 | }
|
| 556 | + else |
| 557 | + { |
| 558 | + if (GetThread() != thread) |
| 559 | + { |
| 560 | + COMPlusThrow(kThreadStateException); |
| 561 | + } |
561 | 562 |
|
562 |
| - retVal = thread->SetApartment((Thread::ApartmentState)iState); |
| 563 | + retVal = thread->SetApartment((Thread::ApartmentState)iState); |
| 564 | + } |
563 | 565 |
|
564 | 566 | END_QCALL;
|
565 | 567 | return retVal;
|
@@ -713,19 +715,31 @@ void ThreadBaseObject::InitExisting()
|
713 | 715 | m_Priority = ThreadNative::PRIORITY_NORMAL;
|
714 | 716 | break;
|
715 | 717 | }
|
716 |
| - |
717 | 718 | }
|
718 | 719 |
|
719 | 720 | FCIMPL1(void, ThreadNative::Finalize, ThreadBaseObject* pThisUNSAFE)
|
720 | 721 | {
|
721 | 722 | FCALL_CONTRACT;
|
722 | 723 |
|
723 |
| - // This function is intentionally blank. |
724 |
| - // See comment in code:MethodTable::CallFinalizer. |
| 724 | + THREADBASEREF refThis = (THREADBASEREF)pThisUNSAFE; |
| 725 | + Thread* thread = refThis->GetInternal(); |
| 726 | + |
| 727 | + // Prevent multiple calls to Finalize |
| 728 | + // Objects can be resurrected after being finalized. However, there is no |
| 729 | + // race condition here. We always check whether an exposed thread object is |
| 730 | + // still attached to the internal Thread object, before proceeding. |
| 731 | + if (thread) |
| 732 | + { |
| 733 | + refThis->ResetStartHelper(); |
725 | 734 |
|
726 |
| - _ASSERTE (!"Should not be called"); |
| 735 | + if (GetThreadNULLOk() != thread) |
| 736 | + { |
| 737 | + refThis->ClearInternal(); |
| 738 | + } |
727 | 739 |
|
728 |
| - FCUnique(0x21); |
| 740 | + thread->SetThreadState(Thread::TS_Finalized); |
| 741 | + Thread::SetCleanupNeededForFinalizedThread(); |
| 742 | + } |
729 | 743 | }
|
730 | 744 | FCIMPLEND
|
731 | 745 |
|
|
0 commit comments