fuzzing_event_engine.cc
Go to the documentation of this file.
1 // Copyright 2022 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <inttypes.h>
18 
19 #include <chrono>
20 
21 #include <grpc/grpc.h>
22 
24 #include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h"
25 
26 extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
27 
28 namespace grpc_event_engine {
29 namespace experimental {
30 
31 namespace {
32 const intptr_t kTaskHandleSalt = 12345;
33 FuzzingEventEngine* g_fuzzing_event_engine = nullptr;
34 } // namespace
35 
37  Options options, const fuzzing_event_engine::Actions& actions)
38  : final_tick_length_(options.final_tick_length) {
39  GPR_ASSERT(g_fuzzing_event_engine == nullptr);
40  g_fuzzing_event_engine = this;
41 
43 
44  tick_increments_.clear();
45  task_delays_.clear();
46  tasks_by_id_.clear();
47  tasks_by_time_.clear();
48  next_task_id_ = 1;
49  current_tick_ = 0;
50  // Start at 5 seconds after the epoch.
51  // This needs to be more than 1, and otherwise is kind of arbitrary.
52  // The grpc_core::Timer code special cases the zero second time period after
53  // epoch to allow for some fancy atomic stuff.
54  now_ = Time() + std::chrono::seconds(5);
55 
56  // Whilst a fuzzing event engine is active we override grpc's now function.
58 
59  auto update_delay = [](std::map<intptr_t, Duration>* map,
60  fuzzing_event_engine::Delay delay, Duration max) {
61  auto& value = (*map)[delay.id()];
62  if (delay.delay_us() > static_cast<uint64_t>(max.count() / GPR_NS_PER_US)) {
63  value = max;
64  return;
65  }
66  Duration add = std::chrono::microseconds(delay.delay_us());
67  if (add >= max - value) {
68  value = max;
69  } else {
70  value += add;
71  }
72  };
73 
74  for (const auto& delay : actions.tick_lengths()) {
75  update_delay(&tick_increments_, delay, std::chrono::hours(24));
76  }
77  for (const auto& delay : actions.run_delay()) {
78  update_delay(&task_delays_, delay, std::chrono::seconds(30));
79  }
80 }
81 
84  tick_increments_.clear();
85 }
86 
88  GPR_ASSERT(g_fuzzing_event_engine == this);
89  g_fuzzing_event_engine = nullptr;
90 }
91 
93  // TODO(ctiller): add a facility to track realtime and monotonic clocks
94  // separately to simulate divergence.
95  GPR_ASSERT(clock_type != GPR_TIMESPAN);
96  const Duration d = now_.time_since_epoch();
97  auto secs = std::chrono::duration_cast<std::chrono::seconds>(d);
98  return {secs.count(), static_cast<int32_t>((d - secs).count()), clock_type};
99 }
100 
102  GPR_ASSERT(g_fuzzing_event_engine != nullptr);
103  grpc_core::MutexLock lock(&g_fuzzing_event_engine->mu_);
104  return g_fuzzing_event_engine->NowAsTimespec(clock_type);
105 }
106 
108  std::vector<std::function<void()>> to_run;
109  {
110  grpc_core::MutexLock lock(&mu_);
111  // Increment time
112  auto tick_it = tick_increments_.find(current_tick_);
113  if (tick_it != tick_increments_.end()) {
114  now_ += tick_it->second;
115  GPR_ASSERT(now_.time_since_epoch().count() >= 0);
116  tick_increments_.erase(tick_it);
117  } else if (tick_increments_.empty()) {
118  now_ += final_tick_length_;
119  GPR_ASSERT(now_.time_since_epoch().count() >= 0);
120  }
121  ++current_tick_;
122  // Find newly expired timers.
123  while (!tasks_by_time_.empty() && tasks_by_time_.begin()->first <= now_) {
124  tasks_by_id_.erase(tasks_by_time_.begin()->second->id);
125  to_run.push_back(std::move(tasks_by_time_.begin()->second->closure));
126  tasks_by_time_.erase(tasks_by_time_.begin());
127  }
128  }
129  for (auto& closure : to_run) {
130  closure();
131  }
132 }
133 
135  grpc_core::MutexLock lock(&mu_);
136  return now_;
137 }
138 
142  const EndpointConfig&,
143  std::unique_ptr<MemoryAllocatorFactory>) {
144  abort();
145 }
146 
150  abort();
151 }
152 
154 
156 
157 std::unique_ptr<EventEngine::DNSResolver> FuzzingEventEngine::GetDNSResolver(
158  const DNSResolver::ResolverOptions&) {
159  abort();
160 }
161 
163  RunAfter(Duration::zero(), closure);
164 }
165 
167  RunAfter(Duration::zero(), closure);
168 }
169 
171  Closure* closure) {
172  return RunAfter(when, [closure]() { closure->Run(); });
173 }
174 
176  Duration when, std::function<void()> closure) {
177  grpc_core::MutexLock lock(&mu_);
178  const intptr_t id = next_task_id_;
179  ++next_task_id_;
180  const auto delay_it = task_delays_.find(id);
181  // Under fuzzer configuration control, maybe make the task run later.
182  if (delay_it != task_delays_.end()) {
183  when += delay_it->second;
184  task_delays_.erase(delay_it);
185  }
186  auto task = std::make_shared<Task>(id, std::move(closure));
187  tasks_by_id_.emplace(id, task);
188  tasks_by_time_.emplace(now_ + when, std::move(task));
189  return TaskHandle{id, kTaskHandleSalt};
190 }
191 
193  grpc_core::MutexLock lock(&mu_);
194  GPR_ASSERT(handle.keys[1] == kTaskHandleSalt);
195  const intptr_t id = handle.keys[0];
196  auto it = tasks_by_id_.find(id);
197  if (it == tasks_by_id_.end()) {
198  return false;
199  }
200  if (it->second == nullptr) {
201  return false;
202  }
203  it->second = nullptr;
204  return true;
205 }
206 
207 } // namespace experimental
208 } // namespace grpc_event_engine
GPR_TIMESPAN
@ GPR_TIMESPAN
Definition: gpr_types.h:45
absl::time_internal::cctz::seconds
std::chrono::duration< std::int_fast64_t > seconds
Definition: abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h:40
regen-readme.it
it
Definition: regen-readme.py:15
grpc_event_engine::experimental::FuzzingEventEngine::CancelConnect
bool CancelConnect(ConnectionHandle handle) override
Definition: fuzzing_event_engine.cc:153
grpc_event_engine::experimental::FuzzingEventEngine::Cancel
bool Cancel(TaskHandle handle) override
Definition: fuzzing_event_engine.cc:192
grpc_event_engine::experimental::EventEngine::Listener::AcceptCallback
std::function< void(std::unique_ptr< Endpoint >, MemoryAllocator memory_allocator)> AcceptCallback
Called when the listener has accepted a new client connection.
Definition: event_engine.h:232
grpc_event_engine::experimental::MemoryAllocator
Definition: memory_allocator.h:35
grpc_event_engine::experimental::FuzzingEventEngine::GlobalNowImpl
static gpr_timespec GlobalNowImpl(gpr_clock_type clock_type) ABSL_LOCKS_EXCLUDED(mu_)
Definition: fuzzing_event_engine.cc:101
grpc_core::TestOnlySetProcessEpoch
void TestOnlySetProcessEpoch(gpr_timespec epoch)
Definition: src/core/lib/gprpp/time.cc:201
grpc_core::MutexLock
Definition: src/core/lib/gprpp/sync.h:88
gpr_now_impl
gpr_timespec(* gpr_now_impl)(gpr_clock_type clock_type)
options
double_dict options[]
Definition: capstone_test.c:55
grpc_event_engine::experimental::EventEngine::TaskHandle
Definition: event_engine.h:102
map
zval * map
Definition: php/ext/google/protobuf/encode_decode.c:480
grpc_event_engine::experimental::EndpointConfig
Definition: endpoint_config.h:31
grpc_event_engine::experimental::EventEngine::ResolvedAddress
Definition: event_engine.h:118
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
fuzzing_event_engine.h
grpc_event_engine::experimental::FuzzingEventEngine::Time
std::chrono::time_point< FuzzingEventEngine, Duration > Time
Definition: fuzzing_event_engine.h:72
closure
grpc_closure closure
Definition: src/core/lib/surface/server.cc:466
grpc.h
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
grpc_event_engine::experimental::EventEngine::ConnectionHandle
Definition: event_engine.h:108
grpc_event_engine::experimental::FuzzingEventEngine::CreateListener
absl::StatusOr< std::unique_ptr< Listener > > CreateListener(Listener::AcceptCallback on_accept, std::function< void(absl::Status)> on_shutdown, const EndpointConfig &config, std::unique_ptr< MemoryAllocatorFactory > memory_allocator_factory) override
Definition: fuzzing_event_engine.cc:140
time.h
GPR_CLOCK_MONOTONIC
@ GPR_CLOCK_MONOTONIC
Definition: gpr_types.h:36
intptr_t
_W64 signed int intptr_t
Definition: stdint-msvc2008.h:118
GPR_NS_PER_US
#define GPR_NS_PER_US
Definition: include/grpc/support/time.h:43
grpc_event_engine::experimental::FuzzingEventEngine::~FuzzingEventEngine
~FuzzingEventEngine() override
Definition: fuzzing_event_engine.cc:87
add
static void add(const char *beg, const char *end, char ***ss, size_t *ns)
Definition: debug/trace.cc:96
value
const char * value
Definition: hpack_parser_table.cc:165
grpc_event_engine::experimental::EventEngine::OnConnectCallback
std::function< void(absl::StatusOr< std::unique_ptr< Endpoint > >)> OnConnectCallback
Definition: event_engine.h:224
grpc_event_engine::experimental::EventEngine::Closure
Definition: event_engine.h:87
grpc_event_engine::experimental::FuzzingEventEngine::final_tick_length_
const Duration final_tick_length_
Definition: fuzzing_event_engine.h:89
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
gpr_timespec
struct gpr_timespec gpr_timespec
grpc_event_engine::experimental::FuzzingEventEngine::Options
Definition: fuzzing_event_engine.h:34
absl::Status
Definition: third_party/abseil-cpp/absl/status/status.h:424
grpc_event_engine::experimental::FuzzingEventEngine::IsWorkerThread
bool IsWorkerThread() override
Definition: fuzzing_event_engine.cc:155
grpc_event_engine::experimental::FuzzingEventEngine::NowAsTimespec
gpr_timespec NowAsTimespec(gpr_clock_type clock_type) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_)
Definition: fuzzing_event_engine.cc:92
grpc_event_engine::experimental::FuzzingEventEngine::GetDNSResolver
std::unique_ptr< DNSResolver > GetDNSResolver(const DNSResolver::ResolverOptions &options) override
Definition: fuzzing_event_engine.cc:157
grpc_event_engine
Definition: endpoint_config.h:24
grpc_event_engine::experimental::FuzzingEventEngine::Tick
void Tick()
Definition: fuzzing_event_engine.cc:107
closure
Definition: proxy.cc:59
handle
static csh handle
Definition: test_arm_regression.c:16
Duration
Definition: bloaty/third_party/protobuf/src/google/protobuf/duration.pb.h:69
absl::StatusOr
Definition: abseil-cpp/absl/status/statusor.h:187
gpr_timespec
Definition: gpr_types.h:50
grpc_event_engine::experimental::FuzzingEventEngine::Connect
ConnectionHandle Connect(OnConnectCallback on_connect, const ResolvedAddress &addr, const EndpointConfig &args, MemoryAllocator memory_allocator, Duration timeout) override
Definition: fuzzing_event_engine.cc:147
function
std::function< bool(GrpcTool *, int, const char **, const CliCredentials &, GrpcToolOutputCallback)> function
Definition: grpc_tool.cc:250
grpc_event_engine::experimental::FuzzingEventEngine::mu_
grpc_core::Mutex mu_
Definition: fuzzing_event_engine.h:91
grpc_event_engine::experimental::FuzzingEventEngine::Run
void Run(Closure *closure) override
Definition: fuzzing_event_engine.cc:162
grpc_event_engine::experimental::FuzzingEventEngine::FuzzingDone
void FuzzingDone()
Definition: fuzzing_event_engine.cc:82
int32_t
signed int int32_t
Definition: stdint-msvc2008.h:77
grpc_event_engine::experimental::FuzzingEventEngine::Now
Time Now() ABSL_LOCKS_EXCLUDED(mu_)
Definition: fuzzing_event_engine.cc:134
grpc_event_engine::experimental::FuzzingEventEngine::FuzzingEventEngine
FuzzingEventEngine(Options options, const fuzzing_event_engine::Actions &actions)
Definition: fuzzing_event_engine.cc:36
id
uint32_t id
Definition: flow_control_fuzzer.cc:70
gpr_clock_type
gpr_clock_type
Definition: gpr_types.h:34
grpc_event_engine::experimental::FuzzingEventEngine::RunAfter
TaskHandle RunAfter(Duration when, Closure *closure) override
Definition: fuzzing_event_engine.cc:170


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:59:23