Skip to content
This repository has been archived by the owner on Sep 4, 2021. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'staging' into 'master'
Notify ContextProperty objects about changed data only once



See merge request !2
  • Loading branch information
Denis Zalevskiy committed Nov 13, 2015
2 parents cf0a4f9 + a30e6e9 commit cba3aa0
Show file tree
Hide file tree
Showing 10 changed files with 360 additions and 39 deletions.
36 changes: 35 additions & 1 deletion rpm/statefs-qt5.spec
Expand Up @@ -57,6 +57,22 @@ Requires: statefs-contextkit-subscriber = %{version}-%{release}
%description %{subscriber_devel}
Contextkit property interface using statefs instead of contextkit

%package -n statefs-declarative-qt5
Summary: Statefs QML plugin
Group: System Environment/Libraries
Requires: statefs-contextkit-subscriber = %{version}-%{release}
%description -n statefs-declarative-qt5
%{summary}

%package -n contextkit-declarative-qt5
Summary: Contextkit QML plugin
Group: System Environment/Libraries
Requires: statefs-contextkit-subscriber = %{version}-%{release}
Obsoletes: nemo-qml-plugin-contextkit-qt5 <= 1.1.8
Provides: nemo-qml-plugin-contextkit-qt5 = 1.1.9
%description -n contextkit-declarative-qt5
%{summary}

%package tests
Summary: Tests for %{name}
Group: System Environment/Libraries
Expand Down Expand Up @@ -86,6 +102,7 @@ rm -rf %{buildroot}

