pike.git / src / modules / _Stdio / buffer.cmod

version» Context lines:

pike.git/src/modules/_Stdio/buffer.cmod:106:    {    if( m ) add_ref(m);    if( io->error_mode ) free_program( io->error_mode );    io->error_mode = m;    }       PMOD_EXPORT Buffer *io_buffer_from_object(struct object *o) {    return get_storage(o, Buffer_program);    }    -  -  static void io_unlock( Buffer *io ) -  { -  io->locked--; -  } -  -  static void io_lock( Buffer *io ) -  { -  io->locked++; -  } -  -  static void io_was_locked( ) -  ATTRIBUTE((noclone,noinline)); -  +     PMOD_EXPORT void io_trim( Buffer *io )    ATTRIBUTE((noinline));       static void io_trim_waste( Buffer *io )    {    if( UNLIKELY(io->allocated > (io_len(io) * (1.0+io->max_waste))) )    io_trim(io);    }       static int io_is_whitespace( Buffer *io, size_t pos )
pike.git/src/modules/_Stdio/buffer.cmod:156:    io->len -= io->offset;    io->offset = 0;   #ifdef PIKE_DEBUG    io->num_move++;   #endif    }    }       PMOD_EXPORT void io_trim( Buffer *io )    { -  if( io->allocated && (io->offset > 64 || io->len > 64) && !io->locked) +  if( io->allocated && (io->offset > 64 || io->len > 64) && !io->child)    {    if( io->offset > 64 && io->offset > io_len(io) )    io_discard_bufstart(io);       if( io->len > 64 && ((io->allocated > (io->len)*(1.0+io->max_waste))))    {    io->buffer = xrealloc( io->buffer, io->len );   #ifdef PIKE_DEBUG    io->num_malloc++;   #endif
pike.git/src/modules/_Stdio/buffer.cmod:181:       static void io_unlink_external_storage( Buffer *io )    ATTRIBUTE((noclone,noinline));       static void io_unlink_external_storage( Buffer *io )    {    switch (io->sourcetype) {    case PIKE_T_STRING:    free_string(io->source.str);    break; -  case PIKE_T_MIXED: { +  case PIKE_T_RING: {    Buffer *parent = io->source.parent; -  io_unlock(parent); +  { +  Buffer *cp = parent, *lc; +  while ((lc = cp->child) != io) +  cp = lc; +  cp->child = io->child; /* Unhook from ring */ +  io->child = 0; +  }    free_object(parent->this);    break;    }    case PIKE_T_OBJECT:    free_object(io->source.obj);    break;    }    io->sourcetype = 0;    }   
pike.git/src/modules/_Stdio/buffer.cmod:254:       /*    * It is actually not certain that checking this is a good idea.    *    * The reason being that if the current buffer size is very small    * (io_len(io)) and the bytes added is large and there is an    * offset, it makes sense to move now when we do not have to copy    * as much.    *    */ -  if( LIKELY(!io->locked) +  if( LIKELY(!io->child)    && UNLIKELY((force && io->offset)    || (io_len(io) && io->offset > io->allocated / 2)) )    {    /* more than 50% of the buffer is available before the read pointer,    * and we can discard that data. Move the data to the beginning, making    * room for more data.    */    io_discard_bufstart(io);    }       if( UNLIKELY(io->len + bytes > io->allocated) )    {    /* Actually grow the buffer. */    -  if (UNLIKELY(io->locked)) { -  struct object *oldobj = io->this; -  struct object *newobj -  = io_read_buffer(io, io->len - io->offset, 1, growth); -  Buffer *newbuffer = get_storage(newobj, Buffer_program); -  unsigned char*cbuf = newbuffer->buffer; -  int locks = io->locked - (io->max_waste < 0); -  oldobj->refs -= locks; /* Swap refs too */ -  newobj->refs += locks; -  /* Orphaned members in the copied (parked) buffer: -  * locked -  * allocated -  * offset -  * len +  if (UNLIKELY(io->child)) { +  /* +  * Growing a locked buffer goes in steps: +  * - Copy the unconsumed content of the locked buffer to new space +  * with room for growth. +  * - Swap the number of refs from the old buffer to the new buffer. +  * - Swap the backreferences to the objects. +  * - The new buffer now is orphaned, and merely exists +  * for the benefit of its subbuffers. As soon as the last +  * subbuffer vanishes, it will get freed as well.    */ -  io->locked = 0; +  struct object *newobj; +  Buffer *newbuffer; +  struct object *oldobj; +  int locks; +  void *ptmp; +  { +  Buffer *cp = io, *lc; +  while (UNLIKELY(lc = cp->child)) { +  if (UNLIKELY(lc == io)) +  Pike_error("Readonly buffer cannot be extended."); +  cp = lc; +  } +  } +  newobj = io_read_buffer(io, io_len(io), 1, growth); +  newbuffer = io_buffer_from_object(newobj); +  locks = 0; +  { +  Buffer *cp = io, *lc; +  while (UNLIKELY((lc = cp->child) != io && lc)) { +  cp = lc; +  cp->source.parent = newbuffer; +  locks++; +  } +  } +  oldobj = io->this; +  oldobj->refs -= locks; /* Swap refs too */ +  newobj->refs += locks - 1; /* Compensate for initial copy */ +  ptmp = newbuffer->buffer; /* Swap buffers */    newbuffer->buffer = io->buffer; -  io->buffer = cbuf; +  io->buffer = ptmp; +  newbuffer->child = io->child; +  io->child = 0; +  io->offset = newbuffer->offset;    io->len = newbuffer->len; -  io->offset = 0; +     io->allocated = newbuffer->allocated; -  io->this = newobj; -  newbuffer->this = oldobj; -  io->max_waste = newbuffer->max_waste; +     } else {    io->buffer = xrealloc( io->buffer, io->allocated + growth );   #ifdef PIKE_DEBUG    io->num_malloc++;   #endif    io->allocated += growth;    }    }    return io->buffer+io->len;    }
pike.git/src/modules/_Stdio/buffer.cmod:608:    io_consume( io, len );       if (UNLIKELY(do_copy))    io_ensure_malloced( to, headroom );    else {    Buffer *parent = io;    switch (to->sourcetype = io->sourcetype) {    case PIKE_T_STRING:    add_ref(to->source.str = io->source.str);    break; -  case PIKE_T_MIXED: +  case PIKE_T_RING:    parent = io->source.parent; -  +  /* FALLTHROUGH */    default: -  to->sourcetype = PIKE_T_MIXED; -  io_lock(to->source.parent = parent); +  to->sourcetype = PIKE_T_RING; +  to->source.parent = parent; +  to->child = parent->child; +  parent->child = to; /* Hook on ring */    add_ref(parent->this);    break;    case PIKE_T_OBJECT:    add_ref(to->source.obj = io->source.obj);    break;    }    }       return b;    }
pike.git/src/modules/_Stdio/buffer.cmod:1764:    push_int(THIS->len-1);    push_int(THIS->len);    push_int(THIS->allocated);    switch (THIS->sourcetype) {    case PIKE_T_STRING:    push_static_text("string");    break;    case PIKE_T_OBJECT:    push_static_text("object");    break; -  case PIKE_T_MIXED: +  case PIKE_T_RING:    push_static_text("subbuffer");    break;    default:    push_static_text("allocated");    break;    } -  if( THIS->locked ) +  if( THIS->child )    push_static_text(" (read only)");    else    push_static_text("");    f_sprintf(10);    }    break;       case 's':    bytes = io_len(THIS);    THIS->locked_move++;
pike.git/src/modules/_Stdio/buffer.cmod:2360:    *!    *! Configure how much free space should be allowed, at most, as a    *! factor of the current buffer size.    *!    *! The default is 0.5, leaving at most half the buffer as waste.    *!    */    PIKEFUN void set_max_waste(float howmuch)    {    Buffer *io = THIS; +  if (LIKELY(howmuch >= 0 && io->max_waste >= 0)) {    io->max_waste = howmuch;    io_add_space( io, 0, 1 );    io_trim_waste( io );    } -  +  }       /*! @decl void trim()    *!    *! Frees unused memory.    *!    *! Note that calling this function excessively will slow things    *! down, since the data often has to be copied.    *!    *! @note    *! This function could possibly throw an out-of-memory error
pike.git/src/modules/_Stdio/buffer.cmod:2753:    /*! @decl void read_only()    *!    *! This makes the existing data in the buffer permanently read only.    *!    *! @note    *! You can use lock() to do this temporarily.    */    PIKEFUN void read_only()    {    Buffer *io = THIS; -  if (!(io->max_waste < 0)) { -  io->max_waste = -1.0; /* Marker to distinguish read-only buffers */ -  io_lock(io); +  { +  Buffer *cp = io, *lc; +  while ((lc = cp->child) != io) { +  if (!lc) { +  /* Append yourself to force readonly */ +  cp->child = io; +  break;    } -  +  cp = lc;    } -  +  } +  }          static struct object* io_create_rewind_key( Buffer *io, int how );       /*! @decl RewindKey rewind_on_error()    *! @decl RewindKey rewind_key()    *!    *! These functions are very similar. The @[rewind_on_error] variant    *! will create an object that, when it goes out of scope without    *! having been destructed explicitly, will cause the buffer to