Line data Source code
1 : #include "fd_forks.h"
2 :
3 : #include "../../flamenco/runtime/context/fd_exec_slot_ctx.h"
4 : #include "../../flamenco/runtime/fd_acc_mgr.h"
5 : #include "../../flamenco/runtime/fd_borrowed_account.h"
6 : #include "../../flamenco/runtime/fd_runtime.h"
7 : #include "../../flamenco/runtime/program/fd_program_util.h"
8 : #include "../../flamenco/runtime/program/fd_vote_program.h"
9 :
10 : void *
11 0 : fd_forks_new( void * shmem, ulong max, ulong seed ) {
12 :
13 0 : if( FD_UNLIKELY( !shmem ) ) {
14 0 : FD_LOG_WARNING( ( "NULL mem" ) );
15 0 : return NULL;
16 0 : }
17 :
18 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_forks_align() ) ) ) {
19 0 : FD_LOG_WARNING( ( "misaligned mem" ) );
20 0 : return NULL;
21 0 : }
22 :
23 0 : ulong footprint = fd_forks_footprint( max );
24 0 : if( FD_UNLIKELY( !footprint ) ) {
25 0 : FD_LOG_WARNING( ( "bad mem" ) );
26 0 : return NULL;
27 0 : }
28 :
29 0 : fd_memset( shmem, 0, footprint );
30 0 : ulong laddr = (ulong)shmem;
31 :
32 0 : laddr = fd_ulong_align_up( laddr, alignof( fd_forks_t ) );
33 0 : laddr += sizeof( fd_forks_t );
34 :
35 0 : laddr = fd_ulong_align_up( laddr, fd_fork_pool_align() );
36 0 : fd_fork_pool_new( (void *)laddr, max );
37 0 : laddr += fd_fork_pool_footprint( max );
38 :
39 0 : laddr = fd_ulong_align_up( laddr, fd_fork_frontier_align() );
40 0 : fd_fork_frontier_new( (void *)laddr, max, seed );
41 0 : laddr += fd_fork_frontier_footprint( max );
42 :
43 0 : return shmem;
44 0 : }
45 :
46 : fd_forks_t *
47 0 : fd_forks_join( void * shforks ) {
48 :
49 0 : if( FD_UNLIKELY( !shforks ) ) {
50 0 : FD_LOG_WARNING( ( "NULL forks" ) );
51 0 : return NULL;
52 0 : }
53 :
54 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shforks, fd_forks_align() ) ) ) {
55 0 : FD_LOG_WARNING( ( "misaligned forks" ) );
56 0 : return NULL;
57 0 : }
58 :
59 0 : ulong laddr = (ulong)shforks;
60 0 : fd_forks_t * forks = (void *)laddr;
61 :
62 0 : laddr = fd_ulong_align_up( laddr, alignof( fd_forks_t ) );
63 0 : laddr += sizeof( fd_forks_t );
64 :
65 0 : laddr = fd_ulong_align_up( laddr, fd_fork_pool_align() );
66 0 : forks->pool = fd_fork_pool_join( (void *)laddr );
67 0 : ulong max = fd_fork_pool_max( forks->pool );
68 0 : laddr += fd_fork_pool_footprint( max );
69 :
70 0 : laddr = fd_ulong_align_up( laddr, fd_fork_frontier_align() );
71 0 : forks->frontier = fd_fork_frontier_join( (void *)laddr );
72 0 : laddr += fd_fork_frontier_footprint( max );
73 :
74 0 : return (fd_forks_t *)shforks;
75 0 : }
76 :
77 : void *
78 0 : fd_forks_leave( fd_forks_t const * forks ) {
79 :
80 0 : if( FD_UNLIKELY( !forks ) ) {
81 0 : FD_LOG_WARNING( ( "NULL forks" ) );
82 0 : return NULL;
83 0 : }
84 :
85 0 : return (void *)forks;
86 0 : }
87 :
88 : void *
89 0 : fd_forks_delete( void * forks ) {
90 :
91 0 : if( FD_UNLIKELY( !forks ) ) {
92 0 : FD_LOG_WARNING( ( "NULL forks" ) );
93 0 : return NULL;
94 0 : }
95 :
96 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)forks, fd_forks_align() ) ) ) {
97 0 : FD_LOG_WARNING( ( "misaligned forks" ) );
98 0 : return NULL;
99 0 : }
100 :
101 0 : return forks;
102 0 : }
103 :
104 : fd_fork_t *
105 0 : fd_forks_init( fd_forks_t * forks, ulong slot ) {
106 :
107 0 : if( FD_UNLIKELY( !forks ) ) {
108 0 : FD_LOG_WARNING( ( "NULL forks" ) );
109 0 : return NULL;
110 0 : }
111 :
112 0 : fd_fork_t * fork = fd_fork_pool_ele_acquire( forks->pool );
113 0 : fork->slot = slot;
114 0 : fork->prev = fd_fork_pool_idx_null( forks->pool );
115 0 : fork->lock = 0;
116 0 : if( FD_UNLIKELY( !fd_fork_frontier_ele_insert( forks->frontier, fork, forks->pool ) ) ) {
117 0 : FD_LOG_WARNING( ( "Failed to insert fork into frontier" ) );
118 0 : }
119 :
120 0 : return fork;
121 0 : }
122 :
123 : fd_fork_t *
124 0 : fd_forks_query( fd_forks_t * forks, ulong slot ) {
125 0 : return fd_fork_frontier_ele_query( forks->frontier, &slot, NULL, forks->pool );
126 0 : }
127 :
128 : fd_fork_t const *
129 0 : fd_forks_query_const( fd_forks_t const * forks, ulong slot ) {
130 0 : return fd_fork_frontier_ele_query_const( forks->frontier, &slot, NULL, forks->pool );
131 0 : }
132 :
133 : fd_fork_t *
134 0 : fd_forks_prepare( fd_forks_t const * forks, ulong parent_slot ) {
135 :
136 : /* Query for parent_slot in the frontier. */
137 :
138 0 : fd_fork_t * fork = fd_fork_frontier_ele_query( forks->frontier, &parent_slot, NULL, forks->pool );
139 :
140 : /* If the parent block is both present and executed, but isn't in the
141 : frontier, that means this block is starting a new fork and needs to
142 : be added to the frontier. This requires recovering the slot_ctx
143 : as of that parent_slot by executing a funky rollback. */
144 :
145 0 : if( FD_UNLIKELY( !fork ) ) {
146 :
147 : /* Alloc a new slot_ctx */
148 :
149 0 : fork = fd_fork_pool_ele_acquire( forks->pool );
150 0 : fork->prev = fd_fork_pool_idx_null( forks->pool );
151 0 : fork->slot = parent_slot;
152 0 : fork->lock = 1;
153 :
154 : /* Add to frontier */
155 :
156 0 : fd_fork_frontier_ele_insert( forks->frontier, fork, forks->pool );
157 0 : }
158 :
159 0 : return fork;
160 0 : }
161 :
162 : void
163 0 : fd_forks_publish( fd_forks_t * forks, ulong slot ) {
164 0 : fd_fork_t * tail = NULL;
165 0 : fd_fork_t * curr = NULL;
166 :
167 0 : for( fd_fork_frontier_iter_t iter = fd_fork_frontier_iter_init( forks->frontier, forks->pool );
168 0 : !fd_fork_frontier_iter_done( iter, forks->frontier, forks->pool );
169 0 : iter = fd_fork_frontier_iter_next( iter, forks->frontier, forks->pool ) ) {
170 0 : fd_fork_t * fork = fd_fork_frontier_iter_ele( iter, forks->frontier, forks->pool );
171 :
172 : /* Prune any forks not in the ancestry from root.
173 :
174 : Optimize for unlikely because there is usually just one fork. */
175 :
176 0 : if( FD_UNLIKELY( !fork->lock && fork->slot < slot ) ) {
177 0 : if( FD_LIKELY( !curr ) ) {
178 0 : tail = fork;
179 0 : curr = fork;
180 0 : } else {
181 0 : curr->prev = fd_fork_pool_idx( forks->pool, fork );
182 0 : curr = fd_fork_pool_ele( forks->pool, curr->prev );
183 0 : }
184 0 : }
185 0 : }
186 :
187 0 : while( FD_UNLIKELY( tail ) ) {
188 0 : ulong remove = fd_fork_frontier_idx_remove( forks->frontier,
189 0 : &tail->slot,
190 0 : fd_fork_pool_idx_null( forks->pool ),
191 0 : forks->pool );
192 0 : #if FD_FORKS_USE_HANDHOLDING
193 0 : if( FD_UNLIKELY( remove == fd_fork_pool_idx_null( forks->pool ) ) ) {
194 0 : FD_LOG_ERR( ( "failed to remove fork we added to prune." ) );
195 0 : }
196 0 : #endif
197 :
198 : /* pool_idx_release cannot fail given we just removed this from the
199 : frontier directly above. */
200 0 : fd_fork_pool_idx_release( forks->pool, remove );
201 0 : tail = fd_ptr_if( tail->prev != fd_fork_pool_idx_null( forks->pool ),
202 0 : fd_fork_pool_ele( forks->pool, tail->prev ),
203 0 : NULL );
204 0 : }
205 0 : }
206 :
207 : #include <stdio.h>
208 :
209 : void
210 0 : fd_forks_print( fd_forks_t const * forks ) {
211 0 : FD_LOG_NOTICE( ( "\n\n[Forks]" ) );
212 0 : for( fd_fork_frontier_iter_t iter = fd_fork_frontier_iter_init( forks->frontier, forks->pool );
213 0 : !fd_fork_frontier_iter_done( iter, forks->frontier, forks->pool );
214 0 : iter = fd_fork_frontier_iter_next( iter, forks->frontier, forks->pool ) ) {
215 0 : printf( "%lu\n", fd_fork_frontier_iter_ele_const( iter, forks->frontier, forks->pool )->slot );
216 0 : }
217 : printf( "\n" );
218 0 : }
|