Line data Source code
1 : #include "fd_racesan_async.h" 2 : #include "../../util/fd_util.h" 3 : #include <errno.h> 4 : 5 : /* fd_racesan_async_yield context switches out to the caller of the 6 : fd_racesan_async_step function. */ 7 : 8 : static void 9 0 : fd_racesan_async_yield( fd_racesan_async_t * async ) { 10 0 : if( FD_UNLIKELY( 0!=swapcontext( &async->ctx, FD_VOLATILE_CONST( async->caller ) ) ) ) { 11 0 : FD_LOG_ERR(( "failed to yield from async fn: swapcontext failed (%i-%s)", errno, fd_io_strerror( errno ) )); 12 0 : } 13 0 : } 14 : 15 : /* fd_racesan_async_hook is called whenever the target reaches a racesan 16 : hook. The racesan_async logic here context-switches out back to the 17 : caller of step. */ 18 : 19 : static void 20 : fd_racesan_async_hook( void * ctx, 21 0 : ulong name_hash ) { 22 0 : fd_racesan_async_t * async = ctx; 23 0 : async->name_hash = name_hash; 24 0 : fd_racesan_exit(); 25 0 : fd_racesan_async_yield( async ); 26 0 : } 27 : 28 : /* fd_racesan_async_target is a long-lived / async function with its own 29 : stack. */ 30 : 31 : static void 32 0 : fd_racesan_async_target( fd_racesan_async_t * async ) { 33 0 : fd_racesan_t racesan[1]; 34 0 : fd_racesan_new( racesan, async ); 35 0 : fd_racesan_inject_default( racesan, fd_racesan_async_hook ); 36 0 : fd_racesan_enter( racesan ); 37 0 : async->fn( async->fn_ctx ); 38 0 : fd_racesan_delete( racesan ); 39 : 40 0 : async->done = 1; 41 0 : fd_racesan_async_yield( async ); 42 0 : } 43 : 44 : fd_racesan_async_t * 45 : fd_racesan_async_new( fd_racesan_async_t * async, 46 : fd_racesan_async_fn_t * async_fn, 47 0 : void * ctx ) { 48 0 : memset( async, 0, sizeof(fd_racesan_async_t) ); 49 : 50 0 : async->fn_ctx = ctx; 51 0 : async->fn = async_fn; 52 : 53 0 : if( FD_UNLIKELY( 0!=getcontext( &async->ctx ) ) ) { 54 0 : FD_LOG_ERR(( "getcontext failed" )); 55 0 : } 56 0 : async->ctx.uc_stack.ss_sp = async->stack; 57 0 : async->ctx.uc_stack.ss_size = sizeof(async->stack); 58 0 : makecontext( &async->ctx, (void (*)( void ))fd_racesan_async_target, 1, async ); 59 : 60 0 : return async; 61 0 : } 62 : 63 : void * 64 0 : fd_racesan_async_delete( fd_racesan_async_t * async ) { 65 0 : (void)async; 66 0 : return NULL; 67 0 : } 68 : 69 : int 70 0 : fd_racesan_async_step( fd_racesan_async_t * async ) { 71 0 : if( FD_UNLIKELY( async->done ) ) return 0; 72 : 73 0 : ucontext_t caller; 74 0 : async->caller = &caller; 75 0 : if( FD_UNLIKELY( 0!=swapcontext( &caller, &async->ctx ) ) ) { 76 0 : FD_LOG_ERR(( "failed to step into async fn: swapcontext failed (%i-%s)", errno, fd_io_strerror( errno ) )); 77 0 : } 78 : /* fd_racesan_async_yield jumps to here */ 79 0 : return 1; 80 0 : } 81 : 82 : int 83 : fd_racesan_async_hook_name_eq( fd_racesan_async_t * async, 84 0 : char const * hook_name ) { 85 0 : ulong len = strlen( hook_name ); 86 0 : ulong hash = fd_racesan_strhash( hook_name, len ); 87 0 : return async->name_hash==hash; 88 0 : } 89 : 90 : void 91 0 : fd_racesan_async_reset( fd_racesan_async_t * async ) { 92 0 : makecontext( &async->ctx, (void (*)( void ))fd_racesan_async_target, 1, async ); 93 0 : async->done = 0; 94 0 : }