Skip to content

Commit

Permalink
Completely redo buffer accesses. Buffers are now stored as IOBuffer P…
Browse files Browse the repository at this point in the history
…MCs as properties on the handle PMCs. Rewrite all the accessor routines and initialization logic for buffers to account for this new situation.
  • Loading branch information
Whiteknight committed Nov 17, 2012
1 parent eb68007 commit b50b1c0
Show file tree
Hide file tree
Showing 14 changed files with 272 additions and 114 deletions.
1 change: 1 addition & 0 deletions MANIFEST
Expand Up @@ -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 []
Expand Down
7 changes: 6 additions & 1 deletion config/gen/makefiles/root.in
Expand Up @@ -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 \
Expand Down Expand Up @@ -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) \
Expand Down
56 changes: 41 additions & 15 deletions include/parrot/io.h
Expand Up @@ -178,21 +178,17 @@ 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
#define BUFFER_FLAGS_ANY (INTVAL)0

/* 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 */
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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))
Expand All @@ -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))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 = (\
Expand Down
93 changes: 46 additions & 47 deletions src/io/api.c
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -135,8 +135,8 @@ Retrieves the vtable at index C<idx>. If C<idx> is -1, the vtable is instead
searched for by C<name>. Notice that name lookups are much slower. If both the
C<idx> and C<name> are missing or invalid, the default vtable is returned.
=item C<const IO_VTABLE *Parrot_io_get_vtable_for_pmc(PARROT_INTERP, ARGIN(PMC
*handle))>
=item C<const IO_VTABLE * Parrot_io_get_vtable_for_pmc(PARROT_INTERP, PMC
*handle)>
Retrieves the vtable for the given handle type.
Expand Down Expand Up @@ -180,75 +180,72 @@ 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 */
for (i = 0; i < interp->piodata->num_vtables; i++) {
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
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<IO_BUFFER * Parrot_io_get_handle_read_buffer(PARROT_INTERP, PMC *handle,
INTVAL autocreate)>
=item C<IO_BUFFER * Parrot_io_get_handle_read_buffer(PARROT_INTERP, PMC
*handle)>
Get the read buffer for the given handle, if any.
=item C<IO_BUFFER * Parrot_io_get_handle_write_buffer(PARROT_INTERP, PMC *handle,
INTVAL autocreate)>
=item C<IO_BUFFER * Parrot_io_get_handle_write_buffer(PARROT_INTERP, PMC
*handle)>
Get the write buffer for the given handle, if any.
=item C<void Parrot_io_set_handle_buffer(PARROT_INTERP, PMC *handle, IO_BUFFER
*buffer)>
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;
}

/*
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit b50b1c0

Please sign in to comment.