Merge remote-tracking branch 'origin/master' into merge-to-aosp
Merged the following commits:
- e61717c Fix the virtual lock device
- f1fa93d Add fd event support to EventTaskRunner
- 5ca27be Removing trailing whitespace from speaker.cc
- b51b475 Adding handler for speaker device.
- fdf7515 examples: fix prerequisites for debian
- 82f215e Fixed check for pending tasks
- a627e12 Run CURL in background thread.
diff --git a/examples/daemon/README b/examples/daemon/README
index 287459f..c767420 100644
--- a/examples/daemon/README
+++ b/examples/daemon/README
@@ -8,8 +8,8 @@
examples/prerequisites.sh
- build daemon
examples/build.sh
- - binaries for daemon is at
- out/Debug/weave_daemon
+ - binaries for daemon are in the directory
+ out/Debug/
Prepare Host OS
---------------
@@ -50,7 +50,7 @@
93019287-6b26-04a0-22ee-d55ad23a4226
- go to terminal, register and start the daemon with
- sudo out/Debug/weave_daemon --registration_ticket=93019287-6b26-04a0-22ee-d55ad23a4226
+ sudo out/Debug/weave_daemon_sample --registration_ticket=93019287-6b26-04a0-22ee-d55ad23a4226
you should see something like:
Publishing service
diff --git a/examples/daemon/examples.gyp b/examples/daemon/examples.gyp
index 8fee90d..2b497a5 100644
--- a/examples/daemon/examples.gyp
+++ b/examples/daemon/examples.gyp
@@ -7,7 +7,8 @@
'sample/daemon.gyp:weave_daemon_sample',
'light/daemon.gyp:weave_daemon_light',
'lock/daemon.gyp:weave_daemon_lock',
- 'ledflasher/daemon.gyp:weave_daemon_ledflasher'
+ 'ledflasher/daemon.gyp:weave_daemon_ledflasher',
+ 'speaker/daemon.gyp:weave_daemon_speaker'
]
}
]
diff --git a/examples/daemon/lock/lock.cc b/examples/daemon/lock/lock.cc
index e1ca2d9..3014fb1 100644
--- a/examples/daemon/lock/lock.cc
+++ b/examples/daemon/lock/lock.cc
@@ -34,11 +34,16 @@
device_ = device;
device->AddStateDefinitionsFromJson(R"({
- "lock": {"lockedState": ["locked", "unlocked", "partiallyLocked"]}
+ "lock": {
+ "lockedState": ["locked", "unlocked", "partiallyLocked"],
+ "isLockingSupported": "boolean"}
})");
device->SetStatePropertiesFromJson(R"({
- "lock":{"lockedState": "locked"}
+ "lock":{
+ "lockedState": "locked",
+ "isLockingSupported": true
+ }
})",
nullptr);
diff --git a/examples/daemon/speaker/daemon.gyp b/examples/daemon/speaker/daemon.gyp
new file mode 100644
index 0000000..3bf7a91
--- /dev/null
+++ b/examples/daemon/speaker/daemon.gyp
@@ -0,0 +1,18 @@
+# Copyright 2015 The Weave Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+ 'targets': [
+ {
+ 'target_name': 'weave_daemon_speaker',
+ 'type': 'executable',
+ 'sources': [
+ 'speaker.cc',
+ ],
+ 'dependencies': [
+ '<@(DEPTH)/libweave_standalone.gyp:libweave',
+ '<@(DEPTH)/examples/provider/provider.gyp:libweave_provider',
+ ]
+ }
+ ]
+}
diff --git a/examples/daemon/speaker/speaker.cc b/examples/daemon/speaker/speaker.cc
new file mode 100644
index 0000000..32591f9
--- /dev/null
+++ b/examples/daemon/speaker/speaker.cc
@@ -0,0 +1,154 @@
+// Copyright 2015 The Weave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "examples/daemon/common/daemon.h"
+
+#include <weave/device.h>
+
+#include <base/bind.h>
+#include <base/memory/weak_ptr.h>
+
+// SpeakerHandler is a command handler example that shows
+// how to handle commands for a Weave speaker.
+class SpeakerHandler {
+ public:
+ SpeakerHandler() = default;
+ void Register(weave::Device* device) {
+ device_ = device;
+
+ device->AddStateDefinitionsFromJson(R"({
+ "onOff": {"state": ["on", "standby"]},
+ "volume": {
+ "volume": "integer",
+ "isMuted": "boolean"
+ }
+ })");
+
+ device->SetStatePropertiesFromJson(R"({
+ "onOff":{"state": "standby"},
+ "volume":{
+ "volume": 100,
+ "isMuted": false
+ }
+ })",
+ nullptr);
+
+ device->AddCommandDefinitionsFromJson(R"({
+ "onOff": {
+ "setConfig":{
+ "parameters": {
+ "state": ["on", "standby"]
+ }
+ }
+ },
+ "volume": {
+ "setConfig":{
+ "parameters": {
+ "volume": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 100
+ },
+ "isMuted": "boolean"
+ }
+ }
+ }
+ })");
+ device->AddCommandHandler("onOff.setConfig",
+ base::Bind(&SpeakerHandler::OnOnOffSetConfig,
+ weak_ptr_factory_.GetWeakPtr()));
+ device->AddCommandHandler("volume.setConfig",
+ base::Bind(&SpeakerHandler::OnVolumeSetConfig,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ private:
+ void OnVolumeSetConfig(const std::weak_ptr<weave::Command>& command) {
+ auto cmd = command.lock();
+ if (!cmd)
+ return;
+ LOG(INFO) << "received command: " << cmd->GetName();
+
+ // Handle volume parameter
+ int32_t volume_value = 0;
+ if (cmd->GetParameters()->GetInteger("volume", &volume_value)) {
+ // Display this command in terminal.
+ LOG(INFO) << cmd->GetName() << " volume: " << volume_value;
+
+ if (volume_value_ != volume_value) {
+ volume_value_ = volume_value;
+ UpdateSpeakerState();
+ }
+ cmd->Complete({}, nullptr);
+ return;
+ }
+
+ // Handle isMuted parameter
+ bool isMuted_status = false;
+ if (cmd->GetParameters()->GetBoolean("isMuted", &isMuted_status)) {
+ // Display this command in terminal.
+ LOG(INFO) << cmd->GetName() << " is "
+ << (isMuted_status ? "muted" : "not muted");
+
+ if (isMuted_status_ != isMuted_status) {
+ isMuted_status_ = isMuted_status;
+
+ LOG(INFO) << "Speaker is now: "
+ << (isMuted_status ? "muted" : "not muted");
+ UpdateSpeakerState();
+ }
+ }
+
+ cmd->Complete({}, nullptr);
+ }
+
+ void OnOnOffSetConfig(const std::weak_ptr<weave::Command>& command) {
+ auto cmd = command.lock();
+ if (!cmd)
+ return;
+ LOG(INFO) << "received command: " << cmd->GetName();
+ std::string requested_state;
+ if (cmd->GetParameters()->GetString("state", &requested_state)) {
+ LOG(INFO) << cmd->GetName() << " state: " << requested_state;
+
+ bool new_speaker_status = requested_state == "on";
+ if (new_speaker_status != speaker_status_) {
+ speaker_status_ = new_speaker_status;
+
+ LOG(INFO) << "Speaker is now: " << (speaker_status_ ? "ON" : "OFF");
+ UpdateSpeakerState();
+ }
+ }
+ cmd->Complete({}, nullptr);
+ }
+
+ void UpdateSpeakerState() {
+ base::DictionaryValue state;
+ state.SetString("onOff.state", speaker_status_ ? "on" : "standby");
+ state.SetBoolean("volume.isMuted", isMuted_status_);
+ state.SetInteger("volume.volume", volume_value_);
+ device_->SetStateProperties(state, nullptr);
+ }
+
+ weave::Device* device_{nullptr};
+
+ // Simulate the state of the speaker.
+ bool speaker_status_;
+ bool isMuted_status_;
+ int32_t volume_value_;
+ base::WeakPtrFactory<SpeakerHandler> weak_ptr_factory_{this};
+};
+
+int main(int argc, char** argv) {
+ Daemon::Options opts;
+ if (!opts.Parse(argc, argv)) {
+ Daemon::Options::ShowUsage(argv[0]);
+ return 1;
+ }
+ Daemon daemon{opts};
+ SpeakerHandler speaker;
+ speaker.Register(daemon.GetDevice());
+ daemon.Run();
+ return 0;
+}
diff --git a/examples/prerequisites.sh b/examples/prerequisites.sh
index d1661d0..7358b71 100755
--- a/examples/prerequisites.sh
+++ b/examples/prerequisites.sh
@@ -6,10 +6,11 @@
DIR=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
ROOT_DIR=$(cd -P -- "$(dirname -- "$0")/.." && pwd -P)
-sudo apt-get install ${APT_GET_OPTS} \
+sudo apt-get update && sudo apt-get install ${APT_GET_OPTS} \
autoconf \
automake \
binutils \
+ g++ \
gyp \
hostapd \
libavahi-client-dev \
@@ -17,6 +18,7 @@
libexpat1-dev \
libnl-3-dev \
libnl-route-3-dev \
+ libssl-dev \
libtool \
ninja-build \
|| exit 1
@@ -57,8 +59,10 @@
./autogen.sh || exit 1
./configure --disable-shared || exit 1
make || exit 1
-echo -e "\n\nTesting libevent...\nCan take several minutes.\n"
-make verify || exit 1
+if [ -z "$DISABLE_LIBEVENT_TEST" ]; then
+ echo -e "\n\nTesting libevent...\nCan take several minutes.\n"
+ make verify || exit 1
+fi
cp -rf include/* $ROOT_DIR/third_party/include/ || exit 1
cp -rf .libs/lib* $ROOT_DIR/third_party/lib/ || exit 1
rm -rf $ROOT_DIR/third_party/libevent
diff --git a/examples/provider/curl_http_client.cc b/examples/provider/curl_http_client.cc
index b440f39..32aa4af 100644
--- a/examples/provider/curl_http_client.cc
+++ b/examples/provider/curl_http_client.cc
@@ -4,10 +4,14 @@
#include "examples/provider/curl_http_client.h"
+#include <future>
+#include <thread>
+
#include <base/bind.h>
+#include <base/logging.h>
#include <curl/curl.h>
-#include <weave/provider/task_runner.h>
#include <weave/enum_to_string.h>
+#include <weave/provider/task_runner.h>
namespace weave {
namespace examples {
@@ -30,29 +34,24 @@
return size * nmemb;
}
-} // namespace
-
-CurlHttpClient::CurlHttpClient(provider::TaskRunner* task_runner)
- : task_runner_{task_runner} {}
-
-void CurlHttpClient::SendRequest(Method method,
- const std::string& url,
- const Headers& headers,
- const std::string& data,
- const SendRequestCallback& callback) {
+std::pair<std::unique_ptr<CurlHttpClient::Response>, ErrorPtr>
+SendRequestBlocking(CurlHttpClient::Method method,
+ const std::string& url,
+ const CurlHttpClient::Headers& headers,
+ const std::string& data) {
std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> curl{curl_easy_init(),
&curl_easy_cleanup};
CHECK(curl);
switch (method) {
- case Method::kGet:
+ case CurlHttpClient::Method::kGet:
CHECK_EQ(CURLE_OK, curl_easy_setopt(curl.get(), CURLOPT_HTTPGET, 1L));
break;
- case Method::kPost:
+ case CurlHttpClient::Method::kPost:
CHECK_EQ(CURLE_OK, curl_easy_setopt(curl.get(), CURLOPT_HTTPPOST, 1L));
break;
- case Method::kPatch:
- case Method::kPut:
+ case CurlHttpClient::Method::kPatch:
+ case CurlHttpClient::Method::kPut:
CHECK_EQ(CURLE_OK, curl_easy_setopt(curl.get(), CURLOPT_CUSTOMREQUEST,
weave::EnumToString(method).c_str()));
break;
@@ -66,7 +65,7 @@
CHECK_EQ(CURLE_OK, curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, chunk));
- if (!data.empty() || method == Method::kPost) {
+ if (!data.empty() || method == CurlHttpClient::Method::kPost) {
CHECK_EQ(CURLE_OK,
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, data.c_str()));
}
@@ -89,8 +88,7 @@
if (res != CURLE_OK) {
Error::AddTo(&error, FROM_HERE, "curl", "curl_easy_perform_error",
curl_easy_strerror(res));
- return task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(callback, nullptr, base::Passed(&error)), {});
+ return {nullptr, std::move(error)};
}
const std::string kContentType = "\r\nContent-Type:";
@@ -98,8 +96,7 @@
if (pos == std::string::npos) {
Error::AddTo(&error, FROM_HERE, "curl", "no_content_header",
"Content-Type header is missing");
- return task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(callback, nullptr, base::Passed(&error)), {});
+ return {nullptr, std::move(error)};
}
pos += kContentType.size();
auto pos_end = response->content_type.find("\r\n", pos);
@@ -112,8 +109,57 @@
CHECK_EQ(CURLE_OK, curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE,
&response->status));
+ return {std::move(response), nullptr};
+}
+
+} // namespace
+
+CurlHttpClient::CurlHttpClient(provider::TaskRunner* task_runner)
+ : task_runner_{task_runner} {}
+
+void CurlHttpClient::SendRequest(Method method,
+ const std::string& url,
+ const Headers& headers,
+ const std::string& data,
+ const SendRequestCallback& callback) {
+ pending_tasks_.emplace_back(
+ std::async(std::launch::async, SendRequestBlocking, method, url, headers,
+ data),
+ callback);
+ if (pending_tasks_.size() == 1) // More means check is scheduled.
+ CheckTasks();
+}
+
+void CurlHttpClient::CheckTasks() {
+ VLOG(4) << "CurlHttpClient::CheckTasks, size=" << pending_tasks_.size();
+ auto ready_begin =
+ std::partition(pending_tasks_.begin(), pending_tasks_.end(),
+ [](const decltype(pending_tasks_)::value_type& value) {
+ return value.first.wait_for(std::chrono::seconds(0)) !=
+ std::future_status::ready;
+ });
+
+ for (auto it = ready_begin; it != pending_tasks_.end(); ++it) {
+ CHECK(it->first.valid());
+ auto result = it->first.get();
+ VLOG(2) << "CurlHttpClient::CheckTasks done";
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(it->second, base::Passed(&result.first),
+ base::Passed(&result.second)),
+ {});
+ }
+
+ pending_tasks_.erase(ready_begin, pending_tasks_.end());
+
+ if (pending_tasks_.empty()) {
+ VLOG(2) << "No more CurlHttpClient tasks";
+ return;
+ }
+
task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(callback, base::Passed(&response), nullptr), {});
+ FROM_HERE,
+ base::Bind(&CurlHttpClient::CheckTasks, weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(100));
}
} // namespace examples
diff --git a/examples/provider/curl_http_client.h b/examples/provider/curl_http_client.h
index b2f4bca..c342076 100644
--- a/examples/provider/curl_http_client.h
+++ b/examples/provider/curl_http_client.h
@@ -5,7 +5,9 @@
#ifndef LIBWEAVE_EXAMPLES_PROVIDER_CURL_HTTP_CLIENT_H_
#define LIBWEAVE_EXAMPLES_PROVIDER_CURL_HTTP_CLIENT_H_
+#include <future>
#include <string>
+#include <utility>
#include <base/memory/weak_ptr.h>
#include <weave/provider/http_client.h>
@@ -31,6 +33,11 @@
const SendRequestCallback& callback) override;
private:
+ void CheckTasks();
+
+ std::vector<
+ std::pair<std::future<std::pair<std::unique_ptr<Response>, ErrorPtr>>,
+ SendRequestCallback>> pending_tasks_;
provider::TaskRunner* task_runner_{nullptr};
base::WeakPtrFactory<CurlHttpClient> weak_ptr_factory_{this};
diff --git a/examples/provider/event_deleter.h b/examples/provider/event_deleter.h
new file mode 100644
index 0000000..078c326
--- /dev/null
+++ b/examples/provider/event_deleter.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Weave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIBWEAVE_EXAMPLES_PROVIDER_EVENT_DELETER_H
+#define LIBWEAVE_EXAMPLES_PROVIDER_EVENT_DELETER_H
+
+#include <memory>
+
+#include <third_party/include/event2/event.h>
+#include <third_party/include/event2/event_struct.h>
+#include <third_party/include/event2/http.h>
+
+namespace weave {
+namespace examples {
+
+// Defines overloaded deletion methods for various event_ objects
+// so we can use one unique_ptr definition for all of them
+class EventDeleter {
+ public:
+ void operator()(evhttp_uri* http_uri) { evhttp_uri_free(http_uri); }
+ void operator()(evhttp_connection* conn) { evhttp_connection_free(conn); }
+ void operator()(evhttp_request* req) { evhttp_request_free(req); }
+ void operator()(event_base* base) { event_base_free(base); }
+ void operator()(event* ev) {
+ event_del(ev);
+ event_free(ev);
+ }
+};
+
+template <typename T>
+using EventPtr = std::unique_ptr<T, EventDeleter>;
+
+} // namespace examples
+} // namespace weave
+
+#endif // LIBWEAVE_EXAMPLES_PROVIDER_EVENT_DELETER_H
diff --git a/examples/provider/event_http_client.cc b/examples/provider/event_http_client.cc
index b38bd55..03da97f 100644
--- a/examples/provider/event_http_client.cc
+++ b/examples/provider/event_http_client.cc
@@ -5,15 +5,14 @@
#include "examples/provider/event_http_client.h"
#include "examples/provider/event_task_runner.h"
-#include <weave/enum_to_string.h>
-
-#include <string>
#include <base/bind.h>
-
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/http.h>
+#include <weave/enum_to_string.h>
+
+#include "examples/provider/event_deleter.h"
// EventHttpClient based on libevent2 http-client sample
// TODO(proppy): https
@@ -38,13 +37,6 @@
namespace {
-class EventDeleter {
- public:
- void operator()(evhttp_uri* http_uri) { evhttp_uri_free(http_uri); }
- void operator()(evhttp_connection* conn) { evhttp_connection_free(conn); }
- void operator()(evhttp_request* req) { evhttp_request_free(req); }
-};
-
class EventHttpResponse : public weave::provider::HttpClient::Response {
public:
int GetStatusCode() const override { return status; }
@@ -58,8 +50,8 @@
struct EventRequestState {
TaskRunner* task_runner_;
- std::unique_ptr<evhttp_uri, EventDeleter> http_uri_;
- std::unique_ptr<evhttp_connection, EventDeleter> evcon_;
+ EventPtr<evhttp_uri> http_uri_;
+ EventPtr<evhttp_connection> evcon_;
HttpClient::SendRequestCallback callback_;
};
@@ -101,8 +93,7 @@
const SendRequestCallback& callback) {
evhttp_cmd_type method_id;
CHECK(weave::StringToEnum(weave::EnumToString(method), &method_id));
- std::unique_ptr<evhttp_uri, EventDeleter> http_uri{
- evhttp_uri_parse(url.c_str())};
+ EventPtr<evhttp_uri> http_uri{evhttp_uri_parse(url.c_str())};
CHECK(http_uri);
auto host = evhttp_uri_get_host(http_uri.get());
CHECK(host);
@@ -121,11 +112,10 @@
auto bev = bufferevent_socket_new(task_runner_->GetEventBase(), -1,
BEV_OPT_CLOSE_ON_FREE);
CHECK(bev);
- std::unique_ptr<evhttp_connection, EventDeleter> conn{
- evhttp_connection_base_bufferevent_new(task_runner_->GetEventBase(), NULL,
- bev, host, port)};
+ EventPtr<evhttp_connection> conn{evhttp_connection_base_bufferevent_new(
+ task_runner_->GetEventBase(), NULL, bev, host, port)};
CHECK(conn);
- std::unique_ptr<evhttp_request, EventDeleter> req{evhttp_request_new(
+ EventPtr<evhttp_request> req{evhttp_request_new(
&RequestDoneCallback,
new EventRequestState{task_runner_, std::move(http_uri), std::move(conn),
callback})};
diff --git a/examples/provider/event_http_client.h b/examples/provider/event_http_client.h
index 7ad117e..378c4a3 100644
--- a/examples/provider/event_http_client.h
+++ b/examples/provider/event_http_client.h
@@ -10,11 +10,11 @@
#include <base/memory/weak_ptr.h>
#include <weave/provider/http_client.h>
+#include "examples/provider/event_task_runner.h"
+
namespace weave {
namespace examples {
-class EventTaskRunner;
-
// Basic implementation of weave::HttpClient using libevent.
class EventHttpClient : public provider::HttpClient {
public:
diff --git a/examples/provider/event_task_runner.cc b/examples/provider/event_task_runner.cc
index c14a934..c07e912 100644
--- a/examples/provider/event_task_runner.cc
+++ b/examples/provider/event_task_runner.cc
@@ -24,6 +24,24 @@
queue_.emplace(std::make_pair(new_time, ++counter_), task);
}
+void EventTaskRunner::AddIoCompletionTask(
+ int fd,
+ int16_t what,
+ const EventTaskRunner::IoCompletionCallback& task) {
+ int16_t flags = EV_PERSIST | EV_ET;
+ flags |= (what & kReadable) ? EV_READ : 0;
+ flags |= (what & kWriteable) ? EV_WRITE : 0;
+ flags |= (what & kClosed) ? EV_CLOSED : 0;
+ event* ioevent = event_new(base_.get(), fd, flags, FdEventHandler, this);
+ EventPtr<event> ioeventPtr{ioevent};
+ fd_task_map_.emplace(fd, std::make_pair(std::move(ioeventPtr), task));
+ event_add(ioevent, nullptr);
+}
+
+void EventTaskRunner::RemoveIoCompletionTask(int fd) {
+ fd_task_map_.erase(fd);
+}
+
void EventTaskRunner::Run() {
g_event_base = base_.get();
@@ -44,7 +62,9 @@
event_add(task_event_.get(), &tv);
}
-void EventTaskRunner::EventHandler(int, int16_t, void* runner) {
+void EventTaskRunner::EventHandler(int /* fd */,
+ int16_t /* what */,
+ void* runner) {
static_cast<EventTaskRunner*>(runner)->Process();
}
@@ -66,5 +86,17 @@
}
}
+void EventTaskRunner::FdEventHandler(int fd, int16_t what, void* runner) {
+ static_cast<EventTaskRunner*>(runner)->ProcessFd(fd, what);
+}
+
+void EventTaskRunner::ProcessFd(int fd, int16_t what) {
+ auto it = fd_task_map_.find(fd);
+ if (it != fd_task_map_.end()) {
+ const IoCompletionCallback& callback = it->second.second;
+ callback.Run(fd, what, this);
+ }
+}
+
} // namespace examples
} // namespace weave
diff --git a/examples/provider/event_task_runner.h b/examples/provider/event_task_runner.h
index 473441e..7291314 100644
--- a/examples/provider/event_task_runner.h
+++ b/examples/provider/event_task_runner.h
@@ -10,9 +10,10 @@
#include <vector>
#include <event2/event.h>
-
#include <weave/provider/task_runner.h>
+#include "examples/provider/event_deleter.h"
+
namespace weave {
namespace examples {
@@ -23,6 +24,40 @@
const base::Closure& task,
base::TimeDelta delay) override;
+ // Defines the types of I/O completion events that the
+ // application can register to receive on a file descriptor.
+ enum IOEvent : int16_t {
+ kReadable = 0x01,
+ kWriteable = 0x02,
+ kClosed = 0x04,
+ kReadableWriteable = kReadable | kWriteable,
+ kReadableOrClosed = kReadable | kClosed,
+ kAll = kReadableOrClosed | kWriteable,
+ };
+
+ // Callback type for I/O completion events.
+ // Arguments:
+ // fd - file descriptor that triggered the event
+ // what - combination of IOEvent flags indicating
+ // which event(s) occurred
+ // sender - reference to the EventTaskRunner that
+ // called the IoCompletionCallback
+ using IoCompletionCallback =
+ base::Callback<void(int fd, int16_t what, EventTaskRunner* sender)>;
+
+ // Adds a handler for the specified IO completion events on a file
+ // descriptor. The 'what' parameter is a combination of IOEvent flags.
+ // Only one callback is allowed per file descriptor; calling this function
+ // with an fd that has already been registered will replace the previous
+ // callback with the new one.
+ void AddIoCompletionTask(int fd,
+ int16_t what,
+ const IoCompletionCallback& task);
+
+ // Remove the callback associated with this fd and stop listening for
+ // events related to it.
+ void RemoveIoCompletionTask(int fd);
+
event_base* GetEventBase() const { return base_.get(); }
void Run();
@@ -33,6 +68,9 @@
static void FreeEvent(event* evnt);
void Process();
+ static void FdEventHandler(int fd, int16_t what, void* runner);
+ void ProcessFd(int fd, int16_t what);
+
using QueueItem = std::pair<std::pair<base::Time, size_t>, base::Closure>;
struct Greater {
@@ -47,10 +85,12 @@
std::vector<QueueItem>,
EventTaskRunner::Greater> queue_;
- std::unique_ptr<event_base, decltype(&event_base_free)> base_{
- event_base_new(), &event_base_free};
- std::unique_ptr<event, decltype(&FreeEvent)> task_event_{
- event_new(base_.get(), -1, EV_TIMEOUT, &EventHandler, this), &FreeEvent};
+ EventPtr<event_base> base_{event_base_new()};
+
+ EventPtr<event> task_event_{
+ event_new(base_.get(), -1, EV_TIMEOUT, &EventHandler, this)};
+
+ std::map<int, std::pair<EventPtr<event>, IoCompletionCallback>> fd_task_map_;
};
} // namespace examples
diff --git a/examples/provider/wifi_manager.cc b/examples/provider/wifi_manager.cc
index 6e216e4..ed6a9fd 100644
--- a/examples/provider/wifi_manager.cc
+++ b/examples/provider/wifi_manager.cc
@@ -42,7 +42,7 @@
WifiImpl::WifiImpl(provider::TaskRunner* task_runner, EventNetworkImpl* network)
: task_runner_{task_runner}, network_{network} {
- CHECK_EQ(0, getuid())
+ CHECK_EQ(0u, getuid())
<< "WiFi manager expects root access to control WiFi capabilities";
StopAccessPoint();
}