[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC v3 03/14] blockjobs: add state transition table
From: |
John Snow |
Subject: |
[Qemu-devel] [RFC v3 03/14] blockjobs: add state transition table |
Date: |
Fri, 26 Jan 2018 21:05:04 -0500 |
The state transition table has mostly been implied. We're about to make
it a bit more complex, so let's make the STM explicit instead.
Perform state transitions with a function that for now just asserts the
transition is appropriate.
undefined: May only transition to 'created'.
created: May only transition to 'running'.
It cannot transition to pause directly, but if a created job
is requested to pause prior to starting, it will transition
synchronously to 'running' and then to 'paused'.
running: May transition either to 'paused' or 'ready'.
paused: May transition to either 'running' or 'ready', but only in
terms of returning to that prior state.
p->r->y is not possible, but this is not encapsulated by the
STM table.
ready: May transition to paused.
Signed-off-by: John Snow <address@hidden>
---
blockjob.c | 39 ++++++++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 5 deletions(-)
diff --git a/blockjob.c b/blockjob.c
index 6eb783a354..d084a1e318 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -42,6 +42,35 @@
* block_job_enter. */
static QemuMutex block_job_mutex;
+/* BlockJob State Transition Table */
+bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
+ /* U, C, R, P, Y */
+ /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0},
+ /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0},
+ /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1},
+ /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 1},
+ /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 1, 0},
+};
+
+static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
+{
+ BlockJobStatus s0 = job->status;
+ if (s0 == s1) {
+ return;
+ }
+ assert(s1 >= 0 && s1 <= BLOCK_JOB_STATUS__MAX);
+ assert(BlockJobSTT[s0][s1]);
+ switch (s1) {
+ case BLOCK_JOB_STATUS_WAITING:
+ case BLOCK_JOB_STATUS_PENDING:
+ case BLOCK_JOB_STATUS_CONCLUDED:
+ assert(job->manual);
+ default:
+ break;
+ }
+ job->status = s1;
+}
+
static void block_job_lock(void)
{
qemu_mutex_lock(&block_job_mutex);
@@ -321,7 +350,7 @@ void block_job_start(BlockJob *job)
job->pause_count--;
job->busy = true;
job->paused = false;
- job->status = BLOCK_JOB_STATUS_RUNNING;
+ block_job_state_transition(job, BLOCK_JOB_STATUS_RUNNING);
bdrv_coroutine_enter(blk_bs(job->blk), job->co);
}
@@ -709,7 +738,7 @@ void *block_job_create(const char *job_id, const
BlockJobDriver *driver,
job->pause_count = 1;
job->refcnt = 1;
job->manual = manual;
- job->status = BLOCK_JOB_STATUS_CREATED;
+ block_job_state_transition(job, BLOCK_JOB_STATUS_CREATED);
aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
QEMU_CLOCK_REALTIME, SCALE_NS,
block_job_sleep_timer_cb, job);
@@ -815,11 +844,11 @@ void coroutine_fn block_job_pause_point(BlockJob *job)
if (block_job_should_pause(job) && !block_job_is_cancelled(job)) {
BlockJobStatus status = job->status;
- job->status = BLOCK_JOB_STATUS_PAUSED;
+ block_job_state_transition(job, BLOCK_JOB_STATUS_PAUSED);
job->paused = true;
block_job_do_yield(job, -1);
job->paused = false;
- job->status = status;
+ block_job_state_transition(job, status);
}
if (job->driver->resume) {
@@ -925,7 +954,7 @@ void block_job_iostatus_reset(BlockJob *job)
void block_job_event_ready(BlockJob *job)
{
- job->status = BLOCK_JOB_STATUS_READY;
+ block_job_state_transition(job, BLOCK_JOB_STATUS_READY);
job->ready = true;
if (block_job_is_internal(job)) {
--
2.14.3