Branch: Tag:

2014-09-03

2014-09-03 18:30:32 by Per Hedbor <ph@opera.com>

Added buffered asynchronous I/O mode to Stdio.File

In this mode the input and output is kept in buffers in the file object.
Adding data to the output buffer will write it to the filedescriptor, and
the read callback will receive the input buffer as its argument.

The write callback will have the output buffer as a second argument,
but most of the time this can be ignored since you keep the buffer
object around.

The write callback will only be called if the buffer needs more data,
so if you implement a range_error function in the buffer that refills
the buffer it will only be called once that callback returns 0.

252:    }    }    +  static struct pike_string *io_read_string( IOBuffer *io, size_t len ); +  static size_t io_rewind( IOBuffer *io, INT_TYPE n ); +  +  static void io_trigger_output( IOBuffer *io ) +  { +  if( io->output && !io->output_triggered ) +  { +  struct my_file *fd; +  if( (fd = get_storage( io->output, file_program )) ) +  { +  /* actual fd? Just register the callback. */ +  fd->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB); +  if(!SAFE_IS_ZERO(&fd->event_cbs[PIKE_FD_WRITE]) +  && fd->box.backend) +  set_fd_callback_events(&fd->box, fd->box.events|PIKE_BIT_FD_WRITE, 0); +  io->output_triggered = 1; +  } +  else +  { +  size_t bytes = MINIMUM(io_len(io),100); +  INT_TYPE l; +  struct pike_string *s = io_read_string( io,bytes ); +  if( s ) +  { +  /* Call write to triggger. */ +  io->output_triggered = 1; +  push_string( s ); +  apply( io->output, "write", 1 ); +  l = Pike_sp[-1].u.integer; +  pop_stack(); +  if( l < 0 ) +  l = 0; +  if( bytes > (unsigned)l ) +  io_rewind( io, bytes-l ); +  } +  } +  } +  } +     static int io_range_error( IOBuffer *io, int howmuch )    {    int res;
283:    {    memcpy( io_add_space( io, bytes, 0 ), p, bytes );    io->len += bytes; +  io_trigger_output( io );    return io_len(io);    }   
401:    x[bytes] = i&255;    i>>=8;    } +  io_trigger_output( io );    return io_len( io );    }   
415:    return -1;    }    io->offset -= n; +  io_trigger_output( io );    return io->offset;    }   
499:    break;    }    fd->box.revents &= ~(PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB); +  if(!SAFE_IS_ZERO(&fd->event_cbs[PIKE_FD_READ]) +  && fd->box.backend) +  set_fd_callback_events(&fd->box, fd->box.events|PIKE_BIT_FD_READ, 0);    }    else    {
519:    RETURN bread;    }    +  /*! @decl int __fd_set_output( object f ) +  *! +  *! This tells the buffer to trigger the write callback for the +  *! specified filedescriptor when data is added to the buffer. +  *! +  *! This is used internally by Stdio.File to handle nonblocking +  *! buffered mode, and is not really intended to be used directly. +  *! +  *! If f is 0 the state is cleared. +  */ +  +  PIKEFUN void __fd_set_output( object f ) +  { +  IOBuffer *io = THIS; +  if( io->output ) free_object(io->output); +  io->output_triggered = 0; +  io->output = f; +  io->output->refs++; +  } +  +  PIKEFUN void __fd_set_output( int(0..0) f ) +  { +  IOBuffer *io = THIS; +  if( io->output ) free_object(io->output); +  io->output = 0; +  io->output_triggered = 0; +  } +     /*! @decl int output_to( Stdio.Stream f, int|void nbytes )    *!    *! Write data from the buffer to the indicated file.
1559:    free_object( this->sub );    io_unlock( get_storage(this->sub,IOBuffer_program ) );    } +  if( this->output ) +  free_object(this->output);    if( this->source )    free_object( this->source );    if( this->str )