blob: ede18152017f387b7178f0a39fe5887736fe3bc5 [file] [log] [blame]
// Copyright (c) 2014 The Chromium OS 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 SHILL_DBUS_ASYNC_CALL_HELPER_H_
#define SHILL_DBUS_ASYNC_CALL_HELPER_H_
#include "shill/logging.h"
#include <memory>
#include <string>
#include <base/macros.h> // for ignore_result
#include <dbus-c++/error.h>
#include "shill/error.h"
using std::string;
namespace shill {
namespace Logging {
static auto kModuleLogScope = ScopeLogger::kDBus;
static string ObjectID(const DBus::Path* p) { return *p;}
}
// The dbus-c++ async call mechanism has a funny way of handling the
// callback parameter. In particular, the caller is responsible for
// cleaning up the callback. (This is unlike the low-level D-Bus
// library, which accepts a function pointer for the cleanup
// function.)
//
// In cases where the call completes asynchronously, we delete the
// callback in the return-handling code. However, if the call
// generates a synchronous error, we need to delete the callback
// immediately.
//
// This template simply factors out that pattern, so that we don't
// need to repeat the code in every async stub.
template<
typename TraceMsgT, typename ProxyT, typename CallT,
typename CallbackT, typename... ArgTypes>
void BeginAsyncDBusCall(const TraceMsgT& trace_msg,
ProxyT& proxy, // NOLINT(runtime/references)
const CallT& call, const CallbackT& callback,
Error* error,
void(*error_converter)(const DBus::Error&, Error*),
int timeout, ArgTypes... call_args) {
SLOG(&proxy.path(), 2) << trace_msg << " [timeout=" << timeout << "]";
std::unique_ptr<CallbackT> cb(new CallbackT(callback));
try {
(proxy.*call)(call_args..., cb.get(), timeout);
// We've successfully passed ownership of |cb| to |proxy|, so we
// must release() ownership. (Otherwise, |cb| will be deleted on
// return from this function.)
//
// Since we have no further need to reference the CallbackT in
// this scope, we ignore the return value of release(). Ignoring
// the return value is normally an error, because that means
// you're leaking the object. However, it's fine here, because
// |proxy| now owns |cb|.
ignore_result(cb.release());
} catch (const DBus::Error& e) {
if (error)
error_converter(e, error);
}
}
} // namespace shill
#endif // SHILL_DBUS_ASYNC_CALL_HELPER_H_