QThreadData *QThreadData::current() { pthread_once(¤t_thread_data_once, create_current_thread_data_key); QThreadData *data = reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key)); if (!data) { void *a; if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, &a)) { QThread *adopted = static_cast<QThread*>(a); Q_ASSERT(adopted); data = QThreadData::get2(adopted); pthread_setspecific(current_thread_data_key, data); adopted->d_func()->running = true; adopted->d_func()->finished = false; static_cast<QAdoptedThread *>(adopted)->init(); } else { data = new QThreadData; pthread_setspecific(current_thread_data_key, data); QT_TRY { data->thread = new QAdoptedThread(data); } QT_CATCH(...) { pthread_setspecific(current_thread_data_key, 0); data->deref(); data = 0; QT_RETHROW; } data->deref(); }
QThreadData *QThreadData::current() { QThreadData *data = get_thread_data(); if (!data) { void *a; if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, &a)) { QThread *adopted = static_cast<QThread*>(a); Q_ASSERT(adopted); data = QThreadData::get2(adopted); set_thread_data(data); adopted->d_func()->running = true; adopted->d_func()->finished = false; static_cast<QAdoptedThread *>(adopted)->init(); } else { data = new QThreadData; QT_TRY { set_thread_data(data); data->thread = new QAdoptedThread(data); } QT_CATCH(...) { clear_thread_data(); data->deref(); data = 0; QT_RETHROW; } data->deref(); }
/* 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); QT_TRY { threadData->thread = new QAdoptedThread(threadData); } QT_CATCH(...) { TlsSetValue(qt_current_thread_data_tls_index, 0); threadData->deref(); threadData = 0; QT_RETHROW; } threadData->deref(); }
QThreadData *QThreadData::current() { pthread_once(¤t_thread_data_once, create_current_thread_data_key); QThreadData *data = reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key)); if (!data) { void *a; if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, &a)) { QThread *adopted = static_cast<QThread*>(a); Q_ASSERT(adopted); data = QThreadData::get2(adopted); pthread_setspecific(current_thread_data_key, data); adopted->d_func()->running = true; adopted->d_func()->finished = false; static_cast<QAdoptedThread *>(adopted)->init(); } else { data = new QThreadData; pthread_setspecific(current_thread_data_key, data); data->thread = new QAdoptedThread(data); data->deref(); } (void) q_atomic_test_and_set_ptr(&QCoreApplicationPrivate::theMainThread, 0, data->thread); } return data; }
static void destroy_current_thread_data(void *p) { #if defined(Q_OS_VXWORKS) // Calling setspecific(..., 0) sets the value to 0 for ALL threads. // The 'set to 1' workaround adds a bit of an overhead though, // since this function is called twice now. if (p == (void *)1) return; #endif // POSIX says the value in our key is set to zero before calling // this destructor function, so we need to set it back to the // right value... pthread_setspecific(current_thread_data_key, p); QThreadData *data = static_cast<QThreadData *>(p); if (data->isAdopted) { QThread *thread = data->thread; Q_ASSERT(thread); QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread)); Q_ASSERT(!thread_p->finished); thread_p->finish(thread); } data->deref(); // ... but we must reset it to zero before returning so we aren't // called again (POSIX allows implementations to call destructor // functions repeatedly until all values are zero) pthread_setspecific(current_thread_data_key, #if defined(Q_OS_VXWORKS) (void *)1); #else 0); #endif }
/* QThreadData */ QThreadData *QThreadData::current() { qt_create_tls(); QThreadData *threadData = *qt_tls; if (!threadData) { QThread *adopted = 0; if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, (void **) &adopted)) { Q_ASSERT(adopted); threadData = QThreadData::get2(adopted); *qt_tls = 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. *qt_tls = threadData; threadData->thread = new QAdoptedThread(threadData); threadData->deref(); } if (!QCoreApplicationPrivate::theMainThread) { QCoreApplicationPrivate::theMainThread = threadData->thread; } else { PTIB ptib; DosGetInfoBlocks(&ptib, NULL); qt_watch_adopted_thread(ptib->tib_ptib2->tib2_ultid, threadData->thread); } } return threadData; }
void QObject::moveToThread(QThread *targetThread) { if (m_threadData.load()->thread == targetThread) { // object is already in this thread return; } if (m_parent != 0) { qWarning("QObject::moveToThread() Can not move an object with a parent"); return; } if (isWidgetType()) { qWarning("QObject::moveToThread() Widgets can not be moved to a new thread"); return; } QThreadData *currentData = QThreadData::current(); QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : new QThreadData(0); QThreadData *threadData = m_threadData.load(); if (threadData->thread == 0 && currentData == targetData) { // exception: allow moving objects with no thread affinity to the current thread currentData = threadData; } else if (threadData != currentData) { qWarning("QObject::moveToThread() Current thread (%p) is not the current object's thread (%p).\n" "Can not move to target thread (%p)\n", currentData->thread, threadData->thread, targetData->thread); #ifdef Q_WS_MAC qWarning("Multiple libraries might be loaded in the same process. Verify all plugins are " "linked with the correct binaries. Export DYLD_PRINT_LIBRARIES=1 and verify only one set of " "binaries are being loaded."); #endif return; } // prepare to move this->moveToThread_helper(); QOrderedMutexLocker locker(¤tData->postEventList.mutex, &targetData->postEventList.mutex); // keep currentData alive currentData->ref(); // move the object this->setThreadData_helper(currentData, targetData); locker.unlock(); currentData->deref(); }
QThreadData *QThreadData::current() { QThreadData *data = get_thread_data(); if (!data) { data = new QThreadData; QT_TRY { set_thread_data(data); data->thread = new QAdoptedThread(data); } QT_CATCH(...) { clear_thread_data(); data->deref(); data = 0; QT_RETHROW; }
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; }
QThreadData *QThreadData::current(bool createIfNecessary) { static bool winmainThread = true; QThreadData *threadData = qt_current_thread_data; if (!threadData && createIfNecessary) { threadData = new QThreadData; // This needs to be called prior to new AdoptedThread() to // avoid recursion. qt_current_thread_data = threadData; QT_TRY { threadData->thread = new QAdoptedThread(threadData); } QT_CATCH(...) { qt_current_thread_data = 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(); } }