err_t qbuffer_copyin(qbuffer_t* buf, qbuffer_iter_t start, qbuffer_iter_t end, const void* ptr, size_t ret_len)
{
  int64_t num_bytes = qbuffer_iter_num_bytes(start, end);
  ssize_t num_parts = qbuffer_iter_num_parts(start, end);
  struct iovec* iov = NULL;
  size_t iovcnt;
  size_t i,j;
  MAYBE_STACK_SPACE(struct iovec, iov_onstack);
  err_t err;
 
  if( num_bytes < 0 || num_parts < 0 || start.offset < buf->offset_start || end.offset > buf->offset_end ) return EINVAL;

  MAYBE_STACK_ALLOC(struct iovec, num_parts, iov, iov_onstack);
  if( ! iov ) return ENOMEM;

  err = qbuffer_to_iov(buf, start, end, num_parts, iov, NULL, &iovcnt);
  if( err ) goto error;

  j = 0;
  for( i = 0; i < iovcnt; i++ ) {
    if( j + iov[i].iov_len > ret_len ) goto error_nospace;
    memcpy(iov[i].iov_base, PTR_ADDBYTES(ptr, j), iov[i].iov_len);
    j += iov[i].iov_len;
  }

  MAYBE_STACK_FREE(iov, iov_onstack);
  return 0;

error_nospace:
  err = EMSGSIZE;
error:
  MAYBE_STACK_FREE(iov, iov_onstack);
  return err;
}
Exemple #2
0
qioerr qbuffer_flatten(qbuffer_t* buf, qbuffer_iter_t start, qbuffer_iter_t end, qbytes_t** bytes_out)
{
  int64_t num_bytes = qbuffer_iter_num_bytes(start, end);
  ssize_t num_parts = qbuffer_iter_num_parts(start, end);
  struct iovec* iov = NULL;
  size_t iovcnt;
  size_t i,j;
  qbytes_t* ret;
  MAYBE_STACK_SPACE(struct iovec, iov_onstack);
  qioerr err;
 
  if( num_bytes < 0 || num_parts < 0 ||
      start.offset < buf->offset_start || end.offset > buf->offset_end ) {
    *bytes_out = 0;
    QIO_RETURN_CONSTANT_ERROR(EINVAL, "range outside of buffer");
  }

  err = qbytes_create_calloc(&ret, num_bytes);
  if( err ) {
    *bytes_out = 0;
    return err;
  }

  MAYBE_STACK_ALLOC(struct iovec, num_parts, iov, iov_onstack);
  if( ! iov ) {
    // The buffer was successfully allocated, so we have to release it here.
    qbytes_release(ret);
    *bytes_out = 0;
    return QIO_ENOMEM;
  }

  err = qbuffer_to_iov(buf, start, end, num_parts, iov, NULL, &iovcnt);
  if( err ) {
    MAYBE_STACK_FREE(iov, iov_onstack);
    // The buffer was successfully allocated, so we have to release it here.
    qbytes_release(ret);
    *bytes_out = 0;
    return err;
  }

  j = 0;
  for( i = 0; i < iovcnt; i++ ) {
    qio_memcpy(PTR_ADDBYTES(ret->data, j), iov[i].iov_base, iov[i].iov_len);
    j += iov[i].iov_len;
  }

  MAYBE_STACK_FREE(iov, iov_onstack);

  *bytes_out = ret;
  return 0;
}
Exemple #3
0
err_t bulk_put_buffer(int64_t dst_locale, void* dst_addr, int64_t dst_len,
                      qbuffer_t* buf, qbuffer_iter_t start, qbuffer_iter_t end)
{
  int64_t num_bytes = qbuffer_iter_num_bytes(start, end);
  ssize_t num_parts = qbuffer_iter_num_parts(start, end);
  struct iovec* iov = NULL;
  size_t iovcnt;
  size_t i,j;
  int iov_onstack;
  err_t err;
 
  if( num_bytes < 0 || num_parts < 0 || start.offset < buf->offset_start || end.offset > buf->offset_end ) return EINVAL;

  MAYBE_STACK_ALLOC(num_parts*sizeof(struct iovec), iov, iov_onstack);
  if( ! iov ) return ENOMEM;

  err = qbuffer_to_iov(buf, start, end, num_parts, iov, NULL, &iovcnt);
  if( err ) goto error;

  j = 0;
  for( i = 0; i < iovcnt; i++ ) {
    if( j + iov[i].iov_len > dst_len ) goto error_nospace;
    //memcpy(PTR_ADDBYTES(ptr, j), iov[i].iov_base, iov[i].iov_len);

    // TODO -- note -- technically, this should be gasnet_put_bulk,
    // since we don't want to require src/dst to have a particular alignment.
    chpl_gen_comm_put( iov[i].iov_base,
                       dst_locale,
                       PTR_ADDBYTES(dst_addr, j),
                       sizeof(uint8_t), CHPL_TYPE_uint8_t,
                       iov[i].iov_len,
                       -1, "<internal>" );

    j += iov[i].iov_len;
  }

  MAYBE_STACK_FREE(iov, iov_onstack);
  return 0;

error_nospace:
  err = EMSGSIZE;
error:
  MAYBE_STACK_FREE(iov, iov_onstack);
  return err;
}
err_t qbuffer_flatten(qbuffer_t* buf, qbuffer_iter_t start, qbuffer_iter_t end, qbytes_t** bytes_out)
{
  int64_t num_bytes = qbuffer_iter_num_bytes(start, end);
  ssize_t num_parts = qbuffer_iter_num_parts(start, end);
  struct iovec* iov = NULL;
  size_t iovcnt;
  size_t i,j;
  qbytes_t* ret;
  MAYBE_STACK_SPACE(struct iovec, iov_onstack);
  err_t err;
 
  if( num_bytes < 0 || num_parts < 0 || start.offset < buf->offset_start || end.offset > buf->offset_end ) return EINVAL;

  err = qbytes_create_calloc(&ret, num_bytes);
  if( err ) return err;

  MAYBE_STACK_ALLOC(struct iovec, num_parts, iov, iov_onstack);
  if( ! iov ) {
    qbytes_release(ret);
    return ENOMEM;
  }

  err = qbuffer_to_iov(buf, start, end, num_parts, iov, NULL, &iovcnt);
  if( err ) {
    MAYBE_STACK_FREE(iov, iov_onstack);
    qbytes_release(ret);
    return err;
  }

  j = 0;
  for( i = 0; i < iovcnt; i++ ) {
    memcpy(PTR_ADDBYTES(ret->data, j), iov[i].iov_base, iov[i].iov_len);
    j += iov[i].iov_len;
  }

  MAYBE_STACK_FREE(iov, iov_onstack);

  *bytes_out = ret;
  return 0;
}
Exemple #5
0
qioerr qbuffer_copyin(qbuffer_t* buf, qbuffer_iter_t start, qbuffer_iter_t end, const void* ptr, size_t ret_len)
{
  int64_t num_bytes = qbuffer_iter_num_bytes(start, end);
  ssize_t num_parts = qbuffer_iter_num_parts(start, end);
  struct iovec* iov = NULL;
  size_t iovcnt;
  size_t i,j;
  MAYBE_STACK_SPACE(struct iovec, iov_onstack);
  qioerr err;
 
  if( num_bytes < 0 || num_parts < 0 ||
      start.offset < buf->offset_start || end.offset > buf->offset_end ) {
    QIO_RETURN_CONSTANT_ERROR(EINVAL, "range outside of buffer");
  }

  MAYBE_STACK_ALLOC(struct iovec, num_parts, iov, iov_onstack);
  if( ! iov ) return QIO_ENOMEM;

  err = qbuffer_to_iov(buf, start, end, num_parts, iov, NULL, &iovcnt);
  if( err ) goto error;

  j = 0;
  for( i = 0; i < iovcnt; i++ ) {
    if( j + iov[i].iov_len > ret_len ) goto error_nospace;
    qio_memcpy(iov[i].iov_base, PTR_ADDBYTES(ptr, j), iov[i].iov_len);
    j += iov[i].iov_len;
  }

  MAYBE_STACK_FREE(iov, iov_onstack);
  return 0;

error_nospace:
  QIO_GET_CONSTANT_ERROR(err, EMSGSIZE, "no space in buffer");
error:
  MAYBE_STACK_FREE(iov, iov_onstack);
  return err;
}
Exemple #6
0
qioerr qbuffer_to_iov(qbuffer_t* buf, qbuffer_iter_t start, qbuffer_iter_t end, 
                     size_t max_iov, struct iovec *iov_out, 
                     qbytes_t** bytes_out /* can be NULL */,
                     size_t *iovcnt_out)
{
  deque_iterator_t d_end = deque_end(& buf->deque);
  deque_iterator_t iter;
  qbuffer_part_t* qbp;
  size_t i = 0;

  iter = start.iter;

  // invalid range!
  if( start.offset > end.offset ) {
    *iovcnt_out = 0;
    QIO_RETURN_CONSTANT_ERROR(EINVAL, "invalid range");
  }

  if( deque_it_equals(iter, d_end) ) {
    // start is actually pointing to the end of the deque. no data.
    *iovcnt_out = 0;
    return 0;
  }

  if( deque_it_equals(iter, end.iter) ) {
    // we're only pointing to a single block.
    qbp = (qbuffer_part_t*) deque_it_get_cur_ptr(sizeof(qbuffer_part_t), iter);
    if( i >= max_iov ) goto error_nospace;
    iov_out[i].iov_base = PTR_ADDBYTES(qbp->bytes->data, qbp->skip_bytes + (start.offset - (qbp->end_offset - qbp->len_bytes)));
    iov_out[i].iov_len = end.offset - start.offset;
    if( bytes_out ) bytes_out[i] = qbp->bytes;
    if( iov_out[i].iov_len > 0 ) i++;
  } else {
    // otherwise, there's a possibly partial block in start.
    qbp = (qbuffer_part_t*) deque_it_get_cur_ptr(sizeof(qbuffer_part_t), iter);
    if( i >= max_iov ) goto error_nospace;
    iov_out[i].iov_base = PTR_ADDBYTES(qbp->bytes->data, qbp->skip_bytes + (start.offset - (qbp->end_offset - qbp->len_bytes)));
    iov_out[i].iov_len = qbp->end_offset - start.offset;
    if( bytes_out ) bytes_out[i] = qbp->bytes;
    // store it if we had any data there.
    if( iov_out[i].iov_len > 0 ) i++;


    // Now, on to the next.
    deque_it_forward_one(sizeof(qbuffer_part_t), &iter);

    // until we get to the same block as end, we need to store full blocks.
    while( ! deque_it_equals( iter, end.iter ) ) {
      if( deque_it_equals( iter, d_end ) ) {
        // error: end is not in deque.
        *iovcnt_out = 0;
        QIO_RETURN_CONSTANT_ERROR(EINVAL, "end is not in deque");
      }

      qbp = (qbuffer_part_t*) deque_it_get_cur_ptr(sizeof(qbuffer_part_t), iter);
      if( i >= max_iov ) goto error_nospace;
      iov_out[i].iov_base = PTR_ADDBYTES(qbp->bytes->data, qbp->skip_bytes);
      iov_out[i].iov_len = qbp->len_bytes;
      if( bytes_out ) bytes_out[i] = qbp->bytes;
      // store it if we had any data there.
      if( iov_out[i].iov_len > 0 ) i++;

      // Now, on to the next.
      deque_it_forward_one(sizeof(qbuffer_part_t), &iter);
    }

    // at the end of the loop
    // is there any data in end?
    if( deque_it_equals(iter, d_end) ) {
      // we're currently pointing to the end; no need to add more.
    } else {
      qbp = (qbuffer_part_t*) deque_it_get_cur_ptr(sizeof(qbuffer_part_t), iter);
      // add a partial end block. We know it's different from
      // start since we handled that above.
      if( i >= max_iov ) goto error_nospace;
      iov_out[i].iov_base = PTR_ADDBYTES(qbp->bytes->data, qbp->skip_bytes);
      iov_out[i].iov_len = end.offset - (qbp->end_offset - qbp->len_bytes);
      if( bytes_out ) bytes_out[i] = qbp->bytes;
      if( iov_out[i].iov_len > 0 ) i++;
    }
  }

  *iovcnt_out = i;
  return 0;

error_nospace:
  *iovcnt_out = 0;
  // EOVERFLOW or ENOBUFS would make sense too
  QIO_RETURN_CONSTANT_ERROR(EMSGSIZE, "no space in buffer");
}