codegen: gen_io: fix double-free of ctx->var_aux if
[ajla.git] / ipio.c
blob058fcfe9fda34738be66e3918e0e8cd4275161b6
1 /*
2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
9 * version.
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 #include "ajla.h"
21 #ifndef FILE_OMIT
23 #include <fcntl.h>
25 #include "ipunalg.h"
26 #include "data.h"
27 #include "arindex.h"
28 #include "array.h"
29 #include "arrayu.h"
30 #include "tick.h"
31 #include "obj_reg.h"
32 #include "os.h"
33 #include "iomux.h"
34 #include "timer.h"
35 #include "resolver.h"
36 #include "ipfn.h"
37 #include "module.h"
38 #include "pcode.h"
39 #include "args.h"
40 #include "builtin.h"
41 #include "save.h"
42 #include "task.h"
43 #include "ipret.h"
45 #include "ipio.h"
47 #if defined(OS_HAS_DLOPEN) && defined(HAVE_LIBFFI)
48 #include <ffi.h>
49 #define SUPPORTS_FFI
50 #endif
52 #ifndef PIPE_BUF
53 #define PIPE_BUF 512
54 #endif
56 #if !defined(OS_WIN32)
57 extern char **environ;
58 #endif
60 struct resource_handle {
61 handle_t fd;
62 bool nonblocking;
63 os_termios_t *old_termios;
66 struct resource_dir_handle {
67 dir_handle_t fd;
70 struct resource_notify_handle {
71 notify_handle_t id;
72 uint64_t seq;
75 struct resource_proc_handle {
76 struct proc_handle *ph;
79 struct msgqueue_entry {
80 pointer_t tag;
81 pointer_t ptr;
84 struct resource_msgqueue {
85 struct msgqueue_entry *queue;
86 size_t queue_len;
87 size_t queue_allocated;
88 struct list wait_list;
89 struct list list_entry;
92 struct resource_signal {
93 int s;
96 static mutex_t lib_path_mutex;
97 static char *lib_path;
98 static size_t lib_path_len;
100 static mutex_t msgqueue_list_mutex;
101 static struct list msgqueue_list;
103 #define IO_STATUS_STARTED 0
104 #define IO_STATUS_PROGRESS 1
105 #define IO_STATUS_TIMEOUT 2
106 #define IO_STATUS_IOERR 3
107 #define IO_STATUS_THUNK 4
108 #define IO_STATUS_BLOCKED 5
110 struct io_ctx {
111 frame_s *fp;
112 const code_t *ip;
113 const code_t *outputs;
114 const code_t *inputs;
115 const code_t *params;
116 uchar_efficient_t n_outputs;
117 uchar_efficient_t n_inputs;
118 uchar_efficient_t n_params;
119 uchar_efficient_t status;
121 ajla_error_t err;
123 uchar_efficient_t code;
125 tick_stamp_t ts;
126 pointer_t *array_ptr;
128 char *str;
129 size_t str_l;
130 char *str2;
131 size_t str2_l;
133 char **strs;
134 size_t strs_l;
136 void **ptrs;
137 size_t ptrs_l;
139 handle_t *h_src;
140 size_t h_src_l;
141 int *h_dst;
142 size_t h_dst_l;
144 uchar_efficient_t *args;
145 size_t args_l;
147 struct resource_ffi *rf;
149 struct resource_handle *handle;
150 struct resource_handle *handle2;
151 struct resource_dir_handle *dir_handle;
152 struct resource_dir_handle *dir_handle2;
153 struct resource_msgqueue *msgqueue;
154 os_off_t position;
155 os_off_t position2;
156 os_off_t length;
159 static void handle_no_close(struct data *d)
161 struct resource_handle *h = da_resource(d);
162 if (unlikely(h->old_termios != NULL)) {
163 ajla_error_t sink;
164 os_tcsetattr(h->fd, h->old_termios, &sink);
165 mem_free(h->old_termios);
169 static void handle_close(struct data *d)
171 struct resource_handle *h;
172 handle_no_close(d);
173 h = da_resource(d);
174 os_close(h->fd);
177 static void dir_handle_close(struct data *d)
179 struct resource_dir_handle *h = da_resource(d);
180 if (dir_handle_is_valid(h->fd))
181 os_dir_close(h->fd);
184 static void notify_handle_close(struct data *d)
186 struct resource_notify_handle *h = da_resource(d);
187 iomux_directory_handle_free(h->id);
190 static void proc_handle_close(struct data *d)
192 struct resource_proc_handle *rph = da_resource(d);
193 os_proc_free_handle(rph->ph);
196 static void msgqueue_close(struct data *d)
198 size_t i;
199 struct resource_msgqueue *q = da_resource(d);
201 mutex_lock(&msgqueue_list_mutex);
202 list_del(&q->list_entry);
203 mutex_unlock(&msgqueue_list_mutex);
205 for (i = 0; i < q->queue_len; i++) {
206 struct msgqueue_entry *qe = &q->queue[i];
207 pointer_dereference(qe->tag);
208 pointer_dereference(qe->ptr);
210 mem_free(q->queue);
213 static void signal_close(struct data *d)
215 struct resource_signal *s = da_resource(d);
216 os_signal_unhandle(s->s);
219 #define verify_file_handle(d) \
220 do { \
221 struct resource_handle *h; \
222 if (da(d,resource)->close == handle_no_close) \
223 break; \
224 h = da_resource(d); \
225 obj_registry_verify(OBJ_TYPE_HANDLE, (obj_id)h->fd, file_line); \
226 } while (0)
228 #ifndef NO_DIR_HANDLES
229 #define verify_dir_handle(d) \
230 do { \
231 struct resource_dir_handle *h; \
232 h = da_resource(d); \
233 if (dir_handle_is_valid(h->fd)) \
234 obj_registry_verify(OBJ_TYPE_HANDLE, (obj_id)h->fd, file_line);\
235 } while (0)
236 #else
237 #define verify_dir_handle(d) do { } while (0)
238 #endif
240 static inline frame_t get_output(const struct io_ctx *ctx, unsigned offset)
242 ajla_assert(offset < ctx->n_outputs, (file_line, "get_output: invalid output %u >= %u", offset, (unsigned)ctx->n_outputs));
243 return get_unaligned_32(ctx->outputs + offset * 2);
246 static inline frame_t get_input(const struct io_ctx *ctx, unsigned offset)
248 ajla_assert(offset < ctx->n_inputs, (file_line, "get_input: invalid input %u >= %u", offset, (unsigned)ctx->n_inputs));
249 return get_unaligned_32(ctx->inputs + offset * 2);
252 static inline frame_t get_param(const struct io_ctx *ctx, unsigned offset)
254 ajla_assert(offset < ctx->n_params, (file_line, "get_param: invalid param %u >= %u", offset, (unsigned)ctx->n_params));
255 return get_unaligned_32(ctx->params + offset * 2);
258 static void io_terminate_with_thunk(struct io_ctx *ctx, struct thunk *thunk)
260 unsigned i;
262 pointer_reference_owned_multiple(pointer_thunk(thunk), ctx->n_outputs);
264 for (i = 0; i < ctx->n_outputs; i++)
265 frame_free_and_set_pointer(ctx->fp, get_output(ctx, i), pointer_thunk(thunk));
267 pointer_dereference(pointer_thunk(thunk));
270 static void io_terminate_with_error(struct io_ctx *ctx, ajla_error_t err, bool stack_trace, char *msg)
272 struct thunk *t = thunk_alloc_exception_error(err, msg, stack_trace ? ctx->fp : NULL, stack_trace ? ctx->ip : NULL pass_file_line);
273 io_terminate_with_thunk(ctx, t);
276 static void *io_deep_eval(struct io_ctx *ctx, const char *input_positions, bool copy_world)
278 for (; *input_positions; input_positions++) {
279 void *ex;
280 struct thunk *thunk;
281 frame_t slot = get_input(ctx, *input_positions - '0');
282 ex = frame_pointer_deep_eval(ctx->fp, ctx->ip, slot, &thunk);
283 if (likely(ex == POINTER_FOLLOW_THUNK_GO))
284 continue;
285 if (ex == POINTER_FOLLOW_THUNK_EXCEPTION) {
286 io_terminate_with_thunk(ctx, thunk);
288 return ex;
291 if (copy_world) {
292 ajla_assert_lo(get_input(ctx, 0) != get_output(ctx, 0), (file_line, "io_deep_eval: input and output slot is the same"));
293 frame_free(ctx->fp, get_output(ctx, 0));
294 ipret_copy_variable(ctx->fp, get_input(ctx, 0), ctx->fp, get_output(ctx, 0), false);
297 return POINTER_FOLLOW_THUNK_GO;
300 static void io_get_handle(struct io_ctx *ctx, frame_t slot)
302 pointer_t ptr;
303 struct data *d;
304 struct resource_handle *h;
306 ptr = *frame_pointer(ctx->fp, slot);
307 ajla_assert_lo(!pointer_is_thunk(ptr), (file_line, "io_get_handle: pointer is thunk"));
308 d = pointer_get_data(ptr);
310 h = da_resource(d);
311 ctx->handle = h;
313 verify_file_handle(d);
316 static void io_get_dir_handle(struct io_ctx *ctx, frame_t slot)
318 pointer_t ptr;
319 struct data *d;
320 struct resource_dir_handle *h;
322 ptr = *frame_pointer(ctx->fp, slot);
323 ajla_assert_lo(!pointer_is_thunk(ptr), (file_line, "io_get_dir_handle: pointer is thunk"));
324 d = pointer_get_data(ptr);
326 h = da_resource(d);
327 ctx->dir_handle = h;
329 verify_dir_handle(d);
332 static void io_block_on_handle(struct io_ctx *ctx, bool wr, bool attr_unused packet_mode)
334 struct execution_control *ex = frame_execution_control(ctx->fp);
335 #if defined(OS_DOS)
336 if (packet_mode) {
337 dos_wait_on_packet(&ex->wait[0].mutex_to_lock, &ex->wait[0].wait_entry);
338 } else
339 #endif
341 iomux_register_wait(ctx->handle->fd, wr, &ex->wait[0].mutex_to_lock, &ex->wait[0].wait_entry);
343 pointer_follow_wait(ctx->fp, ctx->ip);
347 static unsigned char *io_get_flat_pointer(struct io_ctx *ctx, frame_t slot)
349 if (likely(frame_variable_is_flat(ctx->fp, slot))) {
350 return frame_var(ctx->fp, slot);
351 } else {
352 pointer_t ptr;
353 struct data *d;
354 ptr = *frame_pointer(ctx->fp, slot);
355 ajla_assert_lo(!pointer_is_thunk(ptr), (file_line, "io_get_flat_pointer: pointer is thunk"));
356 d = pointer_get_data(ptr);
357 ajla_assert_lo(da_tag(d) == DATA_TAG_flat, (file_line, "io_get_flat_pointer: invalid data tag %u", da_tag(d)));
358 return da_flat(d);
362 static void io_get_pcode_t(struct io_ctx *ctx, frame_t slot, pcode_t *result)
364 unsigned char *ptr;
365 ajla_assert(frame_get_type_of_local(ctx->fp, slot)->tag == type_get_fixed(2, false)->tag, (file_line, "io_get_pcode_t: invalid type %u", (unsigned)frame_get_type_of_local(ctx->fp, slot)->tag));
366 ptr = io_get_flat_pointer(ctx, slot);
367 barrier_aliasing();
368 *result = *cast_ptr(pcode_t *, ptr);
369 barrier_aliasing();
372 static void attr_unused io_get_int32_t(struct io_ctx *ctx, frame_t slot, int32_t *result, const mpint_t **mp)
374 ajla_assert(frame_get_type_of_local(ctx->fp, slot)->tag == type_get_int(2)->tag ||
375 frame_get_type_of_local(ctx->fp, slot)->tag == type_get_fixed(2, false)->tag ||
376 frame_get_type_of_local(ctx->fp, slot)->tag == type_get_fixed(2, true)->tag, (file_line, "io_get_int32_t: invalid type %u", (unsigned)frame_get_type_of_local(ctx->fp, slot)->tag));
377 if (mp)
378 *mp = NULL;
379 if (likely(!frame_test_flag(ctx->fp, slot))) {
380 barrier_aliasing();
381 *result = *frame_slot(ctx->fp, slot, int32_t);
382 barrier_aliasing();
383 } else {
384 pointer_t ptr;
385 struct data *d;
386 ptr = *frame_pointer(ctx->fp, slot);
387 ajla_assert_lo(!pointer_is_thunk(ptr), (file_line, "io_get_int32_t: pointer is thunk"));
388 d = pointer_get_data(ptr);
389 if (da_tag(d) == DATA_TAG_flat) {
390 *result = *cast_ptr(int32_t *, da_flat(d));
391 } else if (likely(da_tag(d) == DATA_TAG_longint)) {
392 if (unlikely(!mp))
393 internal(file_line, "io_get_int32: unexpected long int");
394 *mp = &da(d,longint)->mp;
395 } else {
396 internal(file_line, "io_get_int32_t: invalid data tag %u", da_tag(d));
401 static void io_get_int64_t(struct io_ctx *ctx, frame_t slot, int64_t *result, const mpint_t **mp)
403 ajla_assert(frame_get_type_of_local(ctx->fp, slot)->tag == type_get_int(3)->tag ||
404 frame_get_type_of_local(ctx->fp, slot)->tag == type_get_fixed(3, false)->tag ||
405 frame_get_type_of_local(ctx->fp, slot)->tag == type_get_fixed(3, true)->tag, (file_line, "io_get_int64_t: invalid type %u", (unsigned)frame_get_type_of_local(ctx->fp, slot)->tag));
406 if (mp)
407 *mp = NULL;
408 if (likely(!frame_test_flag(ctx->fp, slot))) {
409 barrier_aliasing();
410 *result = *frame_slot(ctx->fp, slot, int64_t);
411 barrier_aliasing();
412 } else {
413 pointer_t ptr;
414 struct data *d;
415 ptr = *frame_pointer(ctx->fp, slot);
416 ajla_assert_lo(!pointer_is_thunk(ptr), (file_line, "io_get_int64: pointer is thunk"));
417 d = pointer_get_data(ptr);
418 if (da_tag(d) == DATA_TAG_flat) {
419 *result = *cast_ptr(int64_t *, da_flat(d));
420 } else if (likely(da_tag(d) == DATA_TAG_longint)) {
421 if (unlikely(!mp))
422 internal(file_line, "io_get_int64: unexpected long int");
423 *mp = &da(d,longint)->mp;
424 } else {
425 internal(file_line, "io_get_int64: invalid data tag %u", da_tag(d));
430 static void io_get_option(struct io_ctx *ctx, frame_t slot, ajla_option_t *result, struct data **pointer)
432 if (likely(frame_variable_is_flat(ctx->fp, slot))) {
433 ajla_assert(frame_get_type_of_local(ctx->fp, slot)->tag == TYPE_TAG_flat_option, (file_line, "io_get_int32_t: invalid type %u", (unsigned)frame_get_type_of_local(ctx->fp, slot)->tag));
434 *result = *frame_slot(ctx->fp, slot, ajla_flat_option_t);
435 if (pointer)
436 *pointer = NULL;
437 } else {
438 pointer_t ptr;
439 struct data *d;
440 ptr = *frame_pointer(ctx->fp, slot);
441 ajla_assert_lo(!pointer_is_thunk(ptr), (file_line, "io_get_option: pointer is thunk"));
442 d = pointer_get_data(ptr);
443 ajla_assert_lo(da_tag(d) == DATA_TAG_option, (file_line, "io_get_option: invalid data tag %u", da_tag(d)));
444 *result = da(d,option)->option;
445 if (pointer) {
446 if (!pointer_is_empty(da(d,option)->pointer))
447 *pointer = pointer_get_data(da(d,option)->pointer);
448 else
449 *pointer = NULL;
454 static void *io_get_array_index(struct io_ctx *ctx, frame_s *fp_slot, frame_t slot, array_index_t *i argument_position)
456 pointer_t thunk;
457 void *ex = ipret_get_index(ctx->fp, ctx->ip, fp_slot, slot, NULL, i, &thunk pass_position);
458 if (unlikely(ex == POINTER_FOLLOW_THUNK_EXCEPTION)) {
459 io_terminate_with_thunk(ctx, pointer_get_thunk(thunk));
461 return ex;
464 static void io_store_flat_option(struct io_ctx *ctx, frame_t slot, ajla_flat_option_t val)
466 ajla_assert(frame_get_type_of_local(ctx->fp, slot)->tag == TYPE_TAG_flat_option, (file_line, "io_store_flat_option: invalid type %u", (unsigned)frame_get_type_of_local(ctx->fp, slot)->tag));
467 frame_free(ctx->fp, slot);
468 barrier_aliasing();
469 *frame_slot(ctx->fp, slot, ajla_flat_option_t) = val;
470 barrier_aliasing();
473 static void io_store_integer(struct io_ctx *ctx, frame_t slot, array_index_t val)
475 ajla_assert(frame_get_type_of_local(ctx->fp, slot)->tag == type_get_int(INT_DEFAULT_N)->tag, (file_line, "io_store_integer: invalid type %u", (unsigned)frame_get_type_of_local(ctx->fp, slot)->tag));
476 frame_free(ctx->fp, slot);
477 if (likely(index_is_int(val))) {
478 barrier_aliasing();
479 *frame_slot(ctx->fp, slot, int_default_t) = index_to_int(val);
480 barrier_aliasing();
481 } else {
482 struct data *d;
483 d = data_alloc_longint_mayfail(sizeof(int_default_t) * 16, NULL pass_file_line);
484 index_to_mpint(val, &da(d,longint)->mp);
485 frame_set_pointer(ctx->fp, slot, pointer_data(d));
489 #define io_get_positive_number(ctx, fp_slot, slot, result_type_, result_)\
490 do { \
491 array_index_t int_; \
492 result_type_ r_ = 0; /* avoid warning */ \
493 result_ = 0; /* avoid warning */ \
495 test = io_get_array_index(ctx, fp_slot, slot, &int_ pass_file_line);\
496 if (unlikely(test != POINTER_FOLLOW_THUNK_GO)) \
497 break; \
499 if (likely(index_is_int(int_))) { \
500 int_default_t id = index_to_int(int_); \
501 r_ = id; \
502 if ((is_unsigned(result_type_) && unlikely(id < 0)) || \
503 unlikely((int_default_t)r_ != id)) { \
504 index_free(&int_); \
505 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE), true, NULL);\
506 test = POINTER_FOLLOW_THUNK_EXCEPTION; \
507 break; \
509 } else { \
510 bool success; \
511 if (sizeof(result_type_) < sizeof(int_default_t) || \
512 (sizeof(result_type_) == sizeof(int_default_t) && !is_unsigned(result_type_))) {\
513 index_free(&int_); \
514 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE), true, NULL);\
515 test = POINTER_FOLLOW_THUNK_EXCEPTION; \
516 break; \
518 mpint_export_to_variable(index_get_mp(int_), result_type_, r_, success);\
519 if (unlikely(!success)) { \
520 index_free(&int_); \
521 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE), true, NULL);\
522 test = POINTER_FOLLOW_THUNK_EXCEPTION; \
523 break; \
526 test = POINTER_FOLLOW_THUNK_GO; \
527 index_free(&int_); \
528 result_ = r_; \
529 } while (0)
531 #define io_get_number(ctx, slot, slot_type_, result_type_, result_) \
532 do { \
533 slot_type_ int_; \
534 const mpint_t *mp_; \
535 result_type_ r_ = 0; \
536 cat(io_get_,slot_type_)(ctx, slot, &int_, &mp_); \
537 if (likely(!mp_)) { \
538 r_ = int_; \
539 if ((is_unsigned(result_type_) && unlikely(int_ < 0)) ||\
540 unlikely((slot_type_)r_ != int_)) { \
541 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE), true, NULL);\
542 test = POINTER_FOLLOW_THUNK_EXCEPTION; \
543 break; \
545 } else { \
546 bool success; \
547 mpint_export_to_variable(mp_, result_type_, r_, success);\
548 if (unlikely(!success)) { \
549 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE), true, NULL);\
550 test = POINTER_FOLLOW_THUNK_EXCEPTION; \
551 break; \
554 test = POINTER_FOLLOW_THUNK_GO; \
555 result_ = r_; \
556 } while (0)
558 #define io_store_typed_number(ctx, slot, slot_type_, slot_type_idx, result_type_, result_)\
559 do { \
560 result_type_ r_; \
561 ajla_assert(frame_get_type_of_local(ctx->fp, slot)->tag == type_get_int(slot_type_idx)->tag, (file_line, "io_store_typed_number: invalid type %u, expected %u", (unsigned)frame_get_type_of_local(ctx->fp, slot)->tag, (unsigned)type_get_int(slot_type_idx)->tag));\
562 r_ = (result_); \
563 frame_free(ctx->fp, slot); \
564 if (!(is_unsigned(result_type_) && unlikely((slot_type_)(r_) < (slot_type_)zero)) &&\
565 likely((r_) == (result_type_)(slot_type_)(r_))) { \
566 barrier_aliasing(); \
567 *frame_slot(ctx->fp, slot, slot_type_) = (r_); \
568 barrier_aliasing(); \
569 } else { \
570 struct data *d; \
571 d = data_alloc_longint_mayfail(sizeof(result_type_) * 8, &ctx->err pass_file_line);\
572 if (unlikely(!d)) { \
573 io_terminate_with_error(ctx, ctx->err, true, NULL);\
574 test = POINTER_FOLLOW_THUNK_EXCEPTION; \
575 break; \
577 mpint_import_from_variable(&da(d,longint)->mp, result_type_, r_);\
578 frame_set_pointer(ctx->fp, slot, pointer_data(d)); \
580 test = POINTER_FOLLOW_THUNK_GO; \
581 } while (0)
583 #define io_get_time(ctx, slot, result) \
584 io_get_number(ctx, slot, int64_t, int64_t, result)
585 #define io_store_time(ctx, slot, result) \
586 io_store_typed_number(ctx, slot, int64_t, 3, ajla_time_t, result)
588 static void io_get_bytes(struct io_ctx *ctx, frame_t slot)
590 array_onstack_to_bytes(ctx->fp, slot, &ctx->str, &ctx->str_l);
593 static void io_get_bytes2(struct io_ctx *ctx, frame_t slot)
595 array_onstack_to_bytes(ctx->fp, slot, &ctx->str2, &ctx->str2_l);
598 static void free_strings(struct io_ctx *ctx)
600 size_t i;
601 for (i = 0; i < ctx->strs_l; i++) {
602 if (ctx->strs[i])
603 mem_free(ctx->strs[i]);
605 mem_free(ctx->strs);
608 static int_default_t io_get_strings_callback(unsigned char *flat, const struct type attr_unused * type, int_default_t n_elements, pointer_t *ptr, void *ctx_)
610 struct io_ctx *ctx = cast_ptr(struct io_ctx *, ctx_);
611 if (unlikely(flat != NULL)) {
612 internal(file_line, "io_get_strings_callback: flat type");
613 } else {
614 char *str;
615 size_t str_l;
616 array_to_bytes(ptr, &str, &str_l);
617 array_add(char *, &ctx->strs, &ctx->strs_l, str);
619 return n_elements;
622 static void io_get_strings(struct io_ctx *ctx, frame_t slot)
624 array_index_t idx;
625 array_init(char *, &ctx->strs, &ctx->strs_l);
626 index_from_int(&idx, 0);
628 if (!array_onstack_iterate(ctx->fp, slot, &idx, io_get_strings_callback, ctx))
629 internal(file_line, "io_get_strings: array_onstack_iterate failed");
631 index_free(&idx);
634 /* see option unit_type in system.ajla */
635 static void set_uniq_type(struct io_ctx *ctx)
637 frame_t slot = get_output(ctx, 0);
638 const struct type *t = frame_get_type_of_local(ctx->fp, slot);
640 if (likely(t == type_get_fixed(0, 1))) {
641 *frame_slot(ctx->fp, slot, uint8_t) = 0;
642 } else {
643 struct data *d;
644 pointer_t ptr;
645 ajla_error_t err;
646 #if 0
647 d = data_alloc_option_mayfail(&err pass_file_line);
648 if (unlikely(!d)) {
649 ptr = pointer_error(err, ctx->fp, ctx->ip pass_file_line);
650 } else {
651 da(d,option)->pointer = pointer_empty();
652 da(d,option)->option = 0;
653 ptr = pointer_data(d);
655 #else
656 uint8_t val = 0;
657 d = data_alloc_flat_mayfail(t->tag, &val, 1, &err pass_file_line);
658 if (unlikely(!d)) {
659 ptr = pointer_error(err, ctx->fp, ctx->ip pass_file_line);
660 } else {
661 ptr = pointer_data(d);
663 #endif
664 frame_set_pointer(ctx->fp, slot, ptr);
669 static void * attr_fastcall io_exception_make_handler(struct io_ctx *ctx)
671 ajla_error_t e;
672 void *test;
673 ajla_option_t stack_trace;
675 ctx->str = NULL;
677 if (ctx->n_inputs >= 4) {
678 short error_class, error_type;
679 int error_aux;
681 test = io_deep_eval(ctx, "0123", false);
682 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
683 goto ret_test;
685 if (ctx->n_inputs >= 5) {
686 test = io_deep_eval(ctx, "4", false);
687 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
688 goto ret_test;
690 io_get_bytes(ctx, get_input(ctx, 4));
693 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 0), short, error_class);
694 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
695 goto ret_test;
696 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 1), short, error_type);
697 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
698 goto ret_test;
699 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), int, error_aux);
700 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
701 goto ret_test;
703 io_get_option(ctx, get_input(ctx, 3), &stack_trace, NULL);
705 if (unlikely(error_class <= 0) || unlikely(error_class >= EC_N))
706 e = error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION);
707 else if (unlikely(error_type < AJLA_ERROR_BASE) || unlikely(error_type >= AJLA_ERROR_N))
708 e = error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION);
709 else
710 e = error_ajla_aux(error_class, error_type, error_aux);
711 } else {
712 e = error_ajla_aux(get_param(ctx, 0), get_param(ctx, 1), get_param(ctx, 2));
713 stack_trace = get_param(ctx, 3);
716 io_terminate_with_error(ctx, e, stack_trace, ctx->str);
718 test = POINTER_FOLLOW_THUNK_EXCEPTION;
720 ret_test:
721 if (ctx->str)
722 mem_free(ctx->str);
723 return test;
726 #define IOESS_STRING 1
727 #define IOESS_PAYLOAD 2
728 #define IOESS_STACK 3
730 static void *io_exception_string_stack(struct io_ctx *ctx, int mode)
732 void *ex;
733 char *msg;
734 struct thunk *thunk;
735 void *test;
736 struct data *a;
738 ex = frame_pointer_deep_eval(ctx->fp, ctx->ip, get_input(ctx, 0), &thunk);
739 if (unlikely(ex == POINTER_FOLLOW_THUNK_GO)) {
740 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), true, NULL);
741 test = POINTER_FOLLOW_THUNK_EXCEPTION;
742 goto ret_test;
744 if (ex != POINTER_FOLLOW_THUNK_EXCEPTION)
745 return ex;
747 switch (mode) {
748 case IOESS_STRING:
749 msg = thunk_exception_string(thunk, &ctx->err);
750 break;
751 case IOESS_PAYLOAD:
752 msg = thunk_exception_payload(thunk, &ctx->err);
753 break;
754 case IOESS_STACK:
755 msg = stack_trace_string(&thunk->u.exception.tr, &ctx->err);
756 break;
757 default:
758 internal(file_line, "io_exception_string_stack: invalid mode %d", mode);
760 pointer_dereference(pointer_thunk(thunk));
761 if (unlikely(!msg)) {
762 io_terminate_with_error(ctx, ctx->err, true, NULL);
763 test = POINTER_FOLLOW_THUNK_EXCEPTION;
764 goto ret_test;
767 a = array_from_flat_mem(type_get_fixed(0, true), msg, strlen(msg), &ctx->err);
768 mem_free(msg);
769 if (unlikely(!a)) {
770 io_terminate_with_error(ctx, ctx->err, true, NULL);
771 test = POINTER_FOLLOW_THUNK_EXCEPTION;
772 goto ret_test;
775 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_data(a));
777 test = POINTER_FOLLOW_THUNK_GO;
779 ret_test:
780 return test;
783 static void * attr_fastcall io_exception_string_handler(struct io_ctx *ctx)
785 return io_exception_string_stack(ctx, IOESS_STRING);
788 static void * attr_fastcall io_exception_payload_handler(struct io_ctx *ctx)
790 return io_exception_string_stack(ctx, IOESS_PAYLOAD);
793 static void * attr_fastcall io_exception_stack_handler(struct io_ctx *ctx)
795 return io_exception_string_stack(ctx, IOESS_STACK);
798 static void * attr_fastcall io_n_std_handles_handler(struct io_ctx attr_unused *ctx)
800 unsigned n;
802 void *test;
804 test = io_deep_eval(ctx, "0", true);
805 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
806 goto ret_test;
808 n = os_n_std_handles();
810 io_store_typed_number(ctx, get_output(ctx, 1), int_default_t, INT_DEFAULT_N, unsigned, n);
811 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
812 goto ret_test;
814 return POINTER_FOLLOW_THUNK_GO;
816 ret_test:
817 return test;
820 static void * attr_fastcall io_get_std_handle_handler(struct io_ctx attr_unused *ctx)
822 struct resource_handle *h;
823 struct data *d;
824 unsigned p;
826 void *test;
828 test = io_deep_eval(ctx, "01", true);
829 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
830 return test;
832 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 1), unsigned, p);
833 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
834 return test;
836 d = data_alloc_resource_mayfail(sizeof(struct resource_handle), handle_no_close, &ctx->err pass_file_line);
837 if (unlikely(!d))
838 goto ret_thunk;
839 h = da_resource(d);
840 h->fd = os_get_std_handle(p);
842 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
843 return POINTER_FOLLOW_THUNK_GO;
845 ret_thunk:
846 io_terminate_with_error(ctx, ctx->err, true, NULL);
847 return POINTER_FOLLOW_THUNK_GO;
850 static void * attr_fastcall io_get_args_handler(struct io_ctx *ctx)
852 void *test;
853 struct data *a;
854 int i;
856 test = io_deep_eval(ctx, "0", false);
857 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
858 goto ret_test;
860 a = data_alloc_array_pointers_mayfail(n_args_left, n_args_left, &ctx->err pass_file_line);
861 if (unlikely(!a))
862 goto ret_thunk;
863 for (i = 0; i < n_args_left; i++) {
864 da(a,array_pointers)->pointer[i] = pointer_empty();
867 for (i = 0; i < n_args_left; i++) {
868 struct data *b;
869 b = array_from_flat_mem(type_get_fixed(0, true), args_left[i], strlen(args_left[i]), &ctx->err);
870 if (unlikely(!b))
871 goto free_a_ret_thunk;
872 da(a,array_pointers)->pointer[i] = pointer_data(b);
875 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_data(a));
876 return POINTER_FOLLOW_THUNK_GO;
878 free_a_ret_thunk:
879 data_dereference(a);
880 ret_thunk:
881 io_terminate_with_error(ctx, ctx->err, true, NULL);
882 test = POINTER_FOLLOW_THUNK_GO;
883 ret_test:
884 return test;
887 static void * attr_fastcall io_get_environment_handler(struct io_ctx *ctx)
889 void *test;
890 struct data *b;
891 #if !defined(OS_WIN32)
892 size_t i;
893 #endif
895 test = io_deep_eval(ctx, "0", true);
896 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
897 return test;
898 #if defined(OS_WIN32)
899 os_get_environment(&ctx->str, &ctx->str_l);
900 #else
901 array_init(char, &ctx->str, &ctx->str_l);
903 for (i = 0; environ[i]; i++) {
904 const char *e = environ[i];
905 if (unlikely(!strchr(e, '=')))
906 continue;
907 #if defined(OS_OS2) || defined(OS_WIN32)
908 while (*e != '=') {
909 char c = *e++;
910 if (c >= 'a' && c <= 'z')
911 c -= 0x20;
912 array_add(char, &ctx->str, &ctx->str_l, c);
914 #endif
915 array_add_multiple(char, &ctx->str, &ctx->str_l, e, strlen(e) + 1);
917 #endif
918 b = array_from_flat_mem(type_get_fixed(0, true), ctx->str, ctx->str_l, NULL);
919 mem_free(ctx->str);
921 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(b));
923 return POINTER_FOLLOW_THUNK_GO;
926 static void * attr_fastcall io_stream_open_handler(struct io_ctx *ctx)
928 struct resource_handle *h;
929 handle_t p = handle_none;
930 struct data *d;
931 int ajla_flags;
932 int flags;
933 int mode;
934 bool test_symlink;
935 os_stat_t st;
936 void *test;
938 ctx->str = NULL;
939 d = NULL;
940 h = NULL; /* avoid warning */
942 test = io_deep_eval(ctx, "01234", true);
943 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
944 return test;
946 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), int, ajla_flags);
947 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
948 return test;
950 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 4), int, mode);
951 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
952 return test;
954 if (ajla_flags & -IO_Open_Flag_N)
955 goto invalid_op;
957 io_get_dir_handle(ctx, get_input(ctx, 1));
959 io_get_bytes(ctx, get_input(ctx, 2));
961 d = data_alloc_resource_mayfail(sizeof(struct resource_handle), handle_close, &ctx->err pass_file_line);
962 if (unlikely(!d))
963 goto ret_thunk;
965 flags = 0;
966 test_symlink = false;
968 if (ajla_flags & IO_Open_Flag_No_Follow) {
969 ajla_flags &= ~IO_Open_Flag_No_Follow;
970 #if !defined(OS_DOS) && !defined(OS_OS2) && !defined(OS_WIN32)
971 #if defined(O_NOFOLLOW)
972 flags |= O_NOFOLLOW;
973 #else
974 test_symlink = true;
975 #endif
976 #endif
979 if (ctx->code == IO_Stream_Open_Read) {
980 if (ajla_flags)
981 goto invalid_op;
982 flags |= O_RDONLY;
983 } else if (ctx->code == IO_Stream_Open_Write) {
984 if (ajla_flags & (IO_Open_Flag_Read | IO_Open_Flag_Write))
985 goto invalid_op;
986 flags |= O_WRONLY | O_APPEND;
987 if (!(ajla_flags & IO_Open_Flag_Append))
988 flags |= O_TRUNC;
989 } else {
990 switch (ajla_flags & (IO_Open_Flag_Read | IO_Open_Flag_Write)) {
991 case 0x0:
992 goto invalid_op;
993 case IO_Open_Flag_Read:
994 flags |= O_RDONLY; break;
995 case IO_Open_Flag_Write:
996 flags |= O_WRONLY; break;
997 case IO_Open_Flag_Read | IO_Open_Flag_Write:
998 flags |= O_RDWR; break;
999 default:
1000 internal(file_line, "invalid flags %x", ajla_flags);
1004 if (ajla_flags & IO_Open_Flag_Create)
1005 flags |= O_CREAT;
1006 if (ajla_flags & IO_Open_Flag_Must_Create) {
1007 if (ajla_flags & IO_Open_Flag_Create)
1008 flags |= O_EXCL;
1009 else
1010 goto invalid_op;
1013 flags |= O_NONBLOCK;
1015 p = os_open(ctx->dir_handle->fd, ctx->str, flags, mode, &ctx->err);
1016 if (unlikely(!handle_is_valid(p)))
1017 goto ret_thunk;
1019 if (ctx->code == IO_Block_Open || test_symlink) {
1020 if (unlikely(!os_fstat(p, &st, &ctx->err)))
1021 goto ret_thunk;
1023 if (ctx->code == IO_Block_Open) {
1024 if (unlikely(!S_ISREG(st.st_mode))
1025 #ifdef S_ISBLK
1026 && unlikely(!S_ISBLK(st.st_mode))
1027 #endif
1029 goto invalid_op;
1031 if (test_symlink) {
1032 #ifdef S_ISLNK
1033 os_stat_t st2;
1034 if (unlikely(!os_stat(ctx->dir_handle->fd, ctx->str, true, &st2, &ctx->err)))
1035 goto ret_thunk;
1036 if (unlikely(memcmp(&st.st_dev, &st2.st_dev, sizeof st.st_dev)) ||
1037 unlikely(st.st_ino != st2.st_ino)) {
1038 if (S_ISLNK(st2.st_mode)) {
1039 ctx->err = error_ajla_aux(EC_SYSCALL, AJLA_ERROR_SYSTEM, SYSTEM_ERROR_ELOOP);
1040 goto ret_thunk;
1042 goto invalid_op;
1044 #endif
1047 h = da_resource(d);
1048 h->fd = p;
1049 h->nonblocking = true;
1051 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
1053 mem_free(ctx->str);
1054 return POINTER_FOLLOW_THUNK_GO;
1056 invalid_op:
1057 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION);
1058 ret_thunk:
1059 if (handle_is_valid(p))
1060 os_close(p);
1061 if (d)
1062 data_free_r1(d);
1063 io_terminate_with_error(ctx, ctx->err, true, NULL);
1064 if (ctx->str)
1065 mem_free(ctx->str);
1066 return POINTER_FOLLOW_THUNK_GO;
1069 static void * attr_fastcall io_stream_read_handler(struct io_ctx *ctx)
1071 struct data *a;
1072 array_index_t idx;
1073 int_default_t this_step;
1074 ssize_t rd;
1075 struct data *result = NULL;
1076 void *test;
1078 test = io_deep_eval(ctx, ctx->code != IO_Block_Read ? "012" : "0123", true);
1079 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1080 goto ret_test;
1082 io_get_handle(ctx, get_input(ctx, 1));
1084 test = io_get_array_index(ctx, ctx->fp, get_input(ctx, 2), &idx pass_file_line);
1085 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1086 goto ret_test;
1088 if (ctx->code == IO_Block_Read) {
1089 io_get_number(ctx, get_input(ctx, 3), int64_t, os_off_t, ctx->position);
1090 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1091 goto idx_free_ret_test;
1092 if (unlikely(ctx->position < 0)) {
1093 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_NEGATIVE_INDEX);
1094 goto ret_thunk;
1098 do {
1099 if (likely(index_is_int(idx))) {
1100 this_step = index_to_int(idx);
1101 } else {
1102 this_step = signed_maximum(int_default_t);
1104 if (unlikely(this_step > signed_maximum(int) + zero))
1105 this_step = (int_default_t)signed_maximum(int);
1107 try_alloc_again:
1108 a = data_alloc_array_flat_mayfail(type_get_fixed(0, true), this_step, 0, false, &ctx->err pass_file_line);
1109 if (unlikely(!a)) {
1110 this_step >>= 1;
1111 if (this_step)
1112 goto try_alloc_again;
1113 goto ret_thunk;
1116 if (ctx->code != IO_Block_Read) {
1117 if (!ctx->handle->nonblocking) {
1118 if (!iomux_test_handle(ctx->handle->fd, false))
1119 goto block;
1121 rd = os_read(ctx->handle->fd, data_untag(da_array_flat(a)), this_step, &ctx->err);
1122 if (unlikely(rd == OS_RW_WOULDBLOCK)) {
1123 block:
1124 data_free_r1(a);
1125 if (result)
1126 break;
1127 io_block_on_handle(ctx, false, false);
1128 goto ret_exit;
1130 } else {
1131 rd = os_pread(ctx->handle->fd, data_untag(da_array_flat(a)), this_step, ctx->position, &ctx->err);
1134 if (unlikely(rd == OS_RW_ERROR)) {
1135 data_free_r1(a);
1136 if (result)
1137 break;
1138 goto ret_thunk;
1141 if (ctx->code == IO_Block_Read) {
1142 ctx->position += rd;
1144 da(a,array_flat)->n_used_entries = rd;
1146 index_sub_int(&idx, rd);
1148 if (likely(!result)) {
1149 result = a;
1150 } else {
1151 result = array_join(result, a, &ctx->err);
1152 if (!result)
1153 goto ret_thunk;
1156 } while (unlikely(rd != 0) && unlikely(index_ge_int(idx, 1)) && ctx->code == IO_Block_Read);
1158 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(result));
1160 index_free(&idx);
1162 return POINTER_FOLLOW_THUNK_GO;
1164 ret_exit:
1165 test = POINTER_FOLLOW_THUNK_EXIT;
1166 goto idx_free_ret_test;
1168 ret_thunk:
1169 io_terminate_with_error(ctx, ctx->err, true, NULL);
1170 test = POINTER_FOLLOW_THUNK_GO;
1172 idx_free_ret_test:
1173 if (result)
1174 data_dereference(result);
1175 index_free(&idx);
1176 ret_test:
1177 return test;
1180 static int_default_t io_write_callback(unsigned char *flat, const struct type attr_unused * type, int_default_t n_elements, pointer_t *ptr, void *ctx_)
1182 struct io_ctx *ctx = cast_ptr(struct io_ctx *, ctx_);
1183 if (tick_elapsed(&ctx->ts) && ctx->status == IO_STATUS_PROGRESS) {
1184 ctx->status = IO_STATUS_TIMEOUT;
1185 return 0;
1187 if (flat) {
1188 ssize_t rd;
1190 if (unlikely(n_elements > signed_maximum(int) + zero))
1191 n_elements = signed_maximum(int);
1193 if (ctx->code != IO_Block_Write) {
1194 if (!ctx->handle->nonblocking) {
1195 if (!iomux_test_handle(ctx->handle->fd, true))
1196 goto block;
1197 if (n_elements > PIPE_BUF + zero)
1198 n_elements = PIPE_BUF + zero;
1200 rd = os_write(ctx->handle->fd, data_untag(flat), n_elements, &ctx->err);
1201 if (unlikely(rd == OS_RW_WOULDBLOCK)) {
1202 block:
1203 if (ctx->status == IO_STATUS_STARTED) {
1204 io_block_on_handle(ctx, true, false);
1205 ctx->status = IO_STATUS_BLOCKED;
1207 return 0;
1209 } else {
1210 rd = os_pwrite(ctx->handle->fd, data_untag(flat), n_elements, ctx->position, &ctx->err);
1213 if (unlikely(rd == OS_RW_ERROR)) {
1214 if (ctx->status == IO_STATUS_STARTED)
1215 ctx->status = IO_STATUS_IOERR;
1216 return 0;
1218 if (ctx->code == IO_Block_Write) {
1219 ctx->position += rd;
1221 ctx->status = IO_STATUS_PROGRESS;
1222 return rd;
1223 } else {
1224 ajla_assert_lo(pointer_is_thunk(*ptr), (file_line, "io_write_callback: pointer is not thunk (tag %u)", da_tag(pointer_get_data(*ptr))));
1225 ctx->status = IO_STATUS_THUNK;
1226 ctx->array_ptr = ptr;
1227 return 0;
1231 static void * attr_fastcall io_stream_write_handler(struct io_ctx *ctx)
1233 array_index_t idx;
1234 void *test;
1236 test = io_deep_eval(ctx, ctx->code != IO_Block_Write ? "01" : "013", true);
1237 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1238 goto ret_test;
1240 io_get_handle(ctx, get_input(ctx, 1));
1242 again:
1243 index_from_int(&idx, 0);
1245 if (ctx->code == IO_Block_Write) {
1246 io_get_number(ctx, get_input(ctx, 3), int64_t, os_off_t, ctx->position);
1247 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1248 goto idx_free_ret_test;
1249 if (unlikely(ctx->position < 0)) {
1250 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_NEGATIVE_INDEX);
1251 goto ret_thunk;
1255 ctx->status = IO_STATUS_STARTED;
1256 tick_start(&ctx->ts);
1257 if (array_onstack_iterate(ctx->fp, get_input(ctx, 2), &idx, io_write_callback, ctx))
1258 goto free_index_go;
1260 switch (ctx->status) {
1261 case IO_STATUS_PROGRESS:
1262 /* IO_STATUS_PROGRESS happens if size is trimmed to PIPE_BUF or if write returns less bytes than supplied */
1263 case IO_STATUS_TIMEOUT: {
1264 goto free_index_go;
1266 case IO_STATUS_IOERR: {
1267 goto ret_thunk;
1269 case IO_STATUS_THUNK: {
1270 struct data attr_unused *data;
1271 if (index_ge_int(idx, 1))
1272 goto free_index_go;
1273 pointer_follow(ctx->array_ptr, false, data, PF_WAIT, ctx->fp, ctx->ip,
1274 test = ex_;
1275 goto idx_free_ret_test,
1277 thunk_reference(thunk_);
1278 io_terminate_with_thunk(ctx, thunk_);
1279 goto free_index_go;
1281 index_free(&idx);
1282 goto again;
1284 case IO_STATUS_BLOCKED: {
1285 test = POINTER_FOLLOW_THUNK_EXIT;
1286 goto idx_free_ret_test;
1288 default:
1289 internal(file_line, "io_stream_write_handler: invalid status %u", ctx->status);
1292 ret_thunk:
1293 io_terminate_with_error(ctx, ctx->err, true, NULL);
1294 free_index_go:
1295 test = POINTER_FOLLOW_THUNK_GO;
1296 io_store_integer(ctx, get_output(ctx, 1), idx);
1297 idx_free_ret_test:
1298 index_free(&idx);
1299 ret_test:
1300 return test;
1303 static void * attr_fastcall io_lseek_handler(struct io_ctx *ctx)
1305 void *test;
1306 unsigned mode;
1308 test = io_deep_eval(ctx, "012", true);
1309 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1310 goto ret_test;
1312 io_get_handle(ctx, get_input(ctx, 1));
1314 io_get_number(ctx, get_input(ctx, 2), int64_t, os_off_t, ctx->position);
1315 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1316 goto ret_test;
1318 mode = get_param(ctx, 0);
1320 if (unlikely(!os_lseek(ctx->handle->fd, mode, ctx->position, &ctx->position, &ctx->err)))
1321 goto ret_thunk;
1323 io_store_typed_number(ctx, get_output(ctx, 1), int64_t, 3, os_off_t, ctx->position);
1324 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1325 goto ret_test;
1327 return POINTER_FOLLOW_THUNK_GO;
1329 ret_thunk:
1330 io_terminate_with_error(ctx, ctx->err, true, NULL);
1331 test = POINTER_FOLLOW_THUNK_GO;
1332 ret_test:
1333 return test;
1336 static void * attr_fastcall io_ftruncate_handler(struct io_ctx *ctx)
1338 void *test;
1340 test = io_deep_eval(ctx, "012", true);
1341 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1342 goto ret_test;
1344 io_get_handle(ctx, get_input(ctx, 1));
1346 io_get_number(ctx, get_input(ctx, 2), int64_t, os_off_t, ctx->position);
1347 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1348 goto ret_test;
1349 if (unlikely(ctx->position < 0)) {
1350 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_NEGATIVE_INDEX);
1351 goto ret_thunk;
1354 if (unlikely(!os_ftruncate(ctx->handle->fd, ctx->position, &ctx->err)))
1355 goto ret_thunk;
1357 return POINTER_FOLLOW_THUNK_GO;
1359 ret_thunk:
1360 io_terminate_with_error(ctx, ctx->err, true, NULL);
1361 test = POINTER_FOLLOW_THUNK_GO;
1362 ret_test:
1363 return test;
1366 static void * attr_fastcall io_fallocate_handler(struct io_ctx *ctx)
1368 void *test;
1370 test = io_deep_eval(ctx, "0123", true);
1371 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1372 goto ret_test;
1374 io_get_handle(ctx, get_input(ctx, 1));
1376 io_get_number(ctx, get_input(ctx, 2), int64_t, os_off_t, ctx->position);
1377 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1378 goto ret_test;
1379 if (unlikely(ctx->position < 0)) {
1380 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_NEGATIVE_INDEX);
1381 goto ret_thunk;
1384 io_get_number(ctx, get_input(ctx, 3), int64_t, os_off_t, ctx->length);
1385 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1386 goto ret_test;
1387 if (unlikely(ctx->length < 0)) {
1388 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_NEGATIVE_INDEX);
1389 goto ret_thunk;
1392 if (unlikely(!os_fallocate(ctx->handle->fd, ctx->position, ctx->length, &ctx->err)))
1393 goto ret_thunk;
1395 return POINTER_FOLLOW_THUNK_GO;
1397 ret_thunk:
1398 io_terminate_with_error(ctx, ctx->err, true, NULL);
1399 test = POINTER_FOLLOW_THUNK_GO;
1400 ret_test:
1401 return test;
1404 static void * attr_fastcall io_fclone_range_handler(struct io_ctx *ctx)
1406 void *test;
1408 test = io_deep_eval(ctx, "012345", true);
1409 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1410 goto ret_test;
1412 io_get_handle(ctx, get_input(ctx, 1));
1413 ctx->handle2 = ctx->handle;
1415 io_get_number(ctx, get_input(ctx, 2), int64_t, os_off_t, ctx->position);
1416 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1417 goto ret_test;
1418 if (unlikely(ctx->position < 0)) {
1419 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_NEGATIVE_INDEX);
1420 goto ret_thunk;
1422 ctx->position2 = ctx->position;
1424 io_get_handle(ctx, get_input(ctx, 3));
1426 io_get_number(ctx, get_input(ctx, 4), int64_t, os_off_t, ctx->position);
1427 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1428 goto ret_test;
1429 if (unlikely(ctx->position < 0)) {
1430 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_NEGATIVE_INDEX);
1431 goto ret_thunk;
1434 io_get_number(ctx, get_input(ctx, 4), int64_t, os_off_t, ctx->length);
1435 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1436 goto ret_test;
1437 if (unlikely(ctx->length < 0)) {
1438 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_NEGATIVE_INDEX);
1439 goto ret_thunk;
1442 if (unlikely(!os_clone_range(ctx->handle2->fd, ctx->position2, ctx->handle->fd, ctx->position, ctx->length, &ctx->err)))
1443 goto ret_thunk;
1444 return POINTER_FOLLOW_THUNK_GO;
1446 ret_thunk:
1447 io_terminate_with_error(ctx, ctx->err, true, NULL);
1448 test = POINTER_FOLLOW_THUNK_GO;
1449 ret_test:
1450 return test;
1453 static void * attr_fastcall io_fsync_handler(struct io_ctx *ctx)
1455 void *test;
1457 test = io_deep_eval(ctx, "01", true);
1458 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1459 goto ret_test;
1461 io_get_handle(ctx, get_input(ctx, 1));
1463 if (unlikely(!os_fsync(ctx->handle->fd, get_param(ctx, 0), &ctx->err)))
1464 goto ret_thunk;
1466 return POINTER_FOLLOW_THUNK_GO;
1468 ret_thunk:
1469 io_terminate_with_error(ctx, ctx->err, true, NULL);
1470 test = POINTER_FOLLOW_THUNK_GO;
1471 ret_test:
1472 return test;
1475 static void * attr_fastcall io_sync_handler(struct io_ctx *ctx)
1477 void *test;
1479 test = io_deep_eval(ctx, "0", true);
1480 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1481 goto ret_test;
1483 if (unlikely(!os_fsync(handle_none, 3, &ctx->err)))
1484 goto ret_thunk;
1486 return POINTER_FOLLOW_THUNK_GO;
1488 ret_thunk:
1489 io_terminate_with_error(ctx, ctx->err, true, NULL);
1490 test = POINTER_FOLLOW_THUNK_GO;
1491 ret_test:
1492 return test;
1495 static void * attr_fastcall io_read_console_packet_handler(struct io_ctx *ctx)
1497 struct data *a;
1498 ssize_t rd;
1499 void *test;
1500 test = io_deep_eval(ctx, "01", true);
1501 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1502 goto ret_test;
1504 io_get_handle(ctx, get_input(ctx, 1));
1506 a = data_alloc_array_flat_mayfail(type_get_fixed(2, false), CONSOLE_PACKET_ENTRIES, CONSOLE_PACKET_ENTRIES, false, &ctx->err pass_file_line);
1507 if (unlikely(!a))
1508 goto ret_thunk;
1510 rd = os_read_console_packet(ctx->handle->fd, data_untag(da_array_flat(a)), &ctx->err);
1511 if (rd == OS_RW_WOULDBLOCK) {
1512 data_free_r1(a);
1513 io_block_on_handle(ctx, false, true);
1514 test = POINTER_FOLLOW_THUNK_EXIT;
1515 goto ret_test;
1517 if (unlikely(rd == OS_RW_ERROR)) {
1518 data_free_r1(a);
1519 goto ret_thunk;
1521 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(a));
1522 return POINTER_FOLLOW_THUNK_GO;
1524 ret_thunk:
1525 io_terminate_with_error(ctx, ctx->err, true, NULL);
1526 test = POINTER_FOLLOW_THUNK_GO;
1527 ret_test:
1528 return test;
1531 static void * attr_fastcall io_write_console_packet_handler(struct io_ctx *ctx)
1533 void *test;
1535 test = io_deep_eval(ctx, "012", true);
1536 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1537 goto ret_test;
1539 io_get_handle(ctx, get_input(ctx, 1));
1541 io_get_bytes(ctx, get_input(ctx, 2));
1543 if (unlikely(!os_write_console_packet(ctx->handle->fd, cast_ptr(struct console_write_packet *, ctx->str), &ctx->err))) {
1544 io_terminate_with_error(ctx, ctx->err, true, NULL);
1545 test = POINTER_FOLLOW_THUNK_GO;
1546 goto free_ret_test;
1549 free_ret_test:
1550 mem_free(ctx->str);
1551 ret_test:
1552 return test;
1555 static void * attr_fastcall io_pipe_handler(struct io_ctx *ctx)
1557 struct data *d1 = NULL, *d2 = NULL;
1558 struct resource_handle *h1, *h2;
1559 void *test;
1560 handle_t result[2];
1562 test = io_deep_eval(ctx, "0", true);
1563 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1564 return test;
1566 d1 = data_alloc_resource_mayfail(sizeof(struct resource_handle), handle_close, &ctx->err pass_file_line);
1567 if (unlikely(!d1))
1568 goto ret_thunk;
1570 d2 = data_alloc_resource_mayfail(sizeof(struct resource_handle), handle_close, &ctx->err pass_file_line);
1571 if (unlikely(!d2))
1572 goto ret_thunk;
1574 if (unlikely(!os_pipe(result, 3, &ctx->err)))
1575 goto ret_thunk;
1577 h1 = da_resource(d1);
1578 h1->fd = result[0];
1579 h1->nonblocking = true;
1581 h2 = da_resource(d2);
1582 h2->fd = result[1];
1583 h2->nonblocking = true;
1585 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d1));
1586 frame_set_pointer(ctx->fp, get_output(ctx, 2), pointer_data(d2));
1588 return POINTER_FOLLOW_THUNK_GO;
1590 ret_thunk:
1591 if (d1)
1592 data_free_r1(d1);
1593 if (d2)
1594 data_free_r1(d2);
1595 io_terminate_with_error(ctx, ctx->err, true, NULL);
1596 return POINTER_FOLLOW_THUNK_GO;
1599 static void * attr_fastcall io_root_dir_handler(struct io_ctx *ctx)
1601 struct resource_dir_handle *h;
1602 dir_handle_t p;
1603 frame_t fn;
1604 struct data *d;
1605 void *test;
1607 d = NULL;
1608 h = NULL;
1610 test = io_deep_eval(ctx, "0", false);
1611 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1612 return test;
1614 d = data_alloc_resource_mayfail(sizeof(struct resource_dir_handle), dir_handle_close, &ctx->err pass_file_line);
1615 if (unlikely(!d))
1616 goto ret_thunk;
1618 fn = get_param(ctx, 0);
1619 switch (fn) {
1620 case 1:
1621 p = os_dir_root(&ctx->err);
1622 break;
1623 case 2:
1624 p = os_dir_cwd(&ctx->err);
1625 break;
1626 case 3:
1627 p = os_dir_open(os_cwd, builtin_lib_path, 0, &ctx->err);
1628 break;
1629 case 4:
1630 p = os_dir_open(dir_none, os_get_path_to_exe(), 0, &ctx->err);
1631 break;
1632 case 5:
1633 p = dir_none;
1634 goto set_p;
1635 default:
1636 internal(file_line, "io_root_dir_handler: invalid function code %u", (unsigned)fn);
1638 if (unlikely(!dir_handle_is_valid(p)))
1639 goto ret_thunk;
1640 set_p:
1641 h = da_resource(d);
1642 h->fd = p;
1644 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_data(d));
1646 return POINTER_FOLLOW_THUNK_GO;
1648 ret_thunk:
1649 if (d)
1650 data_free_r1(d);
1651 io_terminate_with_error(ctx, ctx->err, true, NULL);
1652 return POINTER_FOLLOW_THUNK_GO;
1655 static void get_lib_path(void)
1657 mutex_lock(&lib_path_mutex);
1658 if (unlikely(!lib_path)) {
1659 const char *e;
1661 array_init(char, &lib_path, &lib_path_len);
1662 array_add_multiple(char, &lib_path, &lib_path_len, builtin_lib_path, strlen(builtin_lib_path));
1663 array_add_multiple(char, &lib_path, &lib_path_len, "/stdlib", strlen("/stdlib") + 1);
1665 #ifdef AJLA_FRAMEWORKS
1666 if (os_path_is_absolute(AJLA_FRAMEWORKS)) {
1667 array_add_multiple(char, &lib_path, &lib_path_len, AJLA_FRAMEWORKS, strlen(AJLA_FRAMEWORKS) + 1);
1668 } else
1669 #endif
1671 array_add_multiple(char, &lib_path, &lib_path_len, builtin_lib_path, strlen(builtin_lib_path));
1672 array_add_multiple(char, &lib_path, &lib_path_len, "/fw", strlen("/fw") + 1);
1675 e = getenv("AJLA_LIBPATH");
1676 if (e) {
1677 size_t l;
1678 next_component:
1679 for (l = 0; e[l] && !os_is_env_separator(e[l]); l++) ;
1680 if (l) {
1681 char *dup = str_dup(e, l, NULL);
1682 if (os_path_is_absolute(dup)) {
1683 array_add_multiple(char, &lib_path, &lib_path_len, e, l);
1684 array_add(char, &lib_path, &lib_path_len, 0);
1686 mem_free(dup);
1688 e += l;
1689 if (*e) {
1690 e++;
1691 goto next_component;
1695 if (os_path_is_absolute("/")) {
1696 array_add_multiple(char, &lib_path, &lib_path_len, "/", 2);
1697 } else {
1698 #ifdef NO_DIR_HANDLES
1699 char *root = os_dir_root(NULL);
1700 array_add_multiple(char, &lib_path, &lib_path_len, root, strlen(root) + 1);
1701 mem_free(root);
1702 #else
1703 fatal("get_lib_path: NO_DIR_HANDLES is not set");
1704 #endif
1706 array_finish(char, &lib_path, &lib_path_len);
1707 #if 0
1709 size_t i;
1710 for (i = 0; i < lib_path_len; i += strlen(lib_path + i) + 1)
1711 debug("libpath: '%s'", lib_path + i);
1713 #endif
1715 mutex_unlock(&lib_path_mutex);
1718 static void * attr_fastcall io_lib_path_handler(struct io_ctx *ctx)
1720 struct data *b;
1722 get_lib_path();
1724 b = array_from_flat_mem(type_get_fixed(0, true), lib_path, lib_path_len, &ctx->err);
1725 if (unlikely(!b))
1726 goto ret_thunk;
1728 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_data(b));
1730 return POINTER_FOLLOW_THUNK_GO;
1732 ret_thunk:
1733 io_terminate_with_error(ctx, ctx->err, true, NULL);
1734 return POINTER_FOLLOW_THUNK_GO;
1737 static void * attr_fastcall io_open_dir_handler(struct io_ctx *ctx)
1739 struct resource_dir_handle *h;
1740 dir_handle_t p;
1741 struct data *d;
1742 void *test;
1743 int ajla_flags;
1744 int flags;
1745 bool test_symlink;
1747 ctx->str = NULL;
1748 d = NULL;
1749 h = NULL;
1751 test = io_deep_eval(ctx, "0123", true);
1752 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1753 return test;
1755 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), int_default_t, ajla_flags);
1756 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1757 return test;
1759 if (ajla_flags & -IO_Open_Flag_N)
1760 goto invalid_op;
1762 io_get_dir_handle(ctx, get_input(ctx, 1));
1764 io_get_bytes(ctx, get_input(ctx, 2));
1766 d = data_alloc_resource_mayfail(sizeof(struct resource_dir_handle), dir_handle_close, &ctx->err pass_file_line);
1767 if (unlikely(!d))
1768 goto ret_thunk;
1770 flags = 0;
1771 test_symlink = false;
1773 if (ajla_flags & IO_Open_Flag_No_Follow) {
1774 ajla_flags &= ~IO_Open_Flag_No_Follow;
1775 #if !defined(OS_DOS) && !defined(OS_OS2) && !defined(OS_WIN32)
1776 #if defined(O_NOFOLLOW)
1777 flags |= O_NOFOLLOW;
1778 #else
1779 test_symlink = true;
1780 #endif
1781 #endif
1784 if (unlikely(ajla_flags != 0))
1785 goto invalid_op;
1787 p = os_dir_open(ctx->dir_handle->fd, ctx->str, flags, &ctx->err);
1788 if (unlikely(!dir_handle_is_valid(p)))
1789 goto ret_thunk;
1791 if (test_symlink) {
1792 #ifdef S_ISLNK
1793 os_stat_t st;
1794 os_stat_t st2;
1795 if (unlikely(!os_stat(p, ".", true, &st, &ctx->err)))
1796 goto ret_thunk;
1797 if (unlikely(!os_stat(ctx->dir_handle->fd, ctx->str, true, &st2, &ctx->err)))
1798 goto ret_thunk;
1799 if (unlikely(memcmp(&st.st_dev, &st2.st_dev, sizeof st.st_dev)) ||
1800 unlikely(st.st_ino != st2.st_ino)) {
1801 if (S_ISLNK(st2.st_mode)) {
1802 ctx->err = error_ajla_aux(EC_SYSCALL, AJLA_ERROR_SYSTEM, SYSTEM_ERROR_ELOOP);
1803 goto ret_thunk;
1805 goto invalid_op;
1807 #endif
1810 h = da_resource(d);
1811 h->fd = p;
1813 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
1815 mem_free(ctx->str);
1816 return POINTER_FOLLOW_THUNK_GO;
1818 invalid_op:
1819 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION);
1820 ret_thunk:
1821 if (d)
1822 data_free_r1(d);
1823 io_terminate_with_error(ctx, ctx->err, true, NULL);
1824 if (ctx->str)
1825 mem_free(ctx->str);
1826 return POINTER_FOLLOW_THUNK_GO;
1829 static int name_cmp(const void *p1, const void *p2)
1831 int diff;
1832 unsigned char *c1 = *cast_ptr(unsigned char **, p1);
1833 unsigned char *c2 = *cast_ptr(unsigned char **, p2);
1834 next:
1835 diff = *c1 - *c2;
1836 if (likely(diff) || !*c1) return diff;
1837 c1++;
1838 c2++;
1839 goto next;
1842 static void * attr_fastcall io_read_dir_handler(struct io_ctx *ctx)
1844 void *test;
1845 char **files;
1846 size_t n_files;
1847 struct data *a;
1848 size_t i;
1850 test = io_deep_eval(ctx, "01", true);
1851 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1852 return test;
1854 io_get_dir_handle(ctx, get_input(ctx, 1));
1856 if (unlikely(!dir_handle_is_valid(ctx->dir_handle->fd))) {
1857 fatal_mayfail(error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), &ctx->err, "dummy dir handle");
1858 goto ret_error;
1861 if (unlikely(!os_dir_read(ctx->dir_handle->fd, &files, &n_files, &ctx->err)))
1862 goto ret_error;
1864 qsort(files, n_files, sizeof(char *), name_cmp);
1866 a = data_alloc_array_pointers_mayfail(n_files, n_files, &ctx->err pass_file_line);
1867 if (unlikely(!a)) {
1868 goto free_dir_ret_error;
1871 for (i = 0; i < n_files; i++) {
1872 da(a,array_pointers)->pointer[i] = pointer_empty();
1875 for (i = 0; i < n_files; i++) {
1876 struct data *b;
1877 b = array_from_flat_mem(type_get_fixed(0, true), files[i], strlen(files[i]), &ctx->err);
1878 if (unlikely(!b))
1879 goto free_a_ret_error;
1880 da(a,array_pointers)->pointer[i] = pointer_data(b);
1883 os_dir_free(files, n_files);
1885 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(a));
1887 return POINTER_FOLLOW_THUNK_GO;
1889 free_a_ret_error:
1890 data_dereference(a);
1891 free_dir_ret_error:
1892 os_dir_free(files, n_files);
1893 ret_error:
1894 io_terminate_with_error(ctx, ctx->err, true, NULL);
1895 return POINTER_FOLLOW_THUNK_GO;
1898 static void * attr_fastcall io_dir_path_handler(struct io_ctx *ctx)
1900 void *test;
1901 char *lnk;
1902 struct data *a;
1904 test = io_deep_eval(ctx, "01", true);
1905 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1906 goto ret_test;
1908 io_get_dir_handle(ctx, get_input(ctx, 1));
1910 if (unlikely(!dir_handle_is_valid(ctx->dir_handle->fd))) {
1911 fatal_mayfail(error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), &ctx->err, "dummy dir handle");
1912 io_terminate_with_error(ctx, ctx->err, true, NULL);
1913 test = POINTER_FOLLOW_THUNK_EXCEPTION;
1914 goto ret_test;
1917 lnk = os_dir_path(ctx->dir_handle->fd, &ctx->err);
1918 if (unlikely(!lnk)) {
1919 io_terminate_with_error(ctx, ctx->err, true, NULL);
1920 test = POINTER_FOLLOW_THUNK_EXCEPTION;
1921 goto ret_test;
1924 a = array_from_flat_mem(type_get_fixed(0, true), lnk, strlen(lnk), &ctx->err);
1925 mem_free(lnk);
1926 if (unlikely(!a)) {
1927 io_terminate_with_error(ctx, ctx->err, true, NULL);
1928 test = POINTER_FOLLOW_THUNK_EXCEPTION;
1929 goto ret_test;
1932 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(a));
1934 test = POINTER_FOLLOW_THUNK_GO;
1936 ret_test:
1937 return test;
1940 static void * attr_fastcall io_dmonitor_prepare_handler(struct io_ctx *ctx)
1942 struct resource_notify_handle *h;
1943 struct data *d;
1944 void *test;
1946 test = io_deep_eval(ctx, "01", true);
1947 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1948 goto ret_test;
1950 io_get_dir_handle(ctx, get_input(ctx, 1));
1952 if (unlikely(!dir_handle_is_valid(ctx->dir_handle->fd))) {
1953 fatal_mayfail(error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), &ctx->err, "dummy dir handle");
1954 goto ret_thunk;
1957 d = data_alloc_resource_mayfail(sizeof(struct resource_notify_handle), notify_handle_close, &ctx->err pass_file_line);
1958 if (unlikely(!d))
1959 goto ret_thunk;
1960 h = da_resource(d);
1962 if (unlikely(!iomux_directory_handle_alloc(ctx->dir_handle->fd, &h->id, &h->seq, &ctx->err))) {
1963 data_free_r1(d);
1964 goto ret_thunk;
1967 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
1969 return POINTER_FOLLOW_THUNK_GO;
1971 ret_test:
1972 return test;
1974 ret_thunk:
1975 io_terminate_with_error(ctx, ctx->err, true, NULL);
1976 return POINTER_FOLLOW_THUNK_GO;
1979 static void * attr_fastcall io_dmonitor_wait_handler(struct io_ctx *ctx)
1981 pointer_t ptr;
1982 struct data *d;
1983 struct resource_notify_handle *h;
1984 struct execution_control *ex;
1985 void *test;
1987 test = io_deep_eval(ctx, "01", true);
1988 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
1989 goto ret_test;
1991 ptr = *frame_pointer(ctx->fp, get_input(ctx, 1));
1992 ajla_assert_lo(!pointer_is_thunk(ptr), (file_line, "io_dmonitor_wait_handler: pointer is thunk"));
1993 d = pointer_get_data(ptr);
1995 h = da_resource(d);
1996 ex = frame_execution_control(ctx->fp);
1997 /*debug("testing wait");*/
1998 if (!iomux_directory_handle_wait(h->id, h->seq, &ex->wait[0].mutex_to_lock, &ex->wait[0].wait_entry)) {
1999 /*debug("waiting");*/
2000 pointer_follow_wait(ctx->fp, ctx->ip);
2001 return POINTER_FOLLOW_THUNK_EXIT;
2003 /*debug("early exit");*/
2005 return POINTER_FOLLOW_THUNK_GO;
2007 ret_test:
2008 return test;
2011 static void *io_stat(struct io_ctx *ctx, os_stat_t *st, unsigned stat_select)
2013 struct data *o;
2014 int pos;
2015 int64_t val;
2016 int popc = pop_count(stat_select);
2018 o = data_alloc_array_flat_mayfail(type_get_int(3), popc, popc, false, &ctx->err pass_file_line);
2019 if (unlikely(!o)) {
2020 io_terminate_with_error(ctx, ctx->err, true, NULL);
2021 return POINTER_FOLLOW_THUNK_EXCEPTION;
2024 pos = 0;
2025 while (stat_select) {
2026 unsigned bit = 1U << low_bit(stat_select);
2027 stat_select &= ~bit;
2028 switch (bit) {
2029 case IO_Stat_Flag_DevMajor:
2030 val = os_dev_t_major(st->st_dev);
2031 break;
2032 case IO_Stat_Flag_DevMinor:
2033 val = os_dev_t_minor(st->st_dev);
2034 break;
2035 case IO_Stat_Flag_Inode:
2036 val = st->st_ino;
2037 break;
2038 case IO_Stat_Flag_Type:
2039 if (S_ISREG(st->st_mode)) { val = IO_Stat_Type_File; break; }
2040 if (S_ISDIR(st->st_mode)) { val = IO_Stat_Type_Directory; break; }
2041 #ifdef S_ISLNK
2042 if (S_ISLNK(st->st_mode)) { val = IO_Stat_Type_Link; break; }
2043 #endif
2044 if (S_ISFIFO(st->st_mode)) { val = IO_Stat_Type_Pipe; break; }
2045 if (S_ISCHR(st->st_mode)) { val = IO_Stat_Type_CharDev; break; }
2046 #ifdef S_ISBLK
2047 if (S_ISBLK(st->st_mode)) { val = IO_Stat_Type_BlockDev; break; }
2048 #endif
2049 #ifdef S_ISSOCK
2050 if (S_ISSOCK(st->st_mode)) { val = IO_Stat_Type_Socket; break; }
2051 #endif
2052 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_SYSTEM_RETURNED_INVALID_DATA), true, NULL);
2053 return POINTER_FOLLOW_THUNK_EXCEPTION;
2054 case IO_Stat_Flag_Mode:
2055 val = st->st_mode & 07777;
2056 break;
2057 case IO_Stat_Flag_NLink:
2058 val = st->st_nlink;
2059 break;
2060 case IO_Stat_Flag_UID:
2061 val = st->st_uid;
2062 break;
2063 case IO_Stat_Flag_GID:
2064 val = st->st_gid;
2065 break;
2066 case IO_Stat_Flag_RDevMajor:
2067 val = os_dev_t_major(st->st_rdev);
2068 break;
2069 case IO_Stat_Flag_RDevMinor:
2070 val = os_dev_t_minor(st->st_rdev);
2071 break;
2072 case IO_Stat_Flag_Size:
2073 val = st->st_size;
2074 break;
2075 case IO_Stat_Flag_OptimalIOSize:
2076 val = st->st_blksize;
2077 break;
2078 case IO_Stat_Flag_Allocated:
2079 #if defined(__DJGPP__)
2080 val = st->st_size;
2081 #else
2082 val = (uint64_t)st->st_blocks * 512;
2083 #endif
2084 break;
2085 case IO_Stat_Flag_ATime:
2086 #if defined(HAVE_STRUCT_STAT_ST_ATIM)
2087 val = os_timespec_to_ajla_time(&st->st_atim);
2088 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
2089 val = os_timespec_to_ajla_time(&st->st_atimespec);
2090 #else
2091 val = os_time_t_to_ajla_time(st->st_atime);
2092 #endif
2093 break;
2094 case IO_Stat_Flag_MTime:
2095 #if defined(HAVE_STRUCT_STAT_ST_ATIM)
2096 val = os_timespec_to_ajla_time(&st->st_mtim);
2097 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
2098 val = os_timespec_to_ajla_time(&st->st_mtimespec);
2099 #else
2100 val = os_time_t_to_ajla_time(st->st_mtime);
2101 #endif
2102 break;
2103 case IO_Stat_Flag_CTime:
2104 #if defined(HAVE_STRUCT_STAT_ST_ATIM)
2105 val = os_timespec_to_ajla_time(&st->st_ctim);
2106 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
2107 val = os_timespec_to_ajla_time(&st->st_ctimespec);
2108 #else
2109 val = os_time_t_to_ajla_time(st->st_ctime);
2110 #endif
2111 break;
2112 default:
2113 pointer_dereference(pointer_data(o));
2114 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), true, NULL);
2115 return POINTER_FOLLOW_THUNK_EXCEPTION;
2117 cast_ptr(int64_t *, da_array_flat(o))[pos] = val;
2118 pos++;
2121 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(o));
2123 return POINTER_FOLLOW_THUNK_GO;
2126 static void * attr_fastcall io_stat_handler(struct io_ctx *ctx)
2128 void *test;
2129 os_stat_t st;
2130 unsigned stat_select;
2131 frame_t fn;
2132 bool lnk;
2134 ctx->str = NULL;
2136 test = io_deep_eval(ctx, "0123", true);
2137 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2138 goto ret_test;
2140 io_get_dir_handle(ctx, get_input(ctx, 1));
2142 io_get_bytes(ctx, get_input(ctx, 2));
2144 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), unsigned, stat_select);
2145 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2146 goto ret_test;
2148 fn = get_param(ctx, 0);
2149 switch (fn) {
2150 case 1:
2151 lnk = false;
2152 break;
2153 case 2:
2154 lnk = true;
2155 break;
2156 default:
2157 internal(file_line, "io_stat_handler: invalid function code %u", (unsigned)fn);
2160 if (unlikely(!os_stat(ctx->dir_handle->fd, ctx->str, lnk, &st, &ctx->err))) {
2161 io_terminate_with_error(ctx, ctx->err, true, NULL);
2162 test = POINTER_FOLLOW_THUNK_EXCEPTION;
2163 goto ret_test;
2166 mem_free(ctx->str);
2168 return io_stat(ctx, &st, stat_select);
2170 ret_test:
2171 if (ctx->str)
2172 mem_free(ctx->str);
2173 return test;
2176 static void * attr_fastcall io_fstat_handler(struct io_ctx *ctx)
2178 void *test;
2179 os_stat_t st;
2180 unsigned stat_select;
2182 test = io_deep_eval(ctx, "012", true);
2183 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2184 return test;
2186 io_get_handle(ctx, get_input(ctx, 1));
2188 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), unsigned, stat_select);
2189 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2190 goto ret_test;
2192 if (unlikely(!os_fstat(ctx->handle->fd, &st, &ctx->err))) {
2193 io_terminate_with_error(ctx, ctx->err, true, NULL);
2194 return POINTER_FOLLOW_THUNK_EXCEPTION;
2197 return io_stat(ctx, &st, stat_select);
2199 ret_test:
2200 return test;
2203 static void *io_statfs(struct io_ctx *ctx, os_statvfs_t *st, unsigned stat_select)
2205 struct data *o;
2206 int pos;
2207 int64_t val;
2208 int popc = pop_count(stat_select);
2210 o = data_alloc_array_flat_mayfail(type_get_int(3), popc, popc, false, &ctx->err pass_file_line);
2211 if (unlikely(!o)) {
2212 io_terminate_with_error(ctx, ctx->err, true, NULL);
2213 return POINTER_FOLLOW_THUNK_EXCEPTION;
2216 pos = 0;
2217 while (stat_select) {
2218 unsigned bit = 1U << low_bit(stat_select);
2219 stat_select &= ~bit;
2220 switch (bit) {
2221 case IO_StatFS_Flag_BSize:
2222 val = st->f_bsize;
2223 break;
2224 case IO_StatFS_Flag_FrSize:
2225 val = st->f_frsize;
2226 break;
2227 case IO_StatFS_Flag_FrTotal:
2228 val = st->f_blocks;
2229 break;
2230 case IO_StatFS_Flag_FrFree:
2231 val = st->f_bfree;
2232 break;
2233 case IO_StatFS_Flag_FrAvail:
2234 val = st->f_bavail;
2235 break;
2236 case IO_StatFS_Flag_InTotal:
2237 val = st->f_files;
2238 break;
2239 case IO_StatFS_Flag_InFree:
2240 val = st->f_ffree;
2241 break;
2242 case IO_StatFS_Flag_InAvail:
2243 val = st->f_favail;
2244 break;
2245 case IO_StatFS_Flag_FSId:
2246 val = st->f_fsid;
2247 break;
2248 case IO_StatFS_Flag_Flags:
2249 val = 0;
2250 #ifdef ST_RDONLY
2251 if (st->f_flag & ST_RDONLY)
2252 val |= IO_StatFS_ST_ReadOnly;
2253 #endif
2254 #ifdef ST_NOSUID
2255 if (st->f_flag & ST_NOSUID)
2256 val |= IO_StatFS_ST_NoSuid;
2257 #endif
2258 #ifdef ST_NODEV
2259 if (st->f_flag & ST_NODEV)
2260 val |= IO_StatFS_ST_NoDev;
2261 #endif
2262 #ifdef ST_NOEXEC
2263 if (st->f_flag & ST_NOEXEC)
2264 val |= IO_StatFS_ST_NoExec;
2265 #endif
2266 #ifdef ST_SYNCHRONOUS
2267 if (st->f_flag & ST_SYNCHRONOUS)
2268 val |= IO_StatFS_ST_Synchronous;
2269 #endif
2270 #ifdef ST_MANDLOCK
2271 if (st->f_flag & ST_MANDLOCK)
2272 val |= IO_StatFS_ST_MandLock;
2273 #endif
2274 #ifdef ST_NOATIME
2275 if (st->f_flag & ST_NOATIME)
2276 val |= IO_StatFS_ST_NoAtime;
2277 #endif
2278 #ifdef ST_NODIRATIME
2279 if (st->f_flag & ST_NODIRATIME)
2280 val |= IO_StatFS_ST_NoDirAtime;
2281 #endif
2282 #ifdef ST_RELATIME
2283 if (st->f_flag & ST_RELATIME)
2284 val |= IO_StatFS_ST_RelAtime;
2285 #endif
2286 break;
2287 case IO_StatFS_Flag_NameLen:
2288 val = st->f_namemax;
2289 break;
2290 default:
2291 pointer_dereference(pointer_data(o));
2292 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), true, NULL);
2293 return POINTER_FOLLOW_THUNK_EXCEPTION;
2295 cast_ptr(int64_t *, da_array_flat(o))[pos] = val;
2296 pos++;
2299 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(o));
2301 return POINTER_FOLLOW_THUNK_GO;
2304 static void * attr_fastcall io_fstatfs_handler(struct io_ctx *ctx)
2306 void *test;
2307 os_statvfs_t st;
2308 unsigned stat_select;
2310 test = io_deep_eval(ctx, "012", true);
2311 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2312 return test;
2314 io_get_handle(ctx, get_input(ctx, 1));
2316 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), unsigned, stat_select);
2317 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2318 return test;
2320 if (unlikely(!os_fstatvfs(ctx->handle->fd, &st, &ctx->err))) {
2321 io_terminate_with_error(ctx, ctx->err, true, NULL);
2322 return POINTER_FOLLOW_THUNK_EXCEPTION;
2325 return io_statfs(ctx, &st, stat_select);
2328 static void * attr_fastcall io_dstatfs_handler(struct io_ctx *ctx)
2330 void *test;
2331 os_statvfs_t st;
2332 unsigned stat_select;
2334 test = io_deep_eval(ctx, "012", true);
2335 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2336 return test;
2338 io_get_dir_handle(ctx, get_input(ctx, 1));
2340 if (unlikely(!dir_handle_is_valid(ctx->dir_handle->fd))) {
2341 fatal_mayfail(error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), &ctx->err, "dummy dir handle");
2342 io_terminate_with_error(ctx, ctx->err, true, NULL);
2343 return POINTER_FOLLOW_THUNK_EXCEPTION;
2346 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), unsigned, stat_select);
2347 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2348 return test;
2350 if (unlikely(!os_dstatvfs(ctx->dir_handle->fd, &st, &ctx->err))) {
2351 io_terminate_with_error(ctx, ctx->err, true, NULL);
2352 return POINTER_FOLLOW_THUNK_EXCEPTION;
2355 return io_statfs(ctx, &st, stat_select);
2358 static void * attr_fastcall io_readlink_handler(struct io_ctx *ctx)
2360 void *test;
2361 char *lnk;
2362 struct data *a;
2364 ctx->str = NULL;
2366 test = io_deep_eval(ctx, "012", true);
2367 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2368 goto ret_test;
2370 io_get_dir_handle(ctx, get_input(ctx, 1));
2372 io_get_bytes(ctx, get_input(ctx, 2));
2374 lnk = os_readlink(ctx->dir_handle->fd, ctx->str, &ctx->err);
2375 if (unlikely(!lnk)) {
2376 io_terminate_with_error(ctx, ctx->err, true, NULL);
2377 test = POINTER_FOLLOW_THUNK_EXCEPTION;
2378 goto ret_test;
2381 a = array_from_flat_mem(type_get_fixed(0, true), lnk, strlen(lnk), &ctx->err);
2382 mem_free(lnk);
2383 if (unlikely(!a)) {
2384 io_terminate_with_error(ctx, ctx->err, true, NULL);
2385 test = POINTER_FOLLOW_THUNK_EXCEPTION;
2386 goto ret_test;
2389 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(a));
2391 test = POINTER_FOLLOW_THUNK_GO;
2393 ret_test:
2394 if (ctx->str)
2395 mem_free(ctx->str);
2396 return test;
2399 static void * attr_fastcall io_dir_action_handler(struct io_ctx *ctx)
2401 void *test;
2402 int mode = 0;
2403 ajla_time_t dev_major = 0, dev_minor = 0;
2404 int action;
2406 ctx->str = NULL;
2407 ctx->str2 = NULL;
2409 test = io_deep_eval(ctx, "012", true);
2410 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2411 goto ret_test;
2413 io_get_dir_handle(ctx, get_input(ctx, 1));
2415 io_get_bytes(ctx, get_input(ctx, 2));
2417 action = get_param(ctx, 0);
2419 if (action == IO_Action_Mk_Dir || action == IO_Action_Mk_Pipe || action == IO_Action_Mk_Socket || action == IO_Action_Mk_CharDev || action == IO_Action_Mk_BlockDev || action == IO_Action_ChMod) {
2420 test = io_deep_eval(ctx, "3", false);
2421 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2422 goto ret_test;
2423 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), int, mode);
2424 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2425 goto ret_test;
2428 if (action == IO_Action_Mk_CharDev || action == IO_Action_Mk_BlockDev) {
2429 test = io_deep_eval(ctx, "45", false);
2430 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2431 goto ret_test;
2432 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 4), ajla_time_t, dev_major);
2433 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2434 goto ret_test;
2435 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 5), ajla_time_t, dev_minor);
2436 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2437 goto ret_test;
2440 if (action == IO_Action_UTime || action == IO_Action_LUTime) {
2441 test = io_deep_eval(ctx, "34", false);
2442 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2443 goto ret_test;
2444 io_get_time(ctx, get_input(ctx, 3), dev_major);
2445 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2446 return test;
2447 io_get_time(ctx, get_input(ctx, 4), dev_minor);
2448 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2449 return test;
2452 if (action == IO_Action_Mk_SymLink) {
2453 test = io_deep_eval(ctx, "3", false);
2454 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2455 goto ret_test;
2456 io_get_bytes2(ctx, get_input(ctx, 3));
2459 if (action == IO_Action_ChOwn || action == IO_Action_LChOwn) {
2460 test = io_deep_eval(ctx, "34", false);
2461 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2462 goto ret_test;
2463 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), ajla_time_t, dev_major);
2464 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2465 goto ret_test;
2466 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 4), ajla_time_t, dev_minor);
2467 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2468 goto ret_test;
2471 if (unlikely(!os_dir_action(ctx->dir_handle->fd, ctx->str, action, mode, dev_major, dev_minor, ctx->str2, &ctx->err))) {
2472 io_terminate_with_error(ctx, ctx->err, true, NULL);
2473 test = POINTER_FOLLOW_THUNK_EXCEPTION;
2474 goto ret_test;
2477 test = POINTER_FOLLOW_THUNK_GO;
2479 ret_test:
2480 if (ctx->str)
2481 mem_free(ctx->str);
2482 if (ctx->str2)
2483 mem_free(ctx->str2);
2484 return test;
2487 static void * attr_fastcall io_dir2_action_handler(struct io_ctx *ctx)
2489 void *test;
2490 int action;
2492 ctx->str = NULL;
2493 ctx->str2 = NULL;
2495 test = io_deep_eval(ctx, "01234", true);
2496 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2497 goto ret_test;
2499 io_get_dir_handle(ctx, get_input(ctx, 3));
2500 ctx->dir_handle2 = ctx->dir_handle;
2501 io_get_bytes2(ctx, get_input(ctx, 4));
2503 io_get_dir_handle(ctx, get_input(ctx, 1));
2504 io_get_bytes(ctx, get_input(ctx, 2));
2506 action = get_param(ctx, 0);
2508 if (unlikely(!os_dir2_action(ctx->dir_handle->fd, ctx->str, action, ctx->dir_handle2->fd, ctx->str2, &ctx->err))) {
2509 io_terminate_with_error(ctx, ctx->err, true, NULL);
2510 test = POINTER_FOLLOW_THUNK_EXCEPTION;
2511 goto ret_test;
2514 test = POINTER_FOLLOW_THUNK_GO;
2516 ret_test:
2517 if (ctx->str)
2518 mem_free(ctx->str);
2519 if (ctx->str2)
2520 mem_free(ctx->str2);
2521 return test;
2524 static void * attr_fastcall io_drives_handler(struct io_ctx *ctx)
2526 void *test;
2527 char *drives;
2528 size_t drives_l;
2529 struct data *d;
2531 test = io_deep_eval(ctx, "0", true);
2532 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2533 goto ret_test;
2535 if (unlikely(!os_drives(&drives, &drives_l, &ctx->err)))
2536 goto ret_thunk;
2538 d = data_alloc_array_flat_mayfail(type_get_fixed(0, true), drives_l, drives_l, false, &ctx->err pass_file_line);
2539 if (unlikely(!d)) {
2540 mem_free(drives);
2541 goto ret_thunk;
2543 memcpy(da_array_flat(d), drives, drives_l);
2544 mem_free(drives);
2546 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
2548 return POINTER_FOLLOW_THUNK_GO;
2550 ret_thunk:
2551 io_terminate_with_error(ctx, ctx->err, true, NULL);
2552 test = POINTER_FOLLOW_THUNK_EXCEPTION;
2553 ret_test:
2554 return test;
2557 static void * attr_fastcall io_stty_handler(struct io_ctx *ctx)
2559 void *test;
2560 int flags;
2561 os_termios_t t;
2562 os_termios_t *new_termios = NULL;
2564 test = io_deep_eval(ctx, "012", true);
2565 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2566 goto ret_test;
2568 io_get_handle(ctx, get_input(ctx, 1));
2570 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), int, flags);
2572 new_termios = mem_alloc_mayfail(os_termios_t *, sizeof(os_termios_t), &ctx->err);
2573 if (unlikely(!new_termios))
2574 goto ret_error;
2576 address_lock(ctx->handle, DEPTH_THUNK);
2577 if (!ctx->handle->old_termios) {
2578 ctx->handle->old_termios = new_termios;
2579 new_termios = NULL;
2580 if (unlikely(!os_tcgetattr(ctx->handle->fd, ctx->handle->old_termios, &ctx->err))) {
2581 new_termios = ctx->handle->old_termios;
2582 ctx->handle->old_termios = NULL;
2583 goto unlock_ret_error;
2586 memcpy(&t, ctx->handle->old_termios, sizeof(os_termios_t));
2587 os_tcflags(&t, flags);
2588 if (unlikely(!os_tcsetattr(ctx->handle->fd, &t, &ctx->err)))
2589 goto unlock_ret_error;
2590 address_unlock(ctx->handle, DEPTH_THUNK);
2592 test = POINTER_FOLLOW_THUNK_GO;
2594 ret_test:
2595 if (new_termios)
2596 mem_free(new_termios);
2597 return test;
2599 unlock_ret_error:
2600 address_unlock(ctx->handle, DEPTH_THUNK);
2601 ret_error:
2602 io_terminate_with_error(ctx, ctx->err, true, NULL);
2603 test = POINTER_FOLLOW_THUNK_EXCEPTION;
2604 goto ret_test;
2607 static void * attr_fastcall io_tty_size_handler(struct io_ctx *ctx)
2609 void *test;
2610 int nx, ny, ox, oy;
2612 test = io_deep_eval(ctx, "01", true);
2613 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2614 return test;
2616 io_get_handle(ctx, get_input(ctx, 1));
2618 if (unlikely(!os_tty_size(ctx->handle->fd, &nx, &ny, &ox, &oy, &ctx->err))) {
2619 io_terminate_with_error(ctx, ctx->err, true, NULL);
2620 return POINTER_FOLLOW_THUNK_EXCEPTION;
2623 io_store_typed_number(ctx, get_output(ctx, 1), int_default_t, INT_DEFAULT_N, int, nx);
2624 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2625 return test;
2626 io_store_typed_number(ctx, get_output(ctx, 2), int_default_t, INT_DEFAULT_N, int, ny);
2627 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2628 return test;
2629 io_store_typed_number(ctx, get_output(ctx, 3), int_default_t, INT_DEFAULT_N, int, ox);
2630 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2631 return test;
2632 io_store_typed_number(ctx, get_output(ctx, 4), int_default_t, INT_DEFAULT_N, int, oy);
2633 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2634 return test;
2636 return POINTER_FOLLOW_THUNK_GO;
2639 static void * attr_fastcall io_tty_background_handler(struct io_ctx *ctx)
2641 void *test;
2643 test = io_deep_eval(ctx, "0", true);
2644 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2645 return test;
2647 os_background();
2649 return POINTER_FOLLOW_THUNK_GO;
2652 static void * attr_fastcall io_tty_foreground_handler(struct io_ctx *ctx)
2654 void *test;
2655 bool b;
2657 test = io_deep_eval(ctx, "0", true);
2658 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2659 return test;
2661 b = os_foreground();
2662 io_store_flat_option(ctx, get_output(ctx, 1), b);
2664 return POINTER_FOLLOW_THUNK_GO;
2667 static int_default_t io_get_spawn_handles_callback(unsigned char *flat, const struct type attr_unused * type, int_default_t n_elements, pointer_t *ptr, void *ctx_)
2669 struct io_ctx *ctx = cast_ptr(struct io_ctx *, ctx_);
2670 if (flat) {
2671 internal(file_line, "io_get_spawn_handles_callback: flat type");
2672 } else {
2673 struct data *rec;
2674 const struct record_definition *def;
2675 frame_t slot_1, slot_2;
2676 struct data *d;
2677 struct resource_handle *h;
2678 int dst_h;
2679 void *test;
2681 rec = pointer_get_data(*ptr);
2682 def = type_def(da(rec,record)->definition,record);
2683 ajla_assert_lo(def->n_entries == 2, (file_line, "io_get_spawn_handles_callback: record doesn't have 2 entries"));
2684 slot_1 = record_definition_slot(def, 0);
2685 slot_2 = record_definition_slot(def, 1);
2686 ajla_assert(frame_test_flag(da_record_frame(rec), slot_2), (file_line, "io_get_spawn_handles_callback: bit for slot %u not set", slot_2));
2688 d = pointer_get_data(*frame_pointer(da_record_frame(rec), slot_2));
2689 h = da_resource(d);
2690 verify_file_handle(d);
2691 array_add(handle_t, &ctx->h_src, &ctx->h_src_l, h->fd);
2693 io_get_positive_number(ctx, da_record_frame(rec), slot_1, int, dst_h);
2694 if (test != POINTER_FOLLOW_THUNK_GO)
2695 return 0;
2697 if (unlikely(dst_h < 0)) {
2698 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), true, NULL);
2699 return 0;
2702 array_add(int, &ctx->h_dst, &ctx->h_dst_l, dst_h);
2704 return n_elements;
2707 static int cmp_int(const void *p1, const void *p2)
2709 int i1 = *cast_ptr(const int *, p1);
2710 int i2 = *cast_ptr(const int *, p2);
2711 if (i1 < i2)
2712 return -1;
2713 if (i1 > i2)
2714 return 1;
2715 return 0;
2718 static bool io_get_spawn_handles(struct io_ctx *ctx, frame_t slot)
2720 bool ret;
2721 array_index_t idx;
2722 int *h_dst_sorted;
2723 size_t i;
2725 array_init(handle_t, &ctx->h_src, &ctx->h_src_l);
2726 array_init(int, &ctx->h_dst, &ctx->h_dst_l);
2727 index_from_int(&idx, 0);
2729 ret = array_onstack_iterate(ctx->fp, slot, &idx, io_get_spawn_handles_callback, ctx);
2731 index_free(&idx);
2732 array_finish(handle_t, &ctx->h_src, &ctx->h_src_l);
2733 array_finish(int, &ctx->h_dst, &ctx->h_dst_l);
2735 if (!ret)
2736 return false;
2738 h_dst_sorted = mem_alloc_array_mayfail(mem_alloc_mayfail, int *, 0, 0, ctx->h_dst_l, sizeof(int), &ctx->err);
2739 if (!unlikely(h_dst_sorted != NULL)) {
2740 io_terminate_with_error(ctx, ctx->err, true, NULL);
2741 return false;
2743 memcpy(h_dst_sorted, ctx->h_dst, ctx->h_dst_l * sizeof(int));
2744 qsort(h_dst_sorted, ctx->h_dst_l, sizeof(int), cmp_int);
2745 for (i = 1; i < ctx->h_dst_l; i++) {
2746 if (h_dst_sorted[i - 1] == h_dst_sorted[i]) {
2747 mem_free(h_dst_sorted);
2748 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), true, NULL);
2749 return false;
2752 mem_free(h_dst_sorted);
2754 return true;
2757 static void * attr_fastcall io_uname_handler(struct io_ctx *ctx)
2759 void *test;
2760 unsigned uname_select;
2761 os_utsname_t un;
2762 int popc;
2763 struct data *o;
2765 test = io_deep_eval(ctx, "0", false);
2766 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2767 return test;
2769 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 0), unsigned, uname_select);
2770 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2771 return test;
2773 if (uname_select & (IO_UName_Flag_System | IO_UName_Flag_Release | IO_UName_Flag_Version | IO_UName_Flag_Machine))
2774 os_get_uname(&un);
2776 popc = pop_count(uname_select);
2777 o = data_alloc_array_pointers_mayfail(popc, 0, &ctx->err pass_file_line);
2778 if (unlikely(!o)) {
2779 io_terminate_with_error(ctx, ctx->err, true, NULL);
2780 return POINTER_FOLLOW_THUNK_EXCEPTION;
2783 while (uname_select) {
2784 const char *str;
2785 struct data *a;
2786 unsigned bit = 1U << low_bit(uname_select);
2787 uname_select &= ~bit;
2788 switch (bit) {
2789 case IO_UName_Flag_Ajla_Version:
2790 str = AJLA_VERSION;
2791 break;
2792 case IO_UName_Flag_Flavor:
2793 str = os_get_flavor();
2794 break;
2795 case IO_UName_Flag_System:
2796 str = un.sysname;
2797 break;
2798 case IO_UName_Flag_Release:
2799 str = un.release;
2800 break;
2801 case IO_UName_Flag_Version:
2802 str = un.version;
2803 break;
2804 case IO_UName_Flag_Machine:
2805 str = un.machine;
2806 break;
2807 default:
2808 pointer_dereference(pointer_data(o));
2809 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), true, NULL);
2810 return POINTER_FOLLOW_THUNK_EXCEPTION;
2812 a = array_from_flat_mem(type_get_fixed(0, true), str, strlen(str), &ctx->err);
2813 if (unlikely(!a)) {
2814 pointer_dereference(pointer_data(o));
2815 io_terminate_with_error(ctx, ctx->err, true, NULL);
2816 return POINTER_FOLLOW_THUNK_EXCEPTION;
2818 da(o,array_pointers)->pointer[da(o,array_pointers)->n_used_entries++] = pointer_data(a);
2821 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_data(o));
2823 return POINTER_FOLLOW_THUNK_GO;
2826 static void * attr_fastcall io_get_host_name_handler(struct io_ctx *ctx)
2828 void *test;
2829 char *hn;
2830 struct data *a;
2832 test = io_deep_eval(ctx, "0", true);
2833 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2834 return test;
2836 hn = os_get_host_name(&ctx->err);
2837 if (unlikely(!hn)) {
2838 io_terminate_with_error(ctx, ctx->err, true, NULL);
2839 return POINTER_FOLLOW_THUNK_EXCEPTION;
2842 a = array_from_flat_mem(type_get_fixed(0, true), hn, strlen(hn), &ctx->err);
2843 mem_free(hn);
2844 if (unlikely(!a)) {
2845 io_terminate_with_error(ctx, ctx->err, true, NULL);
2846 return POINTER_FOLLOW_THUNK_EXCEPTION;
2849 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(a));
2851 return POINTER_FOLLOW_THUNK_GO;
2854 static void * attr_fastcall io_spawn_handler(struct io_ctx *ctx)
2856 struct data *d = NULL;
2857 char *exe_path = NULL;
2858 char *envc = NULL;
2859 void *test;
2860 struct resource_proc_handle *h;
2861 struct proc_handle *handle;
2863 ctx->str = NULL;
2864 ctx->strs = NULL;
2865 ctx->h_src = NULL;
2866 ctx->h_dst = NULL;
2868 test = io_deep_eval(ctx, "012345", true);
2869 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2870 goto ret_test;
2872 io_get_dir_handle(ctx, get_input(ctx, 1));
2874 if (unlikely(!dir_handle_is_valid(ctx->dir_handle->fd))) {
2875 fatal_mayfail(error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), &ctx->err, "dummy dir handle");
2876 goto ret_thunk;
2879 if (!io_get_spawn_handles(ctx, get_input(ctx, 2))) {
2880 test = POINTER_FOLLOW_THUNK_EXCEPTION;
2881 goto ret_test;
2884 io_get_bytes(ctx, get_input(ctx, 3));
2885 exe_path = ctx->str;
2886 ctx->str = NULL;
2888 io_get_strings(ctx, get_input(ctx, 4));
2890 io_get_bytes(ctx, get_input(ctx, 5));
2891 envc = ctx->str;
2892 ctx->str = NULL;
2894 d = data_alloc_resource_mayfail(sizeof(struct resource_proc_handle), proc_handle_close, &ctx->err pass_file_line);
2895 if (unlikely(!d))
2896 goto ret_thunk;
2898 array_add(char *, &ctx->strs, &ctx->strs_l, NULL);
2900 handle = os_proc_spawn(ctx->dir_handle->fd, exe_path, ctx->h_src_l, ctx->h_src, ctx->h_dst, ctx->strs, envc, &ctx->err);
2901 if (unlikely(!handle))
2902 goto ret_thunk;
2904 h = da_resource(d);
2905 h->ph = handle;
2907 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
2909 test = POINTER_FOLLOW_THUNK_GO;
2910 goto ret_free;
2912 ret_thunk:
2913 test = POINTER_FOLLOW_THUNK_GO;
2914 io_terminate_with_error(ctx, ctx->err, true, NULL);
2915 ret_test:
2916 if (d)
2917 data_free_r1(d);
2918 ret_free:
2919 if (ctx->h_src)
2920 mem_free(ctx->h_src);
2921 if (ctx->h_dst)
2922 mem_free(ctx->h_dst);
2923 if (ctx->strs)
2924 free_strings(ctx);
2925 if (ctx->str)
2926 mem_free(ctx->str);
2927 if (envc)
2928 mem_free(envc);
2929 if (exe_path)
2930 mem_free(exe_path);
2931 return test;
2934 static void * attr_fastcall io_wait_handler(struct io_ctx *ctx)
2936 void *test;
2937 pointer_t *ptr;
2938 struct data *d;
2939 struct execution_control *ex;
2940 struct resource_proc_handle *h;
2941 int status;
2943 test = io_deep_eval(ctx, "0", true);
2944 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2945 goto ret_test;
2947 ptr = frame_pointer(ctx->fp, get_input(ctx, 1));
2949 pointer_follow(ptr, true, d, PF_WAIT, ctx->fp, ctx->ip,
2950 test = ex_;
2951 goto ret_test,
2952 thunk_reference(thunk_);
2953 io_terminate_with_thunk(ctx, thunk_);
2954 test = POINTER_FOLLOW_THUNK_EXCEPTION;
2955 goto ret_test;
2958 h = da_resource(d);
2960 ex = frame_execution_control(ctx->fp);
2961 if (os_proc_register_wait(h->ph, &ex->wait[0].mutex_to_lock, &ex->wait[0].wait_entry, &status)) {
2962 io_store_typed_number(ctx, get_output(ctx, 1), int_default_t, INT_DEFAULT_N, int, status);
2963 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2964 goto ret_test;
2965 } else {
2966 pointer_follow_wait(ctx->fp, ctx->ip);
2967 test = POINTER_FOLLOW_THUNK_EXIT;
2968 goto ret_test;
2971 ret_test:
2972 return test;
2975 static void * attr_fastcall io_get_time_handler(struct io_ctx *ctx)
2977 void *test;
2978 frame_t fn;
2979 ajla_time_t t;
2981 test = io_deep_eval(ctx, "0", true);
2982 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2983 goto ret_test;
2985 fn = get_param(ctx, 0);
2986 switch (fn) {
2987 case 1:
2988 t = os_time_real();
2989 break;
2990 case 2:
2991 t = os_time_monotonic();
2992 break;
2993 default:
2994 internal(file_line, "io_get_time_handler: invalid function code %u", (unsigned)fn);
2997 io_store_time(ctx, get_output(ctx, 1), t);
2998 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
2999 goto ret_test;
3001 return POINTER_FOLLOW_THUNK_GO;
3003 ret_test:
3004 return test;
3007 static void * attr_fastcall io_time_to_calendar_handler(struct io_ctx *ctx)
3009 void *test;
3010 ajla_time_t t = 0; /* avoid warning */
3011 ajla_option_t local;
3012 int year, month, day, hour, min, sec, usec, yday, wday, is_dst;
3014 test = io_deep_eval(ctx, "01", false);
3015 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3016 goto ret_test;
3018 io_get_time(ctx, get_input(ctx, 0), t);
3019 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3020 return test;
3022 io_get_option(ctx, get_input(ctx, 1), &local, NULL);
3024 if (unlikely(!os_time_to_calendar(t, local, &year, &month, &day, &hour, &min, &sec, &usec, &yday, &wday, &is_dst, &ctx->err))) {
3025 io_terminate_with_error(ctx, ctx->err, true, NULL);
3026 test = POINTER_FOLLOW_THUNK_EXCEPTION;
3027 goto ret_test;
3030 io_store_typed_number(ctx, get_output(ctx, 0), int_default_t, INT_DEFAULT_N, int, year);
3031 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3032 goto ret_test;
3033 io_store_typed_number(ctx, get_output(ctx, 1), int_default_t, INT_DEFAULT_N, int, month);
3034 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3035 goto ret_test;
3036 io_store_typed_number(ctx, get_output(ctx, 2), int_default_t, INT_DEFAULT_N, int, day);
3037 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3038 goto ret_test;
3039 io_store_typed_number(ctx, get_output(ctx, 3), int_default_t, INT_DEFAULT_N, int, hour);
3040 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3041 goto ret_test;
3042 io_store_typed_number(ctx, get_output(ctx, 4), int_default_t, INT_DEFAULT_N, int, min);
3043 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3044 goto ret_test;
3045 io_store_typed_number(ctx, get_output(ctx, 5), int_default_t, INT_DEFAULT_N, int, sec);
3046 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3047 goto ret_test;
3048 io_store_typed_number(ctx, get_output(ctx, 6), int_default_t, INT_DEFAULT_N, int, usec);
3049 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3050 goto ret_test;
3051 io_store_typed_number(ctx, get_output(ctx, 7), int_default_t, INT_DEFAULT_N, int, yday);
3052 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3053 goto ret_test;
3054 io_store_typed_number(ctx, get_output(ctx, 8), int_default_t, INT_DEFAULT_N, int, wday);
3055 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3056 goto ret_test;
3057 io_store_typed_number(ctx, get_output(ctx, 9), int_default_t, INT_DEFAULT_N, int, is_dst);
3058 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3059 goto ret_test;
3061 test = POINTER_FOLLOW_THUNK_GO;
3063 ret_test:
3064 return test;
3067 static void * attr_fastcall io_calendar_to_time_handler(struct io_ctx *ctx)
3069 void *test;
3070 ajla_time_t t;
3071 int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, usec = 0, is_dst = 0; /* avoid warning */
3072 ajla_option_t local;
3074 test = io_deep_eval(ctx, "012345678", false);
3075 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3076 goto ret_test;
3078 io_get_number(ctx, get_input(ctx, 0), int_default_t, int, year);
3079 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3080 goto ret_test;
3081 io_get_number(ctx, get_input(ctx, 1), int_default_t, int, month);
3082 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3083 goto ret_test;
3084 io_get_number(ctx, get_input(ctx, 2), int_default_t, int, day);
3085 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3086 goto ret_test;
3087 io_get_number(ctx, get_input(ctx, 3), int_default_t, int, hour);
3088 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3089 goto ret_test;
3090 io_get_number(ctx, get_input(ctx, 4), int_default_t, int, min);
3091 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3092 goto ret_test;
3093 io_get_number(ctx, get_input(ctx, 5), int_default_t, int, sec);
3094 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3095 goto ret_test;
3096 io_get_number(ctx, get_input(ctx, 6), int_default_t, int, usec);
3097 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3098 goto ret_test;
3099 io_get_number(ctx, get_input(ctx, 7), int_default_t, int, is_dst);
3100 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3101 goto ret_test;
3102 io_get_option(ctx, get_input(ctx, 8), &local, NULL);
3104 if (unlikely(!os_calendar_to_time(local, year, month, day, hour, min, sec, usec, is_dst, &t, &ctx->err))) {
3105 io_terminate_with_error(ctx, ctx->err, true, NULL);
3106 test = POINTER_FOLLOW_THUNK_EXCEPTION;
3107 goto ret_test;
3110 io_store_time(ctx, get_output(ctx, 0), t);
3111 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3112 goto ret_test;
3114 return POINTER_FOLLOW_THUNK_GO;
3116 ret_test:
3117 return test;
3120 static void * attr_fastcall io_sleep_handler(struct io_ctx *ctx)
3122 struct execution_control *ex;
3123 void *test;
3124 ajla_time_t mt = 0; /* avoid warning */
3126 frame_s *fp = ctx->fp;
3127 frame_t slot_r = get_output(ctx, 0);
3128 frame_t slot_1 = get_input(ctx, 0);
3130 test = io_deep_eval(ctx, "1", false);
3131 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3132 return test;
3134 io_get_time(ctx, get_input(ctx, 1), mt);
3135 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3136 return test;
3138 if (mt <= os_time_monotonic()) {
3139 ipret_copy_variable(fp, slot_1, fp, slot_r, false);
3140 return POINTER_FOLLOW_THUNK_GO;
3143 ex = frame_execution_control(ctx->fp);
3144 if (unlikely(!timer_register_wait(mt, &ex->wait[0].mutex_to_lock, &ex->wait[0].wait_entry, &ctx->err))) {
3145 io_terminate_with_error(ctx, ctx->err, true, NULL);
3146 return POINTER_FOLLOW_THUNK_EXCEPTION;
3148 pointer_follow_wait(ctx->fp, ctx->ip);
3149 return POINTER_FOLLOW_THUNK_EXIT;
3152 static void * attr_fastcall io_any_handler(struct io_ctx *ctx)
3154 frame_s *fp = ctx->fp;
3155 frame_t slot_b = get_output(ctx, 0);
3156 frame_t slot_1 = get_input(ctx, 0);
3157 frame_t slot_2 = get_input(ctx, 1);
3159 retry_1:
3160 if (!frame_variable_is_flat(fp, slot_1) && pointer_is_thunk(*frame_pointer(fp, slot_1))) {
3161 pointer_follow_thunk_noeval(frame_pointer(fp, slot_1),
3162 goto retry_1,
3163 goto return_1,
3164 break
3166 } else {
3167 return_1:
3168 io_store_flat_option(ctx, slot_b, false);
3169 return POINTER_FOLLOW_THUNK_GO;
3171 retry_2:
3172 if (!frame_variable_is_flat(fp, slot_2) && pointer_is_thunk(*frame_pointer(fp, slot_2))) {
3173 pointer_follow_thunk_noeval(frame_pointer(fp, slot_2),
3174 goto retry_2,
3175 goto return_2,
3176 break
3178 } else {
3179 return_2:
3180 io_store_flat_option(ctx, slot_b, true);
3181 return POINTER_FOLLOW_THUNK_GO;
3184 eval_both(ctx->fp, ctx->ip, slot_1, slot_2);
3186 return POINTER_FOLLOW_THUNK_EXIT;
3189 static void * attr_fastcall io_never_handler(struct io_ctx *ctx)
3191 struct execution_control *ex;
3193 ex = frame_execution_control(ctx->fp);
3195 iomux_never(&ex->wait[0].mutex_to_lock, &ex->wait[0].wait_entry);
3196 pointer_follow_wait(ctx->fp, ctx->ip);
3198 return POINTER_FOLLOW_THUNK_EXIT;
3201 static void * attr_fastcall io_fork_handler(struct io_ctx *ctx)
3203 frame_s *fp = ctx->fp;
3204 frame_t slot_r1 = get_output(ctx, 0);
3205 frame_t slot_r2 = get_output(ctx, 1);
3206 frame_t slot = get_input(ctx, 0);
3208 ipret_copy_variable(fp, slot, fp, slot_r1, false);
3209 ipret_copy_variable(fp, slot, fp, slot_r2, false);
3211 return POINTER_FOLLOW_THUNK_GO;
3214 static void * attr_fastcall io_atomic_enter_handler(struct io_ctx *ctx)
3216 void *test;
3217 struct execution_control *ex;
3219 test = io_deep_eval(ctx, "0", true);
3220 if (unlikely(test != POINTER_FOLLOW_THUNK_GO) && unlikely(test != POINTER_FOLLOW_THUNK_EXCEPTION))
3221 return test;
3223 ex = frame_execution_control(ctx->fp);
3224 ex->atomic++;
3226 return POINTER_FOLLOW_THUNK_GO;
3229 static void * attr_fastcall io_atomic_exit_handler(struct io_ctx *ctx)
3231 void *test;
3232 struct execution_control *ex;
3234 test = io_deep_eval(ctx, "0", true);
3235 if (unlikely(test != POINTER_FOLLOW_THUNK_GO) && unlikely(test != POINTER_FOLLOW_THUNK_EXCEPTION))
3236 return test;
3238 ex = frame_execution_control(ctx->fp);
3240 if (unlikely(!ex->atomic))
3241 return POINTER_FOLLOW_THUNK_GO;
3243 if (likely(!--ex->atomic) && unlikely(ex->atomic_interrupted)) {
3244 ex->atomic_interrupted = false;
3245 ex->current_frame = ctx->fp;
3246 ex->current_ip = frame_ip(ctx->fp, ctx->ip);
3247 task_submit(ex, true);
3248 return POINTER_FOLLOW_THUNK_EXIT;
3251 return POINTER_FOLLOW_THUNK_GO;
3254 static void * attr_fastcall io_wait_for_dereferenced_handler(struct io_ctx *ctx)
3256 void *test;
3258 test = io_deep_eval(ctx, "0", true);
3259 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3260 return test;
3262 if (unlikely(are_there_dereferenced())) {
3263 struct execution_control *ex = frame_execution_control(ctx->fp);
3264 if (unlikely(!timer_register_wait(os_time_monotonic() + tick_us, &ex->wait[0].mutex_to_lock, &ex->wait[0].wait_entry, &ctx->err))) {
3265 io_terminate_with_error(ctx, ctx->err, true, NULL);
3266 return POINTER_FOLLOW_THUNK_EXCEPTION;
3268 pointer_follow_wait(ctx->fp, ctx->ip);
3269 return POINTER_FOLLOW_THUNK_EXIT;
3272 return POINTER_FOLLOW_THUNK_GO;
3275 static void * attr_fastcall io_int_to_native_handler(struct io_ctx *ctx)
3277 void *test;
3278 ajla_option_t o;
3279 frame_t f;
3280 union {
3281 short x0;
3282 unsigned short x1;
3283 int x2;
3284 unsigned x3;
3285 long x4;
3286 unsigned long x5;
3287 #ifdef HAVE_LONG_LONG
3288 long long x6;
3289 unsigned long long x7;
3290 #endif
3291 int16_t x8;
3292 uint16_t x9;
3293 int32_t x10;
3294 uint32_t x11;
3295 #if TYPE_FIXED_N >= 4
3296 int64_t x12;
3297 uint64_t x13;
3298 #endif
3299 } u;
3300 size_t size;
3301 struct data *d;
3303 test = io_deep_eval(ctx, "01", false);
3304 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3305 return test;
3307 f = get_input(ctx, 1);
3309 io_get_option(ctx, get_input(ctx, 0), &o, NULL);
3311 switch (o) {
3312 #define int_to_native_case(i, t) \
3313 case i: { \
3314 io_get_number(ctx, f, int_default_t, t, u.x##i);\
3315 if (unlikely(test != POINTER_FOLLOW_THUNK_GO)) \
3316 return test; \
3317 size = sizeof(t); \
3318 break; \
3320 int_to_native_case(0, short);
3321 int_to_native_case(1, unsigned short);
3322 int_to_native_case(2, int);
3323 int_to_native_case(3, unsigned);
3324 int_to_native_case(4, long);
3325 int_to_native_case(5, unsigned long);
3326 #ifdef HAVE_LONG_LONG
3327 int_to_native_case(6, long long);
3328 int_to_native_case(7, unsigned long long);
3329 #endif
3330 int_to_native_case(8, int16_t);
3331 int_to_native_case(9, uint16_t);
3332 int_to_native_case(10, int32_t);
3333 int_to_native_case(11, uint32_t);
3334 #if TYPE_FIXED_N >= 4
3335 int_to_native_case(12, int64_t);
3336 int_to_native_case(13, uint64_t);
3337 #endif
3338 default:
3339 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), true, NULL);
3340 return POINTER_FOLLOW_THUNK_EXCEPTION;
3341 #undef int_to_native_case
3344 d = data_alloc_array_flat_mayfail(type_get_fixed(0, true), size, size, false, &ctx->err pass_file_line);
3345 if (unlikely(!d)) {
3346 io_terminate_with_error(ctx, ctx->err, true, NULL);
3347 return POINTER_FOLLOW_THUNK_GO;
3350 memcpy(da_array_flat(d), &u, size);
3352 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_data(d));
3354 return POINTER_FOLLOW_THUNK_GO;
3357 static void * attr_fastcall io_native_to_int_handler(struct io_ctx *ctx)
3359 void *test;
3360 ajla_option_t o;
3361 frame_t f;
3363 test = io_deep_eval(ctx, "01", false);
3364 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3365 goto ret_test;
3367 f = get_output(ctx, 0);
3369 io_get_bytes(ctx, get_input(ctx, 1));
3371 io_get_option(ctx, get_input(ctx, 0), &o, NULL);
3373 switch (o) {
3374 #define native_to_int_case(i, t) \
3375 case i: { \
3376 t s; \
3377 if (unlikely(ctx->str_l - 1 != sizeof(t))) \
3378 goto invalid_op; \
3379 s = *cast_ptr(t *, ctx->str); \
3380 mem_free(ctx->str); \
3381 io_store_typed_number(ctx, f, int_default_t, INT_DEFAULT_N, t, s);\
3382 if (unlikely(test != POINTER_FOLLOW_THUNK_GO)) \
3383 goto ret_test; \
3384 break; \
3386 native_to_int_case(0, short);
3387 native_to_int_case(1, unsigned short);
3388 native_to_int_case(2, int);
3389 native_to_int_case(3, unsigned);
3390 native_to_int_case(4, long);
3391 native_to_int_case(5, unsigned long);
3392 #ifdef HAVE_LONG_LONG
3393 native_to_int_case(6, long long);
3394 native_to_int_case(7, unsigned long long);
3395 #endif
3396 native_to_int_case(8, int16_t);
3397 native_to_int_case(9, uint16_t);
3398 native_to_int_case(10, int32_t);
3399 native_to_int_case(11, uint32_t);
3400 #if TYPE_FIXED_N >= 4
3401 native_to_int_case(12, int64_t);
3402 native_to_int_case(13, uint64_t);
3403 #endif
3404 default:
3405 invalid_op:
3406 mem_free(ctx->str);
3407 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), true, NULL);
3408 test = POINTER_FOLLOW_THUNK_EXCEPTION;
3409 goto ret_test;
3410 #undef native_to_int_case
3413 return POINTER_FOLLOW_THUNK_GO;
3415 ret_test:
3416 return test;
3419 static void * attr_fastcall io_socket_handler(struct io_ctx *ctx)
3421 int pf, type, protocol;
3422 struct data *d = NULL;
3423 struct resource_handle *h;
3424 void *test;
3425 handle_t result;
3427 test = io_deep_eval(ctx, "0123", true);
3428 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3429 return test;
3431 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 1), int, pf);
3432 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3433 return test;
3434 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), int, type);
3435 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3436 return test;
3437 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), int, protocol);
3438 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3439 return test;
3441 d = data_alloc_resource_mayfail(sizeof(struct resource_handle), handle_close, &ctx->err pass_file_line);
3442 if (unlikely(!d))
3443 goto ret_thunk;
3445 result = os_socket(pf, type, protocol, &ctx->err);
3446 if (unlikely(!handle_is_valid(result)))
3447 goto ret_thunk;
3449 h = da_resource(d);
3450 h->fd = result;
3451 h->nonblocking = true;
3453 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
3455 return POINTER_FOLLOW_THUNK_GO;
3457 ret_thunk:
3458 if (d)
3459 data_free_r1(d);
3460 io_terminate_with_error(ctx, ctx->err, true, NULL);
3461 return POINTER_FOLLOW_THUNK_GO;
3464 static void * attr_fastcall io_bind_connect_handler(struct io_ctx *ctx)
3466 void *test;
3468 ctx->str = NULL;
3470 test = io_deep_eval(ctx, "012", true);
3471 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3472 goto ret_test;
3474 io_get_handle(ctx, get_input(ctx, 1));
3475 io_get_bytes(ctx, get_input(ctx, 2));
3476 ctx->str_l--;
3478 if (unlikely(!os_bind_connect(unlikely(ctx->code == IO_Bind), ctx->handle->fd, cast_ptr(unsigned char *, ctx->str), ctx->str_l, &ctx->err))) {
3479 io_terminate_with_error(ctx, ctx->err, true, NULL);
3480 test = POINTER_FOLLOW_THUNK_GO;
3481 goto ret_test;
3484 test = POINTER_FOLLOW_THUNK_GO;
3486 ret_test:
3487 if (ctx->str)
3488 mem_free(ctx->str);
3489 return test;
3492 static void * attr_fastcall io_connect_wait_handler(struct io_ctx *ctx)
3494 void *test;
3496 test = io_deep_eval(ctx, "01", true);
3497 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3498 return test;
3500 io_get_handle(ctx, get_input(ctx, 1));
3502 if (!iomux_test_handle(ctx->handle->fd, true)) {
3503 io_block_on_handle(ctx, true, false);
3504 return POINTER_FOLLOW_THUNK_EXIT;
3507 if (unlikely(!os_connect_completed(ctx->handle->fd, &ctx->err))) {
3508 io_terminate_with_error(ctx, ctx->err, true, NULL);
3509 return POINTER_FOLLOW_THUNK_GO;
3512 return POINTER_FOLLOW_THUNK_GO;
3515 static void * attr_fastcall io_listen_handler(struct io_ctx *ctx)
3517 void *test;
3519 test = io_deep_eval(ctx, "01", true);
3520 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3521 return test;
3523 io_get_handle(ctx, get_input(ctx, 1));
3525 if (unlikely(!os_listen(ctx->handle->fd, &ctx->err))) {
3526 io_terminate_with_error(ctx, ctx->err, true, NULL);
3527 return POINTER_FOLLOW_THUNK_GO;
3530 return POINTER_FOLLOW_THUNK_GO;
3533 static void * attr_fastcall io_accept_handler(struct io_ctx *ctx)
3535 struct data *d = NULL;
3536 struct resource_handle *h;
3537 void *test;
3538 int r;
3539 handle_t result;
3541 test = io_deep_eval(ctx, "01", true);
3542 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3543 return test;
3545 io_get_handle(ctx, get_input(ctx, 1));
3547 d = data_alloc_resource_mayfail(sizeof(struct resource_handle), handle_close, &ctx->err pass_file_line);
3548 if (unlikely(!d))
3549 goto ret_thunk;
3551 r = os_accept(ctx->handle->fd, &result, &ctx->err);
3552 if (r == OS_RW_WOULDBLOCK) {
3553 data_free_r1(d);
3554 io_block_on_handle(ctx, false, false);
3555 return POINTER_FOLLOW_THUNK_EXIT;
3557 if (unlikely(r == OS_RW_ERROR))
3558 goto ret_thunk;
3560 h = da_resource(d);
3561 h->fd = result;
3562 h->nonblocking = true;
3564 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
3566 return POINTER_FOLLOW_THUNK_GO;
3568 ret_thunk:
3569 if (d)
3570 data_free_r1(d);
3571 io_terminate_with_error(ctx, ctx->err, true, NULL);
3572 return POINTER_FOLLOW_THUNK_GO;
3575 static void * attr_fastcall io_getsockpeername_handler(struct io_ctx *ctx)
3577 unsigned char *addr;
3578 size_t addr_len;
3579 struct data *a;
3580 void *test;
3582 test = io_deep_eval(ctx, "01", true);
3583 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3584 return test;
3586 io_get_handle(ctx, get_input(ctx, 1));
3588 if (unlikely(!os_getsockpeername(ctx->code == IO_Get_Peer_Name, ctx->handle->fd, &addr, &addr_len, &ctx->err))) {
3589 io_terminate_with_error(ctx, ctx->err, true, NULL);
3590 return POINTER_FOLLOW_THUNK_GO;
3593 a = array_from_flat_mem(type_get_fixed(0, true), cast_ptr(const char *, addr), addr_len, &ctx->err);
3594 mem_free(addr);
3595 if (unlikely(!a)) {
3596 io_terminate_with_error(ctx, ctx->err, true, NULL);
3597 return POINTER_FOLLOW_THUNK_GO;
3600 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(a));
3602 return POINTER_FOLLOW_THUNK_GO;
3605 static void * attr_fastcall io_recvfrom_handler(struct io_ctx *ctx)
3607 void *test;
3608 int flags;
3609 int_default_t length;
3610 struct data *a = NULL, *d = NULL;
3611 unsigned char *addr = NULL;
3612 size_t addr_len;
3613 ssize_t rd;
3615 test = io_deep_eval(ctx, "0123", true);
3616 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3617 return test;
3619 io_get_handle(ctx, get_input(ctx, 1));
3620 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), int_default_t, length);
3621 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3622 return test;
3623 if (unlikely(length < 0)) {
3624 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE);
3625 return POINTER_FOLLOW_THUNK_EXCEPTION;
3627 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), int, flags);
3628 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3629 return test;
3631 d = data_alloc_array_flat_mayfail(type_get_fixed(0, true), length, 0, false, &ctx->err pass_file_line);
3632 if (unlikely(!d))
3633 goto ret_thunk;
3635 rd = os_recvfrom(ctx->handle->fd, data_untag(da_array_flat(d)), length, flags, &addr, &addr_len, &ctx->err);
3636 if (rd == OS_RW_WOULDBLOCK) {
3637 data_free_r1(d);
3638 io_block_on_handle(ctx, false, false);
3639 return POINTER_FOLLOW_THUNK_EXIT;
3641 if (unlikely(rd == OS_RW_ERROR))
3642 goto ret_thunk;
3644 da(d,array_flat)->n_used_entries = rd;
3646 a = data_alloc_array_flat_mayfail(type_get_fixed(0, true), addr_len, addr_len, false, &ctx->err pass_file_line);
3647 if (unlikely(!a))
3648 goto ret_thunk;
3650 memcpy(da_array_flat(a), addr, addr_len);
3651 mem_free(addr), addr = NULL;
3653 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
3654 frame_set_pointer(ctx->fp, get_output(ctx, 2), pointer_data(a));
3656 return POINTER_FOLLOW_THUNK_GO;
3658 ret_thunk:
3659 if (addr)
3660 mem_free(addr);
3661 if (d)
3662 data_free_r1(d);
3663 if (a)
3664 data_free_r1(a);
3665 io_terminate_with_error(ctx, ctx->err, true, NULL);
3666 return POINTER_FOLLOW_THUNK_GO;
3669 static void * attr_fastcall io_sendto_handler(struct io_ctx *ctx)
3671 int flags;
3672 void *test;
3673 ssize_t wr;
3675 test = io_deep_eval(ctx, "01234", true);
3676 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3677 goto ret_test;
3679 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), int, flags);
3680 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3681 goto ret_test;
3683 io_get_handle(ctx, get_input(ctx, 1));
3684 io_get_bytes(ctx, get_input(ctx, 2));
3685 io_get_bytes2(ctx, get_input(ctx, 4));
3687 wr = os_sendto(ctx->handle->fd, ctx->str, ctx->str_l - 1, flags, cast_ptr(unsigned char *, ctx->str2), ctx->str2_l - 1, &ctx->err);
3689 mem_free(ctx->str);
3690 mem_free(ctx->str2);
3692 if (wr == OS_RW_WOULDBLOCK) {
3693 io_block_on_handle(ctx, false, false);
3694 test = POINTER_FOLLOW_THUNK_EXIT;
3695 goto ret_test;
3697 if (unlikely(wr == OS_RW_ERROR)) {
3698 io_terminate_with_error(ctx, ctx->err, true, NULL);
3699 test = POINTER_FOLLOW_THUNK_GO;
3700 goto ret_test;
3702 io_store_typed_number(ctx, get_output(ctx, 1), int_default_t, INT_DEFAULT_N, ssize_t, wr);
3703 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3704 goto ret_test;
3705 return POINTER_FOLLOW_THUNK_GO;
3707 ret_test:
3708 return test;
3711 static void * attr_fastcall io_getsockopt_handler(struct io_ctx *ctx)
3713 void *test;
3714 int l, opt;
3715 char b;
3716 char *result;
3717 size_t result_size;
3718 struct data *o;
3720 test = io_deep_eval(ctx, "0123", true);
3721 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3722 return test;
3724 io_get_handle(ctx, get_input(ctx, 1));
3726 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), int, l);
3727 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3728 return test;
3730 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), int, opt);
3731 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3732 return test;
3734 b = os_getsockopt(ctx->handle->fd, l, opt, &result, &result_size, &ctx->err);
3735 if (unlikely(!b))
3736 goto ret_thunk;
3738 o = data_alloc_array_flat_mayfail(type_get_fixed(0, true), result_size, result_size, false, &ctx->err pass_file_line);
3739 if (unlikely(!o)) {
3740 mem_free(result);
3741 goto ret_thunk;
3744 memcpy(da_array_flat(o), result, result_size);
3745 mem_free(result);
3747 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(o));
3749 return POINTER_FOLLOW_THUNK_GO;
3751 ret_thunk:
3752 io_terminate_with_error(ctx, ctx->err, true, NULL);
3753 return POINTER_FOLLOW_THUNK_GO;
3756 static void * attr_fastcall io_setsockopt_handler(struct io_ctx *ctx)
3758 void *test;
3759 int l, opt;
3760 bool b;
3762 test = io_deep_eval(ctx, "01234", true);
3763 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3764 return test;
3766 io_get_handle(ctx, get_input(ctx, 1));
3768 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), int, l);
3769 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3770 return test;
3772 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 3), int, opt);
3773 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3774 return test;
3776 io_get_bytes(ctx, get_input(ctx, 4));
3778 b = os_setsockopt(ctx->handle->fd, l, opt, ctx->str, ctx->str_l - 1, &ctx->err);
3779 mem_free(ctx->str);
3780 if (unlikely(!b))
3781 goto ret_thunk;
3783 return POINTER_FOLLOW_THUNK_GO;
3785 ret_thunk:
3786 io_terminate_with_error(ctx, ctx->err, true, NULL);
3787 return POINTER_FOLLOW_THUNK_GO;
3790 static void * attr_fastcall io_getaddrinfo_handler(struct io_ctx *ctx)
3792 struct data *d;
3793 struct resource_handle *h;
3794 void *test;
3795 handle_t result[2];
3796 int port;
3798 ctx->str = NULL;
3799 d = NULL;
3801 test = io_deep_eval(ctx, "012", true);
3802 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3803 return test;
3805 d = data_alloc_resource_mayfail(sizeof(struct resource_handle), handle_close, &ctx->err pass_file_line);
3806 if (unlikely(!d))
3807 goto ret_thunk;
3809 io_get_bytes(ctx, get_input(ctx, 1));
3810 io_get_positive_number(ctx, ctx->fp, get_input(ctx, 2), int, port);
3811 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3812 goto ret_exc;
3814 if (unlikely(!os_pipe(result, 1, &ctx->err)))
3815 goto ret_thunk;
3817 h = da_resource(d);
3818 h->fd = result[0];
3819 h->nonblocking = true;
3821 if (!resolver_resolve(ctx->str, port, result[1], &ctx->err))
3822 goto ret_thunk_close;
3824 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
3826 mem_free(ctx->str);
3828 return POINTER_FOLLOW_THUNK_GO;
3830 ret_thunk_close:
3831 os_close(result[0]);
3832 os_close(result[1]);
3833 ret_thunk:
3834 io_terminate_with_error(ctx, ctx->err, true, NULL);
3835 ret_exc:
3836 if (d)
3837 data_free_r1(d);
3838 if (ctx->str)
3839 mem_free(ctx->str);
3840 return POINTER_FOLLOW_THUNK_GO;
3843 static void * attr_fastcall io_getnameinfo_handler(struct io_ctx *ctx)
3845 struct data *d;
3846 struct resource_handle *h;
3847 void *test;
3848 handle_t result[2];
3850 ctx->str = NULL;
3851 d = NULL;
3853 test = io_deep_eval(ctx, "01", true);
3854 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3855 return test;
3857 d = data_alloc_resource_mayfail(sizeof(struct resource_handle), handle_close, &ctx->err pass_file_line);
3858 if (unlikely(!d))
3859 goto ret_thunk;
3861 io_get_bytes(ctx, get_input(ctx, 1));
3862 ctx->str_l--;
3864 if (unlikely(!os_pipe(result, 1, &ctx->err)))
3865 goto ret_thunk;
3867 h = da_resource(d);
3868 h->fd = result[0];
3869 h->nonblocking = true;
3871 if (!resolver_resolve_reverse(ctx->str, ctx->str_l, result[1], &ctx->err))
3872 goto ret_thunk_close;
3874 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
3876 mem_free(ctx->str);
3878 return POINTER_FOLLOW_THUNK_GO;
3880 ret_thunk_close:
3881 os_close(result[0]);
3882 os_close(result[1]);
3883 ret_thunk:
3884 io_terminate_with_error(ctx, ctx->err, true, NULL);
3885 if (d)
3886 data_free_r1(d);
3887 if (ctx->str)
3888 mem_free(ctx->str);
3889 return POINTER_FOLLOW_THUNK_GO;
3892 static void io_get_msgqueue(struct io_ctx *ctx, frame_t slot)
3894 pointer_t ptr;
3895 struct data *d;
3896 struct resource_msgqueue *q;
3898 ptr = *frame_pointer(ctx->fp, slot);
3900 ajla_assert_lo(!pointer_is_thunk(ptr), (file_line, "io_get_handle: pointer is thunk"));
3901 d = pointer_get_data(ptr);
3903 q = da_resource(d);
3904 ctx->msgqueue = q;
3907 static void * attr_fastcall io_msgqueue_new_handler(struct io_ctx *ctx)
3909 struct data *d;
3910 struct resource_msgqueue *q;
3911 void *test;
3913 test = io_deep_eval(ctx, "0", true);
3914 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3915 return test;
3917 d = data_alloc_resource_mayfail(sizeof(struct resource_msgqueue), msgqueue_close, &ctx->err pass_file_line);
3918 if (unlikely(!d))
3919 goto ret_thunk;
3921 q = da_resource(d);
3922 q->queue = mem_alloc_array_mayfail(mem_alloc_mayfail, struct msgqueue_entry *, 0, 0, 1, sizeof(struct msgqueue_entry), &ctx->err);
3923 if (unlikely(!q->queue))
3924 goto free_d_ret_thunk;
3925 q->queue_len = 0;
3926 q->queue_allocated = 1;
3928 list_init(&q->wait_list);
3930 mutex_lock(&msgqueue_list_mutex);
3931 list_add(&msgqueue_list, &q->list_entry);
3932 mutex_unlock(&msgqueue_list_mutex);
3934 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
3936 return POINTER_FOLLOW_THUNK_GO;
3938 free_d_ret_thunk:
3939 data_free_r1(d);
3940 ret_thunk:
3941 io_terminate_with_error(ctx, ctx->err, true, NULL);
3942 return POINTER_FOLLOW_THUNK_GO;
3945 static void * attr_fastcall io_msgqueue_send_handler(struct io_ctx *ctx)
3947 void *test;
3948 struct resource_msgqueue *q;
3949 struct msgqueue_entry qe;
3950 struct msgqueue_entry *to_free;
3951 size_t to_free_len;
3952 struct msgqueue_entry *prealloc;
3953 size_t need_alloc;
3954 unsigned params = get_param(ctx, 0);
3955 bool replace = !!(params & 1);
3957 test = io_deep_eval(ctx, "012", true);
3958 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
3959 return test;
3961 io_get_msgqueue(ctx, get_input(ctx, 1));
3963 q = ctx->msgqueue;
3965 qe.tag = ipret_copy_variable_to_pointer(ctx->fp, get_input(ctx, 2), false);
3966 if (unlikely(pointer_is_thunk(qe.tag))) {
3967 io_terminate_with_thunk(ctx, pointer_get_thunk(qe.tag));
3968 return POINTER_FOLLOW_THUNK_GO;
3970 qe.ptr = ipret_copy_variable_to_pointer(ctx->fp, get_input(ctx, 3), false);
3972 prealloc = NULL;
3973 need_alloc = 0;
3974 alloc_more:
3975 if (unlikely(prealloc != NULL)) {
3976 mem_free(prealloc);
3977 prealloc = NULL;
3979 if (unlikely(need_alloc != 0)) {
3980 prealloc = mem_alloc_array_mayfail(mem_alloc_mayfail, struct msgqueue_entry *, 0, 0, need_alloc, sizeof(struct msgqueue_entry), &ctx->err);
3981 if (unlikely(!prealloc)) {
3982 free_ret_ex:
3983 pointer_dereference(qe.tag);
3984 pointer_dereference(qe.ptr);
3985 io_terminate_with_error(ctx, ctx->err, true, NULL);
3986 return POINTER_FOLLOW_THUNK_GO;
3990 to_free = NULL;
3991 to_free_len = 0;
3993 address_lock(q, DEPTH_THUNK);
3994 if (replace) {
3995 if (need_alloc < q->queue_len) {
3996 need_alloc = q->queue_len;
3997 address_unlock(q, DEPTH_THUNK);
3998 goto alloc_more;
4000 memcpy(prealloc, q->queue, q->queue_len * sizeof(struct msgqueue_entry));
4001 to_free = prealloc;
4002 to_free_len = q->queue_len;
4003 q->queue_len = 0;
4004 prealloc = NULL;
4006 if (unlikely(q->queue_len == q->queue_allocated)) {
4007 if (need_alloc <= q->queue_allocated) {
4008 need_alloc = q->queue_allocated * 2;
4009 address_unlock(q, DEPTH_THUNK);
4010 if (unlikely(need_alloc <= q->queue_allocated)) {
4011 ctx->err = error_ajla(EC_ASYNC, AJLA_ERROR_SIZE_OVERFLOW);
4012 goto free_ret_ex;
4014 goto alloc_more;
4016 memcpy(prealloc, q->queue, q->queue_len * sizeof(struct msgqueue_entry));
4017 to_free = q->queue;
4018 to_free_len = 0;
4019 q->queue = prealloc;
4020 q->queue_allocated = need_alloc;
4021 } else {
4022 if (unlikely(prealloc != NULL)) {
4023 to_free = prealloc;
4024 to_free_len = 0;
4027 q->queue[q->queue_len] = qe;
4028 q->queue_len++;
4029 wake_up_wait_list(&q->wait_list, address_get_mutex(q, DEPTH_THUNK), true);
4031 if (to_free) {
4032 size_t i;
4033 for (i = 0; i < to_free_len; i++) {
4034 pointer_dereference(to_free[i].tag);
4035 pointer_dereference(to_free[i].ptr);
4037 mem_free(to_free);
4039 return POINTER_FOLLOW_THUNK_GO;
4042 static bool msgqueue_numbers_equal(pointer_t num1, pointer_t num2)
4044 return !data_compare_numbers(TYPE_TAG_unknown, NULL, num1, NULL, num2);
4047 static void * attr_fastcall io_msgqueue_receive_handler(struct io_ctx *ctx)
4049 void *test;
4050 struct resource_msgqueue *q;
4051 struct msgqueue_entry qe;
4052 size_t pos;
4053 pointer_t select_number = pointer_empty(); /* avoid warning */
4054 unsigned params = get_param(ctx, 0);
4055 bool select_tag = !!(params & 1);
4056 bool nonblock = !!(params & 2);
4057 bool peek = !!(params & 4);
4059 test = io_deep_eval(ctx, !select_tag ? "01" : "012", true);
4060 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4061 return test;
4063 io_get_msgqueue(ctx, get_input(ctx, 1));
4064 q = ctx->msgqueue;
4066 if (select_tag) {
4067 select_number = ipret_copy_variable_to_pointer(ctx->fp, get_input(ctx, 2), false);
4068 if (unlikely(pointer_is_thunk(select_number))) {
4069 io_terminate_with_thunk(ctx, pointer_get_thunk(select_number));
4070 return POINTER_FOLLOW_THUNK_GO;
4073 address_lock(q, DEPTH_THUNK);
4074 for (pos = 0; pos < q->queue_len; pos++) {
4075 if (!select_tag)
4076 goto found;
4077 if (msgqueue_numbers_equal(q->queue[pos].tag, select_number))
4078 goto found;
4081 if (!nonblock) {
4082 struct execution_control *ex = frame_execution_control(ctx->fp);
4083 list_add(&q->wait_list, &ex->wait[0].wait_entry);
4084 ex->wait[0].mutex_to_lock = address_get_mutex(q, DEPTH_THUNK);
4085 address_unlock(q, DEPTH_THUNK);
4086 pointer_follow_wait(ctx->fp, ctx->ip);
4087 if (select_tag)
4088 pointer_dereference(select_number);
4089 return POINTER_FOLLOW_THUNK_EXIT;
4090 } else {
4091 ajla_error_t e;
4092 struct thunk *t;
4093 address_unlock(q, DEPTH_THUNK);
4094 e = error_ajla(EC_SYNC, AJLA_ERROR_NOT_FOUND);
4095 t = thunk_alloc_exception_error(e, NULL, ctx->fp, ctx->ip pass_file_line);
4096 pointer_reference_owned(pointer_thunk(t));
4097 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_thunk(t));
4098 frame_set_pointer(ctx->fp, get_output(ctx, 2), pointer_thunk(t));
4099 if (select_tag)
4100 pointer_dereference(select_number);
4101 return POINTER_FOLLOW_THUNK_GO;
4104 found:
4105 qe = q->queue[pos];
4106 if (!peek) {
4107 memmove(q->queue + pos, q->queue + pos + 1, (q->queue_len - pos - 1) * sizeof(struct msgqueue_entry));
4108 q->queue_len--;
4109 } else {
4110 pointer_reference_owned(qe.tag);
4111 pointer_reference_owned(qe.ptr);
4113 address_unlock(q, DEPTH_THUNK);
4115 frame_set_pointer(ctx->fp, get_output(ctx, 1), qe.tag);
4116 frame_set_pointer(ctx->fp, get_output(ctx, 2), qe.ptr);
4118 if (select_tag)
4119 pointer_dereference(select_number);
4121 return POINTER_FOLLOW_THUNK_GO;
4124 static void * attr_fastcall io_msgqueue_wait_handler(struct io_ctx *ctx)
4126 void *test;
4127 struct resource_msgqueue *q;
4129 test = io_deep_eval(ctx, "01", false);
4130 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4131 return test;
4133 io_get_msgqueue(ctx, get_input(ctx, 1));
4134 q = ctx->msgqueue;
4136 address_lock(q, DEPTH_THUNK);
4137 if (!q->queue_len) {
4138 struct execution_control *ex = frame_execution_control(ctx->fp);
4139 list_add(&q->wait_list, &ex->wait[0].wait_entry);
4140 ex->wait[0].mutex_to_lock = address_get_mutex(q, DEPTH_THUNK);
4141 address_unlock(q, DEPTH_THUNK);
4142 pointer_follow_wait(ctx->fp, ctx->ip);
4143 return POINTER_FOLLOW_THUNK_EXIT;
4145 address_unlock(q, DEPTH_THUNK);
4147 return POINTER_FOLLOW_THUNK_GO;
4150 static void * attr_fastcall io_msgqueue_is_nonempty_handler(struct io_ctx *ctx)
4152 void *test;
4153 struct resource_msgqueue *q;
4154 ajla_flat_option_t val;
4156 test = io_deep_eval(ctx, "01", false);
4157 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4158 return test;
4160 io_get_msgqueue(ctx, get_input(ctx, 1));
4161 q = ctx->msgqueue;
4163 address_lock(q, DEPTH_THUNK);
4164 val = !!q->queue_len;
4165 address_unlock(q, DEPTH_THUNK);
4167 io_store_flat_option(ctx, get_output(ctx, 0), val);
4169 return POINTER_FOLLOW_THUNK_GO;
4172 static void * attr_fastcall io_signal_handle_handler(struct io_ctx *ctx)
4174 void *test;
4175 struct data *d;
4176 struct resource_signal *s;
4177 signal_seq_t seq;
4179 test = io_deep_eval(ctx, "01", true);
4180 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4181 return test;
4183 io_get_bytes(ctx, get_input(ctx, 1));
4185 d = data_alloc_resource_mayfail(sizeof(struct resource_signal), signal_close, &ctx->err pass_file_line);
4186 if (unlikely(!d))
4187 goto ret_thunk;
4189 s = da_resource(d);
4190 s->s = os_signal_handle(ctx->str, &seq, &ctx->err);
4191 if (unlikely(s->s < 0))
4192 goto free_d_ret_thunk;
4194 io_store_typed_number(ctx, get_output(ctx, 2), int64_t, 3, signal_seq_t, seq);
4195 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4196 goto free_d_ret_thunk;
4197 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(d));
4199 mem_free(ctx->str);
4200 return POINTER_FOLLOW_THUNK_GO;
4202 free_d_ret_thunk:
4203 data_free_r1(d);
4204 ret_thunk:
4205 mem_free(ctx->str);
4206 io_terminate_with_error(ctx, ctx->err, true, NULL);
4207 return POINTER_FOLLOW_THUNK_GO;
4210 static void * attr_fastcall io_signal_prepare_handler(struct io_ctx *ctx)
4212 void *test;
4213 pointer_t ptr;
4214 struct data *d;
4215 struct resource_signal *s;
4216 signal_seq_t seq;
4218 test = io_deep_eval(ctx, "01", true);
4219 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4220 return test;
4222 ptr = *frame_pointer(ctx->fp, get_input(ctx, 1));
4223 d = pointer_get_data(ptr);
4224 s = da_resource(d);
4225 seq = os_signal_seq(s->s);
4227 io_store_typed_number(ctx, get_output(ctx, 1), int64_t, 3, signal_seq_t, seq);
4229 return POINTER_FOLLOW_THUNK_GO;
4232 static void * attr_fastcall io_signal_wait_handler(struct io_ctx *ctx)
4234 void *test;
4235 pointer_t ptr;
4236 struct data *d;
4237 struct resource_signal *s;
4238 signal_seq_t seq = 0; /* avoid warning */
4239 struct execution_control *ex;
4241 test = io_deep_eval(ctx, "012", true);
4242 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4243 return test;
4245 ptr = *frame_pointer(ctx->fp, get_input(ctx, 1));
4246 d = pointer_get_data(ptr);
4247 s = da_resource(d);
4249 io_get_number(ctx, get_input(ctx, 2), int64_t, signal_seq_t, seq);
4250 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4251 return test;
4253 ex = frame_execution_control(ctx->fp);
4254 if (os_signal_wait(s->s, seq, &ex->wait[0].mutex_to_lock, &ex->wait[0].wait_entry)) {
4255 pointer_follow_wait(ctx->fp, ctx->ip);
4256 return POINTER_FOLLOW_THUNK_EXIT;
4259 return POINTER_FOLLOW_THUNK_GO;
4262 static void * attr_fastcall io_consume_parameter_handler(struct io_ctx *ctx)
4264 return io_deep_eval(ctx, "0", true);
4267 static void * attr_fastcall io_load_program_handler(struct io_ctx *ctx)
4269 void *test;
4270 size_t i;
4271 unsigned path_idx;
4272 struct module_designator *md = NULL;
4273 struct function_designator *fd = NULL;
4274 pointer_t *main_ptr;
4275 struct data *main_ref;
4277 test = io_deep_eval(ctx, "01", true);
4278 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4279 return test;
4281 io_get_bytes(ctx, get_input(ctx, 1));
4282 ctx->str_l--;
4284 if (ctx->str_l >= 5 && !strcasecmp(ctx->str + ctx->str_l - 5, ".ajla")) {
4285 ctx->str_l -= 5;
4288 get_lib_path();
4289 path_idx = 0;
4290 for (i = 0; i < lib_path_len; i++)
4291 path_idx += !lib_path[i];
4292 path_idx--;
4294 md = module_designator_alloc(path_idx, cast_ptr(const uint8_t *, ctx->str), ctx->str_l, true, &ctx->err);
4295 mem_free(ctx->str);
4297 if (unlikely(!md))
4298 goto ret_err;
4300 fd = function_designator_alloc_single(0, &ctx->err);
4301 if (unlikely(!fd)) {
4302 module_designator_free(md);
4303 goto ret_err;
4306 main_ptr = module_load_function(md, fd, false, &ctx->err);
4307 module_designator_free(md);
4308 function_designator_free(fd);
4310 if (!main_ptr)
4311 goto ret_err;
4313 main_ref = data_alloc_function_reference_mayfail(0, &ctx->err pass_file_line);
4314 if (unlikely(!main_ref))
4315 goto ret_err;
4316 da(main_ref,function_reference)->is_indirect = false;
4317 da(main_ref,function_reference)->u.direct = main_ptr;
4319 frame_set_pointer(ctx->fp, get_output(ctx, 1), pointer_data(main_ref));
4320 return POINTER_FOLLOW_THUNK_GO;
4322 ret_err:
4323 io_terminate_with_error(ctx, ctx->err, true, NULL);
4324 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4325 return test;
4328 static void * attr_fastcall io_get_function_ptr_handler(struct io_ctx *ctx)
4330 void *test;
4331 struct data *d;
4333 test = io_deep_eval(ctx, "0", false);
4334 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4335 return test;
4337 d = pointer_get_data(*frame_pointer(ctx->fp, get_input(ctx, 0)));
4339 ajla_assert_lo(!da(d,function_reference)->is_indirect, (file_line, "io_get_function_ptr_handler: the reference is not direct"));
4341 barrier_aliasing();
4342 *frame_slot(ctx->fp, get_output(ctx, 0), uint64_t) = ptr_to_num(da(d,function_reference)->u.direct);
4343 barrier_aliasing();
4345 return POINTER_FOLLOW_THUNK_GO;
4348 static void * attr_fastcall io_get_subfunctions_handler(struct io_ctx *ctx)
4350 void *test;
4351 int64_t i64;
4352 pointer_t *fptr;
4353 struct data *function, *o;
4354 frame_t x;
4356 test = io_deep_eval(ctx, "0", false);
4357 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4358 return test;
4360 io_get_int64_t(ctx, get_input(ctx, 0), &i64, NULL);
4361 fptr = num_to_ptr((uintptr_t)i64);
4363 pointer_follow(fptr, false, function, PF_WAIT, ctx->fp, ctx->ip,
4364 return ex_,
4365 thunk_reference(thunk_);
4366 io_terminate_with_thunk(ctx, thunk_);
4367 return POINTER_FOLLOW_THUNK_GO;
4370 o = data_alloc_array_flat_mayfail(type_get_fixed(3, true), da(function,function)->local_directory_size, da(function,function)->local_directory_size, false, &ctx->err pass_file_line);
4371 if (unlikely(!o)) {
4372 io_terminate_with_error(ctx, ctx->err, true, NULL);
4373 return POINTER_FOLLOW_THUNK_EXCEPTION;
4376 for (x = 0; x < da(function,function)->local_directory_size; x++) {
4377 uintptr_t sub = ptr_to_num(da(function,function)->local_directory[x]);
4378 cast_ptr(uint64_t *, da_array_flat(o))[x] = sub;
4381 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_data(o));
4383 return POINTER_FOLLOW_THUNK_GO;
4386 static void * attr_fastcall io_load_optimized_pcode_handler(struct io_ctx *ctx)
4388 void *test;
4389 pcode_t path_idx;
4390 ajla_option_t program;
4391 struct module_designator *md = NULL;
4392 struct function_designator *fd = NULL;
4393 pointer_t *ptr;
4395 ctx->str = NULL;
4396 ctx->str2 = NULL;
4398 test = io_deep_eval(ctx, "0123", false);
4399 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4400 goto ret_test;
4402 io_get_pcode_t(ctx, get_input(ctx, 0), &path_idx);
4403 io_get_bytes(ctx, get_input(ctx, 1));
4404 io_get_option(ctx, get_input(ctx, 2), &program, NULL);
4405 io_get_bytes2(ctx, get_input(ctx, 3));
4407 md = module_designator_alloc(path_idx, cast_ptr(uint8_t *, ctx->str), ctx->str_l - 1, program, &ctx->err);
4408 if (unlikely(!md)) {
4409 io_terminate_with_error(ctx, ctx->err, true, NULL);
4410 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4411 goto ret_test;
4413 fd = function_designator_alloc(cast_ptr(pcode_t *, ctx->str2), &ctx->err);
4414 if (unlikely(!fd)) {
4415 io_terminate_with_error(ctx, ctx->err, true, NULL);
4416 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4417 goto ret_test;
4420 ptr = module_load_function(md, fd, true, &ctx->err);
4421 if (unlikely(!ptr)) {
4422 io_terminate_with_error(ctx, ctx->err, true, NULL);
4423 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4424 goto ret_test;
4427 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_reference(ptr));
4429 test = POINTER_FOLLOW_THUNK_GO;
4431 ret_test:
4432 if (ctx->str)
4433 mem_free(ctx->str);
4434 if (ctx->str2)
4435 mem_free(ctx->str2);
4436 if (md)
4437 module_designator_free(md);
4438 if (fd)
4439 function_designator_free(fd);
4440 return test;
4443 static void * attr_fastcall io_register_dependence_handler(struct io_ctx *ctx)
4445 void *test;
4446 test = io_deep_eval(ctx, "01", true);
4447 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4448 return test;
4450 io_get_bytes(ctx, get_input(ctx, 1));
4451 save_register_dependence(ctx->str);
4452 mem_free(ctx->str);
4453 return POINTER_FOLLOW_THUNK_GO;
4456 static void * attr_fastcall io_deep_eval_handler(struct io_ctx *ctx)
4458 void *test;
4459 test = io_deep_eval(ctx, "0", false);
4460 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4461 return test;
4463 ipret_copy_variable(ctx->fp, get_input(ctx, 0), ctx->fp, get_output(ctx, 0), false);
4465 return POINTER_FOLLOW_THUNK_GO;
4468 static void * attr_fastcall io_evaluate_handler(struct io_ctx *ctx)
4470 void *test;
4471 pcode_t src_type, dest_type, op;
4472 const struct type *src_t, *dest_t;
4473 pointer_t fn = pointer_empty();
4474 frame_s *fp = NULL;
4475 struct stack_bottom *st = NULL;
4476 pointer_t res_ptr = pointer_empty();
4477 pcode_t *res_blob = NULL;
4478 size_t res_blob_len;
4479 struct data *a;
4481 ctx->str = NULL;
4482 ctx->str2 = NULL;
4484 test = io_deep_eval(ctx, ctx->n_inputs == 4 ? "0123" : "01234", false);
4485 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4486 goto ret_test;
4488 #if 0
4489 goto unsup;
4490 #endif
4492 io_get_pcode_t(ctx, get_input(ctx, 0), &src_type);
4493 io_get_pcode_t(ctx, get_input(ctx, 1), &dest_type);
4494 io_get_pcode_t(ctx, get_input(ctx, 2), &op);
4496 ajla_assert_lo(Op_IsBinary(op) || Op_IsUnary(op), (file_line, "io_evaluate_handler: invalid operator %ld (%ld, %ld)", (long)op, (long)src_type, (long)dest_type));
4497 ajla_assert_lo(ctx->n_inputs == (uchar_efficient_t)(Op_IsBinary(op) ? 5 : 4), (file_line, "io_evaluate_handler: bad number of arguments %u, op %ld", ctx->n_inputs, (long)op));
4499 src_t = pcode_get_type(src_type);
4500 dest_t = pcode_get_type(dest_type);
4502 if (unlikely(!src_t) || unlikely(!dest_t))
4503 goto unsup;
4505 if (unlikely(ipret_is_privileged)) {
4506 if (unlikely(op == Un_SystemProperty))
4507 goto unsup;
4508 if (TYPE_TAG_IS_REAL(src_t->tag) || TYPE_TAG_IS_REAL(dest_t->tag))
4509 goto unsup;
4512 io_get_bytes(ctx, get_input(ctx, 3));
4513 ctx->str_l--;
4514 if (ctx->n_inputs == 5) {
4515 io_get_bytes2(ctx, get_input(ctx, 4));
4516 ctx->str2_l--;
4517 } else {
4518 ctx->str2_l = 0;
4521 ajla_assert_lo(!(ctx->str_l % sizeof(pcode_t)) && !(ctx->str2_l % sizeof(pcode_t)), (file_line, "io_evaluate_handler: invalid length of blobs: %"PRIuMAX", %"PRIuMAX"", (uintmax_t)ctx->str_l, (uintmax_t)ctx->str2_l));
4523 fn = pcode_build_eval_function(src_type, dest_type, op, cast_ptr(pcode_t *, ctx->str), ctx->str_l / sizeof(pcode_t), cast_ptr(pcode_t *, ctx->str2), ctx->str2_l / sizeof(pcode_t), &ctx->err);
4524 if (unlikely(pointer_is_empty(fn))) {
4525 io_terminate_with_error(ctx, ctx->err, true, NULL);
4526 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4527 goto ret_test;
4530 fp = stack_alloc(NULL, pointer_get_data(fn), &ctx->err);
4531 if (unlikely(!fp))
4532 goto ret_test;
4534 frame_init(fp, pointer_get_data(fn), 0, CALL_MODE_STRICT);
4536 st = frame_stack_bottom(fp);
4537 st->ret = pointer_empty();
4539 run(fp, 0);
4541 res_ptr = st->ret;
4543 ajla_assert_lo(!pointer_is_empty(res_ptr), (file_line, "io_evaluate_handler: the result pointer was not set"));
4545 if (unlikely(pointer_is_thunk(res_ptr))) {
4546 pointer_reference_owned(res_ptr);
4547 io_terminate_with_thunk(ctx, pointer_get_thunk(res_ptr));
4548 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4549 goto ret_test;
4552 if (unlikely(!pcode_generate_blob_from_value(res_ptr, dest_type, &res_blob, &res_blob_len, &ctx->err))) {
4553 io_terminate_with_error(ctx, ctx->err, true, NULL);
4554 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4555 goto ret_test;
4558 a = array_from_flat_mem(type_get_fixed(log_2(sizeof(pcode_t)), false), cast_ptr(const char *, res_blob), res_blob_len, &ctx->err);
4559 if (unlikely(!a)) {
4560 io_terminate_with_error(ctx, ctx->err, true, NULL);
4561 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4562 goto ret_test;
4565 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_data(a));
4567 test = POINTER_FOLLOW_THUNK_GO;
4569 ret_test:
4570 if (ctx->str)
4571 mem_free(ctx->str);
4572 if (ctx->str2)
4573 mem_free(ctx->str2);
4574 if (!pointer_is_empty(fn))
4575 pointer_dereference(fn);
4576 if (st)
4577 stack_free(st);
4578 if (!pointer_is_empty(res_ptr))
4579 pointer_dereference(res_ptr);
4580 if (res_blob)
4581 mem_free(res_blob);
4582 return test;
4584 unsup:
4585 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_NOT_SUPPORTED), false, NULL);
4586 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4587 goto ret_test;
4590 static void * attr_fastcall io_debug_handler(struct io_ctx *ctx)
4592 void *test;
4593 unsigned p;
4595 test = io_deep_eval(ctx, "0", false);
4596 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4597 return test;
4599 io_get_bytes(ctx, get_input(ctx, 0));
4601 p = get_param(ctx, 0);
4603 if (!p) {
4604 #if 1
4605 debug("%s", ctx->str);
4606 #else
4607 debug("%u: %s", tick_stamp, ctx->str);
4608 #endif
4609 } else if (p == 1) {
4610 struct stack_trace st;
4611 stack_trace_capture(&st, ctx->fp, ctx->ip, 20);
4612 stack_trace_print(&st);
4613 stack_trace_free(&st);
4614 internal(file_line, "%s", ctx->str);
4615 } else if (p == 2) {
4616 debug("stop at %s", ctx->str);
4617 os_stop();
4618 } else if (p == 3) {
4619 mem_report_usage(MR_SUMMARY, ctx->str);
4620 } else if (p == 4) {
4621 mem_report_usage(MR_MOST_ALLOCATED, ctx->str);
4622 } else if (p == 5) {
4623 mem_report_usage(MR_LARGEST_BLOCKS, ctx->str);
4624 } else {
4625 internal(file_line, "io_debug_handler: invalid parameter %u", p);
4628 mem_free(ctx->str);
4630 set_uniq_type(ctx);
4632 return POINTER_FOLLOW_THUNK_GO;
4635 static void * attr_fastcall io_stacktrace_handler(struct io_ctx *ctx)
4637 void *ex;
4638 struct thunk *thunk;
4639 frame_t slot = get_input(ctx, 0);
4641 ex = frame_pointer_deep_eval(ctx->fp, ctx->ip, slot, &thunk);
4642 if (likely(ex != POINTER_FOLLOW_THUNK_EXCEPTION))
4643 return ex;
4645 thunk_exception_print(thunk);
4647 pointer_dereference(pointer_thunk(thunk));
4649 set_uniq_type(ctx);
4651 return POINTER_FOLLOW_THUNK_GO;
4654 static void * attr_fastcall io_trace_ctl_handler(struct io_ctx *ctx)
4656 frame_t p = get_param(ctx, 0);
4658 if (!p) {
4659 #ifdef DEBUG_TRACE
4660 store_relaxed(&trace_enabled, 0);
4661 #endif
4662 } else if (p == 1) {
4663 #ifdef DEBUG_TRACE
4664 store_relaxed(&trace_enabled, 1);
4665 #endif
4666 } else {
4667 internal(file_line, "io_trace_ctl_handler: invalid parameter %"PRIuMAX"", (uintmax_t)p);
4670 set_uniq_type(ctx);
4672 return POINTER_FOLLOW_THUNK_GO;
4675 #if defined(SUPPORTS_FFI)
4676 #include "ipio_ffi.inc"
4677 #else
4678 static void * attr_fastcall io_ffi_unsupported(struct io_ctx *ctx)
4680 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_NOT_SUPPORTED), true, NULL);
4681 return POINTER_FOLLOW_THUNK_EXCEPTION;
4683 #define io_ffi_get_size_alignment_handler io_ffi_unsupported
4684 #define io_ffi_create_structure_handler io_ffi_unsupported
4685 #define io_ffi_structure_offset_handler io_ffi_unsupported
4686 #define io_ffi_poke_handler io_ffi_unsupported
4687 #define io_ffi_peek_handler io_ffi_unsupported
4688 #define io_ffi_poke_array_handler io_ffi_unsupported
4689 #define io_ffi_peek_array_handler io_ffi_unsupported
4690 #define io_ffi_create_function_handler io_ffi_unsupported
4691 #define io_ffi_call_function_handler io_ffi_unsupported
4692 #define io_ffi_destructor_new_handler io_ffi_unsupported
4693 #define io_ffi_destructor_allocate_handler io_ffi_unsupported
4694 #define io_ffi_destructor_free_handler io_ffi_unsupported
4695 #define io_ffi_destructor_call_handler io_ffi_unsupported
4696 #define io_ffi_handle_to_number_handler io_ffi_unsupported
4697 #define io_ffi_number_to_handle_handler io_ffi_unsupported
4698 #endif
4700 static void * attr_fastcall io_ffi_encode_real_handler(struct io_ctx *ctx)
4702 void *test;
4703 frame_t slot;
4704 const struct type *type;
4705 unsigned char *var;
4706 struct data *d;
4708 test = io_deep_eval(ctx, "0", false);
4709 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4710 goto ret_test;
4712 slot = get_input(ctx, 0);
4713 type = frame_get_type_of_local(ctx->fp, slot);
4715 var = io_get_flat_pointer(ctx, slot);
4717 d = data_alloc_longint_mayfail(type->size * 8, &ctx->err pass_file_line);
4718 if (unlikely(!d))
4719 goto ret_err;
4720 mpz_import(&da(d,longint)->mp, type->size, -1, 1, 0, 0, var);
4721 frame_set_pointer(ctx->fp, get_output(ctx, 0), pointer_data(d));
4723 test = POINTER_FOLLOW_THUNK_GO;
4725 ret_test:
4726 return test;
4727 ret_err:
4728 io_terminate_with_error(ctx, ctx->err, true, NULL);
4729 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4730 goto ret_test;
4733 static void * attr_fastcall io_ffi_decode_real_handler(struct io_ctx *ctx)
4735 void *test;
4736 frame_t slot, slot_out;
4737 const struct type *type;
4738 int_default_t in;
4739 const mpint_t *mp = NULL;
4740 mpint_t m;
4741 unsigned char *result;
4743 test = io_deep_eval(ctx, "0", false);
4744 if (unlikely(test != POINTER_FOLLOW_THUNK_GO))
4745 goto ret_test;
4747 slot = get_input(ctx, 0);
4748 slot_out = get_output(ctx, 0);
4749 type = frame_get_type_of_local(ctx->fp, slot_out);
4750 result = frame_var(ctx->fp, slot_out);
4752 memset(result, 0, type->size);
4754 cat(io_get_,int_default_t)(ctx, slot, &in, &mp);
4756 if (!mp) {
4757 if (unlikely(!mpint_alloc_mayfail(&m, sizeof(int_default_t) * 8, &ctx->err)))
4758 goto ret_err;
4759 mpint_import_from_variable(&m, int_default_t, in);
4760 mp = &m;
4763 if (unlikely(mpz_sgn(mp) < 0))
4764 goto doesnt_fit;
4765 if (unlikely(mpz_sizeinbase(mp, 2) > (size_t)8 * type->size))
4766 goto doesnt_fit;
4767 mpz_export(result, NULL, -1, 1, 0, 0, mp);
4769 test = POINTER_FOLLOW_THUNK_GO;
4771 ret_test:
4772 if (mp == &m)
4773 mpint_free(&m);
4774 return test;
4776 doesnt_fit:
4777 ctx->err = error_ajla(EC_SYNC, AJLA_ERROR_DOESNT_FIT);
4778 ret_err:
4779 io_terminate_with_error(ctx, ctx->err, true, NULL);
4780 test = POINTER_FOLLOW_THUNK_EXCEPTION;
4781 goto ret_test;
4784 static const struct {
4785 void *(attr_fastcall *do_io)(struct io_ctx *ctx);
4786 } io_handlers [] = {
4787 { io_exception_make_handler },
4788 { io_exception_string_handler },
4789 { io_exception_payload_handler },
4790 { io_exception_stack_handler },
4791 { io_n_std_handles_handler },
4792 { io_get_std_handle_handler },
4793 { io_get_args_handler },
4794 { io_get_environment_handler },
4795 { io_stream_open_handler },
4796 { io_stream_read_handler },
4797 { io_stream_open_handler },
4798 { io_stream_write_handler },
4799 { io_read_console_packet_handler },
4800 { io_write_console_packet_handler },
4801 { io_pipe_handler },
4802 { io_stream_open_handler },
4803 { io_stream_read_handler },
4804 { io_stream_write_handler },
4805 { io_lseek_handler },
4806 { io_ftruncate_handler },
4807 { io_fallocate_handler },
4808 { io_fclone_range_handler },
4809 { io_fsync_handler },
4810 { io_sync_handler },
4811 { io_root_dir_handler },
4812 { io_lib_path_handler },
4813 { io_open_dir_handler },
4814 { io_read_dir_handler },
4815 { io_dir_path_handler },
4816 { io_dmonitor_prepare_handler },
4817 { io_dmonitor_wait_handler },
4818 { io_stat_handler },
4819 { io_fstat_handler },
4820 { io_fstatfs_handler },
4821 { io_dstatfs_handler },
4822 { io_readlink_handler },
4823 { io_dir_action_handler },
4824 { io_dir2_action_handler },
4825 { io_drives_handler },
4826 { io_stty_handler },
4827 { io_tty_size_handler },
4828 { io_tty_background_handler },
4829 { io_tty_foreground_handler },
4830 { io_uname_handler },
4831 { io_get_host_name_handler },
4832 { io_spawn_handler },
4833 { io_wait_handler },
4834 { io_get_time_handler },
4835 { io_time_to_calendar_handler },
4836 { io_calendar_to_time_handler },
4837 { io_sleep_handler },
4838 { io_any_handler },
4839 { io_never_handler },
4840 { io_fork_handler },
4841 { io_atomic_enter_handler },
4842 { io_atomic_exit_handler },
4843 { io_wait_for_dereferenced_handler },
4844 { io_int_to_native_handler },
4845 { io_native_to_int_handler },
4846 { io_socket_handler },
4847 { io_bind_connect_handler },
4848 { io_connect_wait_handler },
4849 { io_bind_connect_handler },
4850 { io_listen_handler },
4851 { io_accept_handler },
4852 { io_getsockpeername_handler },
4853 { io_getsockpeername_handler },
4854 { io_recvfrom_handler },
4855 { io_sendto_handler },
4856 { io_getsockopt_handler },
4857 { io_setsockopt_handler },
4858 { io_getaddrinfo_handler },
4859 { io_getnameinfo_handler },
4860 { io_msgqueue_new_handler },
4861 { io_msgqueue_send_handler },
4862 { io_msgqueue_receive_handler },
4863 { io_msgqueue_wait_handler },
4864 { io_msgqueue_is_nonempty_handler },
4865 { io_signal_handle_handler },
4866 { io_signal_prepare_handler },
4867 { io_signal_wait_handler },
4868 { io_consume_parameter_handler },
4869 { io_load_program_handler },
4870 { io_get_function_ptr_handler },
4871 { io_get_subfunctions_handler },
4872 { io_load_optimized_pcode_handler },
4873 { io_register_dependence_handler },
4874 { io_deep_eval_handler },
4875 { io_evaluate_handler },
4876 { io_debug_handler },
4877 { io_stacktrace_handler },
4878 { io_trace_ctl_handler },
4879 { io_ffi_get_size_alignment_handler },
4880 { io_ffi_create_structure_handler },
4881 { io_ffi_structure_offset_handler },
4882 { io_ffi_poke_handler },
4883 { io_ffi_peek_handler },
4884 { io_ffi_poke_array_handler },
4885 { io_ffi_peek_array_handler },
4886 { io_ffi_handle_to_number_handler },
4887 { io_ffi_number_to_handle_handler },
4888 { io_ffi_create_function_handler },
4889 { io_ffi_call_function_handler },
4890 { io_ffi_encode_real_handler },
4891 { io_ffi_decode_real_handler },
4892 { io_ffi_destructor_new_handler },
4893 { io_ffi_destructor_allocate_handler },
4894 { io_ffi_destructor_free_handler },
4895 { io_ffi_destructor_call_handler },
4898 void *ipret_io(frame_s *fp, const code_t *ip, unsigned char io_code, unsigned char n_outputs, unsigned char n_inputs, unsigned char n_params)
4900 struct io_ctx ctx;
4901 void *ex;
4902 if (n_array_elements(io_handlers) != IO_N)
4903 internal(file_line, "io_handlers doesn't match consts.txt: %lu != %lu", (unsigned long)n_array_elements(io_handlers), (unsigned long)IO_N);
4904 ctx.code = io_code;
4905 ctx.fp = fp;
4906 ctx.ip = ip;
4907 ctx.outputs = ip + 3;
4908 ctx.inputs = ctx.outputs + n_outputs * 2;
4909 ctx.params = ctx.inputs + n_inputs * 2;
4910 ctx.n_outputs = n_outputs;
4911 ctx.n_inputs = n_inputs;
4912 ctx.n_params = n_params;
4913 ajla_assert_lo(io_code < n_array_elements(io_handlers), (file_line, "ipret_io: invalid io code %d", (int)io_code));
4914 ex = io_handlers[io_code].do_io(&ctx);
4915 if (unlikely(ex == POINTER_FOLLOW_THUNK_EXCEPTION))
4916 ex = POINTER_FOLLOW_THUNK_GO;
4917 return ex;
4920 void name(ipio_init)(void)
4922 mutex_init(&lib_path_mutex);
4923 lib_path = NULL;
4925 mutex_init(&msgqueue_list_mutex);
4926 list_init(&msgqueue_list);
4929 void name(ipio_done)(void)
4931 struct list *l;
4932 if (unlikely(!list_is_empty(&msgqueue_list)))
4933 warning("there was leaked message queue");
4934 again:
4935 list_for_each(l, &msgqueue_list) {
4936 struct resource_msgqueue *q = get_struct(l, struct resource_msgqueue, list_entry);
4937 if (q->queue_len) {
4938 struct msgqueue_entry qe = q->queue[q->queue_len - 1];
4939 q->queue_len--;
4940 pointer_dereference(qe.tag);
4941 pointer_dereference(qe.ptr);
4942 goto again;
4945 mutex_done(&msgqueue_list_mutex);
4947 if (lib_path)
4948 mem_free(lib_path);
4949 mutex_done(&lib_path_mutex);
4952 #endif