#include <lunaix/mm/cake.h>
#include <lunaix/mm/valloc.h>
+#include <hal/cpu.h>
+
static struct cake_pile* blkio_reqpile;
void
.flags = options,
.evt_args = evt_args };
breq->vbuf = buffer;
+ waitq_init(&breq->wait);
return breq;
}
}
void
-blkio_commit(struct blkio_context* ctx, struct blkio_req* req)
+blkio_commit(struct blkio_context* ctx, struct blkio_req* req, int options)
{
req->flags |= BLKIO_PENDING;
req->io_ctx = ctx;
llist_append(&ctx->queue, &req->reqs);
// if the pipeline is not running (e.g., stalling). Then we should schedule
- // one immediately and kick it start.
+ // one immediately and kick it started.
+ // NOTE: Possible race condition between blkio_commit and pwait.
+ // Consider: what if scheduler complete the request before pwait even get
+ // called?
+ // Two possible work around:
+ // #1. we disable the interrupt before schedule the request.
+ // #2. we do scheduling within interrupt context (e.g., attach a timer)
+ // As we don't want to overwhelming the interrupt context and also keep the
+ // request RTT as small as possible, hence #1 is preferred.
+
if (!ctx->busy) {
+ if ((options & BLKIO_WAIT)) {
+ cpu_disable_interrupt();
+ blkio_schedule(ctx);
+ pwait(&req->wait);
+ return;
+ }
blkio_schedule(ctx);
+ } else if ((options & BLKIO_WAIT)) {
+ pwait(&req->wait);
}
}
blkio_complete(struct blkio_req* req)
{
req->flags &= ~(BLKIO_BUSY | BLKIO_PENDING);
+
if (req->completed) {
req->completed(req);
}
+
+ // Wake all blocked processes on completion,
+ // albeit should be no more than one process in everycase (by design)
+ pwake_all(&req->wait);
+
if ((req->flags & BLKIO_FOC)) {
blkio_free_req(req);
}
req->io_ctx->busy--;
-
- blkio_schedule(req->io_ctx);
}
\ No newline at end of file