]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2020 Red Hat | |
7 | * Author: Adam C. Emerson <aemerson@redhat.com> | |
8 | * | |
9 | * This is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License version 2.1, as published by the Free Software | |
12 | * Foundation. See file COPYING. | |
13 | * | |
14 | */ | |
15 | ||
16 | #ifndef CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H | |
17 | #define CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H | |
18 | ||
19 | #include <atomic> | |
20 | #include <condition_variable> | |
21 | #include <mutex> | |
22 | #include <optional> | |
23 | #include <type_traits> | |
24 | ||
25 | #include <boost/asio/async_result.hpp> | |
26 | ||
27 | #include <boost/system/error_code.hpp> | |
28 | #include <boost/system/system_error.hpp> | |
29 | ||
30 | #include "include/rados/librados.hpp" | |
31 | #include "librados/AioCompletionImpl.h" | |
32 | ||
33 | // Allow librados::AioCompletion to be provided as a completion | |
34 | // handler. This is only allowed with a signature of | |
35 | // (boost::system::error_code) or (). On completion the AioCompletion | |
36 | // is completed with the error_code converted to an int with | |
37 | // ceph::from_error_code. | |
38 | // | |
39 | // async_result::return_type is void. | |
40 | ||
41 | namespace ceph::async { | |
42 | ||
43 | namespace bs = boost::system; | |
44 | namespace lr = librados; | |
45 | ||
46 | namespace detail { | |
47 | ||
48 | struct librados_handler { | |
49 | lr::AioCompletionImpl* pc; | |
50 | ||
51 | explicit librados_handler(lr::AioCompletion* c) : pc(c->pc) { | |
52 | pc->get(); | |
53 | } | |
54 | ~librados_handler() { | |
55 | if (pc) { | |
56 | pc->put(); | |
57 | pc = nullptr; | |
58 | } | |
59 | } | |
60 | ||
61 | librados_handler(const librados_handler&) = delete; | |
62 | librados_handler& operator =(const librados_handler&) = delete; | |
63 | librados_handler(librados_handler&& rhs) { | |
64 | pc = rhs.pc; | |
65 | rhs.pc = nullptr; | |
66 | } | |
67 | ||
68 | void operator()(bs::error_code ec) { | |
69 | pc->lock.lock(); | |
70 | pc->rval = ceph::from_error_code(ec); | |
71 | pc->complete = true; | |
72 | pc->lock.unlock(); | |
73 | ||
74 | auto cb_complete = pc->callback_complete; | |
75 | auto cb_complete_arg = pc->callback_complete_arg; | |
76 | if (cb_complete) | |
77 | cb_complete(pc, cb_complete_arg); | |
78 | ||
79 | auto cb_safe = pc->callback_safe; | |
80 | auto cb_safe_arg = pc->callback_safe_arg; | |
81 | if (cb_safe) | |
82 | cb_safe(pc, cb_safe_arg); | |
83 | ||
84 | pc->lock.lock(); | |
85 | pc->callback_complete = NULL; | |
86 | pc->callback_safe = NULL; | |
87 | pc->cond.notify_all(); | |
88 | pc->put_unlock(); | |
89 | pc = nullptr; | |
90 | } | |
91 | ||
92 | void operator ()() { | |
93 | (*this)(bs::error_code{}); | |
94 | } | |
95 | }; | |
96 | } // namespace detail | |
97 | } // namespace ceph::async | |
98 | ||
99 | ||
100 | namespace boost::asio { | |
101 | template<typename ReturnType> | |
102 | class async_result<librados::AioCompletion*, ReturnType()> { | |
103 | public: | |
104 | using completion_handler_type = ceph::async::detail::librados_handler; | |
105 | explicit async_result(completion_handler_type&) {}; | |
106 | using return_type = void; | |
107 | void get() { | |
108 | return; | |
109 | } | |
110 | }; | |
111 | ||
112 | template<typename ReturnType> | |
113 | class async_result<librados::AioCompletion*, | |
114 | ReturnType(boost::system::error_code)> { | |
115 | public: | |
116 | using completion_handler_type = ceph::async::detail::librados_handler; | |
117 | explicit async_result(completion_handler_type&) {}; | |
118 | using return_type = void; | |
119 | void get() { | |
120 | return; | |
121 | } | |
122 | }; | |
123 | } | |
124 | ||
125 | #endif // !CEPH_COMMON_ASYNC_LIBRADOS_COMPLETION_H |