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 "src/core/load_balancing/lb_policy.h"
20
21 #include <grpc/support/port_platform.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 //
31 // LoadBalancingPolicy
32 //
33
LoadBalancingPolicy(Args args,intptr_t initial_refcount)34 LoadBalancingPolicy::LoadBalancingPolicy(Args args, intptr_t initial_refcount)
35 : InternallyRefCounted(GRPC_TRACE_FLAG_ENABLED(lb_policy_refcount)
36 ? "LoadBalancingPolicy"
37 : nullptr,
38 initial_refcount),
39 work_serializer_(std::move(args.work_serializer)),
40 interested_parties_(grpc_pollset_set_create()),
41 channel_control_helper_(std::move(args.channel_control_helper)),
42 channel_args_(std::move(args.args)) {}
43
~LoadBalancingPolicy()44 LoadBalancingPolicy::~LoadBalancingPolicy() {
45 grpc_pollset_set_destroy(interested_parties_);
46 }
47
Orphan()48 void LoadBalancingPolicy::Orphan() {
49 ShutdownLocked();
50 Unref(DEBUG_LOCATION, "Orphan");
51 }
52
53 //
54 // LoadBalancingPolicy::SubchannelPicker
55 //
56
SubchannelPicker()57 LoadBalancingPolicy::SubchannelPicker::SubchannelPicker()
58 : DualRefCounted(GRPC_TRACE_FLAG_ENABLED(lb_policy_refcount)
59 ? "SubchannelPicker"
60 : nullptr) {}
61
62 //
63 // LoadBalancingPolicy::QueuePicker
64 //
65
Pick(PickArgs)66 LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
67 PickArgs /*args*/) {
68 // We invoke the parent's ExitIdleLocked() via a closure instead
69 // of doing it directly here because ExitIdleLocked() may cause the
70 // policy's state to change and a new picker to be delivered to the
71 // channel. If that new picker is delivered before ExitIdleLocked()
72 // returns, then by the time this function returns, the pick will already
73 // have been processed, and we'll be trying to re-process the same pick
74 // again, leading to a crash.
75 MutexLock lock(&mu_);
76 if (parent_ != nullptr) {
77 auto* parent = parent_.release(); // ref held by lambda.
78 ExecCtx::Run(DEBUG_LOCATION,
79 GRPC_CLOSURE_CREATE(
80 [](void* arg, grpc_error_handle /*error*/) {
81 auto* parent = static_cast<LoadBalancingPolicy*>(arg);
82 parent->work_serializer()->Run(
83 [parent]() {
84 parent->ExitIdleLocked();
85 parent->Unref();
86 },
87 DEBUG_LOCATION);
88 },
89 parent, nullptr),
90 absl::OkStatus());
91 }
92 return PickResult::Queue();
93 }
94
95 } // namespace grpc_core
96