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()); }
/* * 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); }
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); } }
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(); }
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(); }
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); } }
/* * 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); }