1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/load_balancing/lb_policy.h"
22 
23 #include "src/core/lib/iomgr/closure.h"
24 #include "src/core/lib/iomgr/error.h"
25 #include "src/core/lib/iomgr/exec_ctx.h"
26 #include "src/core/lib/iomgr/pollset_set.h"
27 
28 namespace grpc_core {
29 
30 DebugOnlyTraceFlag grpc_trace_lb_policy_refcount(false, "lb_policy_refcount");
31 
32 //
33 // LoadBalancingPolicy
34 //
35 
LoadBalancingPolicy(Args args,intptr_t initial_refcount)36 LoadBalancingPolicy::LoadBalancingPolicy(Args args, intptr_t initial_refcount)
37     : InternallyRefCounted(
38           GRPC_TRACE_FLAG_ENABLED(grpc_trace_lb_policy_refcount)
39               ? "LoadBalancingPolicy"
40               : nullptr,
41           initial_refcount),
42       work_serializer_(std::move(args.work_serializer)),
43       interested_parties_(grpc_pollset_set_create()),
44       channel_control_helper_(std::move(args.channel_control_helper)),
45       channel_args_(std::move(args.args)) {}
46 
~LoadBalancingPolicy()47 LoadBalancingPolicy::~LoadBalancingPolicy() {
48   grpc_pollset_set_destroy(interested_parties_);
49 }
50 
Orphan()51 void LoadBalancingPolicy::Orphan() {
52   ShutdownLocked();
53   Unref(DEBUG_LOCATION, "Orphan");
54 }
55 
56 //
57 // LoadBalancingPolicy::SubchannelPicker
58 //
59 
SubchannelPicker()60 LoadBalancingPolicy::SubchannelPicker::SubchannelPicker()
61     : DualRefCounted(GRPC_TRACE_FLAG_ENABLED(grpc_trace_lb_policy_refcount)
62                          ? "SubchannelPicker"
63                          : nullptr) {}
64 
65 //
66 // LoadBalancingPolicy::QueuePicker
67 //
68 
Pick(PickArgs)69 LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
70     PickArgs /*args*/) {
71   // We invoke the parent's ExitIdleLocked() via a closure instead
72   // of doing it directly here because ExitIdleLocked() may cause the
73   // policy's state to change and a new picker to be delivered to the
74   // channel.  If that new picker is delivered before ExitIdleLocked()
75   // returns, then by the time this function returns, the pick will already
76   // have been processed, and we'll be trying to re-process the same pick
77   // again, leading to a crash.
78   MutexLock lock(&mu_);
79   if (parent_ != nullptr) {
80     auto* parent = parent_.release();  // ref held by lambda.
81     ExecCtx::Run(DEBUG_LOCATION,
82                  GRPC_CLOSURE_CREATE(
83                      [](void* arg, grpc_error_handle /*error*/) {
84                        auto* parent = static_cast<LoadBalancingPolicy*>(arg);
85                        parent->work_serializer()->Run(
86                            [parent]() {
87                              parent->ExitIdleLocked();
88                              parent->Unref();
89                            },
90                            DEBUG_LOCATION);
91                      },
92                      parent, nullptr),
93                  absl::OkStatus());
94   }
95   return PickResult::Queue();
96 }
97 
98 }  // namespace grpc_core
99