@ -14,6 +14,7 @@
# include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h"
# include <inttypes.h>
# include <stdlib.h>
# include <algorithm>
@ -30,6 +31,7 @@
# include <grpc/support/log.h>
# include <grpc/support/time.h>
# include "src/core/lib/debug/trace.h"
# include "src/core/lib/event_engine/tcp_socket_utils.h"
# include "src/core/lib/gpr/useful.h"
# include "src/core/lib/gprpp/time.h"
@ -40,6 +42,9 @@
extern gpr_timespec ( * gpr_now_impl ) ( gpr_clock_type clock_type ) ;
static grpc_core : : TraceFlag trace_writes ( false , " fuzzing_ee_writes " ) ;
static grpc_core : : TraceFlag trace_timers ( false , " fuzzing_ee_timers " ) ;
using namespace std : : chrono_literals ;
namespace grpc_event_engine {
@ -133,10 +138,13 @@ gpr_timespec FuzzingEventEngine::NowAsTimespec(gpr_clock_type clock_type) {
}
void FuzzingEventEngine : : Tick ( Duration max_time ) {
bool incremented_time = false ;
while ( true ) {
std : : vector < absl : : AnyInvocable < void ( ) > > to_run ;
{
grpc_core : : MutexLock lock ( & * mu_ ) ;
grpc_core : : MutexLock now_lock ( & * now_mu_ ) ;
if ( ! incremented_time ) {
Duration incr = max_time ;
// TODO(ctiller): look at tasks_by_time_ and jump forward (once iomgr
// timers are gone)
@ -155,6 +163,8 @@ void FuzzingEventEngine::Tick(Duration max_time) {
now_ + = incr ;
GPR_ASSERT ( now_ . time_since_epoch ( ) . count ( ) > = 0 ) ;
+ + current_tick_ ;
incremented_time = true ;
}
// Find newly expired timers.
while ( ! tasks_by_time_ . empty ( ) & & tasks_by_time_ . begin ( ) - > first < = now_ ) {
auto & task = * tasks_by_time_ . begin ( ) - > second ;
@ -165,10 +175,12 @@ void FuzzingEventEngine::Tick(Duration max_time) {
tasks_by_time_ . erase ( tasks_by_time_ . begin ( ) ) ;
}
}
if ( to_run . empty ( ) ) return ;
for ( auto & closure : to_run ) {
closure ( ) ;
}
}
}
void FuzzingEventEngine : : TickUntilIdle ( ) {
while ( true ) {
@ -299,6 +311,10 @@ bool FuzzingEventEngine::EndpointMiddle::Write(SliceBuffer* data, int index) {
// If the write_len is zero, we still need to write something, so we write one
// byte.
if ( write_len = = 0 ) write_len = 1 ;
if ( trace_writes . enabled ( ) ) {
gpr_log ( GPR_INFO , " WRITE[%p:%d]: % " PRIdPTR " bytes " , this , index ,
write_len ) ;
}
// Expand the pending buffer.
size_t prev_len = pending [ index ] . size ( ) ;
pending [ index ] . resize ( prev_len + write_len ) ;
@ -526,15 +542,31 @@ EventEngine::TaskHandle FuzzingEventEngine::RunAfterLocked(
RunType run_type , Duration when , absl : : AnyInvocable < void ( ) > closure ) {
const intptr_t id = next_task_id_ ;
+ + next_task_id_ ;
Duration delay_taken = Duration : : zero ( ) ;
if ( run_type ! = RunType : : kExact & & ! task_delays_ . empty ( ) ) {
when + = grpc_core : : Clamp ( task_delays_ . front ( ) , Duration : : zero ( ) ,
delay_taken = grpc_core : : Clamp ( task_delays_ . front ( ) , Duration : : zero ( ) ,
max_delay_ [ static_cast < int > ( run_type ) ] ) ;
when + = delay_taken ;
task_delays_ . pop ( ) ;
}
auto task = std : : make_shared < Task > ( id , std : : move ( closure ) ) ;
tasks_by_id_ . emplace ( id , task ) ;
Time final_time ;
Time now ;
{
grpc_core : : MutexLock lock ( & * now_mu_ ) ;
tasks_by_time_ . emplace ( now_ + when , std : : move ( task ) ) ;
final_time = now_ + when ;
now = now_ ;
tasks_by_time_ . emplace ( final_time , std : : move ( task ) ) ;
}
if ( trace_timers . enabled ( ) ) {
gpr_log ( GPR_INFO ,
" Schedule timer % " PRIx64 " @ % " PRIu64 " (now=% " PRIu64
" ; delay=% " PRIu64 " ; fuzzing_added=% " PRIu64 " ; type=%d) " ,
id , static_cast < uint64_t > ( final_time . time_since_epoch ( ) . count ( ) ) ,
now . time_since_epoch ( ) . count ( ) , when . count ( ) , delay_taken . count ( ) ,
static_cast < int > ( run_type ) ) ;
}
return TaskHandle { id , kTaskHandleSalt } ;
}
@ -549,6 +581,9 @@ bool FuzzingEventEngine::Cancel(TaskHandle handle) {
if ( it - > second - > closure = = nullptr ) {
return false ;
}
if ( trace_timers . enabled ( ) ) {
gpr_log ( GPR_INFO , " Cancel timer % " PRIx64 , id ) ;
}
it - > second - > closure = nullptr ;
return true ;
}