%files devel
%defattr(-,root,root,-)
%dir %{_libqt5_includedir}/statefs/qt
%{_libqt5_includedir}/statefs/qt/*.hpp
%{_libdir}/pkgconfig/statefs-qt5.pc

Expand All @@ -97,17 +114,34 @@ rm -rf %{buildroot}
%defattr(-,root,root,-)
%{_libdir}/libcontextkit-statefs-qt5.so
%{_bindir}/contextkit-monitor
%{_libdir}/qt5/qml/Mer/State/*

%files %{subscriber_devel}
%defattr(-,root,root,-)
%{_includedir}/contextproperty.h
%{_libdir}/pkgconfig/contextkit-statefs.pc
%{_libdir}/pkgconfig/contextsubscriber-1.0.pc


%files -n statefs-declarative-qt5
%defattr(-,root,root,-)
%{_libdir}/qt5/qml/Mer/State/*

%files -n contextkit-declarative-qt5
%defattr(-,root,root,-)
%{_libdir}/qt5/qml/org/freedesktop/contextkit/*

%files tests
%defattr(-,root,root,-)
/opt/tests/%{name}/*

%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig

%post %{subscriber} -p /sbin/ldconfig
%postun %{subscriber} -p /sbin/ldconfig

%post -n statefs-declarative-qt5 -p /sbin/ldconfig
%postun -n statefs-declarative-qt5 -p /sbin/ldconfig

%post -n contextkit-declarative-qt5 -p /sbin/ldconfig
%postun -n contextkit-declarative-qt5 -p /sbin/ldconfig
121 changes: 88 additions & 33 deletions src/contextkit-subscriber/property.cpp
Expand Up @@ -132,8 +132,8 @@ class Event : public QEvent
Subscribed,
Write,
Refresh,
Data,
WriteStatus
WriteStatus,
Ready
};

virtual ~Event();
Expand Down Expand Up @@ -302,15 +302,13 @@ class ReplyEvent : public Event
target_handle tgt_;
};

class DataReplyEvent : public ReplyEvent

class DataReadyEvent : public ReplyEvent
{
public:
DataReplyEvent(QVariant v, target_handle const &tgt)
: ReplyEvent(Event::Data, tgt)
, data_(std::move(v))
DataReadyEvent(target_handle const &tgt)
: ReplyEvent(Event::Ready, tgt)
{}

QVariant data_;
};

class SubscribeRequest : public Event
Expand Down Expand Up @@ -338,7 +336,7 @@ class SubscribeRequest : public Event
SubscribeRequest::~SubscribeRequest()
{
auto notify_fn = [this]() {
tgt_->postEvent(new DataReplyEvent(result, tgt_));
tgt_->dataReady(tgt_);
value_.set_value(result);
};
execute_nothrow(notify_fn, __PRETTY_FUNCTION__);
Expand Down Expand Up @@ -474,10 +472,11 @@ void PropertyMonitor::write(WriteRequest *req)
}
}

void Property::changed(QVariant const &v) const
void Property::changed() const
{
for (auto tgt : targets_)
tgt->postEvent(new DataReplyEvent(v, tgt));
debug::debug("Notify", file_.key(), targets_.size(), "targets");
for (auto target : targets_)
target->dataReady(target);
}

bool Property::add(target_handle const &target)
Expand All @@ -486,6 +485,7 @@ bool Property::add(target_handle const &target)
auto it = targets_.find(target);
if (it == targets_.end()) {
targets_.insert(target);
target->attachCache(cache_);
res = true;
}
return res;
Expand All @@ -506,9 +506,10 @@ void PropertyMonitor::subscribe(SubscribeRequest *req)
{
auto tgt = req->tgt_;
auto key = req->key_;
Property *handler;
std::shared_ptr<Property> handler;
QVariant retval;

debug::debug("Subcribe request:", tgt, key);
if (!tgt) {
debug::warning("Logic issue: subscription target is null");
return;
Expand All @@ -535,6 +536,8 @@ void PropertyMonitor::unsubscribe(UnsubscribeRequest *req)
auto tgt = req->tgt_;
auto key = req->key_;

debug::debug("Unsubcribe request:", tgt, key);

auto phandlers = properties_.find(key);
if (phandlers == properties_.end())
return;
Expand All @@ -544,7 +547,6 @@ void PropertyMonitor::unsubscribe(UnsubscribeRequest *req)
if (handler->remove(tgt) == Property::Removed::Last) {
// last subscriber is gone
properties_.erase(phandlers);
handler->deleteLater();
}
}

Expand All @@ -559,18 +561,32 @@ void PropertyMonitor::refresh(RefreshRequest *req)
handler->update();
}

Property* PropertyMonitor::add(const QString &key)
std::shared_ptr<Property> PropertyMonitor::add(const QString &key)
{
auto it = properties_.insert(key, new Property(key, this));
auto it = properties_.insert
(key, make_qobject_shared<Property>(key, this));
return it.value();
}

void Cache::store(QVariant v)
{
QMutexLocker lock(&mutex_);
data_ = v;
}

QVariant Cache::load() const
{
QMutexLocker lock(&mutex_);
return data_;
}

Property::Property(const QString &key, QObject *parent)
: QObject(parent)
, file_(key)
, reopen_interval_(100)
, reopen_timer_(new QTimer(this))
, is_subscribed_(false)
, cache_(std::make_shared<Cache>())
{
reopen_timer_->setSingleShot(true);
connect(reopen_timer_, SIGNAL(timeout()), this, SLOT(trySubscribe()));
Expand Down Expand Up @@ -622,7 +638,7 @@ bool Property::update()

if (!file_.tryOpen()) {
debug::warning("Can't open ", file_.fileName());
cache_ = statefs::qt::valueDefault(cache_);
cache_->store(statefs::qt::valueDefault(cache_->load()));
resubscribe();
return is_updated;
}
Expand Down Expand Up @@ -659,19 +675,25 @@ bool Property::update()
rc = bytes_read;
}
touchFile.close();
QVariant value, prev_value;
if (rc >= 0) {
buffer_[(int)rc] = '\0';
auto s = QString(buffer_);
prev_value = cache_->load();
if (s.size()) {
cache_ = statefs::qt::valueDecode(s);
value = statefs::qt::valueDecode(s);
} else {
if (cache_.isNull()) {
cache_ = s;
if (prev_value.isNull()) {
value = s;
} else {
cache_ = statefs::qt::valueDefault(cache_);
value = statefs::qt::valueDefault(prev_value);
}
}
is_updated = true;
if (value != prev_value) {
cache_->store(value);
is_updated = true;
debug::debug("Updated", file_.key(), value);
}
} else {
debug::warning("Error accessing? ", rc, "..." + file_.fileName());
resubscribe();
Expand All @@ -683,16 +705,19 @@ bool Property::update()
void Property::handleActivated(int)
{
if (update())
changed(cache_);
changed();
}

QVariant Property::subscribe()
{
return (!is_subscribed_ ? subscribe_() : cache_);
return (!is_subscribed_ ? subscribe_() : cache_->load());
}

QVariant Property::subscribe_()
{
if (reopen_timer_->isActive())
return QVariant();

if (!file_.tryOpen()) {
reopen_timer_->start(reopen_interval_);
return QVariant();
Expand All @@ -702,9 +727,9 @@ QVariant Property::subscribe_()
file_.connect(this, &Property::handleActivated);

if (update())
changed(cache_);
changed();

return cache_;
return cache_->load();
}

void Property::unsubscribe()
Expand All @@ -725,6 +750,7 @@ ContextPropertyPrivate::ContextPropertyPrivate(const QString &key)
, state_(Initial)
, is_cached_(false)
, handle_(this)
, update_queued_(ATOMIC_FLAG_INIT)
{
}

Expand Down Expand Up @@ -787,11 +813,14 @@ PropertyMonitor::monitor_ptr ContextPropertyPrivate::actor()

void ContextPropertyPrivate::onChanged(QVariant v) const
{
if (state_ == Subscribing)
bool subscribing = state_ == Subscribing;
if (subscribing)
state_ = Subscribed;

if (update(v))
if (update(v) || subscribing) {
debug::debug("Notify data ready", key_, v);
emit valueChanged();
}
}

void ContextPropertyPrivate::postEvent(ReplyEvent *e)
Expand All @@ -803,21 +832,22 @@ void ContextPropertyPrivate::postEvent(ReplyEvent *e)
bool ContextPropertyPrivate::event(QEvent *e)
{
using statefs::qt::Event;
using statefs::qt::DataReplyEvent;
using statefs::qt::DataReadyEvent;
if (e->type() < QEvent::User)
return QObject::event(e);

auto res = true;
auto fn = [this, e, &res]() {
auto t = static_cast<Event::Type>(e->type());
switch (t) {
case Event::Data: {
auto p = EVENT_CAST(e, DataReplyEvent);
if (p) onChanged(std::move(p->data_));
case Event::Ready: {
auto p = EVENT_CAST(e, DataReadyEvent);
debug::debug("Data ready:", this, key_);
if (p) updateFromRemoteCache(p);
break;
}
default:
debug::warning("Unknown user event");
debug::warning("Unknown user event", t);
res = QObject::event(e);
}
};
Expand Down Expand Up @@ -945,6 +975,31 @@ void ContextPropertyPrivate::refresh() const
actor()->postEvent(new RefreshRequest(this->handle_, key_));
}

void ContextPropertyPrivate::attachCache(std::shared_ptr<statefs::qt::Cache> cache) const
{
// called from other thread
remote_cache_ = cache;
}

void ContextPropertyPrivate::dataReady(statefs::qt::target_handle self_handle)
{
// called from other thread
if (!update_queued_.test_and_set(std::memory_order_acquire)) {
postEvent(new statefs::qt::DataReadyEvent(self_handle));
}
}

void ContextPropertyPrivate::updateFromRemoteCache(statefs::qt::DataReadyEvent *)
{
// called from the object thread
update_queued_.clear(std::memory_order_release);
// cache is attached from an other thread, so save pointer copy
auto pcache = remote_cache_.lock();
if (pcache)
onChanged(pcache->load());
}


ContextProperty::ContextProperty(const QString &key, QObject *parent)
: QObject(parent)
, priv(new ContextPropertyPrivate(key))
Expand Down

0 comments on commit cba3aa0

Please sign in to comment.