Line data Source code
1 : #ifndef HEADER_fd_src_util_fibre_fd_fibre_h 2 : #define HEADER_fd_src_util_fibre_fd_fibre_h 3 : 4 : #include <ucontext.h> 5 : 6 : #include "../fd_util.h" 7 : 8 198 : #define FD_FIBRE_ALIGN 128UL 9 : 10 : /* definition of the function to be called when starting a new fibre */ 11 : typedef void (*fd_fibre_fn_t)( void * ); 12 : 13 : struct fd_fibre { 14 : ucontext_t ctx; 15 : void * stack; 16 : size_t stack_sz; 17 : fd_fibre_fn_t fn; 18 : void * arg; 19 : int done; 20 : 21 : /* schedule parameters */ 22 : long sched_time; 23 : struct fd_fibre * next; 24 : int sentinel; 25 : }; 26 : typedef struct fd_fibre fd_fibre_t; 27 : 28 : 29 : struct fd_fibre_pipe { 30 : ulong cap; /* capacity */ 31 : ulong head; /* head index */ 32 : ulong tail; /* tail index */ 33 : 34 : fd_fibre_t * writer; /* fibre that's currently waiting for a write, if any */ 35 : fd_fibre_t * reader; /* fibre that's currently waiting for a read, if any */ 36 : 37 : ulong * entries; 38 : }; 39 : typedef struct fd_fibre_pipe fd_fibre_pipe_t; 40 : 41 : 42 : /* TODO make thread local */ 43 : extern fd_fibre_t * fd_fibre_current; 44 : 45 : 46 : FD_PROTOTYPES_BEGIN 47 : 48 : 49 : /* footprint and alignment required for fd_fibre_init */ 50 : ulong fd_fibre_init_footprint( void ); 51 : ulong fd_fibre_init_align( void ); 52 : 53 : 54 : /* initialize main fibre 55 : 56 : should be called before making any other fibre calls 57 : 58 : creates a new fibre from the current thread, and returns it 59 : caller should keep the fibre for later freeing 60 : 61 : probably shouldn't run this twice on the same thread 62 : 63 : mem is the memory allocated for this object. Use fd_fibre_init{_align,_footprint} to 64 : obtain the appropriate size and alignment requirements */ 65 : 66 : fd_fibre_t * 67 : fd_fibre_init( void * ); 68 : 69 : 70 : /* footprint and alignment required for fd_fibre_start */ 71 : ulong fd_fibre_start_footprint( ulong stack_size ); 72 : ulong fd_fibre_start_align( void ); 73 : 74 : 75 : /* Start a fibre 76 : 77 : This uses get/setcontext to create a new fibre 78 : 79 : fd_fibre_init must be called once before calling this 80 : 81 : The current fibre will continue running, and the other will be 82 : inactive, and ready to switch to 83 : 84 : This fibre may be started on this or another thread 85 : 86 : mem is the memory used for the fibre. Use fd_fibre_start{_align,_footprint} 87 : to determine the size and alignment required for the memory 88 : 89 : stack_sz is the size of the stack required 90 : 91 : fn is the function entry point to call in the new fibre 92 : arg is the value to pass to function fn */ 93 : fd_fibre_t * 94 : fd_fibre_start( void * mem, ulong stack_sz, fd_fibre_fn_t fn, void * arg ); 95 : 96 : 97 : /* Free a fibre 98 : 99 : This frees up the resources of a fibre 100 : 101 : Only call on a fibre that is not currently running */ 102 : void 103 : fd_fibre_free( fd_fibre_t * fibre ); 104 : 105 : 106 : /* switch execution to a fibre 107 : 108 : Switches execution to "swap_to" 109 : The global variable `fd_fibre_current` is updated with the state 110 : of the currently running fibre before switching */ 111 : void 112 : fd_fibre_swap( fd_fibre_t * swap_to ); 113 : 114 : 115 : /* fd_fibre_abort is called when a fatal error occurs */ 116 : #ifndef fd_fibre_abort 117 0 : # define fd_fibre_abort(...) abort( __VA_ARGS__ ) 118 : #endif 119 : 120 : 121 : /* set a clock for scheduler */ 122 : void 123 : fd_fibre_set_clock( long (*clock)(void) ); 124 : 125 : 126 : /* yield current fibre 127 : allows other fibres to execute */ 128 : void 129 : fd_fibre_yield( void ); 130 : 131 : 132 : /* stops running currently executing fibre for a period of time */ 133 : void 134 : fd_fibre_wait( long wait_ns ); 135 : 136 : 137 : /* stops running currently executing fibre until a particular 138 : time */ 139 : void 140 : fd_fibre_wait_until( long resume_time_ns ); 141 : 142 : 143 : /* wakes another fibre */ 144 : void 145 : fd_fibre_wake( fd_fibre_t * fibre ); 146 : 147 : 148 : /* add a fibre to the schedule */ 149 : void 150 : fd_fibre_schedule( fd_fibre_t * fibre ); 151 : 152 : 153 : /* run the current schedule 154 : 155 : returns 156 : the time of the next ready fibre 157 : -1 if there are no fibres in the schedule */ 158 : long 159 : fd_fibre_schedule_run( void ); 160 : 161 : 162 : /* fibre data structures */ 163 : 164 : /* pipe 165 : 166 : send data from one fibre to another 167 : wakes receiving fibre on write */ 168 : 169 : /* pipe footprint and alignment */ 170 : 171 : ulong 172 : fd_fibre_pipe_align( void ); 173 : 174 : ulong 175 : fd_fibre_pipe_footprint( ulong entries ); 176 : 177 : 178 : /* create a new pipe */ 179 : 180 : fd_fibre_pipe_t * 181 : fd_fibre_pipe_new( void * mem, ulong entries ); 182 : 183 : 184 : /* write a value into the pipe 185 : 186 : can block if there isn't any free space 187 : timeout allows the blocking to terminate after a period of time 188 : 189 : pipe the pipe to write to 190 : value the value to write 191 : timeout the amount of time to wait for the write to complete 192 : 193 : returns 0 successful 194 : 1 there was no space for the write operation */ 195 : 196 : int 197 : fd_fibre_pipe_write( fd_fibre_pipe_t * pipe, ulong value, long timeout ); 198 : 199 : 200 : /* read a value from the pipe 201 : 202 : read can block if there isn't any data in the pipe 203 : 204 : timeout allows the read to terminate without a result after 205 : a period of time 206 : 207 : pipe the pipe to write to 208 : value a pointer to the ulong to receive the value 209 : timeout number of nanoseconds to wait for a value 210 : 211 : returns 0 successfully read a value from the pipe 212 : 1 timed out without receiving data */ 213 : int 214 : fd_fibre_pipe_read( fd_fibre_pipe_t * pipe, ulong *value, long timeout ); 215 : 216 : 217 : FD_PROTOTYPES_END 218 : 219 : 220 : #endif /* HEADER_fd_src_util_fibre_fd_fibre_h */