QThreadData *QThreadData::current(bool createIfNecessary) { qt_create_tls(); QThreadData *threadData = reinterpret_cast<QThreadData *>(TlsGetValue(qt_current_thread_data_tls_index)); if (!threadData && createIfNecessary) { threadData = new QThreadData; // This needs to be called prior to new AdoptedThread() to // avoid recursion. TlsSetValue(qt_current_thread_data_tls_index, threadData); QT_TRY { threadData->thread = new QAdoptedThread(threadData); } QT_CATCH(...) { TlsSetValue(qt_current_thread_data_tls_index, 0); threadData->deref(); threadData = 0; QT_RETHROW; }
void QObject::setThreadData_helper(QThreadData *currentData, QThreadData *targetData) { // move posted events int eventsMoved = 0; for (int i = 0; i < currentData->postEventList.size(); ++i) { const QPostEvent &postedEvent = currentData->postEventList.at(i); if (! postedEvent.event) { continue; } if (postedEvent.receiver == this) { // move this post event to the targetList targetData->postEventList.addEvent(postedEvent); const_cast<QPostEvent &>(postedEvent).event = 0; ++eventsMoved; } } if (eventsMoved > 0 && targetData->eventDispatcher) { targetData->canWait = false; targetData->eventDispatcher->wakeUp(); } // the current emitting thread shouldn't restore currentSender after calling moveToThread() if (m_currentSender) { m_currentSender->ref = 0; } m_currentSender = 0; // set new thread data targetData->ref(); QThreadData *threadData = m_threadData.exchange(targetData); threadData->deref(); for (int k = 0; k < m_children.size(); ++k) { QObject *child = m_children.at(k); child->setThreadData_helper(currentData, targetData); } }
/* QThreadData */ QThreadData *QThreadData::current() { qt_create_tls(); QThreadData *threadData = reinterpret_cast<QThreadData *>(TlsGetValue(qt_current_thread_data_tls_index)); if (!threadData) { QThread *adopted = 0; if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, (void **) &adopted)) { Q_ASSERT(adopted); threadData = QThreadData::get2(adopted); TlsSetValue(qt_current_thread_data_tls_index, threadData); adopted->d_func()->running = true; adopted->d_func()->finished = false; static_cast<QAdoptedThread *>(adopted)->init(); } else { threadData = new QThreadData; // This needs to be called prior to new AdoptedThread() to // avoid recursion. TlsSetValue(qt_current_thread_data_tls_index, threadData); threadData->thread = new QAdoptedThread(threadData); threadData->deref(); } if (!QCoreApplicationPrivate::theMainThread) { QCoreApplicationPrivate::theMainThread = threadData->thread; } else { HANDLE realHandle = INVALID_HANDLE_VALUE; #if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600)) DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &realHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); #else realHandle = (HANDLE)GetCurrentThreadId(); #endif qt_watch_adopted_thread(realHandle, threadData->thread); } } return threadData; }
/* QThreadData */ QThreadData *QThreadData::current() { qt_create_tls(); QThreadData *threadData = reinterpret_cast<QThreadData *>(TlsGetValue(qt_current_thread_data_tls_index)); if (!threadData) { QThread *adopted = 0; if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, (void **) &adopted)) { Q_ASSERT(adopted); threadData = QThreadData::get2(adopted); TlsSetValue(qt_current_thread_data_tls_index, threadData); adopted->d_func()->running = true; adopted->d_func()->finished = false; static_cast<QAdoptedThread *>(adopted)->init(); } else { threadData = new QThreadData; // This needs to be called prior to new AdoptedThread() to // avoid recursion. TlsSetValue(qt_current_thread_data_tls_index, threadData); threadData->thread = new QAdoptedThread(threadData); threadData->deref(); } const bool isMainThread = q_atomic_test_and_set_ptr(&QCoreApplicationPrivate::theMainThread, 0, threadData->thread); if (!isMainThread) { HANDLE realHandle; DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &realHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); qt_watch_adopted_thread(realHandle, threadData->thread); } } return threadData; }
QObject::~QObject() { this->m_blockSig = false; // unblock signals so we always emit destroyed() // this code comes before anything else since a signal can not be emited from a dead object try { emit destroyed(this); } catch(...) { // all signal/slots connections are still in place // quit now, as the app will crash soon qWarning("QObject:~QObject() Detected an unexpected exception while emitting destroyed()"); throw; } // this line needs to be located after the emit destroyed this->m_wasDeleted = true; QtSharedPointer::ExternalRefCountData *sharedRefCount = m_sharedRefCount.exchange(0); if (sharedRefCount) { if (sharedRefCount->strongref.load() > 0) { // continue deleting, unclear what else to do qWarning("QObject:~QObject() Shared QObject was deleted directly, application may crash."); } // indicate to all QWeakPointers QObject has now been deleted sharedRefCount->strongref.store(0); if (! sharedRefCount->weakref.deref()) { delete sharedRefCount; } } // if (this->m_declarativeData) { CSAbstractDeclarativeData::destroyed(this->m_declarativeData, this); } // set ref to zero, indicates this object has been deleted if (this->m_currentSender != 0) { this->m_currentSender->ref = 0; } this->m_currentSender = 0; std::unique_lock<std::mutex> senderLock{this->m_mutex_ToReceiver}; std::unique_lock<std::mutex> receiverLock{this->m_mutex_FromSender}; // disconnect all receivers from sender for(auto index = this->m_connectList_ToReceiver.begin(); index != this->m_connectList_ToReceiver.end(); ++index) { const ConnectStruct &temp = *index; if (temp.sender == 0) { // connection is marked for deletion continue; } if (! temp.receiver) { continue; } std::unique_lock<std::mutex> tempReceiverLock{temp.receiver->m_mutex_FromSender, std::defer_lock}; if (this != temp.receiver) { tempReceiverLock.lock(); } for (int x = 0; x < temp.receiver->m_connectList_FromSender.count(); ++x) { if (this == temp.receiver->m_connectList_FromSender[x].sender) { temp.receiver->m_connectList_FromSender.removeAt(x); // yes, this is required x = x - 1; } } } // disconnect all senders from receiver bool isDone = false; for(auto index = this->m_connectList_FromSender.begin(); index != this->m_connectList_FromSender.end(); ++index) { ConnectStruct &temp = *index; std::unique_lock<std::mutex> tempSenderLock{temp.sender->m_mutex_ToReceiver, std::defer_lock}; if (this != temp.sender) { tempSenderLock.lock(); } for (int x = 0; x < temp.sender->m_connectList_ToReceiver.count(); ++x) { // connection is in another object to one of our slots ConnectStruct &connection = temp.sender->m_connectList_ToReceiver[x]; if (connection.sender == 0) { // connection is marked for deletion continue; } if (this == connection.receiver) { if (temp.sender->m_activateBusy) { if (! isDone) { // warns activate the connectList has changed temp.sender->m_raceCount++; isDone = true; } // mark connection for deletion, activate() will finish connection.sender = 0; } else { temp.sender->m_connectList_ToReceiver.removeAt(x); // yes, this is required x = x - 1; } } } } if (! this->m_children.isEmpty()) { this->deleteChildren(); } this->removeObject(); if (this->m_parent) { // remove 'this' from parent object this->setParent(0); } QThreadData *threadData = m_threadData.load(); if (m_pendTimer) { // unregister pending timers if (threadData && threadData->eventDispatcher) { threadData->eventDispatcher->unregisterTimers(this); } } if (m_postedEvents) { QCoreApplication::removePostedEvents(this, 0); } if (threadData) { threadData->deref(); } }