From b50b1c0af521eb4816e84af6bf4d08e4f401f7c4 Mon Sep 17 00:00:00 2001 From: Whiteknight Date: Sat, 17 Nov 2012 18:35:23 -0500 Subject: [PATCH] Completely redo buffer accesses. Buffers are now stored as IOBuffer PMCs as properties on the handle PMCs. Rewrite all the accessor routines and initialization logic for buffers to account for this new situation. --- MANIFEST | 1 + config/gen/makefiles/root.in | 7 ++- include/parrot/io.h | 56 +++++++++++++----- src/io/api.c | 93 +++++++++++++++-------------- src/io/buffer.c | 34 ++++------- src/io/filehandle.c | 2 + src/io/io_private.h | 48 +++++++++++++-- src/io/pipe.c | 2 + src/io/socket.c | 2 + src/io/stringhandle.c | 2 + src/io/userhandle.c | 1 + src/io/utilities.c | 110 +++++++++++++++++++++++++++++++---- src/pmc/iobuffer.pmc | 24 ++++---- src/runcore/cores.c | 4 +- 14 files changed, 272 insertions(+), 114 deletions(-) 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); } }