diff --git a/MANIFEST b/MANIFEST index f08b6b705e..5df78add57 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1378,6 +1378,7 @@ src/pmc/imageiostrings.pmc [] src/pmc/imageiothaw.pmc [] src/pmc/imccompiler.pmc [] src/pmc/integer.pmc [] +src/pmc/iobuffer.pmc [] src/pmc/iterator.pmc [] src/pmc/key.pmc [] src/pmc/lexinfo.pmc [] diff --git a/config/gen/makefiles/root.in b/config/gen/makefiles/root.in index ebe29c2424..37f13f93cf 100644 --- a/config/gen/makefiles/root.in +++ b/config/gen/makefiles/root.in @@ -702,6 +702,7 @@ STR_FILES = \ src/interp/inter_cb.str \ src/interp/api.str \ src/io/api.str \ + src/io/utilities.str \ src/key.str \ src/library.str \ src/multidispatch.str \ @@ -1050,7 +1051,11 @@ src/events$(O) : \ src/alarm$(O) : $(PARROT_H_HEADERS) src/alarm.c \ $(INC_DIR)/alarm.h -src/io/utilities$(O) : $(PARROT_H_HEADERS) src/io/io_private.h src/io/utilities.c +src/io/utilities$(O) : \ + $(PARROT_H_HEADERS) \ + src/io/io_private.h \ + src/io/utilities.str \ + src/io/utilities.c src/io/socket$(O) : \ $(PARROT_H_HEADERS) \ diff --git a/include/parrot/io.h b/include/parrot/io.h index d5e7012b9a..46af221295 100644 --- a/include/parrot/io.h +++ b/include/parrot/io.h @@ -178,12 +178,8 @@ typedef struct _io_vtable { #define IO_VTABLE_STRINGHANDLE 3 #define IO_VTABLE_USER 4 -/* get_pointer values for common io-related pointer values. - ALL IO handle types MUST implement get_pointer and MUST respond to these - values. */ -#define IO_PTR_IDX_VTABLE 0 -#define IO_PTR_IDX_READ_BUFFER 1 -#define IO_PTR_IDX_WRITE_BUFFER 2 +#define IO_IDX_READ_BUFFER 1 +#define IO_IDX_WRITE_BUFFER 2 /* Specify that the buffer may be any size */ #define BUFFER_SIZE_ANY (size_t)-1 @@ -191,8 +187,8 @@ typedef struct _io_vtable { /* Helpful wrappers to get common pointers from IO handle PMCs */ #define IO_GET_VTABLE(i, p) ((const IO_VTABLE *)Parrot_io_get_vtable_for_pmc((i), (p))) -#define IO_GET_READ_BUFFER(i, p) Parrot_io_get_handle_read_buffer((i), (p), 0) -#define IO_GET_WRITE_BUFFER(i, p) Parrot_io_get_handle_write_buffer((i), (p), 0) +#define IO_GET_READ_BUFFER(i, p) Parrot_io_get_handle_read_buffer((i), (p)) +#define IO_GET_WRITE_BUFFER(i, p) Parrot_io_get_handle_write_buffer((i), (p)) /* io/api.c - Public API functions */ /* HEADERIZER BEGIN: src/io/api.c */ @@ -631,6 +627,22 @@ INTVAL Parrot_io_get_flags(PARROT_INTERP, ARGIN(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2); +PARROT_CANNOT_RETURN_NULL +PARROT_WARN_UNUSED_RESULT +IO_BUFFER * Parrot_io_get_handle_read_buffer(PARROT_INTERP, + ARGMOD(PMC *handle)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + +PARROT_CANNOT_RETURN_NULL +PARROT_WARN_UNUSED_RESULT +IO_BUFFER * Parrot_io_get_handle_write_buffer(PARROT_INTERP, + ARGMOD(PMC *handle)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + PARROT_WARN_UNUSED_RESULT PIOHANDLE Parrot_io_get_os_handle(PARROT_INTERP, ARGIN(PMC *handle)) __attribute__nonnull__(1) @@ -641,12 +653,19 @@ PIOHANDLE Parrot_io_get_standard_piohandle(PARROT_INTERP, INTVAL idx) __attribute__nonnull__(1); PARROT_WARN_UNUSED_RESULT -PARROT_CAN_RETURN_NULL +PARROT_CANNOT_RETURN_NULL const IO_VTABLE * Parrot_io_get_vtable(PARROT_INTERP, INTVAL idx, ARGIN_NULLOK(const char * name)) __attribute__nonnull__(1); +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL +const IO_VTABLE * Parrot_io_get_vtable_for_pmc(PARROT_INTERP, + ARGIN(PMC *handle)) + __attribute__nonnull__(1) + __attribute__nonnull__(2); + PARROT_WARN_UNUSED_RESULT PIOOFF_T Parrot_io_make_offset_pmc(PARROT_INTERP, ARGMOD(PMC *pmc)) __attribute__nonnull__(1) @@ -850,6 +869,14 @@ INTVAL Parrot_io_write_byte_buffer_pmc(PARROT_INTERP, #define ASSERT_ARGS_Parrot_io_get_flags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_Parrot_io_get_handle_read_buffer \ + __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_Parrot_io_get_handle_write_buffer \ + __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_Parrot_io_get_os_handle __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -858,6 +885,9 @@ INTVAL Parrot_io_write_byte_buffer_pmc(PARROT_INTERP, PARROT_ASSERT_ARG(interp)) #define ASSERT_ARGS_Parrot_io_get_vtable __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) +#define ASSERT_ARGS_Parrot_io_get_vtable_for_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_Parrot_io_make_offset_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(pmc)) @@ -945,13 +975,10 @@ void Parrot_io_buffer_advance_position(PARROT_INTERP, PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT IO_BUFFER * Parrot_io_buffer_allocate(PARROT_INTERP, - ARGMOD(PMC *owner), INTVAL flags, ARGIN_NULLOK(const STR_VTABLE *encoding), size_t init_size) - __attribute__nonnull__(1) - __attribute__nonnull__(2) - FUNC_MODIFIES(*owner); + __attribute__nonnull__(1); void Parrot_io_buffer_clear(PARROT_INTERP, ARGMOD_NULLOK(IO_BUFFER *buffer)) __attribute__nonnull__(1) @@ -1086,8 +1113,7 @@ size_t Parrot_io_buffer_write_b(PARROT_INTERP, __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) #define ASSERT_ARGS_Parrot_io_buffer_allocate __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ - PARROT_ASSERT_ARG(interp) \ - , PARROT_ASSERT_ARG(owner)) + PARROT_ASSERT_ARG(interp)) #define ASSERT_ARGS_Parrot_io_buffer_clear __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) #define ASSERT_ARGS_Parrot_io_buffer_content_size __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ diff --git a/src/io/api.c b/src/io/api.c index 2e09d675c6..0ae00aadff 100644 --- a/src/io/api.c +++ b/src/io/api.c @@ -70,13 +70,13 @@ Parrot_io_init(PARROT_INTERP) os_handle = Parrot_io_internal_std_os_handle(interp, PIO_STDIN_FILENO); handle = Parrot_io_fdopen_flags(interp, PMCNULL, os_handle, PIO_F_READ); - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY, + Parrot_io_buffer_add_to_handle(interp, handle, IO_IDX_READ_BUFFER, BUFFER_SIZE_ANY, PIO_BF_BLKBUF); _PIO_STDIN(interp) = handle; os_handle = Parrot_io_internal_std_os_handle(interp, PIO_STDOUT_FILENO); handle = Parrot_io_fdopen_flags(interp, PMCNULL, os_handle, PIO_F_WRITE); - /* Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, + /* Parrot_io_buffer_add_to_handle(interp, handle, IO_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, PIO_BF_LINEBUF); */ _PIO_STDOUT(interp) = handle; @@ -110,8 +110,8 @@ io_setup_vtables(PARROT_INTERP) const int number_of_vtables = 5; interp->piodata->vtables = (const IO_VTABLE*)mem_gc_allocate_n_zeroed_typed(interp, number_of_vtables, const IO_VTABLE); - interp->piodata->vtable_maps = Parrot_hash_create(interp, enum_type_INTVAL, - Hash_key_type_ptr; + interp->piodata->vtable_map = Parrot_hash_create(interp, enum_type_INTVAL, + Hash_key_type_ptr); interp->piodata->num_vtables = number_of_vtables; io_filehandle_setup_vtable(interp, NULL, IO_VTABLE_FILEHANDLE); @@ -135,8 +135,8 @@ Retrieves the vtable at index C. If C is -1, the vtable is instead searched for by C. Notice that name lookups are much slower. If both the C and C are missing or invalid, the default vtable is returned. -=item C +=item C Retrieves the vtable for the given handle type. @@ -180,7 +180,7 @@ Parrot_io_get_vtable(PARROT_INTERP, INTVAL idx, ARGIN_NULLOK(const char * name)) /* If we have neither an idx nor a name, return the default user vtable */ if (!name) - return interp->piodata->vtables[IO_VTABLE_USER]; + return &(interp->piodata->vtables[IO_VTABLE_USER]); /* If we have a name, try to look it up by name. If we can't find it, return the default */ @@ -188,7 +188,7 @@ Parrot_io_get_vtable(PARROT_INTERP, INTVAL idx, ARGIN_NULLOK(const char * name)) if (!strcmp(name, interp->piodata->vtables[i].name)) return &(interp->piodata->vtables[i]); } - return interp->piodata->vtables[IO_VTABLE_USER]; + return &(interp->piodata->vtables[IO_VTABLE_USER]); } PARROT_WARN_UNUSED_RESULT @@ -196,59 +196,56 @@ PARROT_CANNOT_RETURN_NULL const IO_VTABLE * Parrot_io_get_vtable_for_pmc(PARROT_INTERP, ARGIN(PMC *handle)) { - ASSERT_AGS(Parrot_io_get_vtable_for_pmc) - const IO_VTABLE * vtable = Parrot_hash_get(interp, interp->piodata->vtable_maps, + ASSERT_ARGS(Parrot_io_get_vtable_for_pmc) + const IO_VTABLE * vtable = Parrot_hash_get(interp, interp->piodata->vtable_map, handle->vtable->base_type); if (!vtable) - return interp->piodata->vtables[IO_VTABLE_USER]; + return &(interp->piodata->vtables[IO_VTABLE_USER]); return vtable; } /* -=item C +=item C Get the read buffer for the given handle, if any. -=item C +=item C Get the write buffer for the given handle, if any. -=item C - -Set the buffer for the given handle, if any. - =cut */ -PARROT_CAN_RETURN_NULL +PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT IO_BUFFER * -Parrot_io_get_handle_read_buffer(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL autocreate) +Parrot_io_get_handle_read_buffer(PARROT_INTERP, ARGMOD(PMC *handle)) { ASSERT_ARGS(Parrot_io_get_handle_read_buffer) - PMC * const buffer = VTABLE_get_prop(interp, handle, CONST_STRING("!io_read_buffer!")); - if (PMC_IS_NULL(buffer) && autocreate) { - // TODO: When we have buffer pmcs, fill them in here. - } - return buffer; + IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); + PMC * const buffer_pmc = io_get_handle_buffer_pmc(interp, handle, IO_IDX_READ_BUFFER, + vtable, BUFFER_SIZE_ANY, BUFFER_FLAGS_ANY, 0); + if (!PMC_IS_NULL(buffer_pmc)) + return VTABLE_get_pointer(interp, buffer_pmc); + return NULL; } -PARROT_CAN_RETURN_NULL +PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT IO_BUFFER * -Parrot_io_get_handle_write_buffer(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL autocreate) +Parrot_io_get_handle_write_buffer(PARROT_INTERP, ARGMOD(PMC *handle)) { ASSERT_ARGS(Parrot_io_get_handle_write_buffer) - PMC * const buffer = VTABLE_get_prop(interp, handle, CONST_STRING("!io_write_buffer!")); - if (PMC_IS_NULL(buffer) && autocreate) { - // TODO: When we have buffer pmcs, fill them in here. - } - return buffer; + IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); + PMC * const buffer_pmc = io_get_handle_buffer_pmc(interp, handle, IO_IDX_WRITE_BUFFER, + vtable, BUFFER_SIZE_ANY, BUFFER_FLAGS_ANY, 0); + if (!PMC_IS_NULL(buffer_pmc)) + return VTABLE_get_pointer(interp, buffer_pmc); + return NULL; } /* @@ -419,10 +416,10 @@ Parrot_io_open(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(STRING *path), /* If this type uses buffers by default, set them up, and if we're in an acceptable mode, set up buffers. */ if (vtable->flags & PIO_VF_DEFAULT_READ_BUF && flags & PIO_F_READ) - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY, + Parrot_io_buffer_add_to_handle(interp, handle, IO_IDX_READ_BUFFER, BUFFER_SIZE_ANY, PIO_BF_BLKBUF); if (vtable->flags & PIO_VF_DEFAULT_WRITE_BUF && flags & PIO_F_WRITE) - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, + Parrot_io_buffer_add_to_handle(interp, handle, IO_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, PIO_BF_BLKBUF); } @@ -781,7 +778,8 @@ Parrot_io_read_s(PARROT_INTERP, ARGMOD(PMC *handle), size_t length) avoid using a read_buffer here. Detect that case and don't assign a buffer if not needed. */ if (read_buffer == NULL) - read_buffer = io_verify_has_read_buffer(interp, handle, vtable, BUFFER_SIZE_ANY); + read_buffer = io_verify_has_buffer(interp, handle, IO_IDX_READ_BUFFER, + vtable, BUFFER_SIZE_ANY, BUFFER_FLAGS_ANY); io_verify_is_open_for(interp, handle, vtable, PIO_F_READ); io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer); @@ -843,8 +841,8 @@ Parrot_io_readall_s(PARROT_INTERP, ARGMOD(PMC *handle)) return Parrot_str_new_init(interp, "", 0, encoding, 0); if (total_size == PIO_UNKNOWN_SIZE) { - IO_BUFFER * const read_buffer = io_verify_has_read_buffer(interp, handle, vtable, - BUFFER_FLAGS_ANY); + IO_BUFFER * const read_buffer = io_verify_has_buffer(interp, handle, + IO_IDX_READ_BUFFER, vtable, BUFFER_SIZE_ANY, BUFFER_FLAGS_ANY); size_t available_bytes = Parrot_io_buffer_fill(interp, read_buffer, handle, vtable); STRING * const s = io_get_new_empty_string(interp, encoding, -1, PIO_STRING_BUFFER_MINSIZE); @@ -1033,7 +1031,8 @@ Parrot_io_readline_s(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING * terminat io_verify_is_open_for(interp, handle, vtable, PIO_F_READ); if (read_buffer == NULL) - read_buffer = io_verify_has_read_buffer(interp, handle, vtable, BUFFER_SIZE_ANY); + read_buffer = io_verify_has_buffer(interp, handle,IO_IDX_READ_BUFFER, + vtable, BUFFER_SIZE_ANY, BUFFER_FLAGS_ANY); /* Because of the way buffering works, the terminator sequence may be, at most, one character shorter than half the size of the buffer. @@ -2089,19 +2088,19 @@ Parrot_io_set_buffer_mode(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING *mode uses separate read/write buffers, so we have to act on them separately. */ if (STRING_equal(interp, mode, CONST_STRING(interp, "unbuffered"))) { - Parrot_io_buffer_remove_from_handle(interp, handle, IO_PTR_IDX_READ_BUFFER); - Parrot_io_buffer_remove_from_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER); + Parrot_io_buffer_remove_from_handle(interp, handle, IO_IDX_READ_BUFFER); + Parrot_io_buffer_remove_from_handle(interp, handle, IO_IDX_WRITE_BUFFER); } else if (STRING_equal(interp, mode, CONST_STRING(interp, "line-buffered"))) { - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY, + Parrot_io_buffer_add_to_handle(interp, handle, IO_IDX_READ_BUFFER, BUFFER_SIZE_ANY, PIO_BF_LINEBUF); - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, + Parrot_io_buffer_add_to_handle(interp, handle, IO_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, PIO_BF_LINEBUF); } else if (STRING_equal(interp, mode, CONST_STRING(interp, "full-buffered"))) { - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY, + Parrot_io_buffer_add_to_handle(interp, handle, IO_IDX_READ_BUFFER, BUFFER_SIZE_ANY, PIO_BF_BLKBUF); - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, + Parrot_io_buffer_add_to_handle(interp, handle, IO_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, PIO_BF_BLKBUF); } else @@ -2140,7 +2139,7 @@ Parrot_io_buffer_size(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL size, INTVAL ha ASSERT_ARGS(Parrot_io_buffer_size) if (has_size) - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, + Parrot_io_buffer_add_to_handle(interp, handle, IO_IDX_READ_BUFFER, size, PIO_BF_BLKBUF); { IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle); diff --git a/src/io/buffer.c b/src/io/buffer.c index 5cabd503e5..1bcbd7406c 100644 --- a/src/io/buffer.c +++ b/src/io/buffer.c @@ -74,10 +74,10 @@ static size_t io_buffer_transfer_to_mem(PARROT_INTERP, /* -=item C +=item C -Allocate a new buffer for PMC C with the given flags and settings. +Allocate a new buffer with the given flags and settings. =item C @@ -91,7 +91,7 @@ Free the C memory. PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT IO_BUFFER * -Parrot_io_buffer_allocate(PARROT_INTERP, ARGMOD(PMC *owner), INTVAL flags, +Parrot_io_buffer_allocate(PARROT_INTERP, INTVAL flags, ARGIN_NULLOK(const STR_VTABLE *encoding), size_t init_size) { ASSERT_ARGS(Parrot_io_buffer_allocate) @@ -145,15 +145,15 @@ Parrot_io_buffer_free(PARROT_INTERP, ARGFREE(IO_BUFFER *buffer)) idx, size_t length, INTVAL flags)> Allocate a new C and attach it to PMC C at position -C. Valid positions are C and -C. If the buffer already exists, resize it to match +C. Valid positions are C and +C. If the buffer already exists, resize it to match the specifications. =item C Remove the buffer from C at position C. Valid positions are -C and C. +C and C. =cut @@ -164,22 +164,12 @@ Parrot_io_buffer_add_to_handle(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL idx, size_t length, INTVAL flags) { ASSERT_ARGS(Parrot_io_buffer_add_to_handle) - if (idx != IO_PTR_IDX_READ_BUFFER && idx != IO_PTR_IDX_WRITE_BUFFER) + if (idx != IO_IDX_READ_BUFFER && idx != IO_IDX_WRITE_BUFFER) Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR, "Unknown buffer number %d", idx); { - IO_BUFFER * buffer = (IO_BUFFER *)VTABLE_get_pointer_keyed_int(interp, handle, idx); - if (buffer) { - Parrot_io_buffer_resize(interp, buffer, length); - PARROT_ASSERT(length == BUFFER_SIZE_ANY || buffer->buffer_size >= length); - } - else { - buffer = Parrot_io_buffer_allocate(interp, handle, flags, NULL, length); - PARROT_ASSERT(buffer); - VTABLE_set_pointer_keyed_int(interp, handle, idx, buffer); - } - if (flags != BUFFER_FLAGS_ANY) - buffer->flags = flags; + const IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); + io_verify_has_buffer(interp, handle, idx, vtable, length, flags); } } @@ -187,7 +177,7 @@ void Parrot_io_buffer_remove_from_handle(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL idx) { ASSERT_ARGS(Parrot_io_buffer_remove_from_handle) - if (idx != IO_PTR_IDX_READ_BUFFER && idx != IO_PTR_IDX_WRITE_BUFFER) + if (idx != IO_IDX_READ_BUFFER && idx != IO_IDX_WRITE_BUFFER) Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR, "Unknown buffer number %d", idx); { @@ -248,8 +238,6 @@ Parrot_io_buffer_mark(SHIM_INTERP, ARGMOD_NULLOK(IO_BUFFER *buffer)) ASSERT_ARGS(Parrot_io_buffer_mark) if (!buffer) return; - /*if (!PMC_IS_NULL(buffer->owner_pmc)) - Parrot_gc_mark_PMC_alive(interp, buffer->owner_pmc);*/ } /* diff --git a/src/io/filehandle.c b/src/io/filehandle.c index 85a3f063bd..21a55cf02d 100644 --- a/src/io/filehandle.c +++ b/src/io/filehandle.c @@ -272,6 +272,8 @@ io_filehandle_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTV vtable->get_flags = io_filehandle_get_flags; vtable->total_size = io_filehandle_total_size; vtable->get_piohandle = io_filehandle_get_piohandle; + + Parrot_hash_put(interp, interp->piodata->vtable_map, enum_class_FileHandle, vtable); } /* diff --git a/src/io/io_private.h b/src/io/io_private.h index 43e95adedb..6140e4b328 100644 --- a/src/io/io_private.h +++ b/src/io/io_private.h @@ -125,7 +125,7 @@ struct _ParrotIOData { PMC ** table; /* Standard IO Streams (STDIN, STDOUT, STDERR) */ INTVAL num_vtables; /* Number of vtables */ const IO_VTABLE * vtables; /* Array of VTABLES */ - Hash * vtable_maps; /* Mapping of pmc base_type -> io_vtable */ + Hash * vtable_map; /* Mapping of pmc base_type -> io_vtable */ }; /* redefine PIO_STD* for internal use */ @@ -190,6 +190,20 @@ const STR_VTABLE * io_get_encoding(PARROT_INTERP, __attribute__nonnull__(3) FUNC_MODIFIES(*handle); +PARROT_CANNOT_RETURN_NULL +PARROT_WARN_UNUSED_RESULT +PMC * io_get_handle_buffer_pmc(PARROT_INTERP, + ARGMOD(PMC *handle), + INTVAL buffer_idx, + ARGIN(const IO_VTABLE *vtable), + size_t buffer_size, + INTVAL flags, + INTVAL autocreate) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + __attribute__nonnull__(4) + FUNC_MODIFIES(*handle); + PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT STRING * io_get_new_empty_string(PARROT_INTERP, @@ -208,6 +222,21 @@ PARROT_WARN_UNUSED_RESULT PMC * io_get_new_socket(PARROT_INTERP) __attribute__nonnull__(1); +PARROT_CANNOT_RETURN_NULL +PARROT_WARN_UNUSED_RESULT +IO_BUFFER * io_initialize_buffer_pmc(PARROT_INTERP, + ARGMOD(PMC * buffer_pmc), + ARGMOD(PMC * handle), + ARGIN(const IO_VTABLE *vtable), + size_t buffer_size, + INTVAL flags) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + __attribute__nonnull__(3) + __attribute__nonnull__(4) + FUNC_MODIFIES(* buffer_pmc) + FUNC_MODIFIES(* handle); + void io_read_chars_append_string(PARROT_INTERP, ARGMOD(STRING * s), ARGMOD(PMC *handle), @@ -279,13 +308,15 @@ void io_sync_buffers_for_write(PARROT_INTERP, PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL -IO_BUFFER * io_verify_has_read_buffer(PARROT_INTERP, +IO_BUFFER * io_verify_has_buffer(PARROT_INTERP, ARGIN(PMC *handle), + INTVAL buffer_idx, ARGIN(const IO_VTABLE *vtable), + size_t buffer_size, INTVAL flags) __attribute__nonnull__(1) __attribute__nonnull__(2) - __attribute__nonnull__(3); + __attribute__nonnull__(4); void io_verify_is_open_for(PARROT_INTERP, ARGIN(PMC *handle), @@ -314,12 +345,21 @@ STRING * io_verify_string_encoding(PARROT_INTERP, PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle) \ , PARROT_ASSERT_ARG(vtable)) +#define ASSERT_ARGS_io_get_handle_buffer_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle) \ + , PARROT_ASSERT_ARG(vtable)) #define ASSERT_ARGS_io_get_new_empty_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) #define ASSERT_ARGS_io_get_new_filehandle __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) #define ASSERT_ARGS_io_get_new_socket __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) +#define ASSERT_ARGS_io_initialize_buffer_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(buffer_pmc) \ + , PARROT_ASSERT_ARG(handle) \ + , PARROT_ASSERT_ARG(vtable)) #define ASSERT_ARGS_io_read_chars_append_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(s) \ @@ -344,7 +384,7 @@ STRING * io_verify_string_encoding(PARROT_INTERP, PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle) \ , PARROT_ASSERT_ARG(vtable)) -#define ASSERT_ARGS_io_verify_has_read_buffer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ +#define ASSERT_ARGS_io_verify_has_buffer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle) \ , PARROT_ASSERT_ARG(vtable)) diff --git a/src/io/pipe.c b/src/io/pipe.c index c07ebb304f..6135089a8e 100644 --- a/src/io/pipe.c +++ b/src/io/pipe.c @@ -240,6 +240,8 @@ io_pipe_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx vtable->get_flags = io_pipe_get_flags; vtable->total_size = io_pipe_total_size; vtable->get_piohandle = io_pipe_get_piohandle; + + Parrot_hash_put(interp, interp->piodata->vtable_map, enum_class_Pipe, vtable); } /* diff --git a/src/io/socket.c b/src/io/socket.c index ba1c14a5ac..646afbfeae 100644 --- a/src/io/socket.c +++ b/src/io/socket.c @@ -243,6 +243,8 @@ io_socket_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL i vtable->set_flags = io_socket_set_flags; vtable->get_flags = io_socket_get_flags; vtable->total_size = io_socket_total_size; + + Parrot_hash_put(interp, interp->piodata->vtable_map, enum_class_Socket, vtable); } /* diff --git a/src/io/stringhandle.c b/src/io/stringhandle.c index ded7af2871..5b8e902aa4 100644 --- a/src/io/stringhandle.c +++ b/src/io/stringhandle.c @@ -251,6 +251,8 @@ io_stringhandle_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), IN vtable->get_flags = io_stringhandle_get_flags; vtable->total_size = io_stringhandle_total_size; vtable->get_piohandle = io_stringhandle_get_piohandle; + + Parrot_hash_put(interp, interp->piodata->vtable_map, enum_class_StringHandle, vtable); } /* diff --git a/src/io/userhandle.c b/src/io/userhandle.c index 6827de51a3..b488623eab 100644 --- a/src/io/userhandle.c +++ b/src/io/userhandle.c @@ -199,6 +199,7 @@ io_userhandle_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTV vtable->total_size = io_userhandle_total_size; vtable->get_piohandle = io_userhandle_get_piohandle; */ + Parrot_hash_put(interp, interp->piodata->vtable_map, enum_class_Object, vtable); } diff --git a/src/io/utilities.c b/src/io/utilities.c index b177133ed4..e8909d89d8 100644 --- a/src/io/utilities.c +++ b/src/io/utilities.c @@ -21,10 +21,22 @@ of intelligence between the IO API and the buffering API. #include "parrot/parrot.h" #include "io_private.h" +#include "utilities.str" /* HEADERIZER HFILE: src/io/io_private.h */ /* HEADERIZER BEGIN: static */ +/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ + +PARROT_CANNOT_RETURN_NULL +PARROT_WARN_UNUSED_RESULT +PARROT_PURE_FUNCTION +static STRING * io_get_buffer_prop_name(PARROT_INTERP, INTVAL buffer_idx) + __attribute__nonnull__(1); + +#define ASSERT_ARGS_io_get_buffer_prop_name __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp)) +/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ /* HEADERIZER END: static */ /* @@ -199,6 +211,18 @@ IO_VTABLE *vtable, INTVAL flags)> Verify that the given C has a read buffer attached. If not, allocate one. +=item C + +Get the read buffer PMC for the given handle, if any. Autocreate the buffer +if necessary. + +=item C + +Get the write buffer for the given handle, if any. Autocreate the buffer +if necessary. + =cut */ @@ -206,22 +230,86 @@ one. PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL IO_BUFFER * -io_verify_has_read_buffer(PARROT_INTERP, ARGIN(PMC *handle), - ARGIN(const IO_VTABLE *vtable), INTVAL flags) +io_verify_has_buffer(PARROT_INTERP, ARGIN(PMC *handle), INTVAL buffer_idx, + ARGIN(const IO_VTABLE *vtable), size_t buffer_size, INTVAL flags) +{ + ASSERT_ARGS(io_verify_has_buffer) + PMC * buffer_pmc = io_get_handle_buffer_pmc(interp, handle, buffer_idx, + vtable, buffer_size, flags, 1); + return (IO_BUFFER*) VTABLE_get_pointer(interp, buffer_pmc); +} + +PARROT_CANNOT_RETURN_NULL +PARROT_WARN_UNUSED_RESULT +PARROT_PURE_FUNCTION +static STRING * +io_get_buffer_prop_name(PARROT_INTERP, INTVAL buffer_idx) +{ + ASSERT_ARGS(io_get_buffer_prop_name) + switch (buffer_idx) { + case IO_IDX_READ_BUFFER: + return CONST_STRING(interp, "!Parrot_io_read_buffer!"); + case IO_IDX_WRITE_BUFFER: + return CONST_STRING(interp, "!Parrot_io_write_buffer!"); + default: + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR, + "Unknown buffer index %d", buffer_idx); + } +} + +PARROT_CANNOT_RETURN_NULL +PARROT_WARN_UNUSED_RESULT +PMC * +io_get_handle_buffer_pmc(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL buffer_idx, + ARGIN(const IO_VTABLE *vtable), size_t buffer_size, INTVAL flags, + INTVAL autocreate) +{ + ASSERT_ARGS(io_get_handle_buffer_pmc) + STRING * const prop_name = io_get_buffer_prop_name(interp, buffer_idx); + + PMC * buffer_pmc = Parrot_pmc_getprop(interp, handle, prop_name); + /* TODO: Verify that the buffer is at least the size specified */ + if (PMC_IS_NULL(buffer_pmc) && autocreate) { + buffer_pmc = Parrot_pmc_new(interp, enum_class_IOBuffer); + io_initialize_buffer_pmc(interp, buffer_pmc, handle, vtable, buffer_size, flags); + + /* Store the buffer on the handle as a property */ + Parrot_pmc_setprop(interp, handle, prop_name, buffer_pmc); + } + return buffer_pmc; +} + +PARROT_CANNOT_RETURN_NULL +PARROT_WARN_UNUSED_RESULT +IO_BUFFER * +io_initialize_buffer_pmc(PARROT_INTERP, ARGMOD(PMC * buffer_pmc), + ARGMOD(PMC * handle), ARGIN(const IO_VTABLE *vtable), size_t buffer_size, + INTVAL flags) { - ASSERT_ARGS(io_verify_has_read_buffer) - IO_BUFFER * buffer = IO_GET_READ_BUFFER(interp, handle); - if (!buffer) { + ASSERT_ARGS(io_initialize_buffer_pmc) + PARROT_ASSERT(!PMC_IS_NULL(buffer_pmc)); + PARROT_ASSERT(!PMC_IS_NULL(handle)); + vtable = vtable ? vtable : IO_GET_VTABLE(interp, handle); + PARROT_ASSERT(vtable); + { + /* Set up the buffer with the correct encoding */ const STR_VTABLE * encoding = vtable->get_encoding(interp, handle); if (encoding == NULL) encoding = Parrot_platform_encoding_ptr; - buffer = Parrot_io_buffer_allocate(interp, handle, flags, encoding, BUFFER_SIZE_ANY); - VTABLE_set_pointer_keyed_int(interp, handle, IO_PTR_IDX_READ_BUFFER, buffer); + { + IO_BUFFER * const buffer = Parrot_io_buffer_allocate(interp, + BUFFER_FLAGS_ANY, encoding, + buffer_size); + + /* Make sure to use the correct flags */ + if (flags != BUFFER_FLAGS_ANY) + buffer->flags = flags; + + /* Assign the buffer to the IOBuffer PMC */ + VTABLE_set_pointer(interp, buffer_pmc, buffer); + return buffer; + } } - PARROT_ASSERT(buffer); - if (flags != BUFFER_FLAGS_ANY) - buffer->flags = flags; - return buffer; } /* diff --git a/src/pmc/iobuffer.pmc b/src/pmc/iobuffer.pmc index 85311c5d9b..d140e94ecf 100644 --- a/src/pmc/iobuffer.pmc +++ b/src/pmc/iobuffer.pmc @@ -2,24 +2,26 @@ pmclass IOBuffer auto_attrs { ATTR IO_BUFFER * buffer; VTABLE void init() { - Parrot_IOBuffer_attributes * const attrs = - PMC_data_typed(SELF, Parrot_IOBuffer_attributes *); - - attrs->buffer = Parrot_io_buffer_allocate(INTERP, SELF, 0, Parrot_str_default_encoding, BUFFER_SIZE_ANY); - + Parrot_IOBuffer_attributes * const attrs = PARROT_IOBUFFER(SELF); + attrs->buffer = NULL; PObj_custom_mark_SET(SELF); PObj_custom_destroy_SET(SELF); } VTABLE void init_int(INTVAL buffer_size) { - Parrot_IOBuffer_attributes * const attrs = - PMC_data_typed(SELF, Parrot_IOBuffer_attributes *); + VTABLE_init(INTERP, SELF); + VTABLE_set_integer_native(INTERP, SELF, buffer_size); + } - PARROT_ASSERT(buffer_size > 0); - attrs->buffer = Parrot_io_buffer_allocate(INTERP, SELF, 0, Parrot_str_default_encoding, (size_t)buffer_size); + VTABLE void set_integer_native(INTVAL buffer_size) { + Parrot_IOBuffer_attributes * const attrs = PARROT_IOBUFFER(SELF); - PObj_custom_mark_SET(SELF); - PObj_custom_destroy_SET(SELF); + PARROT_ASSERT(buffer_size > 0); + if (attrs->buffer) + Parrot_io_buffer_resize(INTERP, attrs->buffer, buffer_size); + else + attrs->buffer = Parrot_io_buffer_allocate(INTERP, 0, + Parrot_platform_encoding_ptr, (size_t)buffer_size); } VTABLE void mark() { diff --git a/src/runcore/cores.c b/src/runcore/cores.c index 026b8d1d0c..c4ff7d0334 100644 --- a/src/runcore/cores.c +++ b/src/runcore/cores.c @@ -564,8 +564,8 @@ runops_trace_core(PARROT_INTERP, ARGIN(opcode_t *pc)) if (!Parrot_io_is_tty_handle(debugger, pio)) { /* this is essential (100 x faster!) and should probably * be in init/open code */ - Parrot_io_buffer_add_to_handle(debugger, pio, IO_PTR_IDX_WRITE_BUFFER, 8192, - BUFFER_FLAGS_ANY); + Parrot_io_buffer_add_to_handle(debugger, pio, IO_IDX_WRITE_BUFFER, 8192, + BUFFER_FLAGS_ANY); } }