1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include <cstddef>
17 #include <cstdint>
18
19 #include "pw_rpc/channel.h"
20 #include "pw_rpc/internal/lock.h"
21
22 namespace pw::rpc {
23
24 class Service;
25
26 namespace internal {
27
28 class Endpoint;
29 class LockedCallContext;
30 class LockedEndpoint;
31 class Method;
32
33 // The Server creates a CallContext object to represent a method invocation. The
34 // CallContext is used to initialize a call object for the RPC.
35 class CallContext {
36 public:
CallContext(Endpoint & server,uint32_t channel_id,Service & service,const internal::Method & method,uint32_t call_id)37 constexpr CallContext(Endpoint& server,
38 uint32_t channel_id,
39 Service& service,
40 const internal::Method& method,
41 uint32_t call_id)
42 : server_(server),
43 channel_id_(channel_id),
44 service_(service),
45 method_(method),
46 call_id_(call_id) {}
47
48 // Claims that `rpc_lock()` is held, returning a wrapped context.
49 //
50 // This function should only be called in contexts in which it is clear that
51 // `rpc_lock()` is held. When calling this function from a constructor, the
52 // lock annotation will not result in errors, so care should be taken to
53 // ensure that `rpc_lock()` is held.
54 const LockedCallContext& ClaimLocked() const
55 PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock());
56
57 LockedCallContext& ClaimLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock());
58
server()59 constexpr Endpoint& server() const { return server_; }
60
channel_id()61 constexpr const uint32_t& channel_id() const { return channel_id_; }
62
service()63 constexpr Service& service() const { return service_; }
64
method()65 constexpr const internal::Method& method() const { return method_; }
66
call_id()67 constexpr const uint32_t& call_id() const { return call_id_; }
68
69 // For testing use only
set_channel_id(uint32_t channel_id)70 void set_channel_id(uint32_t channel_id) { channel_id_ = channel_id; }
71
72 private:
73 Endpoint& server_;
74 uint32_t channel_id_;
75 Service& service_;
76 const internal::Method& method_;
77 uint32_t call_id_;
78 };
79
80 // A `CallContext` indicating that `rpc_lock()` is held.
81 //
82 // This is used as a constructor argument to supplement
83 // `PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock())`. Current compilers do not enforce
84 // lock annotations on constructors; no warnings or errors are produced when
85 // calling an annotated constructor without holding `rpc_lock()`.
86 class LockedCallContext : public CallContext {
87 public:
88 friend class CallContext;
89 // No public constructor: this is created only via the `ClaimLocked` method on
90 // `CallContext`.
91 constexpr LockedCallContext() = delete;
92 };
93
ClaimLocked()94 inline const LockedCallContext& CallContext::ClaimLocked() const {
95 return *static_cast<const LockedCallContext*>(this);
96 }
97
ClaimLocked()98 inline LockedCallContext& CallContext::ClaimLocked() {
99 return *static_cast<LockedCallContext*>(this);
100 }
101
102 } // namespace internal
103 } // namespace pw::rpc
104