Permalink
Browse files

[GH #893] improve concurrent say. concat with \n, then puts

Provide better atomicity with threads. To avoid mixing strings with
newlines in most cases. This is not foolproof of course.
concat only if it will not extend the already allocated buffer to
avoid copying.
make bootstrap-ops for say
  • Loading branch information...
1 parent b1d0662 commit 4fff43a7634efa791b075794a07541420b36e297 Reini Urban committed Dec 20, 2012
Showing with 84 additions and 16 deletions.
  1. +41 −8 src/ops/core_ops.c
  2. +43 −8 src/ops/io.ops
View
@@ -13802,7 +13802,7 @@ Parrot_jump_i(opcode_t *cur_opcode, PARROT_INTERP) {
}
opcode_t *
-Parrot_jump_ic(opcode_t *cur_opcode, SHIM_INTERP) {
+Parrot_jump_ic(opcode_t *cur_opcode, PARROT_INTERP) {
opcode_t * const loc = INTVAL2PTR(opcode_t *, ICONST(1));
return (opcode_t *)loc;
@@ -17031,24 +17031,46 @@ Parrot_say_nc(opcode_t *cur_opcode, PARROT_INTERP) {
opcode_t *
Parrot_say_s(opcode_t *cur_opcode, PARROT_INTERP) {
STRING * const s = SREG(1);
+ STRING * const nl = Parrot_str_new_constant(interp, "\n");
if ((s && Parrot_str_byte_length(interp, s))) {
- Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
+ if (((!PObj_is_growable_TESTALL(s)) || (Buffer_buflen(s) <= (s->bufused + s->encoding->to_encoding(interp, nl)->bufused)))) {
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
+ }
+ else {
+ PARROT_ASSERT((s->strstart == Parrot_str_concat(interp, s, nl)->strstart));
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), Parrot_str_concat(interp, s, nl));
+ }
+
+ }
+ else {
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
}
- Parrot_io_putps(interp, _PIO_STDOUT(interp), Parrot_str_new_constant(interp, "\n"));
return cur_opcode + 2;
}
opcode_t *
Parrot_say_sc(opcode_t *cur_opcode, PARROT_INTERP) {
STRING * const s = SCONST(1);
+ STRING * const nl = Parrot_str_new_constant(interp, "\n");
if ((s && Parrot_str_byte_length(interp, s))) {
- Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
+ if (((!PObj_is_growable_TESTALL(s)) || (Buffer_buflen(s) <= (s->bufused + s->encoding->to_encoding(interp, nl)->bufused)))) {
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
+ }
+ else {
+ PARROT_ASSERT((s->strstart == Parrot_str_concat(interp, s, nl)->strstart));
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), Parrot_str_concat(interp, s, nl));
+ }
+
+ }
+ else {
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
}
- Parrot_io_putps(interp, _PIO_STDOUT(interp), Parrot_str_new_constant(interp, "\n"));
return cur_opcode + 2;
}
@@ -17063,12 +17085,23 @@ Parrot_say_p(opcode_t *cur_opcode, PARROT_INTERP) {
}
else {
STRING * const s = VTABLE_get_string(interp, p);
+ STRING * const nl = Parrot_str_new_constant(interp, "\n");
if (s) {
- Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
+ if (((!PObj_is_growable_TESTALL(s)) || (Buffer_buflen(s) <= (s->bufused + s->encoding->to_encoding(interp, nl)->bufused)))) {
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
+ }
+ else {
+ PARROT_ASSERT((s->strstart == Parrot_str_concat(interp, s, nl)->strstart));
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), Parrot_str_concat(interp, s, nl));
+ }
+
+ }
+ else {
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
}
- Parrot_io_putps(interp, _PIO_STDOUT(interp), Parrot_str_new_constant(interp, "\n"));
}
return cur_opcode + 2;
@@ -24553,7 +24586,7 @@ Parrot_enable_preemption(opcode_t *cur_opcode, PARROT_INTERP) {
}
opcode_t *
-Parrot_terminate(opcode_t *cur_opcode, SHIM_INTERP) {
+Parrot_terminate(opcode_t *cur_opcode, PARROT_INTERP) {
return (opcode_t *)0;
return cur_opcode + 1;
}
View
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002-2008, Parrot Foundation.
+ * Copyright (C) 2002-2012, Parrot Foundation.
** io.ops
*/
@@ -16,7 +16,7 @@ io.ops - I/O Opcodes
=head1 DESCRIPTION
-Parrot's IO API
+Parrot IO API
When making changes to any ops file, run C<make bootstrap-ops> to regenerate
all generated ops files.
@@ -106,11 +106,33 @@ inline op say(in NUM) :base_io {
#endif
}
+/*
+
+If the string argument can be extended by \n without copying,
+concat the strings before calling io_putps to provider better atomicity
+with threads. To avoid mixing strings with newlines in most cases.
+This is not foolproof of course. [GH #893]
+
+*/
+
op say(in STR) :base_io {
STRING * const s = $1;
- if (s && Parrot_str_byte_length(interp, s))
- Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
- Parrot_io_putps(interp, _PIO_STDOUT(interp), Parrot_str_new_constant(interp, "\n"));
+ STRING * const nl = Parrot_str_new_constant(interp, "\n");
+
+ if (s && Parrot_str_byte_length(interp, s)) {
+ if (!PObj_is_growable_TESTALL(s)
+ || Buffer_buflen(s) <= s->bufused + s->encoding->to_encoding(interp, nl)->bufused) {
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
+ }
+ else {
+ PARROT_ASSERT( s->strstart == Parrot_str_concat(interp, s, nl)->strstart );
+ Parrot_io_putps(interp, _PIO_STDOUT(interp),
+ Parrot_str_concat(interp, s, nl));
+ }
+ }
+ else
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
}
op say(invar PMC) :base_io {
@@ -124,9 +146,22 @@ op say(invar PMC) :base_io {
}
else {
STRING * const s = VTABLE_get_string(interp, p);
- if (s)
- Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
- Parrot_io_putps(interp, _PIO_STDOUT(interp), Parrot_str_new_constant(interp, "\n"));
+ STRING * const nl = Parrot_str_new_constant(interp, "\n");
+
+ if (s) {
+ if (!PObj_is_growable_TESTALL(s)
+ || Buffer_buflen(s) <= s->bufused + s->encoding->to_encoding(interp, nl)->bufused) {
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), s);
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
+ }
+ else {
+ PARROT_ASSERT( s->strstart == Parrot_str_concat(interp, s, nl)->strstart );
+ Parrot_io_putps(interp, _PIO_STDOUT(interp),
+ Parrot_str_concat(interp, s, nl));
+ }
+ }
+ else
+ Parrot_io_putps(interp, _PIO_STDOUT(interp), nl);
}
}

0 comments on commit 4fff43a

Please sign in to comment.