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
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/>.
47 #if defined(OS_HAS_DLOPEN) && defined(HAVE_LIBFFI)
56 #if !defined(OS_WIN32)
57 extern char **environ
;
60 struct resource_handle
{
63 os_termios_t
*old_termios
;
66 struct resource_dir_handle
{
70 struct resource_notify_handle
{
75 struct resource_proc_handle
{
76 struct proc_handle
*ph
;
79 struct msgqueue_entry
{
84 struct resource_msgqueue
{
85 struct msgqueue_entry
*queue
;
87 size_t queue_allocated
;
88 struct list wait_list
;
89 struct list list_entry
;
92 struct resource_signal
{
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
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
;
123 uchar_efficient_t code
;
126 pointer_t
*array_ptr
;
144 uchar_efficient_t
*args
;
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
;
159 static void handle_no_close(struct data
*d
)
161 struct resource_handle
*h
= da_resource(d
);
162 if (unlikely(h
->old_termios
!= NULL
)) {
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
;
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
))
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
)
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
);
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) \
221 struct resource_handle *h; \
222 if (da(d,resource)->close == handle_no_close) \
224 h = da_resource(d); \
225 obj_registry_verify(OBJ_TYPE_HANDLE, (obj_id)h->fd, file_line); \
228 #ifndef NO_DIR_HANDLES
229 #define verify_dir_handle(d) \
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);\
237 #define verify_dir_handle(d) do { } while (0)
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
)
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
++) {
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
))
285 if (ex
== POINTER_FOLLOW_THUNK_EXCEPTION
) {
286 io_terminate_with_thunk(ctx
, thunk
);
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
)
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
);
313 verify_file_handle(d
);
316 static void io_get_dir_handle(struct io_ctx
*ctx
, frame_t slot
)
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
);
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
);
337 dos_wait_on_packet(&ex
->wait
[0].mutex_to_lock
, &ex
->wait
[0].wait_entry
);
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
);
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
)));
362 static void io_get_pcode_t(struct io_ctx
*ctx
, frame_t slot
, pcode_t
*result
)
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
);
368 *result
= *cast_ptr(pcode_t
*, ptr
);
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
));
379 if (likely(!frame_test_flag(ctx
->fp
, slot
))) {
381 *result
= *frame_slot(ctx
->fp
, slot
, int32_t);
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
)) {
393 internal(file_line
, "io_get_int32: unexpected long int");
394 *mp
= &da(d
,longint
)->mp
;
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
));
408 if (likely(!frame_test_flag(ctx
->fp
, slot
))) {
410 *result
= *frame_slot(ctx
->fp
, slot
, int64_t);
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
)) {
422 internal(file_line
, "io_get_int64: unexpected long int");
423 *mp
= &da(d
,longint
)->mp
;
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
);
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
;
446 if (!pointer_is_empty(da(d
,option
)->pointer
))
447 *pointer
= pointer_get_data(da(d
,option
)->pointer
);
454 static void *io_get_array_index(struct io_ctx
*ctx
, frame_s
*fp_slot
, frame_t slot
, array_index_t
*i argument_position
)
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
));
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
);
469 *frame_slot(ctx
->fp
, slot
, ajla_flat_option_t
) = val
;
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
))) {
479 *frame_slot(ctx
->fp
, slot
, int_default_t
) = index_to_int(val
);
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_)\
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)) \
499 if (likely(index_is_int(int_))) { \
500 int_default_t id = index_to_int(int_); \
502 if ((is_unsigned(result_type_) && unlikely(id < 0)) || \
503 unlikely((int_default_t)r_ != id)) { \
505 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE), true, NULL);\
506 test = POINTER_FOLLOW_THUNK_EXCEPTION; \
511 if (sizeof(result_type_) < sizeof(int_default_t) || \
512 (sizeof(result_type_) == sizeof(int_default_t) && !is_unsigned(result_type_))) {\
514 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE), true, NULL);\
515 test = POINTER_FOLLOW_THUNK_EXCEPTION; \
518 mpint_export_to_variable(index_get_mp(int_), result_type_, r_, success);\
519 if (unlikely(!success)) { \
521 io_terminate_with_error(ctx, error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE), true, NULL);\
522 test = POINTER_FOLLOW_THUNK_EXCEPTION; \
526 test = POINTER_FOLLOW_THUNK_GO; \
531 #define io_get_number(ctx, slot, slot_type_, result_type_, result_) \
534 const mpint_t *mp_; \
535 result_type_ r_ = 0; \
536 cat(io_get_,slot_type_)(ctx, slot, &int_, &mp_); \
537 if (likely(!mp_)) { \
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; \
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; \
554 test = POINTER_FOLLOW_THUNK_GO; \
558 #define io_store_typed_number(ctx, slot, slot_type_, slot_type_idx, result_type_, result_)\
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));\
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(); \
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; \
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; \
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
)
601 for (i
= 0; i
< ctx
->strs_l
; i
++) {
603 mem_free(ctx
->strs
[i
]);
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");
616 array_to_bytes(ptr
, &str
, &str_l
);
617 array_add(char *, &ctx
->strs
, &ctx
->strs_l
, str
);
622 static void io_get_strings(struct io_ctx
*ctx
, frame_t slot
)
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");
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;
647 d
= data_alloc_option_mayfail(&err pass_file_line
);
649 ptr
= pointer_error(err
, ctx
->fp
, ctx
->ip pass_file_line
);
651 da(d
,option
)->pointer
= pointer_empty();
652 da(d
,option
)->option
= 0;
653 ptr
= pointer_data(d
);
657 d
= data_alloc_flat_mayfail(t
->tag
, &val
, 1, &err pass_file_line
);
659 ptr
= pointer_error(err
, ctx
->fp
, ctx
->ip pass_file_line
);
661 ptr
= pointer_data(d
);
664 frame_set_pointer(ctx
->fp
, slot
, ptr
);
669 static void * attr_fastcall
io_exception_make_handler(struct io_ctx
*ctx
)
673 ajla_option_t stack_trace
;
677 if (ctx
->n_inputs
>= 4) {
678 short error_class
, error_type
;
681 test
= io_deep_eval(ctx
, "0123", false);
682 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
685 if (ctx
->n_inputs
>= 5) {
686 test
= io_deep_eval(ctx
, "4", false);
687 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
696 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 1), short, error_type
);
697 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
699 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 2), int, error_aux
);
700 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
710 e
= error_ajla_aux(error_class
, error_type
, error_aux
);
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
;
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
)
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
;
744 if (ex
!= POINTER_FOLLOW_THUNK_EXCEPTION
)
749 msg
= thunk_exception_string(thunk
, &ctx
->err
);
752 msg
= thunk_exception_payload(thunk
, &ctx
->err
);
755 msg
= stack_trace_string(&thunk
->u
.exception
.tr
, &ctx
->err
);
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
;
767 a
= array_from_flat_mem(type_get_fixed(0, true), msg
, strlen(msg
), &ctx
->err
);
770 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
771 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
775 frame_set_pointer(ctx
->fp
, get_output(ctx
, 0), pointer_data(a
));
777 test
= POINTER_FOLLOW_THUNK_GO
;
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
)
804 test
= io_deep_eval(ctx
, "0", true);
805 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
814 return POINTER_FOLLOW_THUNK_GO
;
820 static void * attr_fastcall
io_get_std_handle_handler(struct io_ctx attr_unused
*ctx
)
822 struct resource_handle
*h
;
828 test
= io_deep_eval(ctx
, "01", true);
829 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
832 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 1), unsigned, p
);
833 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
836 d
= data_alloc_resource_mayfail(sizeof(struct resource_handle
), handle_no_close
, &ctx
->err pass_file_line
);
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
;
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
)
856 test
= io_deep_eval(ctx
, "0", false);
857 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
860 a
= data_alloc_array_pointers_mayfail(n_args_left
, n_args_left
, &ctx
->err pass_file_line
);
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
++) {
869 b
= array_from_flat_mem(type_get_fixed(0, true), args_left
[i
], strlen(args_left
[i
]), &ctx
->err
);
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
;
881 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
882 test
= POINTER_FOLLOW_THUNK_GO
;
887 static void * attr_fastcall
io_get_environment_handler(struct io_ctx
*ctx
)
891 #if !defined(OS_WIN32)
895 test
= io_deep_eval(ctx
, "0", true);
896 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
898 #if defined(OS_WIN32)
899 os_get_environment(&ctx
->str
, &ctx
->str_l
);
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
, '=')))
907 #if defined(OS_OS2) || defined(OS_WIN32)
910 if (c
>= 'a' && c
<= 'z')
912 array_add(char, &ctx
->str
, &ctx
->str_l
, c
);
915 array_add_multiple(char, &ctx
->str
, &ctx
->str_l
, e
, strlen(e
) + 1);
918 b
= array_from_flat_mem(type_get_fixed(0, true), ctx
->str
, ctx
->str_l
, NULL
);
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
;
940 h
= NULL
; /* avoid warning */
942 test
= io_deep_eval(ctx
, "01234", true);
943 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
946 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 3), int, ajla_flags
);
947 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
950 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 4), int, mode
);
951 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
954 if (ajla_flags
& -IO_Open_Flag_N
)
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
);
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)
979 if (ctx
->code
== IO_Stream_Open_Read
) {
983 } else if (ctx
->code
== IO_Stream_Open_Write
) {
984 if (ajla_flags
& (IO_Open_Flag_Read
| IO_Open_Flag_Write
))
986 flags
|= O_WRONLY
| O_APPEND
;
987 if (!(ajla_flags
& IO_Open_Flag_Append
))
990 switch (ajla_flags
& (IO_Open_Flag_Read
| IO_Open_Flag_Write
)) {
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;
1000 internal(file_line
, "invalid flags %x", ajla_flags
);
1004 if (ajla_flags
& IO_Open_Flag_Create
)
1006 if (ajla_flags
& IO_Open_Flag_Must_Create
) {
1007 if (ajla_flags
& IO_Open_Flag_Create
)
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
)))
1019 if (ctx
->code
== IO_Block_Open
|| test_symlink
) {
1020 if (unlikely(!os_fstat(p
, &st
, &ctx
->err
)))
1023 if (ctx
->code
== IO_Block_Open
) {
1024 if (unlikely(!S_ISREG(st
.st_mode
))
1026 && unlikely(!S_ISBLK(st
.st_mode
))
1034 if (unlikely(!os_stat(ctx
->dir_handle
->fd
, ctx
->str
, true, &st2
, &ctx
->err
)))
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
);
1049 h
->nonblocking
= true;
1051 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(d
));
1054 return POINTER_FOLLOW_THUNK_GO
;
1057 ctx
->err
= error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
);
1059 if (handle_is_valid(p
))
1063 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1066 return POINTER_FOLLOW_THUNK_GO
;
1069 static void * attr_fastcall
io_stream_read_handler(struct io_ctx
*ctx
)
1073 int_default_t this_step
;
1075 struct data
*result
= NULL
;
1078 test
= io_deep_eval(ctx
, ctx
->code
!= IO_Block_Read
? "012" : "0123", true);
1079 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
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
);
1099 if (likely(index_is_int(idx
))) {
1100 this_step
= index_to_int(idx
);
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);
1108 a
= data_alloc_array_flat_mayfail(type_get_fixed(0, true), this_step
, 0, false, &ctx
->err pass_file_line
);
1112 goto try_alloc_again
;
1116 if (ctx
->code
!= IO_Block_Read
) {
1117 if (!ctx
->handle
->nonblocking
) {
1118 if (!iomux_test_handle(ctx
->handle
->fd
, false))
1121 rd
= os_read(ctx
->handle
->fd
, data_untag(da_array_flat(a
)), this_step
, &ctx
->err
);
1122 if (unlikely(rd
== OS_RW_WOULDBLOCK
)) {
1127 io_block_on_handle(ctx
, false, false);
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
)) {
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
)) {
1151 result
= array_join(result
, a
, &ctx
->err
);
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
));
1162 return POINTER_FOLLOW_THUNK_GO
;
1165 test
= POINTER_FOLLOW_THUNK_EXIT
;
1166 goto idx_free_ret_test
;
1169 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1170 test
= POINTER_FOLLOW_THUNK_GO
;
1174 data_dereference(result
);
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
;
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))
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
)) {
1203 if (ctx
->status
== IO_STATUS_STARTED
) {
1204 io_block_on_handle(ctx
, true, false);
1205 ctx
->status
= IO_STATUS_BLOCKED
;
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
;
1218 if (ctx
->code
== IO_Block_Write
) {
1219 ctx
->position
+= rd
;
1221 ctx
->status
= IO_STATUS_PROGRESS
;
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
;
1231 static void * attr_fastcall
io_stream_write_handler(struct io_ctx
*ctx
)
1236 test
= io_deep_eval(ctx
, ctx
->code
!= IO_Block_Write
? "01" : "013", true);
1237 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
1240 io_get_handle(ctx
, get_input(ctx
, 1));
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
);
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
))
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
: {
1266 case IO_STATUS_IOERR
: {
1269 case IO_STATUS_THUNK
: {
1270 struct data attr_unused
*data
;
1271 if (index_ge_int(idx
, 1))
1273 pointer_follow(ctx
->array_ptr
, false, data
, PF_WAIT
, ctx
->fp
, ctx
->ip
,
1275 goto idx_free_ret_test
,
1277 thunk_reference(thunk_
);
1278 io_terminate_with_thunk(ctx
, thunk_
);
1284 case IO_STATUS_BLOCKED
: {
1285 test
= POINTER_FOLLOW_THUNK_EXIT
;
1286 goto idx_free_ret_test
;
1289 internal(file_line
, "io_stream_write_handler: invalid status %u", ctx
->status
);
1293 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1295 test
= POINTER_FOLLOW_THUNK_GO
;
1296 io_store_integer(ctx
, get_output(ctx
, 1), idx
);
1303 static void * attr_fastcall
io_lseek_handler(struct io_ctx
*ctx
)
1308 test
= io_deep_eval(ctx
, "012", true);
1309 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
1318 mode
= get_param(ctx
, 0);
1320 if (unlikely(!os_lseek(ctx
->handle
->fd
, mode
, ctx
->position
, &ctx
->position
, &ctx
->err
)))
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
))
1327 return POINTER_FOLLOW_THUNK_GO
;
1330 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1331 test
= POINTER_FOLLOW_THUNK_GO
;
1336 static void * attr_fastcall
io_ftruncate_handler(struct io_ctx
*ctx
)
1340 test
= io_deep_eval(ctx
, "012", true);
1341 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
1349 if (unlikely(ctx
->position
< 0)) {
1350 ctx
->err
= error_ajla(EC_SYNC
, AJLA_ERROR_NEGATIVE_INDEX
);
1354 if (unlikely(!os_ftruncate(ctx
->handle
->fd
, ctx
->position
, &ctx
->err
)))
1357 return POINTER_FOLLOW_THUNK_GO
;
1360 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1361 test
= POINTER_FOLLOW_THUNK_GO
;
1366 static void * attr_fastcall
io_fallocate_handler(struct io_ctx
*ctx
)
1370 test
= io_deep_eval(ctx
, "0123", true);
1371 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
1379 if (unlikely(ctx
->position
< 0)) {
1380 ctx
->err
= error_ajla(EC_SYNC
, AJLA_ERROR_NEGATIVE_INDEX
);
1384 io_get_number(ctx
, get_input(ctx
, 3), int64_t, os_off_t
, ctx
->length
);
1385 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
1387 if (unlikely(ctx
->length
< 0)) {
1388 ctx
->err
= error_ajla(EC_SYNC
, AJLA_ERROR_NEGATIVE_INDEX
);
1392 if (unlikely(!os_fallocate(ctx
->handle
->fd
, ctx
->position
, ctx
->length
, &ctx
->err
)))
1395 return POINTER_FOLLOW_THUNK_GO
;
1398 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1399 test
= POINTER_FOLLOW_THUNK_GO
;
1404 static void * attr_fastcall
io_fclone_range_handler(struct io_ctx
*ctx
)
1408 test
= io_deep_eval(ctx
, "012345", true);
1409 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
1418 if (unlikely(ctx
->position
< 0)) {
1419 ctx
->err
= error_ajla(EC_SYNC
, AJLA_ERROR_NEGATIVE_INDEX
);
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
))
1429 if (unlikely(ctx
->position
< 0)) {
1430 ctx
->err
= error_ajla(EC_SYNC
, AJLA_ERROR_NEGATIVE_INDEX
);
1434 io_get_number(ctx
, get_input(ctx
, 4), int64_t, os_off_t
, ctx
->length
);
1435 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
1437 if (unlikely(ctx
->length
< 0)) {
1438 ctx
->err
= error_ajla(EC_SYNC
, AJLA_ERROR_NEGATIVE_INDEX
);
1442 if (unlikely(!os_clone_range(ctx
->handle2
->fd
, ctx
->position2
, ctx
->handle
->fd
, ctx
->position
, ctx
->length
, &ctx
->err
)))
1444 return POINTER_FOLLOW_THUNK_GO
;
1447 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1448 test
= POINTER_FOLLOW_THUNK_GO
;
1453 static void * attr_fastcall
io_fsync_handler(struct io_ctx
*ctx
)
1457 test
= io_deep_eval(ctx
, "01", true);
1458 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
1461 io_get_handle(ctx
, get_input(ctx
, 1));
1463 if (unlikely(!os_fsync(ctx
->handle
->fd
, get_param(ctx
, 0), &ctx
->err
)))
1466 return POINTER_FOLLOW_THUNK_GO
;
1469 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1470 test
= POINTER_FOLLOW_THUNK_GO
;
1475 static void * attr_fastcall
io_sync_handler(struct io_ctx
*ctx
)
1479 test
= io_deep_eval(ctx
, "0", true);
1480 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
1483 if (unlikely(!os_fsync(handle_none
, 3, &ctx
->err
)))
1486 return POINTER_FOLLOW_THUNK_GO
;
1489 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1490 test
= POINTER_FOLLOW_THUNK_GO
;
1495 static void * attr_fastcall
io_read_console_packet_handler(struct io_ctx
*ctx
)
1500 test
= io_deep_eval(ctx
, "01", true);
1501 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
1510 rd
= os_read_console_packet(ctx
->handle
->fd
, data_untag(da_array_flat(a
)), &ctx
->err
);
1511 if (rd
== OS_RW_WOULDBLOCK
) {
1513 io_block_on_handle(ctx
, false, true);
1514 test
= POINTER_FOLLOW_THUNK_EXIT
;
1517 if (unlikely(rd
== OS_RW_ERROR
)) {
1521 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(a
));
1522 return POINTER_FOLLOW_THUNK_GO
;
1525 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1526 test
= POINTER_FOLLOW_THUNK_GO
;
1531 static void * attr_fastcall
io_write_console_packet_handler(struct io_ctx
*ctx
)
1535 test
= io_deep_eval(ctx
, "012", true);
1536 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
;
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
;
1562 test
= io_deep_eval(ctx
, "0", true);
1563 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
1566 d1
= data_alloc_resource_mayfail(sizeof(struct resource_handle
), handle_close
, &ctx
->err pass_file_line
);
1570 d2
= data_alloc_resource_mayfail(sizeof(struct resource_handle
), handle_close
, &ctx
->err pass_file_line
);
1574 if (unlikely(!os_pipe(result
, 3, &ctx
->err
)))
1577 h1
= da_resource(d1
);
1579 h1
->nonblocking
= true;
1581 h2
= da_resource(d2
);
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
;
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
;
1610 test
= io_deep_eval(ctx
, "0", false);
1611 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
1614 d
= data_alloc_resource_mayfail(sizeof(struct resource_dir_handle
), dir_handle_close
, &ctx
->err pass_file_line
);
1618 fn
= get_param(ctx
, 0);
1621 p
= os_dir_root(&ctx
->err
);
1624 p
= os_dir_cwd(&ctx
->err
);
1627 p
= os_dir_open(os_cwd
, builtin_lib_path
, 0, &ctx
->err
);
1630 p
= os_dir_open(dir_none
, os_get_path_to_exe(), 0, &ctx
->err
);
1636 internal(file_line
, "io_root_dir_handler: invalid function code %u", (unsigned)fn
);
1638 if (unlikely(!dir_handle_is_valid(p
)))
1644 frame_set_pointer(ctx
->fp
, get_output(ctx
, 0), pointer_data(d
));
1646 return POINTER_FOLLOW_THUNK_GO
;
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
)) {
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);
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");
1679 for (l
= 0; e
[l
] && !os_is_env_separator(e
[l
]); 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);
1691 goto next_component
;
1695 if (os_path_is_absolute("/")) {
1696 array_add_multiple(char, &lib_path
, &lib_path_len
, "/", 2);
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);
1703 fatal("get_lib_path: NO_DIR_HANDLES is not set");
1706 array_finish(char, &lib_path
, &lib_path_len
);
1710 for (i
= 0; i
< lib_path_len
; i
+= strlen(lib_path
+ i
) + 1)
1711 debug("libpath: '%s'", lib_path
+ i
);
1715 mutex_unlock(&lib_path_mutex
);
1718 static void * attr_fastcall
io_lib_path_handler(struct io_ctx
*ctx
)
1724 b
= array_from_flat_mem(type_get_fixed(0, true), lib_path
, lib_path_len
, &ctx
->err
);
1728 frame_set_pointer(ctx
->fp
, get_output(ctx
, 0), pointer_data(b
));
1730 return POINTER_FOLLOW_THUNK_GO
;
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
;
1751 test
= io_deep_eval(ctx
, "0123", true);
1752 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
1759 if (ajla_flags
& -IO_Open_Flag_N
)
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
);
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
;
1779 test_symlink
= true;
1784 if (unlikely(ajla_flags
!= 0))
1787 p
= os_dir_open(ctx
->dir_handle
->fd
, ctx
->str
, flags
, &ctx
->err
);
1788 if (unlikely(!dir_handle_is_valid(p
)))
1795 if (unlikely(!os_stat(p
, ".", true, &st
, &ctx
->err
)))
1797 if (unlikely(!os_stat(ctx
->dir_handle
->fd
, ctx
->str
, true, &st2
, &ctx
->err
)))
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
);
1813 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(d
));
1816 return POINTER_FOLLOW_THUNK_GO
;
1819 ctx
->err
= error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
);
1823 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1826 return POINTER_FOLLOW_THUNK_GO
;
1829 static int name_cmp(const void *p1
, const void *p2
)
1832 unsigned char *c1
= *cast_ptr(unsigned char **, p1
);
1833 unsigned char *c2
= *cast_ptr(unsigned char **, p2
);
1836 if (likely(diff
) || !*c1
) return diff
;
1842 static void * attr_fastcall
io_read_dir_handler(struct io_ctx
*ctx
)
1850 test
= io_deep_eval(ctx
, "01", true);
1851 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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");
1861 if (unlikely(!os_dir_read(ctx
->dir_handle
->fd
, &files
, &n_files
, &ctx
->err
)))
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
);
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
++) {
1877 b
= array_from_flat_mem(type_get_fixed(0, true), files
[i
], strlen(files
[i
]), &ctx
->err
);
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
;
1890 data_dereference(a
);
1892 os_dir_free(files
, n_files
);
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
)
1904 test
= io_deep_eval(ctx
, "01", true);
1905 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
;
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
;
1924 a
= array_from_flat_mem(type_get_fixed(0, true), lnk
, strlen(lnk
), &ctx
->err
);
1927 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
1928 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
1932 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(a
));
1934 test
= POINTER_FOLLOW_THUNK_GO
;
1940 static void * attr_fastcall
io_dmonitor_prepare_handler(struct io_ctx
*ctx
)
1942 struct resource_notify_handle
*h
;
1946 test
= io_deep_eval(ctx
, "01", true);
1947 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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");
1957 d
= data_alloc_resource_mayfail(sizeof(struct resource_notify_handle
), notify_handle_close
, &ctx
->err pass_file_line
);
1962 if (unlikely(!iomux_directory_handle_alloc(ctx
->dir_handle
->fd
, &h
->id
, &h
->seq
, &ctx
->err
))) {
1967 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(d
));
1969 return POINTER_FOLLOW_THUNK_GO
;
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
)
1983 struct resource_notify_handle
*h
;
1984 struct execution_control
*ex
;
1987 test
= io_deep_eval(ctx
, "01", true);
1988 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
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
;
2011 static void *io_stat(struct io_ctx
*ctx
, os_stat_t
*st
, unsigned stat_select
)
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
);
2020 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
2021 return POINTER_FOLLOW_THUNK_EXCEPTION
;
2025 while (stat_select
) {
2026 unsigned bit
= 1U << low_bit(stat_select
);
2027 stat_select
&= ~bit
;
2029 case IO_Stat_Flag_DevMajor
:
2030 val
= os_dev_t_major(st
->st_dev
);
2032 case IO_Stat_Flag_DevMinor
:
2033 val
= os_dev_t_minor(st
->st_dev
);
2035 case IO_Stat_Flag_Inode
:
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; }
2042 if (S_ISLNK(st
->st_mode
)) { val
= IO_Stat_Type_Link
; break; }
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; }
2047 if (S_ISBLK(st
->st_mode
)) { val
= IO_Stat_Type_BlockDev
; break; }
2050 if (S_ISSOCK(st
->st_mode
)) { val
= IO_Stat_Type_Socket
; break; }
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;
2057 case IO_Stat_Flag_NLink
:
2060 case IO_Stat_Flag_UID
:
2063 case IO_Stat_Flag_GID
:
2066 case IO_Stat_Flag_RDevMajor
:
2067 val
= os_dev_t_major(st
->st_rdev
);
2069 case IO_Stat_Flag_RDevMinor
:
2070 val
= os_dev_t_minor(st
->st_rdev
);
2072 case IO_Stat_Flag_Size
:
2075 case IO_Stat_Flag_OptimalIOSize
:
2076 val
= st
->st_blksize
;
2078 case IO_Stat_Flag_Allocated
:
2079 #if defined(__DJGPP__)
2082 val
= (uint64_t)st
->st_blocks
* 512;
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
);
2091 val
= os_time_t_to_ajla_time(st
->st_atime
);
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
);
2100 val
= os_time_t_to_ajla_time(st
->st_mtime
);
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
);
2109 val
= os_time_t_to_ajla_time(st
->st_ctime
);
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
;
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
)
2130 unsigned stat_select
;
2136 test
= io_deep_eval(ctx
, "0123", true);
2137 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
2148 fn
= get_param(ctx
, 0);
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
;
2168 return io_stat(ctx
, &st
, stat_select
);
2176 static void * attr_fastcall
io_fstat_handler(struct io_ctx
*ctx
)
2180 unsigned stat_select
;
2182 test
= io_deep_eval(ctx
, "012", true);
2183 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
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
);
2203 static void *io_statfs(struct io_ctx
*ctx
, os_statvfs_t
*st
, unsigned stat_select
)
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
);
2212 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
2213 return POINTER_FOLLOW_THUNK_EXCEPTION
;
2217 while (stat_select
) {
2218 unsigned bit
= 1U << low_bit(stat_select
);
2219 stat_select
&= ~bit
;
2221 case IO_StatFS_Flag_BSize
:
2224 case IO_StatFS_Flag_FrSize
:
2227 case IO_StatFS_Flag_FrTotal
:
2230 case IO_StatFS_Flag_FrFree
:
2233 case IO_StatFS_Flag_FrAvail
:
2236 case IO_StatFS_Flag_InTotal
:
2239 case IO_StatFS_Flag_InFree
:
2242 case IO_StatFS_Flag_InAvail
:
2245 case IO_StatFS_Flag_FSId
:
2248 case IO_StatFS_Flag_Flags
:
2251 if (st
->f_flag
& ST_RDONLY
)
2252 val
|= IO_StatFS_ST_ReadOnly
;
2255 if (st
->f_flag
& ST_NOSUID
)
2256 val
|= IO_StatFS_ST_NoSuid
;
2259 if (st
->f_flag
& ST_NODEV
)
2260 val
|= IO_StatFS_ST_NoDev
;
2263 if (st
->f_flag
& ST_NOEXEC
)
2264 val
|= IO_StatFS_ST_NoExec
;
2266 #ifdef ST_SYNCHRONOUS
2267 if (st
->f_flag
& ST_SYNCHRONOUS
)
2268 val
|= IO_StatFS_ST_Synchronous
;
2271 if (st
->f_flag
& ST_MANDLOCK
)
2272 val
|= IO_StatFS_ST_MandLock
;
2275 if (st
->f_flag
& ST_NOATIME
)
2276 val
|= IO_StatFS_ST_NoAtime
;
2278 #ifdef ST_NODIRATIME
2279 if (st
->f_flag
& ST_NODIRATIME
)
2280 val
|= IO_StatFS_ST_NoDirAtime
;
2283 if (st
->f_flag
& ST_RELATIME
)
2284 val
|= IO_StatFS_ST_RelAtime
;
2287 case IO_StatFS_Flag_NameLen
:
2288 val
= st
->f_namemax
;
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
;
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
)
2308 unsigned stat_select
;
2310 test
= io_deep_eval(ctx
, "012", true);
2311 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
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
)
2332 unsigned stat_select
;
2334 test
= io_deep_eval(ctx
, "012", true);
2335 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
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
)
2366 test
= io_deep_eval(ctx
, "012", true);
2367 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
;
2381 a
= array_from_flat_mem(type_get_fixed(0, true), lnk
, strlen(lnk
), &ctx
->err
);
2384 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
2385 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
2389 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(a
));
2391 test
= POINTER_FOLLOW_THUNK_GO
;
2399 static void * attr_fastcall
io_dir_action_handler(struct io_ctx
*ctx
)
2403 ajla_time_t dev_major
= 0, dev_minor
= 0;
2409 test
= io_deep_eval(ctx
, "012", true);
2410 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
2423 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 3), int, mode
);
2424 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
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
))
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
))
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
))
2444 io_get_time(ctx
, get_input(ctx
, 3), dev_major
);
2445 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
2447 io_get_time(ctx
, get_input(ctx
, 4), dev_minor
);
2448 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
2452 if (action
== IO_Action_Mk_SymLink
) {
2453 test
= io_deep_eval(ctx
, "3", false);
2454 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
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
))
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
))
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
;
2477 test
= POINTER_FOLLOW_THUNK_GO
;
2483 mem_free(ctx
->str2
);
2487 static void * attr_fastcall
io_dir2_action_handler(struct io_ctx
*ctx
)
2495 test
= io_deep_eval(ctx
, "01234", true);
2496 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
;
2514 test
= POINTER_FOLLOW_THUNK_GO
;
2520 mem_free(ctx
->str2
);
2524 static void * attr_fastcall
io_drives_handler(struct io_ctx
*ctx
)
2531 test
= io_deep_eval(ctx
, "0", true);
2532 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
2535 if (unlikely(!os_drives(&drives
, &drives_l
, &ctx
->err
)))
2538 d
= data_alloc_array_flat_mayfail(type_get_fixed(0, true), drives_l
, drives_l
, false, &ctx
->err pass_file_line
);
2543 memcpy(da_array_flat(d
), drives
, drives_l
);
2546 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(d
));
2548 return POINTER_FOLLOW_THUNK_GO
;
2551 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
2552 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
2557 static void * attr_fastcall
io_stty_handler(struct io_ctx
*ctx
)
2562 os_termios_t
*new_termios
= NULL
;
2564 test
= io_deep_eval(ctx
, "012", true);
2565 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
2576 address_lock(ctx
->handle
, DEPTH_THUNK
);
2577 if (!ctx
->handle
->old_termios
) {
2578 ctx
->handle
->old_termios
= new_termios
;
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
;
2596 mem_free(new_termios
);
2600 address_unlock(ctx
->handle
, DEPTH_THUNK
);
2602 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
2603 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
2607 static void * attr_fastcall
io_tty_size_handler(struct io_ctx
*ctx
)
2612 test
= io_deep_eval(ctx
, "01", true);
2613 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
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
))
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
))
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
))
2636 return POINTER_FOLLOW_THUNK_GO
;
2639 static void * attr_fastcall
io_tty_background_handler(struct io_ctx
*ctx
)
2643 test
= io_deep_eval(ctx
, "0", true);
2644 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
2649 return POINTER_FOLLOW_THUNK_GO
;
2652 static void * attr_fastcall
io_tty_foreground_handler(struct io_ctx
*ctx
)
2657 test
= io_deep_eval(ctx
, "0", true);
2658 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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_
);
2671 internal(file_line
, "io_get_spawn_handles_callback: flat type");
2674 const struct record_definition
*def
;
2675 frame_t slot_1
, slot_2
;
2677 struct resource_handle
*h
;
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
));
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
)
2697 if (unlikely(dst_h
< 0)) {
2698 io_terminate_with_error(ctx
, error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), true, NULL
);
2702 array_add(int, &ctx
->h_dst
, &ctx
->h_dst_l
, dst_h
);
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
);
2718 static bool io_get_spawn_handles(struct io_ctx
*ctx
, frame_t slot
)
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
);
2732 array_finish(handle_t
, &ctx
->h_src
, &ctx
->h_src_l
);
2733 array_finish(int, &ctx
->h_dst
, &ctx
->h_dst_l
);
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
);
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
);
2752 mem_free(h_dst_sorted
);
2757 static void * attr_fastcall
io_uname_handler(struct io_ctx
*ctx
)
2760 unsigned uname_select
;
2765 test
= io_deep_eval(ctx
, "0", false);
2766 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
2769 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 0), unsigned, uname_select
);
2770 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
2773 if (uname_select
& (IO_UName_Flag_System
| IO_UName_Flag_Release
| IO_UName_Flag_Version
| IO_UName_Flag_Machine
))
2776 popc
= pop_count(uname_select
);
2777 o
= data_alloc_array_pointers_mayfail(popc
, 0, &ctx
->err pass_file_line
);
2779 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
2780 return POINTER_FOLLOW_THUNK_EXCEPTION
;
2783 while (uname_select
) {
2786 unsigned bit
= 1U << low_bit(uname_select
);
2787 uname_select
&= ~bit
;
2789 case IO_UName_Flag_Ajla_Version
:
2792 case IO_UName_Flag_Flavor
:
2793 str
= os_get_flavor();
2795 case IO_UName_Flag_System
:
2798 case IO_UName_Flag_Release
:
2801 case IO_UName_Flag_Version
:
2804 case IO_UName_Flag_Machine
:
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
);
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
)
2832 test
= io_deep_eval(ctx
, "0", true);
2833 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
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
;
2860 struct resource_proc_handle
*h
;
2861 struct proc_handle
*handle
;
2868 test
= io_deep_eval(ctx
, "012345", true);
2869 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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");
2879 if (!io_get_spawn_handles(ctx
, get_input(ctx
, 2))) {
2880 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
2884 io_get_bytes(ctx
, get_input(ctx
, 3));
2885 exe_path
= ctx
->str
;
2888 io_get_strings(ctx
, get_input(ctx
, 4));
2890 io_get_bytes(ctx
, get_input(ctx
, 5));
2894 d
= data_alloc_resource_mayfail(sizeof(struct resource_proc_handle
), proc_handle_close
, &ctx
->err pass_file_line
);
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
))
2907 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(d
));
2909 test
= POINTER_FOLLOW_THUNK_GO
;
2913 test
= POINTER_FOLLOW_THUNK_GO
;
2914 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
2920 mem_free(ctx
->h_src
);
2922 mem_free(ctx
->h_dst
);
2934 static void * attr_fastcall
io_wait_handler(struct io_ctx
*ctx
)
2939 struct execution_control
*ex
;
2940 struct resource_proc_handle
*h
;
2943 test
= io_deep_eval(ctx
, "0", true);
2944 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
2947 ptr
= frame_pointer(ctx
->fp
, get_input(ctx
, 1));
2949 pointer_follow(ptr
, true, d
, PF_WAIT
, ctx
->fp
, ctx
->ip
,
2952 thunk_reference(thunk_
);
2953 io_terminate_with_thunk(ctx
, thunk_
);
2954 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
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
))
2966 pointer_follow_wait(ctx
->fp
, ctx
->ip
);
2967 test
= POINTER_FOLLOW_THUNK_EXIT
;
2975 static void * attr_fastcall
io_get_time_handler(struct io_ctx
*ctx
)
2981 test
= io_deep_eval(ctx
, "0", true);
2982 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
2985 fn
= get_param(ctx
, 0);
2991 t
= os_time_monotonic();
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
))
3001 return POINTER_FOLLOW_THUNK_GO
;
3007 static void * attr_fastcall
io_time_to_calendar_handler(struct io_ctx
*ctx
)
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
))
3018 io_get_time(ctx
, get_input(ctx
, 0), t
);
3019 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
;
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
))
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
))
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
))
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
))
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
))
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
))
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
))
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
))
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
))
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
))
3061 test
= POINTER_FOLLOW_THUNK_GO
;
3067 static void * attr_fastcall
io_calendar_to_time_handler(struct io_ctx
*ctx
)
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
))
3078 io_get_number(ctx
, get_input(ctx
, 0), int_default_t
, int, year
);
3079 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3081 io_get_number(ctx
, get_input(ctx
, 1), int_default_t
, int, month
);
3082 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3084 io_get_number(ctx
, get_input(ctx
, 2), int_default_t
, int, day
);
3085 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3087 io_get_number(ctx
, get_input(ctx
, 3), int_default_t
, int, hour
);
3088 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3090 io_get_number(ctx
, get_input(ctx
, 4), int_default_t
, int, min
);
3091 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3093 io_get_number(ctx
, get_input(ctx
, 5), int_default_t
, int, sec
);
3094 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3096 io_get_number(ctx
, get_input(ctx
, 6), int_default_t
, int, usec
);
3097 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3099 io_get_number(ctx
, get_input(ctx
, 7), int_default_t
, int, is_dst
);
3100 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
;
3110 io_store_time(ctx
, get_output(ctx
, 0), t
);
3111 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3114 return POINTER_FOLLOW_THUNK_GO
;
3120 static void * attr_fastcall
io_sleep_handler(struct io_ctx
*ctx
)
3122 struct execution_control
*ex
;
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
))
3134 io_get_time(ctx
, get_input(ctx
, 1), mt
);
3135 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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);
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
),
3168 io_store_flat_option(ctx
, slot_b
, false);
3169 return POINTER_FOLLOW_THUNK_GO
;
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
),
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
)
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
))
3223 ex
= frame_execution_control(ctx
->fp
);
3226 return POINTER_FOLLOW_THUNK_GO
;
3229 static void * attr_fastcall
io_atomic_exit_handler(struct io_ctx
*ctx
)
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
))
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
)
3258 test
= io_deep_eval(ctx
, "0", true);
3259 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
)
3287 #ifdef HAVE_LONG_LONG
3289 unsigned long long x7
;
3295 #if TYPE_FIXED_N >= 4
3303 test
= io_deep_eval(ctx
, "01", false);
3304 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3307 f
= get_input(ctx
, 1);
3309 io_get_option(ctx
, get_input(ctx
, 0), &o
, NULL
);
3312 #define int_to_native_case(i, t) \
3314 io_get_number(ctx, f, int_default_t, t, u.x##i);\
3315 if (unlikely(test != POINTER_FOLLOW_THUNK_GO)) \
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);
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);
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
);
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
)
3363 test
= io_deep_eval(ctx
, "01", false);
3364 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
3374 #define native_to_int_case(i, t) \
3377 if (unlikely(ctx->str_l - 1 != sizeof(t))) \
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)) \
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);
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);
3407 io_terminate_with_error(ctx
, error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), true, NULL
);
3408 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
3410 #undef native_to_int_case
3413 return POINTER_FOLLOW_THUNK_GO
;
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
;
3427 test
= io_deep_eval(ctx
, "0123", true);
3428 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3431 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 1), int, pf
);
3432 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3434 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 2), int, type
);
3435 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3437 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 3), int, protocol
);
3438 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3441 d
= data_alloc_resource_mayfail(sizeof(struct resource_handle
), handle_close
, &ctx
->err pass_file_line
);
3445 result
= os_socket(pf
, type
, protocol
, &ctx
->err
);
3446 if (unlikely(!handle_is_valid(result
)))
3451 h
->nonblocking
= true;
3453 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(d
));
3455 return POINTER_FOLLOW_THUNK_GO
;
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
)
3470 test
= io_deep_eval(ctx
, "012", true);
3471 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3474 io_get_handle(ctx
, get_input(ctx
, 1));
3475 io_get_bytes(ctx
, get_input(ctx
, 2));
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
;
3484 test
= POINTER_FOLLOW_THUNK_GO
;
3492 static void * attr_fastcall
io_connect_wait_handler(struct io_ctx
*ctx
)
3496 test
= io_deep_eval(ctx
, "01", true);
3497 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
)
3519 test
= io_deep_eval(ctx
, "01", true);
3520 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
;
3541 test
= io_deep_eval(ctx
, "01", true);
3542 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
3551 r
= os_accept(ctx
->handle
->fd
, &result
, &ctx
->err
);
3552 if (r
== OS_RW_WOULDBLOCK
) {
3554 io_block_on_handle(ctx
, false, false);
3555 return POINTER_FOLLOW_THUNK_EXIT
;
3557 if (unlikely(r
== OS_RW_ERROR
))
3562 h
->nonblocking
= true;
3564 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(d
));
3566 return POINTER_FOLLOW_THUNK_GO
;
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
;
3582 test
= io_deep_eval(ctx
, "01", true);
3583 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
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
)
3609 int_default_t length
;
3610 struct data
*a
= NULL
, *d
= NULL
;
3611 unsigned char *addr
= NULL
;
3615 test
= io_deep_eval(ctx
, "0123", true);
3616 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
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
))
3631 d
= data_alloc_array_flat_mayfail(type_get_fixed(0, true), length
, 0, false, &ctx
->err pass_file_line
);
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
) {
3638 io_block_on_handle(ctx
, false, false);
3639 return POINTER_FOLLOW_THUNK_EXIT
;
3641 if (unlikely(rd
== OS_RW_ERROR
))
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
);
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
;
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
)
3675 test
= io_deep_eval(ctx
, "01234", true);
3676 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3679 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 3), int, flags
);
3680 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
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
;
3697 if (unlikely(wr
== OS_RW_ERROR
)) {
3698 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
3699 test
= POINTER_FOLLOW_THUNK_GO
;
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
))
3705 return POINTER_FOLLOW_THUNK_GO
;
3711 static void * attr_fastcall
io_getsockopt_handler(struct io_ctx
*ctx
)
3720 test
= io_deep_eval(ctx
, "0123", true);
3721 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
3730 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 3), int, opt
);
3731 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3734 b
= os_getsockopt(ctx
->handle
->fd
, l
, opt
, &result
, &result_size
, &ctx
->err
);
3738 o
= data_alloc_array_flat_mayfail(type_get_fixed(0, true), result_size
, result_size
, false, &ctx
->err pass_file_line
);
3744 memcpy(da_array_flat(o
), result
, result_size
);
3747 frame_set_pointer(ctx
->fp
, get_output(ctx
, 1), pointer_data(o
));
3749 return POINTER_FOLLOW_THUNK_GO
;
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
)
3762 test
= io_deep_eval(ctx
, "01234", true);
3763 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
))
3772 io_get_positive_number(ctx
, ctx
->fp
, get_input(ctx
, 3), int, opt
);
3773 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
3783 return POINTER_FOLLOW_THUNK_GO
;
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
)
3793 struct resource_handle
*h
;
3801 test
= io_deep_eval(ctx
, "012", true);
3802 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3805 d
= data_alloc_resource_mayfail(sizeof(struct resource_handle
), handle_close
, &ctx
->err pass_file_line
);
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
))
3814 if (unlikely(!os_pipe(result
, 1, &ctx
->err
)))
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
));
3828 return POINTER_FOLLOW_THUNK_GO
;
3831 os_close(result
[0]);
3832 os_close(result
[1]);
3834 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
3840 return POINTER_FOLLOW_THUNK_GO
;
3843 static void * attr_fastcall
io_getnameinfo_handler(struct io_ctx
*ctx
)
3846 struct resource_handle
*h
;
3853 test
= io_deep_eval(ctx
, "01", true);
3854 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3857 d
= data_alloc_resource_mayfail(sizeof(struct resource_handle
), handle_close
, &ctx
->err pass_file_line
);
3861 io_get_bytes(ctx
, get_input(ctx
, 1));
3864 if (unlikely(!os_pipe(result
, 1, &ctx
->err
)))
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
));
3878 return POINTER_FOLLOW_THUNK_GO
;
3881 os_close(result
[0]);
3882 os_close(result
[1]);
3884 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
3889 return POINTER_FOLLOW_THUNK_GO
;
3892 static void io_get_msgqueue(struct io_ctx
*ctx
, frame_t slot
)
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
);
3907 static void * attr_fastcall
io_msgqueue_new_handler(struct io_ctx
*ctx
)
3910 struct resource_msgqueue
*q
;
3913 test
= io_deep_eval(ctx
, "0", true);
3914 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
3917 d
= data_alloc_resource_mayfail(sizeof(struct resource_msgqueue
), msgqueue_close
, &ctx
->err pass_file_line
);
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
;
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
;
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
)
3948 struct resource_msgqueue
*q
;
3949 struct msgqueue_entry qe
;
3950 struct msgqueue_entry
*to_free
;
3952 struct msgqueue_entry
*prealloc
;
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
))
3961 io_get_msgqueue(ctx
, get_input(ctx
, 1));
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);
3975 if (unlikely(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
)) {
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
;
3993 address_lock(q
, DEPTH_THUNK
);
3995 if (need_alloc
< q
->queue_len
) {
3996 need_alloc
= q
->queue_len
;
3997 address_unlock(q
, DEPTH_THUNK
);
4000 memcpy(prealloc
, q
->queue
, q
->queue_len
* sizeof(struct msgqueue_entry
));
4002 to_free_len
= q
->queue_len
;
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
);
4016 memcpy(prealloc
, q
->queue
, q
->queue_len
* sizeof(struct msgqueue_entry
));
4019 q
->queue
= prealloc
;
4020 q
->queue_allocated
= need_alloc
;
4022 if (unlikely(prealloc
!= NULL
)) {
4027 q
->queue
[q
->queue_len
] = qe
;
4029 wake_up_wait_list(&q
->wait_list
, address_get_mutex(q
, DEPTH_THUNK
), true);
4033 for (i
= 0; i
< to_free_len
; i
++) {
4034 pointer_dereference(to_free
[i
].tag
);
4035 pointer_dereference(to_free
[i
].ptr
);
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
)
4050 struct resource_msgqueue
*q
;
4051 struct msgqueue_entry qe
;
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
))
4063 io_get_msgqueue(ctx
, get_input(ctx
, 1));
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
++) {
4077 if (msgqueue_numbers_equal(q
->queue
[pos
].tag
, select_number
))
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
);
4088 pointer_dereference(select_number
);
4089 return POINTER_FOLLOW_THUNK_EXIT
;
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
));
4100 pointer_dereference(select_number
);
4101 return POINTER_FOLLOW_THUNK_GO
;
4107 memmove(q
->queue
+ pos
, q
->queue
+ pos
+ 1, (q
->queue_len
- pos
- 1) * sizeof(struct msgqueue_entry
));
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
);
4119 pointer_dereference(select_number
);
4121 return POINTER_FOLLOW_THUNK_GO
;
4124 static void * attr_fastcall
io_msgqueue_wait_handler(struct io_ctx
*ctx
)
4127 struct resource_msgqueue
*q
;
4129 test
= io_deep_eval(ctx
, "01", false);
4130 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
4133 io_get_msgqueue(ctx
, get_input(ctx
, 1));
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
)
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
))
4160 io_get_msgqueue(ctx
, get_input(ctx
, 1));
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
)
4176 struct resource_signal
*s
;
4179 test
= io_deep_eval(ctx
, "01", true);
4180 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
);
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
));
4200 return POINTER_FOLLOW_THUNK_GO
;
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
)
4215 struct resource_signal
*s
;
4218 test
= io_deep_eval(ctx
, "01", true);
4219 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
4222 ptr
= *frame_pointer(ctx
->fp
, get_input(ctx
, 1));
4223 d
= pointer_get_data(ptr
);
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
)
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
))
4245 ptr
= *frame_pointer(ctx
->fp
, get_input(ctx
, 1));
4246 d
= pointer_get_data(ptr
);
4249 io_get_number(ctx
, get_input(ctx
, 2), int64_t, signal_seq_t
, seq
);
4250 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
)
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
))
4281 io_get_bytes(ctx
, get_input(ctx
, 1));
4284 if (ctx
->str_l
>= 5 && !strcasecmp(ctx
->str
+ ctx
->str_l
- 5, ".ajla")) {
4290 for (i
= 0; i
< lib_path_len
; i
++)
4291 path_idx
+= !lib_path
[i
];
4294 md
= module_designator_alloc(path_idx
, cast_ptr(const uint8_t *, ctx
->str
), ctx
->str_l
, true, &ctx
->err
);
4300 fd
= function_designator_alloc_single(0, &ctx
->err
);
4301 if (unlikely(!fd
)) {
4302 module_designator_free(md
);
4306 main_ptr
= module_load_function(md
, fd
, true, false, &ctx
->err
);
4307 module_designator_free(md
);
4308 function_designator_free(fd
);
4313 main_ref
= data_alloc_function_reference_mayfail(0, &ctx
->err pass_file_line
);
4314 if (unlikely(!main_ref
))
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
;
4323 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
4324 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4328 static void * attr_fastcall
io_get_function_ptr_handler(struct io_ctx
*ctx
)
4333 test
= io_deep_eval(ctx
, "0", false);
4334 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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"));
4342 *frame_slot(ctx
->fp
, get_output(ctx
, 0), uint64_t) = ptr_to_num(da(d
,function_reference
)->u
.direct
);
4345 return POINTER_FOLLOW_THUNK_GO
;
4348 static void * attr_fastcall
io_get_subfunctions_handler(struct io_ctx
*ctx
)
4353 struct data
*function
, *o
;
4356 test
= io_deep_eval(ctx
, "0", false);
4357 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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
,
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
);
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
)
4390 ajla_option_t program
, optimized
;
4391 struct module_designator
*md
= NULL
;
4392 struct function_designator
*fd
= NULL
;
4398 test
= io_deep_eval(ctx
, "01234", false);
4399 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
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));
4406 io_get_option(ctx
, get_input(ctx
, 4), &optimized
, NULL
);
4408 md
= module_designator_alloc(path_idx
, cast_ptr(uint8_t *, ctx
->str
), ctx
->str_l
- 1, program
, &ctx
->err
);
4409 if (unlikely(!md
)) {
4410 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
4411 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4414 fd
= function_designator_alloc(cast_ptr(pcode_t
*, ctx
->str2
), &ctx
->err
);
4415 if (unlikely(!fd
)) {
4416 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
4417 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4421 ptr
= module_load_function(md
, fd
, false, optimized
, &ctx
->err
);
4422 if (unlikely(!ptr
)) {
4423 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
4424 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4428 frame_set_pointer(ctx
->fp
, get_output(ctx
, 0), pointer_reference(ptr
));
4430 test
= POINTER_FOLLOW_THUNK_GO
;
4436 mem_free(ctx
->str2
);
4438 module_designator_free(md
);
4440 function_designator_free(fd
);
4444 static void * attr_fastcall
io_register_dependence_handler(struct io_ctx
*ctx
)
4447 test
= io_deep_eval(ctx
, "01", true);
4448 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
4451 io_get_bytes(ctx
, get_input(ctx
, 1));
4452 save_register_dependence(ctx
->str
);
4454 return POINTER_FOLLOW_THUNK_GO
;
4457 static void * attr_fastcall
io_deep_eval_handler(struct io_ctx
*ctx
)
4460 test
= io_deep_eval(ctx
, "0", false);
4461 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
4464 ipret_copy_variable(ctx
->fp
, get_input(ctx
, 0), ctx
->fp
, get_output(ctx
, 0), false);
4466 return POINTER_FOLLOW_THUNK_GO
;
4469 static void * attr_fastcall
io_evaluate_handler(struct io_ctx
*ctx
)
4472 pcode_t src_type
, dest_type
, op
;
4473 const struct type
*src_t
, *dest_t
;
4474 pointer_t fn
= pointer_empty();
4476 struct stack_bottom
*st
= NULL
;
4477 pointer_t res_ptr
= pointer_empty();
4478 pcode_t
*res_blob
= NULL
;
4479 size_t res_blob_len
;
4485 test
= io_deep_eval(ctx
, ctx
->n_inputs
== 4 ? "0123" : "01234", false);
4486 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
4493 io_get_pcode_t(ctx
, get_input(ctx
, 0), &src_type
);
4494 io_get_pcode_t(ctx
, get_input(ctx
, 1), &dest_type
);
4495 io_get_pcode_t(ctx
, get_input(ctx
, 2), &op
);
4497 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
));
4498 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
));
4500 src_t
= pcode_get_type(src_type
);
4501 dest_t
= pcode_get_type(dest_type
);
4503 if (unlikely(!src_t
) || unlikely(!dest_t
))
4506 if (unlikely(ipret_is_privileged
)) {
4507 if (unlikely(op
== Un_SystemProperty
))
4509 if (TYPE_TAG_IS_REAL(src_t
->tag
) || TYPE_TAG_IS_REAL(dest_t
->tag
))
4513 io_get_bytes(ctx
, get_input(ctx
, 3));
4515 if (ctx
->n_inputs
== 5) {
4516 io_get_bytes2(ctx
, get_input(ctx
, 4));
4522 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
));
4524 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
);
4525 if (unlikely(pointer_is_empty(fn
))) {
4526 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
4527 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4531 fp
= stack_alloc(NULL
, pointer_get_data(fn
), &ctx
->err
);
4535 frame_init(fp
, pointer_get_data(fn
), 0, CALL_MODE_STRICT
);
4537 st
= frame_stack_bottom(fp
);
4538 st
->ret
= pointer_empty();
4544 ajla_assert_lo(!pointer_is_empty(res_ptr
), (file_line
, "io_evaluate_handler: the result pointer was not set"));
4546 if (unlikely(pointer_is_thunk(res_ptr
))) {
4547 pointer_reference_owned(res_ptr
);
4548 io_terminate_with_thunk(ctx
, pointer_get_thunk(res_ptr
));
4549 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4553 if (unlikely(!pcode_generate_blob_from_value(res_ptr
, dest_type
, &res_blob
, &res_blob_len
, &ctx
->err
))) {
4554 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
4555 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4559 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
);
4561 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
4562 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4566 frame_set_pointer(ctx
->fp
, get_output(ctx
, 0), pointer_data(a
));
4568 test
= POINTER_FOLLOW_THUNK_GO
;
4574 mem_free(ctx
->str2
);
4575 if (!pointer_is_empty(fn
))
4576 pointer_dereference(fn
);
4579 if (!pointer_is_empty(res_ptr
))
4580 pointer_dereference(res_ptr
);
4586 io_terminate_with_error(ctx
, error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), false, NULL
);
4587 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4591 static void * attr_fastcall
io_debug_handler(struct io_ctx
*ctx
)
4596 test
= io_deep_eval(ctx
, "0", false);
4597 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
4600 io_get_bytes(ctx
, get_input(ctx
, 0));
4602 p
= get_param(ctx
, 0);
4606 debug("%s", ctx
->str
);
4608 debug("%u: %s", tick_stamp
, ctx
->str
);
4610 } else if (p
== 1) {
4611 struct stack_trace st
;
4612 stack_trace_capture(&st
, ctx
->fp
, ctx
->ip
, 20);
4613 stack_trace_print(&st
);
4614 stack_trace_free(&st
);
4615 internal(file_line
, "%s", ctx
->str
);
4616 } else if (p
== 2) {
4617 debug("stop at %s", ctx
->str
);
4619 } else if (p
== 3) {
4620 mem_report_usage(MR_SUMMARY
, ctx
->str
);
4621 } else if (p
== 4) {
4622 mem_report_usage(MR_MOST_ALLOCATED
, ctx
->str
);
4623 } else if (p
== 5) {
4624 mem_report_usage(MR_LARGEST_BLOCKS
, ctx
->str
);
4626 internal(file_line
, "io_debug_handler: invalid parameter %u", p
);
4633 return POINTER_FOLLOW_THUNK_GO
;
4636 static void * attr_fastcall
io_stacktrace_handler(struct io_ctx
*ctx
)
4639 struct thunk
*thunk
;
4640 frame_t slot
= get_input(ctx
, 0);
4642 ex
= frame_pointer_deep_eval(ctx
->fp
, ctx
->ip
, slot
, &thunk
);
4643 if (likely(ex
!= POINTER_FOLLOW_THUNK_EXCEPTION
))
4646 thunk_exception_print(thunk
);
4648 pointer_dereference(pointer_thunk(thunk
));
4652 return POINTER_FOLLOW_THUNK_GO
;
4655 static void * attr_fastcall
io_trace_ctl_handler(struct io_ctx
*ctx
)
4657 frame_t p
= get_param(ctx
, 0);
4661 store_relaxed(&trace_enabled
, 0);
4663 } else if (p
== 1) {
4665 store_relaxed(&trace_enabled
, 1);
4668 internal(file_line
, "io_trace_ctl_handler: invalid parameter %"PRIuMAX
"", (uintmax_t)p
);
4673 return POINTER_FOLLOW_THUNK_GO
;
4676 #if defined(SUPPORTS_FFI)
4677 #include "ipio_ffi.inc"
4679 static void * attr_fastcall
io_ffi_unsupported(struct io_ctx
*ctx
)
4681 io_terminate_with_error(ctx
, error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), true, NULL
);
4682 return POINTER_FOLLOW_THUNK_EXCEPTION
;
4684 #define io_ffi_get_size_alignment_handler io_ffi_unsupported
4685 #define io_ffi_create_structure_handler io_ffi_unsupported
4686 #define io_ffi_structure_offset_handler io_ffi_unsupported
4687 #define io_ffi_poke_handler io_ffi_unsupported
4688 #define io_ffi_peek_handler io_ffi_unsupported
4689 #define io_ffi_poke_array_handler io_ffi_unsupported
4690 #define io_ffi_peek_array_handler io_ffi_unsupported
4691 #define io_ffi_create_function_handler io_ffi_unsupported
4692 #define io_ffi_call_function_handler io_ffi_unsupported
4693 #define io_ffi_destructor_new_handler io_ffi_unsupported
4694 #define io_ffi_destructor_allocate_handler io_ffi_unsupported
4695 #define io_ffi_destructor_free_handler io_ffi_unsupported
4696 #define io_ffi_destructor_call_handler io_ffi_unsupported
4697 #define io_ffi_handle_to_number_handler io_ffi_unsupported
4698 #define io_ffi_number_to_handle_handler io_ffi_unsupported
4701 static void * attr_fastcall
io_ffi_encode_real_handler(struct io_ctx
*ctx
)
4705 const struct type
*type
;
4709 test
= io_deep_eval(ctx
, "0", false);
4710 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
4713 slot
= get_input(ctx
, 0);
4714 type
= frame_get_type_of_local(ctx
->fp
, slot
);
4716 var
= io_get_flat_pointer(ctx
, slot
);
4718 d
= data_alloc_longint_mayfail(type
->size
* 8, &ctx
->err pass_file_line
);
4721 mpz_import(&da(d
,longint
)->mp
, type
->size
, -1, 1, 0, 0, var
);
4722 frame_set_pointer(ctx
->fp
, get_output(ctx
, 0), pointer_data(d
));
4724 test
= POINTER_FOLLOW_THUNK_GO
;
4729 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
4730 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4734 static void * attr_fastcall
io_ffi_decode_real_handler(struct io_ctx
*ctx
)
4737 frame_t slot
, slot_out
;
4738 const struct type
*type
;
4740 const mpint_t
*mp
= NULL
;
4742 unsigned char *result
;
4744 test
= io_deep_eval(ctx
, "0", false);
4745 if (unlikely(test
!= POINTER_FOLLOW_THUNK_GO
))
4748 slot
= get_input(ctx
, 0);
4749 slot_out
= get_output(ctx
, 0);
4750 type
= frame_get_type_of_local(ctx
->fp
, slot_out
);
4751 result
= frame_var(ctx
->fp
, slot_out
);
4753 memset(result
, 0, type
->size
);
4755 cat(io_get_
,int_default_t
)(ctx
, slot
, &in
, &mp
);
4758 if (unlikely(!mpint_alloc_mayfail(&m
, sizeof(int_default_t
) * 8, &ctx
->err
)))
4760 mpint_import_from_variable(&m
, int_default_t
, in
);
4764 if (unlikely(mpz_sgn(mp
) < 0))
4766 if (unlikely(mpz_sizeinbase(mp
, 2) > (size_t)8 * type
->size
))
4768 mpz_export(result
, NULL
, -1, 1, 0, 0, mp
);
4770 test
= POINTER_FOLLOW_THUNK_GO
;
4778 ctx
->err
= error_ajla(EC_SYNC
, AJLA_ERROR_DOESNT_FIT
);
4780 io_terminate_with_error(ctx
, ctx
->err
, true, NULL
);
4781 test
= POINTER_FOLLOW_THUNK_EXCEPTION
;
4785 static const struct {
4786 void *(attr_fastcall
*do_io
)(struct io_ctx
*ctx
);
4787 } io_handlers
[] = {
4788 { io_exception_make_handler
},
4789 { io_exception_string_handler
},
4790 { io_exception_payload_handler
},
4791 { io_exception_stack_handler
},
4792 { io_n_std_handles_handler
},
4793 { io_get_std_handle_handler
},
4794 { io_get_args_handler
},
4795 { io_get_environment_handler
},
4796 { io_stream_open_handler
},
4797 { io_stream_read_handler
},
4798 { io_stream_open_handler
},
4799 { io_stream_write_handler
},
4800 { io_read_console_packet_handler
},
4801 { io_write_console_packet_handler
},
4802 { io_pipe_handler
},
4803 { io_stream_open_handler
},
4804 { io_stream_read_handler
},
4805 { io_stream_write_handler
},
4806 { io_lseek_handler
},
4807 { io_ftruncate_handler
},
4808 { io_fallocate_handler
},
4809 { io_fclone_range_handler
},
4810 { io_fsync_handler
},
4811 { io_sync_handler
},
4812 { io_root_dir_handler
},
4813 { io_lib_path_handler
},
4814 { io_open_dir_handler
},
4815 { io_read_dir_handler
},
4816 { io_dir_path_handler
},
4817 { io_dmonitor_prepare_handler
},
4818 { io_dmonitor_wait_handler
},
4819 { io_stat_handler
},
4820 { io_fstat_handler
},
4821 { io_fstatfs_handler
},
4822 { io_dstatfs_handler
},
4823 { io_readlink_handler
},
4824 { io_dir_action_handler
},
4825 { io_dir2_action_handler
},
4826 { io_drives_handler
},
4827 { io_stty_handler
},
4828 { io_tty_size_handler
},
4829 { io_tty_background_handler
},
4830 { io_tty_foreground_handler
},
4831 { io_uname_handler
},
4832 { io_get_host_name_handler
},
4833 { io_spawn_handler
},
4834 { io_wait_handler
},
4835 { io_get_time_handler
},
4836 { io_time_to_calendar_handler
},
4837 { io_calendar_to_time_handler
},
4838 { io_sleep_handler
},
4840 { io_never_handler
},
4841 { io_fork_handler
},
4842 { io_atomic_enter_handler
},
4843 { io_atomic_exit_handler
},
4844 { io_wait_for_dereferenced_handler
},
4845 { io_int_to_native_handler
},
4846 { io_native_to_int_handler
},
4847 { io_socket_handler
},
4848 { io_bind_connect_handler
},
4849 { io_connect_wait_handler
},
4850 { io_bind_connect_handler
},
4851 { io_listen_handler
},
4852 { io_accept_handler
},
4853 { io_getsockpeername_handler
},
4854 { io_getsockpeername_handler
},
4855 { io_recvfrom_handler
},
4856 { io_sendto_handler
},
4857 { io_getsockopt_handler
},
4858 { io_setsockopt_handler
},
4859 { io_getaddrinfo_handler
},
4860 { io_getnameinfo_handler
},
4861 { io_msgqueue_new_handler
},
4862 { io_msgqueue_send_handler
},
4863 { io_msgqueue_receive_handler
},
4864 { io_msgqueue_wait_handler
},
4865 { io_msgqueue_is_nonempty_handler
},
4866 { io_signal_handle_handler
},
4867 { io_signal_prepare_handler
},
4868 { io_signal_wait_handler
},
4869 { io_consume_parameter_handler
},
4870 { io_load_program_handler
},
4871 { io_get_function_ptr_handler
},
4872 { io_get_subfunctions_handler
},
4873 { io_load_optimized_pcode_handler
},
4874 { io_register_dependence_handler
},
4875 { io_deep_eval_handler
},
4876 { io_evaluate_handler
},
4877 { io_debug_handler
},
4878 { io_stacktrace_handler
},
4879 { io_trace_ctl_handler
},
4880 { io_ffi_get_size_alignment_handler
},
4881 { io_ffi_create_structure_handler
},
4882 { io_ffi_structure_offset_handler
},
4883 { io_ffi_poke_handler
},
4884 { io_ffi_peek_handler
},
4885 { io_ffi_poke_array_handler
},
4886 { io_ffi_peek_array_handler
},
4887 { io_ffi_handle_to_number_handler
},
4888 { io_ffi_number_to_handle_handler
},
4889 { io_ffi_create_function_handler
},
4890 { io_ffi_call_function_handler
},
4891 { io_ffi_encode_real_handler
},
4892 { io_ffi_decode_real_handler
},
4893 { io_ffi_destructor_new_handler
},
4894 { io_ffi_destructor_allocate_handler
},
4895 { io_ffi_destructor_free_handler
},
4896 { io_ffi_destructor_call_handler
},
4899 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
)
4903 if (n_array_elements(io_handlers
) != IO_N
)
4904 internal(file_line
, "io_handlers doesn't match consts.txt: %lu != %lu", (unsigned long)n_array_elements(io_handlers
), (unsigned long)IO_N
);
4908 ctx
.outputs
= ip
+ 3;
4909 ctx
.inputs
= ctx
.outputs
+ n_outputs
* 2;
4910 ctx
.params
= ctx
.inputs
+ n_inputs
* 2;
4911 ctx
.n_outputs
= n_outputs
;
4912 ctx
.n_inputs
= n_inputs
;
4913 ctx
.n_params
= n_params
;
4914 ajla_assert_lo(io_code
< n_array_elements(io_handlers
), (file_line
, "ipret_io: invalid io code %d", (int)io_code
));
4915 ex
= io_handlers
[io_code
].do_io(&ctx
);
4916 if (unlikely(ex
== POINTER_FOLLOW_THUNK_EXCEPTION
))
4917 ex
= POINTER_FOLLOW_THUNK_GO
;
4921 void name(ipio_init
)(void)
4923 mutex_init(&lib_path_mutex
);
4926 mutex_init(&msgqueue_list_mutex
);
4927 list_init(&msgqueue_list
);
4930 void name(ipio_done
)(void)
4933 if (unlikely(!list_is_empty(&msgqueue_list
)))
4934 warning("there was leaked message queue");
4936 list_for_each(l
, &msgqueue_list
) {
4937 struct resource_msgqueue
*q
= get_struct(l
, struct resource_msgqueue
, list_entry
);
4939 struct msgqueue_entry qe
= q
->queue
[q
->queue_len
- 1];
4941 pointer_dereference(qe
.tag
);
4942 pointer_dereference(qe
.ptr
);
4946 mutex_done(&msgqueue_list_mutex
);
4950 mutex_done(&lib_path_mutex
);