bool UpdateThread::doUpdates(bool force, bool *gotData) { KstObject::UpdateType U = KstObject::NO_CHANGE; _updatedCurves.clear(); // HACK if (gotData) { *gotData = false; } #if UPDATEDEBUG > 0 if (force) { qDebug() << "Forced update!" << endl; } #endif _updateCounter++; if (_updateCounter < 1) { _updateCounter = 1; // check for wrap around } #if UPDATEDEBUG > 2 qDebug() << "UPDATE: counter=" << _updateCounter << endl; #endif { // Must make a copy to avoid deadlock KstBaseCurveList cl; KstDataObjectList dol; kstObjectSplitList<KstDataObject, KstBaseCurve>(KST::dataObjectList, cl, dol); qSort(cl); qSort(dol); // Update all curves for (uint i = 0; i < cl.count(); ++i) { KstBaseCurvePtr bcp = cl[i]; bcp->writeLock(); assert(bcp.data()); #if UPDATEDEBUG > 1 qDebug() << "updating curve: " << (void*)bcp << " - " << bcp->tagName() << endl; #endif KstObject::UpdateType ut = bcp->update(_updateCounter); bcp->unlock(); if (ut == KstObject::UPDATE) { // HACK _updatedCurves.append(bcp); } if (U != KstObject::UPDATE) { U = ut; if (U == KstObject::UPDATE) { #if UPDATEDEBUG > 0 qDebug() << "Curve " << bcp->tagName() << " said UPDATE" << endl; #endif } } if (_done || (_paused && !force)) { #if UPDATEDEBUG > 1 qDebug() << "5 Returning from scan with U=" << (int)U << endl; #endif return U == KstObject::UPDATE; } } // Update all data objects for (uint i = 0; i < dol.count(); ++i) { KstDataObjectPtr dp = dol[i]; dp->writeLock(); assert(dp.data()); #if UPDATEDEBUG > 1 qDebug() << "updating data object: " << (void*)dp << " - " << dp->tagName() << endl; #endif dp->update(_updateCounter); dp->unlock(); if (_done || (_paused && !force)) { #if UPDATEDEBUG > 1 qDebug() << "5 Returning from scan with U=" << (int)U << endl; #endif return U == KstObject::UPDATE; } } } // Update the files if (!_paused) { // don't update even if paused && force KST::dataSourceList.lock().readLock(); unsigned cnt = KST::dataSourceList.count(); for (uint i = 0; i < cnt; ++i) { KstDataSourcePtr dsp = KST::dataSourceList[i]; dsp->writeLock(); dsp->update(_updateCounter); dsp->unlock(); if (_done) { KST::dataSourceList.lock().unlock(); return false; } } KST::dataSourceList.lock().unlock(); } if (KstScalar::scalarsDirty()) { KstScalar::clearScalarsDirty(); // Must do this first and take a risk of // falling slightly behind KST::scalarList.lock().readLock(); KstScalarList sl = Q3DeepCopy<KstScalarList>(KST::scalarList.list()); // avoid deadlock on exit KST::scalarList.lock().unlock(); for (KstScalarList::ConstIterator i = sl.begin(); i != sl.end(); ++i) { KstScalarPtr sp = *i; sp->writeLock(); KstObject::UpdateType ut = sp->update(_updateCounter); sp->unlock(); if (ut == KstObject::UPDATE) { U = KstObject::UPDATE; } if (_done) { return false; } } } if (U == KstObject::UPDATE) { qDebug() << "Update plots" << endl; if (gotData) { // FIXME: do we need to consider all the other exit points? *gotData = true; } } #if UPDATEDEBUG > 1 qDebug() << "6 Returning from scan with U=" << (int)U << endl; #endif return U == KstObject::UPDATE; }
KstObject::UpdateType KstCPlugin::update(int update_counter) { Q_ASSERT(myLockStatus() == KstRWLock::WRITELOCKED); if (!isValid()) { return setLastUpdateResult(NO_CHANGE); } if (recursed()) { return setLastUpdateResult(NO_CHANGE); } bool force = dirty(); setDirty(false); if (KstObject::checkUpdateCounter(update_counter) && !force) { return lastUpdateResult(); } #define CLEANUP() do {\ for (unsigned i = 0; i < _outStringCnt; ++i) { \ if (_outStrings[i]) { \ free(_outStrings[i]); \ _outStrings[i] = 0L; \ } \ } \ for (unsigned i = 0; i < _inStringCnt; ++i) { \ if (_inStrings[i]) { \ free(_inStrings[i]); \ _inStrings[i] = 0L; \ } \ } \ } while(0) writeLockInputsAndOutputs(); const QValueList<Plugin::Data::IOValue>& itable = _plugin->data()._inputs; const QValueList<Plugin::Data::IOValue>& otable = _plugin->data()._outputs; int itcnt = 0, vitcnt = 0, sitcnt = 0; bool doUpdate = force; // Populate the input scalars and vectors for (QValueList<Plugin::Data::IOValue>::ConstIterator it = itable.begin(); it != itable.end(); ++it) { if ((*it)._type == Plugin::Data::IOValue::TableType) { if (!_inputVectors.contains((*it)._name)) { KstDebug::self()->log(i18n("Input vector [%1] for plugin %2 not found. Unable to continue.").arg((*it)._name).arg(tagName()), KstDebug::Error); CLEANUP(); return setLastUpdateResult(NO_CHANGE); } KstVectorPtr iv = _inputVectors[(*it)._name]; if (!iv) { kstdFatal() << "Input vector \"" << (*it)._name << "\" for plugin " << tag().displayString() << " is invalid." << endl; } doUpdate = (UPDATE == iv->update(update_counter)) || doUpdate; _inVectors[vitcnt] = iv->value(); _inArrayLens[vitcnt++] = iv->length(); } else if ((*it)._type == Plugin::Data::IOValue::FloatType) { KstScalarPtr is = _inputScalars[(*it)._name]; if (!is) { kstdFatal() << "Input scalar \"" << (*it)._name << "\" for plugin " << tag().displayString() << " is invalid." << endl; } doUpdate = (UPDATE == is->update(update_counter)) || doUpdate; _inScalars[itcnt++] = is->value(); } else if ((*it)._type == Plugin::Data::IOValue::StringType) { KstStringPtr is = _inputStrings[(*it)._name]; if (!is) { kstdFatal() << "Input string \"" << (*it)._name << "\" for plugin " << tag().displayString() << " is invalid." << endl; } doUpdate = (UPDATE == is->update(update_counter)) || doUpdate; // Maybe we should use UTF-8 instead? _inStrings[sitcnt++] = strdup(is->value().latin1()); } else if ((*it)._type == Plugin::Data::IOValue::PidType) { _inScalars[itcnt++] = getpid(); } } if (!doUpdate) { CLEANUP(); unlockInputsAndOutputs(); return setLastUpdateResult(NO_CHANGE); } vitcnt = 0; // Populate the output vectors for (QValueList<Plugin::Data::IOValue>::ConstIterator it = otable.begin(); it != otable.end(); ++it) { if ((*it)._type == Plugin::Data::IOValue::TableType) { if (!_outputVectors.contains((*it)._name)) { KstDebug::self()->log(i18n("Output vector [%1] for plugin %2 not found. Unable to continue.").arg((*it)._name).arg(tagName()), KstDebug::Error); CLEANUP(); unlockInputsAndOutputs(); return setLastUpdateResult(NO_CHANGE); } _outVectors[vitcnt] = _outputVectors[(*it)._name]->value(); _outArrayLens[vitcnt++] = _outputVectors[(*it)._name]->length(); } } if (_outStringCnt > 0) { memset(_outStrings, 0, _outStringCnt*sizeof(char *)); } int rc; if (_inStringCnt > 0 || _outStringCnt > 0) { if (_plugin->data()._localdata) { rc = _plugin->call(_inVectors, _inArrayLens, _inScalars, _outVectors, _outArrayLens, _outScalars, const_cast<const char**>(_inStrings), _outStrings, &_localData); } else { rc = _plugin->call(_inVectors, _inArrayLens, _inScalars, _outVectors, _outArrayLens, _outScalars, const_cast<const char**>(_inStrings), _outStrings); } } else { if (_plugin->data()._localdata) { rc = _plugin->call(_inVectors, _inArrayLens, _inScalars, _outVectors, _outArrayLens, _outScalars, &_localData); } else { rc = _plugin->call(_inVectors, _inArrayLens, _inScalars, _outVectors, _outArrayLens, _outScalars); } } if (rc == 0) { itcnt = 0; vitcnt = 0; sitcnt = 0; setLastUpdateResult(UPDATE); // make sure that provider callbacks work // Read back the output vectors and scalars for (QValueList<Plugin::Data::IOValue>::ConstIterator it = otable.begin(); it != otable.end(); ++it) { if ((*it)._type == Plugin::Data::IOValue::TableType) { KstVectorPtr vp = _outputVectors[(*it)._name]; vectorRealloced(vp, _outVectors[vitcnt], _outArrayLens[vitcnt]); vp->setDirty(); // Inefficient, but do we have any other choice? We don't really know // from the plugin how much of this vector is "new" or "shifted" vp->setNewAndShift(vp->length(), vp->numShift()); vp->update(update_counter); vitcnt++; } else if ((*it)._type == Plugin::Data::IOValue::FloatType) { KstScalarPtr sp = _outputScalars[(*it)._name]; sp->setValue(_outScalars[itcnt++]); sp->update(update_counter); } else if ((*it)._type == Plugin::Data::IOValue::StringType) { KstStringPtr sp = _outputStrings[(*it)._name]; sp->setValue(_outStrings[sitcnt++]); sp->update(update_counter); } } // if we have a fit plugin then create the necessary scalars from the parameter vector createFitScalars(); _lastError = QString::null; } else if (rc > 0) { if (_lastError.isEmpty()) { const char *err = _plugin->errorCode(rc); if (err && *err) { _lastError = err; KstDebug::self()->log(i18n("Plugin %1 produced error: %2.").arg(tagName()).arg(_lastError), KstDebug::Error); } else { _lastError = QString::null; } } } else { bool doSend = _lastError.isEmpty() ? true : false; switch (rc) { case -1: _lastError = i18n("Generic Error"); break; case -2: _lastError = i18n("Input Error"); break; case -3: _lastError = i18n("Memory Error"); break; default: _lastError = i18n("Unknown Error"); break; } if (doSend) { KstDebug::self()->log(i18n("Plugin %2 produced error: %1.").arg(_lastError).arg(tagName()), KstDebug::Error); } } unlockInputsAndOutputs(); CLEANUP(); #undef CLEANUP return setLastUpdateResult(UPDATE); }