Example #1
0
void VirtioBlk::service_RX() {

  req.disable_interrupts();
  while (req.new_incoming())
  {
    auto tok = req.dequeue();
    if (!tok.size()) break;

    // only handle the main header of each request
    auto* hdr = (request_t*) tok.data();
    received.emplace_back(hdr);
  };

  // if we have free space and jobs, start shipping
  bool shipped = false;
  while (free_space() && !jobs.empty()) {
    shipit(jobs.front());
    jobs.pop_front();
    shipped = true;
  }
  if (shipped) req.kick();
  req.enable_interrupts();

  int handled = 0;
  for (request_t* hdr : received) {
    handle(hdr);
    inflight--; handled++;
  }
  received.clear();

  //printf("inflight: %d  handled: %d  shipped: %d  num_free: %u\n",
  //    inflight, handled, scnt, req.num_free());
}
Example #2
0
/*
 * Sends a cross-call to a specified processor.  The caller assumes
 * responsibility for repetition of cross-calls, as appropriate (MARSA for
 * debugging).
 */
static int
kdi_xc_one(int cpuid, void (*func)(uintptr_t, uintptr_t), uintptr_t arg1,
           uintptr_t arg2)
{
    uint64_t idsr;
    uint64_t endtick, tick;

    init_mondo_nocheck((xcfunc_t *)func, arg1, arg2);

    shipit(cpuid, 0);

    /* Spin for at most 1 second for checking */
    endtick = gettick() + (uint64_t)sys_tick_freq;

    idsr = getidsr();

    if (idsr & IDSR_BUSY) {
        do {
            idsr = getidsr();
            tick = gettick();
            if (tick > endtick) {
                return (KDI_XC_RES_BUSY);
            }
        } while (idsr & IDSR_BUSY);
    }

    kdi_tickwait(20000);

    if (idsr & IDSR_NACK)
        return (KDI_XC_RES_NACK);
    else
        return (KDI_XC_RES_OK);
}
Example #3
0
void VirtioBlk::read (block_t blk, on_read_func func) {
  // Virtio Std. § 5.1.6.3
  auto* vbr = new request_t(blk, func);
  if (free_space()) {
    shipit(vbr);
    req.kick();
  }
  else {
    jobs.push_back(vbr);
  }
}
Example #4
0
void VirtioBlk::read (block_t blk, size_t cnt, on_read_func func)
{
  // create big buffer for collecting all the disk data
  auto bigbuf = fs::construct_buffer(block_size() * cnt);
  // number of reads left
  auto results = std::make_shared<size_t> (cnt);
  bool shipped = false;
  //printf("virtioblk: Enqueue blk %llu cnt %u\n", blk, cnt);

  //for (int i = cnt-1; i >= 0; i--)
  for (size_t i = 0; i < cnt; i++)
  {
    // create a special request where we collect all the data
    auto* vbr = new request_t(
      blk + i,
      request_handler_t::make_packed(
      [this, i, func, results, bigbuf] (uint8_t* data) {
        // if the job was already completed, return early
        if (*results == 0) {
          printf("[virtioblk] Job cancelled? results == 0,  blk=%zu\n", i);
          return;
        }
        // validate partial result
        if (data != nullptr) {
          *results -= 1;
          // copy partial block
          memcpy(bigbuf->data() + i * block_size(), data, block_size());
          // check if we have all blocks
          if (*results == 0) {
            // finally, call user-provided callback
            func(bigbuf);
          }
        }
        else {
          (*this->errors)++;
          // if the partial result failed, cancel all
          *results = 0;
          // callback with no data
          func(nullptr);
        }
      })
    );
    //printf("virtioblk: Enqueue blk %llu\n", blk + i);
    //
    if (free_space()) {
      shipit(vbr);
      shipped = true;
    }
    else
      jobs.push_back(vbr);
  }
  // kick when we have enqueued stuff
  if (shipped) req.kick();
}
Example #5
0
void VirtioBlk::read (block_t blk, size_t cnt, on_read_func func) {

  // create big buffer for collecting all the disk data
  buffer_t bigbuf { new uint8_t[block_size() * cnt], std::default_delete<uint8_t[]>() };
  // (initialized) boolean array of partial jobs
  auto results = std::make_shared<size_t> (cnt);
  bool shipped = false;
  //printf("virtioblk: Enqueue blk %llu cnt %u\n", blk, cnt);

  //for (int i = cnt-1; i >= 0; i--)
  for (size_t i = 0; i < cnt; i++)
  {
    // create a special request where we collect all the data
    auto* vbr = new request_t(
      blk + i,
      on_read_func::make_packed(
      [this, i, func, results, bigbuf] (buffer_t buffer) {
        // if the job was already completed, return early
        if (*results == 0) {
          printf("Job cancelled? results == 0,  blk=%u\n", i);
          return;
        }
        // validate partial result
        if (buffer) {
          *results -= 1;
          // copy partial block
          memcpy(bigbuf.get() + i * block_size(), buffer.get(), block_size());
          // check if we have all blocks
          if (*results == 0) {
            // finally, call user-provided callback
            func(bigbuf);
          }
        }
        else {
          (*this->errors)++;
          // if the partial result failed, cancel all
          *results = 0;
          // callback with no data
          func(buffer_t());
        }
      })
    );
    //printf("virtioblk: Enqueue blk %llu\n", blk + i);
    //
    if (free_space()) {
      shipit(vbr);
      shipped = true;
    }
    else
      jobs.push_back(vbr);
  }
  // kick when we have enqueued stuff
  if (shipped) req.kick();
}
Example #6
0
void VirtioBlk::read (block_t blk, on_read_func func) {
  // Virtio Std. § 5.1.6.3
  auto* vbr = new request_t(blk,
    request_handler_t::make_packed(
    [this, func] (uint8_t* data) {
      if (data != nullptr)
        func(fs::construct_buffer(data, data + block_size()));
      else
        func(nullptr);
    }));

  if (free_space()) {
    shipit(vbr);
    req.kick();
  }
  else {
    jobs.push_back(vbr);
  }
}
Example #7
0
/*
 * Sends a cross-call to a specified processor.  The caller assumes
 * responsibility for repetition of cross-calls, as appropriate (MARSA for
 * debugging).
 */
static int
kdi_xc_one(int cpuid, void (*func)(uintptr_t, uintptr_t), uintptr_t arg1,
    uintptr_t arg2)
{
	uint64_t idsr;

	/*
	 * if (idsr_busy())
	 *	return (KDI_XC_RES_ERR);
	 */

	init_mondo_nocheck((xcfunc_t *)func, arg1, arg2);

	shipit(CPUID_TO_UPAID(cpuid));

	if ((idsr = getidsr()) == 0)
		return (KDI_XC_RES_OK);
	else if (idsr & IDSR_BUSY)
		return (KDI_XC_RES_BUSY);
	else
		return (KDI_XC_RES_NACK);
}