Line data Source code
1 : #include "../metrics/fd_metrics.h"
2 : #include "../stem/fd_stem.h"
3 : #include "../topo/fd_topo.h"
4 :
5 : #include <fcntl.h>
6 : #include <errno.h>
7 : #include <stdlib.h>
8 : #include <sys/types.h> /* SEEK_SET */
9 : #include <time.h>
10 : #include <unistd.h>
11 :
12 : #include "generated/fd_diag_tile_seccomp.h"
13 :
14 0 : #define REPORT_INTERVAL_MILLIS (100L)
15 :
16 : struct fd_diag_tile {
17 : long next_report_nanos;
18 :
19 : ulong tile_cnt;
20 :
21 : ulong starttime_nanos[ FD_TILE_MAX ];
22 : long first_seen_died[ FD_TILE_MAX ];
23 :
24 : int stat_fds[ FD_TILE_MAX ];
25 : int sched_fds[ FD_TILE_MAX ];
26 :
27 : volatile ulong * metrics[ FD_TILE_MAX ];
28 : };
29 :
30 : typedef struct fd_diag_tile fd_diag_tile_t;
31 :
32 : FD_FN_CONST static inline ulong
33 0 : scratch_align( void ) {
34 0 : return 128UL;
35 0 : }
36 :
37 : FD_FN_PURE static inline ulong
38 0 : scratch_footprint( fd_topo_tile_t const * tile ) {
39 0 : (void)tile;
40 0 : ulong l = FD_LAYOUT_INIT;
41 0 : l = FD_LAYOUT_APPEND( l, alignof( fd_diag_tile_t ), sizeof( fd_diag_tile_t ) );
42 0 : return FD_LAYOUT_FINI( l, scratch_align() );
43 0 : }
44 :
45 : static int
46 : read_stat_file( int fd,
47 : ulong ns_per_tick,
48 0 : volatile ulong * metrics ) {
49 0 : if( FD_UNLIKELY( -1==lseek( fd, 0, SEEK_SET ) ) ) FD_LOG_ERR(( "lseek failed (%i-%s)", errno, strerror( errno ) ));
50 :
51 0 : char contents[ 4096 ] = {0};
52 0 : ulong contents_len = 0UL;
53 :
54 0 : while( 1 ) {
55 0 : if( FD_UNLIKELY( contents_len>=sizeof( contents ) ) ) FD_LOG_ERR(( "stat contents overflow" ));
56 0 : long n = read( fd, contents + contents_len, sizeof( contents ) - contents_len );
57 0 : if( FD_UNLIKELY( -1==n ) ) {
58 0 : if( FD_UNLIKELY( errno==ESRCH ) ) return 1;
59 0 : FD_LOG_ERR(( "read failed (%i-%s)", errno, strerror( errno ) ));
60 0 : }
61 0 : if( FD_LIKELY( 0==n ) ) break;
62 0 : contents_len += (ulong)n;
63 0 : }
64 :
65 : /* Parse stat file: fields are space-separated.
66 : Field 10 (1-indexed) = minflt, field 12 = majflt,
67 : field 14 = utime, field 15 = stime (all in clock ticks). */
68 0 : char * saveptr;
69 0 : char * token = strtok_r( contents, " ", &saveptr );
70 0 : ulong field_idx = 0UL;
71 :
72 0 : while( token ) {
73 0 : if( FD_UNLIKELY( 9UL==field_idx ) ) {
74 0 : char * endptr;
75 0 : ulong minflt = strtoul( token, &endptr, 10 );
76 0 : if( FD_UNLIKELY( *endptr!='\0' || minflt==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for minflt" ));
77 0 : metrics[ FD_METRICS_COUNTER_TILE_PAGE_FAULT_MINOR_COUNT_OFF ] = minflt;
78 0 : } else if( FD_UNLIKELY( 11UL==field_idx ) ) {
79 0 : char * endptr;
80 0 : ulong majflt = strtoul( token, &endptr, 10 );
81 0 : if( FD_UNLIKELY( *endptr!='\0' || majflt==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for majflt" ));
82 0 : metrics[ FD_METRICS_COUNTER_TILE_PAGE_FAULT_MAJOR_COUNT_OFF ] = majflt;
83 0 : } else if( FD_UNLIKELY( 13UL==field_idx ) ) {
84 0 : char * endptr;
85 0 : ulong utime_ticks = strtoul( token, &endptr, 10 );
86 0 : if( FD_UNLIKELY( *endptr!='\0' || utime_ticks==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for utime" ));
87 0 : metrics[ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_USER_OFF ] = utime_ticks*ns_per_tick;
88 0 : } else if( FD_UNLIKELY( 14UL==field_idx ) ) {
89 0 : char * endptr;
90 0 : ulong stime_ticks = strtoul( token, &endptr, 10 );
91 0 : if( FD_UNLIKELY( *endptr!='\0' || stime_ticks==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for stime" ));
92 0 : metrics[ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_SYSTEM_OFF ] = stime_ticks*ns_per_tick;
93 0 : } else if( FD_UNLIKELY( 39UL==field_idx ) ) {
94 0 : char * endptr;
95 0 : ulong last_cpu_ticks = strtoul( token, &endptr, 10 );
96 0 : if( FD_UNLIKELY( *endptr!='\0' || last_cpu_ticks==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for processor" ));
97 0 : metrics[ FD_METRICS_GAUGE_TILE_LAST_CPU_OFF ] = last_cpu_ticks*ns_per_tick;
98 0 : break; /* No need to parse stat further */
99 0 : }
100 0 : token = strtok_r( NULL, " ", &saveptr );
101 0 : field_idx++;
102 0 : }
103 :
104 0 : if( FD_UNLIKELY( field_idx!=39UL ) ) FD_LOG_ERR(( "failed to parse /proc/<pid>/task/<tid>/stat" ));
105 :
106 0 : return 0;
107 0 : }
108 :
109 : static int
110 : read_sched_file( int fd,
111 0 : volatile ulong * metrics ) {
112 0 : if( FD_UNLIKELY( -1==lseek( fd, 0, SEEK_SET ) ) ) FD_LOG_ERR(( "lseek failed (%i-%s)", errno, strerror( errno ) ));
113 :
114 0 : char contents[ 8192 ] = {0};
115 0 : ulong contents_len = 0UL;
116 :
117 0 : while( 1 ) {
118 0 : if( FD_UNLIKELY( contents_len>=sizeof( contents ) ) ) FD_LOG_ERR(( "sched contents overflow" ));
119 0 : long n = read( fd, contents + contents_len, sizeof( contents ) - contents_len );
120 0 : if( FD_UNLIKELY( -1==n ) ) {
121 0 : if( FD_UNLIKELY( errno==ESRCH ) ) return 1;
122 0 : FD_LOG_ERR(( "read failed (%i-%s)", errno, strerror( errno ) ));
123 0 : }
124 0 : if( FD_LIKELY( 0==n ) ) break;
125 0 : contents_len += (ulong)n;
126 0 : }
127 :
128 0 : int found_wait_sum = 0;
129 0 : int found_voluntary = 0;
130 0 : int found_involuntary = 0;
131 :
132 0 : char * line = contents;
133 0 : while( 1 ) {
134 0 : char * next_line = strchr( line, '\n' );
135 0 : if( FD_UNLIKELY( NULL==next_line ) ) break;
136 0 : *next_line = '\0';
137 :
138 0 : if( FD_UNLIKELY( !strncmp( line, "wait_sum", 8UL ) ) ) {
139 0 : char * colon = strchr( line, ':' );
140 0 : if( FD_LIKELY( colon ) ) {
141 0 : char * value = colon + 1;
142 0 : while( ' '==*value || '\t'==*value ) value++;
143 : /* wait_sum is displayed as seconds.microseconds (e.g., "123.456789").
144 : Parse both components as integers and convert to nanoseconds. */
145 0 : char * endptr;
146 0 : ulong seconds = strtoul( value, &endptr, 10 );
147 0 : if( FD_UNLIKELY( '.'!=*endptr ) ) FD_LOG_ERR(( "expected '.' after seconds in wait_sum" ));
148 0 : if( FD_UNLIKELY( seconds==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for wait_sum seconds" ));
149 0 : ulong microseconds = strtoul( endptr + 1, &endptr, 10 );
150 0 : if( FD_UNLIKELY( '\0'!=*endptr ) ) FD_LOG_ERR(( "unexpected char after microseconds in wait_sum" ));
151 0 : if( FD_UNLIKELY( microseconds==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for wait_sum microseconds" ));
152 0 : ulong wait_sum_ns = seconds*1000000000UL + microseconds*1000UL;
153 0 : metrics[ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_WAIT_OFF ] = wait_sum_ns;
154 0 : found_wait_sum = 1;
155 0 : }
156 0 : } else if( FD_UNLIKELY( !strncmp( line, "nr_voluntary_switches", 21UL ) ) ) {
157 0 : char * colon = strchr( line, ':' );
158 0 : if( FD_LIKELY( colon ) ) {
159 0 : char * value = colon + 1;
160 0 : while( ' '==*value || '\t'==*value ) value++;
161 0 : char * endptr;
162 0 : ulong voluntary_switches = strtoul( value, &endptr, 10 );
163 0 : if( FD_UNLIKELY( '\0'!=*endptr ) ) FD_LOG_ERR(( "unexpected char after nr_voluntary_switches" ));
164 0 : if( FD_UNLIKELY( voluntary_switches==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for nr_voluntary_switches" ));
165 0 : metrics[ FD_METRICS_COUNTER_TILE_CONTEXT_SWITCH_VOLUNTARY_COUNT_OFF ] = voluntary_switches;
166 0 : found_voluntary = 1;
167 0 : }
168 0 : } else if( FD_UNLIKELY( !strncmp( line, "nr_involuntary_switches", 23UL ) ) ) {
169 0 : char * colon = strchr( line, ':' );
170 0 : if( FD_LIKELY( colon ) ) {
171 0 : char * value = colon + 1;
172 0 : while( ' '==*value || '\t'==*value ) value++;
173 0 : char * endptr;
174 0 : ulong involuntary_switches = strtoul( value, &endptr, 10 );
175 0 : if( FD_UNLIKELY( '\0'!=*endptr ) ) FD_LOG_ERR(( "unexpected char after nr_involuntary_switches" ));
176 0 : if( FD_UNLIKELY( involuntary_switches==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for nr_involuntary_switches" ));
177 0 : metrics[ FD_METRICS_COUNTER_TILE_CONTEXT_SWITCH_INVOLUNTARY_COUNT_OFF ] = involuntary_switches;
178 0 : found_involuntary = 1;
179 0 : }
180 0 : }
181 :
182 0 : line = next_line + 1;
183 0 : }
184 :
185 : // wait_sum not present on kernels compiled without CONFIG_SCHEDSTATS=y
186 : // if( FD_UNLIKELY( !found_wait_sum ) ) FD_LOG_ERR(( "wait_sum not found in sched file" ));
187 0 : (void)found_wait_sum;
188 0 : if( FD_UNLIKELY( !found_voluntary ) ) FD_LOG_ERR(( "nr_voluntary_switches not found in sched file" ));
189 0 : if( FD_UNLIKELY( !found_involuntary ) ) FD_LOG_ERR(( "nr_involuntary_switches not found in sched file" ));
190 :
191 0 : return 0;
192 0 : }
193 :
194 : static void
195 : before_credit( fd_diag_tile_t * ctx,
196 : fd_stem_context_t * stem,
197 0 : int * charge_busy ) {
198 0 : (void)stem;
199 :
200 0 : long now = fd_log_wallclock();
201 0 : if( now<ctx->next_report_nanos ) {
202 0 : long diff = ctx->next_report_nanos - now;
203 0 : diff = fd_long_min( diff, 2e6 /* 2ms */ );
204 0 : struct timespec const ts = {
205 0 : .tv_sec = diff / (long)1e9,
206 0 : .tv_nsec = diff % (long)1e9
207 0 : };
208 0 : clock_nanosleep( CLOCK_REALTIME, 0, &ts, NULL );
209 0 : return;
210 0 : }
211 0 : ctx->next_report_nanos += REPORT_INTERVAL_MILLIS*1000L*1000L;
212 :
213 0 : *charge_busy = 1;
214 :
215 0 : struct timespec boottime;
216 0 : if( FD_UNLIKELY( -1==clock_gettime( CLOCK_BOOTTIME, &boottime ) ) ) FD_LOG_ERR(( "clock_gettime(CLOCK_BOOTTIME) failed (%i-%s)", errno, strerror( errno ) ));
217 0 : ulong now_since_boot_nanos = (ulong)boottime.tv_sec*1000000000UL + (ulong)boottime.tv_nsec;
218 :
219 0 : for( ulong i=0UL; i<ctx->tile_cnt; i++ ) {
220 0 : if( FD_UNLIKELY( -1==ctx->stat_fds[ i ] ) ) continue;
221 :
222 : /* CLK_TCK is typically 100, so 1 tick = 10ms = 10,000,000 ns */
223 0 : int process_died1 = read_stat_file( ctx->stat_fds[ i ], 10000000UL, ctx->metrics[ i ] );
224 0 : int process_died2 = read_sched_file( ctx->sched_fds[ i ], ctx->metrics[ i ] );
225 :
226 0 : if( FD_UNLIKELY( process_died1 || process_died2 ) ) {
227 0 : ctx->stat_fds[ i ] = -1;
228 0 : continue;
229 0 : }
230 :
231 0 : ulong task_lifetime_nanos = now_since_boot_nanos - ctx->starttime_nanos[ i ];
232 0 : ulong user_nanos = ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_USER_OFF ];
233 0 : ulong system_nanos = ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_SYSTEM_OFF ];
234 0 : ulong wait_nanos = ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_WAIT_OFF ];
235 0 : ulong busy_nanos = user_nanos+system_nanos+wait_nanos;
236 0 : ulong idle_nanos = (task_lifetime_nanos>busy_nanos) ? (task_lifetime_nanos-busy_nanos) : 0UL;
237 :
238 : /* Counter can't go backwards in Prometheus else it thinks the
239 : application restarted. Use max to ensure monotonicity. */
240 0 : ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_IDLE_OFF ] = fd_ulong_max( idle_nanos, ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_IDLE_OFF ] );
241 0 : }
242 :
243 0 : for( ulong i=0UL; i<ctx->tile_cnt; i++ ) {
244 0 : if( FD_LIKELY( -1!=ctx->stat_fds[ i ] ) ) continue;
245 :
246 : /* The tile died, but it's a tile which is allowed to shutdown, so
247 : just stop updating metrics for it. */
248 0 : if( FD_LIKELY( 2UL==ctx->metrics[ i ][ FD_METRICS_GAUGE_TILE_STATUS_OFF ] ) ) continue;
249 :
250 : /* Supervisor is going to bring the whole process tree down if any
251 : of the target PIDs died, so we can ignore this and wait. */
252 0 : if( FD_UNLIKELY( !ctx->first_seen_died[ i ] ) ) {
253 0 : ctx->first_seen_died[ i ] = now;
254 0 : } else if( FD_LIKELY( ctx->first_seen_died[ i ]==LONG_MAX ) ) {
255 : /* We already reported this, so we can ignore it. */
256 0 : } else if( FD_UNLIKELY( now-ctx->first_seen_died[ i ] < 10L*1000L*1000L*1000L ) ) {
257 : /* Wait 10 seconds for supervisor to kill us before reporting WARNING */
258 0 : } else {
259 0 : FD_LOG_WARNING(( "cannot get metrics for dead tile idx %lu", i ));
260 0 : ctx->first_seen_died[ i ] = LONG_MAX;
261 0 : }
262 0 : }
263 0 : }
264 :
265 : static void
266 : privileged_init( fd_topo_t * topo,
267 0 : fd_topo_tile_t * tile ) {
268 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
269 :
270 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
271 0 : fd_diag_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_diag_tile_t), sizeof(fd_diag_tile_t) );
272 :
273 0 : FD_TEST( topo->tile_cnt<FD_TILE_MAX );
274 :
275 0 : FD_TEST( 100L == sysconf( _SC_CLK_TCK ) );
276 :
277 0 : ctx->tile_cnt = topo->tile_cnt;
278 0 : for( ulong i=0UL; i<FD_TILE_MAX; i++ ) {
279 0 : ctx->stat_fds[ i ] = -1;
280 0 : ctx->sched_fds[ i ] = -1;
281 0 : }
282 :
283 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
284 0 : ulong * metrics = fd_metrics_join( fd_topo_obj_laddr( topo, topo->tiles[ i ].metrics_obj_id ) );
285 :
286 0 : for(;;) {
287 0 : ulong pid, tid;
288 0 : if( FD_UNLIKELY( tile->id==i ) ) {
289 0 : pid = fd_sandbox_getpid();
290 0 : tid = fd_sandbox_gettid();
291 0 : } else {
292 0 : pid = fd_metrics_tile( metrics )[ FD_METRICS_GAUGE_TILE_PID_OFF ];
293 0 : tid = fd_metrics_tile( metrics )[ FD_METRICS_GAUGE_TILE_TID_OFF ];
294 0 : if( FD_UNLIKELY( !pid || !tid ) ) {
295 0 : FD_SPIN_PAUSE();
296 0 : continue;
297 0 : }
298 0 : }
299 :
300 0 : ctx->metrics[ i ] = fd_metrics_tile( metrics );
301 :
302 0 : char path[ 64UL ];
303 0 : FD_TEST( fd_cstr_printf_check( path, sizeof( path ), NULL, "/proc/%lu/task/%lu/stat", pid, tid ) );
304 0 : ctx->stat_fds[ i ] = open( path, O_RDONLY );
305 0 : if( FD_UNLIKELY( -1==ctx->stat_fds[ i ] ) ) {
306 : /* Might be a tile that's allowed to shutdown already did so
307 : before we got to here, due to a race condition. Just
308 : proceed, we will not be able to get metrics for the shut
309 : down process. */
310 0 : if( FD_LIKELY( 2UL!=ctx->metrics[ i ][ FD_METRICS_GAUGE_TILE_STATUS_OFF ] ) ) FD_LOG_ERR(( "open stat failed (%i-%s)", errno, strerror( errno ) ));
311 0 : break;
312 0 : }
313 :
314 0 : FD_TEST( fd_cstr_printf_check( path, sizeof( path ), NULL, "/proc/%lu/task/%lu/sched", pid, tid ) );
315 0 : ctx->sched_fds[ i ] = open( path, O_RDONLY );
316 0 : if( FD_UNLIKELY( -1==ctx->sched_fds[ i ] ) ) {
317 0 : if( FD_LIKELY( 2UL!=ctx->metrics[ i ][ FD_METRICS_GAUGE_TILE_STATUS_OFF ] ) ) FD_LOG_ERR(( "open sched failed (%i-%s)", errno, strerror( errno ) ));
318 0 : ctx->stat_fds[ i ] = -1;
319 0 : }
320 0 : break;
321 0 : }
322 0 : }
323 0 : }
324 :
325 : /* Read starttime (field 22) from stat file. Returns 0 on success, 1 if
326 : process died (ESRCH). */
327 :
328 : static int
329 : read_starttime( int fd,
330 : ulong ns_per_tick,
331 0 : ulong * out_starttime_nanos ) {
332 0 : char contents[ 4096 ] = {0};
333 0 : ulong contents_len = 0UL;
334 :
335 0 : while( 1 ) {
336 0 : if( FD_UNLIKELY( contents_len>=sizeof( contents ) ) ) FD_LOG_ERR(( "stat contents overflow" ));
337 0 : long n = read( fd, contents + contents_len, sizeof( contents ) - contents_len );
338 0 : if( FD_UNLIKELY( -1==n ) ) {
339 0 : if( FD_UNLIKELY( errno==ESRCH ) ) return 1;
340 0 : FD_LOG_ERR(( "read stat failed (%i-%s)", errno, strerror( errno ) ));
341 0 : }
342 0 : if( FD_LIKELY( 0L==n ) ) break;
343 0 : contents_len += (ulong)n;
344 0 : }
345 :
346 : /* Parse field 22 (starttime) from stat file */
347 0 : char * saveptr;
348 0 : char * token = strtok_r( contents, " ", &saveptr );
349 0 : ulong field_idx = 0UL;
350 :
351 0 : while( token && field_idx<21UL ) {
352 0 : token = strtok_r( NULL, " ", &saveptr );
353 0 : field_idx++;
354 0 : }
355 :
356 0 : if( FD_UNLIKELY( !token || field_idx!=21UL ) ) FD_LOG_ERR(( "starttime (field 22) not found in stat" ));
357 :
358 0 : char * endptr;
359 0 : ulong starttime_ticks = strtoul( token, &endptr, 10 );
360 0 : if( FD_UNLIKELY( *endptr!=' ' && *endptr!='\0' ) ) FD_LOG_ERR(( "strtoul failed for starttime" ));
361 0 : if( FD_UNLIKELY( starttime_ticks==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for starttime" ));
362 :
363 0 : *out_starttime_nanos = starttime_ticks * ns_per_tick;
364 0 : return 0;
365 0 : }
366 :
367 : static void
368 : unprivileged_init( fd_topo_t * topo,
369 0 : fd_topo_tile_t * tile ) {
370 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
371 :
372 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
373 0 : fd_diag_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_diag_tile_t), sizeof(fd_diag_tile_t) );
374 :
375 0 : memset( ctx->first_seen_died, 0, sizeof( ctx->first_seen_died ) );
376 0 : ctx->next_report_nanos = fd_log_wallclock();
377 :
378 : /* Read starttime (field 22) once at init for idle time calculation.
379 : CLK_TCK is always 100, so 1 tick = 10ms = 10,000,000 ns. */
380 0 : for( ulong i=0UL; i<ctx->tile_cnt; i++ ) {
381 0 : if( FD_LIKELY( -1!=ctx->stat_fds[ i ] ) ) {
382 0 : int died = read_starttime( ctx->stat_fds[ i ], 10000000UL, &ctx->starttime_nanos[ i ] );
383 0 : if( FD_UNLIKELY( died ) ) ctx->stat_fds[ i ] = -1;
384 0 : }
385 0 : }
386 :
387 0 : ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
388 0 : if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
389 0 : FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
390 0 : }
391 :
392 : static ulong
393 : populate_allowed_seccomp( fd_topo_t const * topo,
394 : fd_topo_tile_t const * tile,
395 : ulong out_cnt,
396 0 : struct sock_filter * out ) {
397 0 : (void)topo;
398 0 : (void)tile;
399 :
400 0 : populate_sock_filter_policy_fd_diag_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
401 0 : return sock_filter_policy_fd_diag_tile_instr_cnt;
402 0 : }
403 :
404 : static ulong
405 : populate_allowed_fds( fd_topo_t const * topo,
406 : fd_topo_tile_t const * tile,
407 : ulong out_fds_cnt,
408 0 : int * out_fds ) {
409 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
410 :
411 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
412 0 : fd_diag_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_diag_tile_t), sizeof(fd_diag_tile_t) );
413 :
414 0 : if( FD_UNLIKELY( out_fds_cnt<2UL+2UL*ctx->tile_cnt ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
415 :
416 0 : ulong out_cnt = 0UL;
417 0 : out_fds[ out_cnt++ ] = 2; /* stderr */
418 0 : if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
419 0 : out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
420 0 : for( ulong i=0UL; i<ctx->tile_cnt; i++ ) {
421 0 : if( -1!=ctx->stat_fds[ i ] ) out_fds[ out_cnt++ ] = ctx->stat_fds[ i ]; /* /proc/<pid>/task/<tid>/stat */
422 0 : if( -1!=ctx->sched_fds[ i ] ) out_fds[ out_cnt++ ] = ctx->sched_fds[ i ]; /* /proc/<pid>/task/<tid>/sched */
423 0 : }
424 0 : return out_cnt;
425 0 : }
426 :
427 0 : #define STEM_BURST (1UL)
428 0 : #define STEM_LAZY ((long)10e6) /* 10ms */
429 :
430 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_diag_tile_t
431 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_diag_tile_t)
432 :
433 0 : #define STEM_CALLBACK_BEFORE_CREDIT before_credit
434 :
435 : #include "../../disco/stem/fd_stem.c"
436 :
437 : fd_topo_run_tile_t fd_tile_diag = {
438 : .name = "diag",
439 : .populate_allowed_seccomp = populate_allowed_seccomp,
440 : .populate_allowed_fds = populate_allowed_fds,
441 : .scratch_align = scratch_align,
442 : .scratch_footprint = scratch_footprint,
443 : .privileged_init = privileged_init,
444 : .unprivileged_init = unprivileged_init,
445 : .run = stem_run,
446 : };
|