#include "qemu/coroutine.h"
#include "qemu/timer.h"
-static void block_job_event_cancelled(BlockJob *job);
-static void block_job_event_completed(BlockJob *job, const char *msg);
-static void block_job_event_pending(BlockJob *job);
-
/* Transactional group of block jobs */
struct BlockJobTxn {
/* Emit events only if we actually started */
if (job_started(&job->job)) {
if (job_is_cancelled(&job->job)) {
- block_job_event_cancelled(job);
+ job_event_cancelled(&job->job);
} else {
- const char *msg = NULL;
- if (job->ret < 0) {
- msg = strerror(-job->ret);
- }
- block_job_event_completed(job, msg);
+ job_event_completed(&job->job);
}
}
{
job_state_transition(&job->job, JOB_STATUS_PENDING);
if (!job->job.auto_finalize) {
- block_job_event_pending(job);
+ job_event_pending(&job->job);
}
return 0;
}
}
}
-static void block_job_event_cancelled(BlockJob *job)
+static void block_job_event_cancelled(Notifier *n, void *opaque)
{
+ BlockJob *job = opaque;
+
if (block_job_is_internal(job)) {
return;
}
&error_abort);
}
-static void block_job_event_completed(BlockJob *job, const char *msg)
+static void block_job_event_completed(Notifier *n, void *opaque)
{
+ BlockJob *job = opaque;
+ const char *msg = NULL;
+
if (block_job_is_internal(job)) {
return;
}
+ if (job->ret < 0) {
+ msg = strerror(-job->ret);
+ }
+
qapi_event_send_block_job_completed(job_type(&job->job),
job->job.id,
job->len,
&error_abort);
}
-static void block_job_event_pending(BlockJob *job)
+static void block_job_event_pending(Notifier *n, void *opaque)
{
+ BlockJob *job = opaque;
+
if (block_job_is_internal(job)) {
return;
}
job->cb = cb;
job->opaque = opaque;
+ job->finalize_cancelled_notifier.notify = block_job_event_cancelled;
+ job->finalize_completed_notifier.notify = block_job_event_completed;
+ job->pending_notifier.notify = block_job_event_pending;
+
+ notifier_list_add(&job->job.on_finalize_cancelled,
+ &job->finalize_cancelled_notifier);
+ notifier_list_add(&job->job.on_finalize_completed,
+ &job->finalize_completed_notifier);
+ notifier_list_add(&job->job.on_pending, &job->pending_notifier);
+
error_setg(&job->blocker, "block device is in use by block job: %s",
job_type_str(&job->job));
block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
/** True if this job should automatically dismiss itself */
bool auto_dismiss;
+ /** Notifiers called when a cancelled job is finalised */
+ NotifierList on_finalize_cancelled;
+
+ /** Notifiers called when a successfully completed job is finalised */
+ NotifierList on_finalize_completed;
+
+ /** Notifiers called when the job transitions to PENDING */
+ NotifierList on_pending;
+
/** Element of the list of jobs */
QLIST_ENTRY(Job) job_list;
} Job;
*/
void job_unref(Job *job);
+/** To be called when a cancelled job is finalised. */
+void job_event_cancelled(Job *job);
+
+/** To be called when a successfully completed job is finalised. */
+void job_event_completed(Job *job);
+
+/** To be called when the job transitions to PENDING */
+void job_event_pending(Job *job);
+
/**
* Conditionally enter the job coroutine if the job is ready to run, not
* already busy and fn() returns true. fn() is called while under the job_lock
job->auto_finalize = !(flags & JOB_MANUAL_FINALIZE);
job->auto_dismiss = !(flags & JOB_MANUAL_DISMISS);
+ notifier_list_init(&job->on_finalize_cancelled);
+ notifier_list_init(&job->on_finalize_completed);
+ notifier_list_init(&job->on_pending);
+
job_state_transition(job, JOB_STATUS_CREATED);
aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
QEMU_CLOCK_REALTIME, SCALE_NS,
}
}
+void job_event_cancelled(Job *job)
+{
+ notifier_list_notify(&job->on_finalize_cancelled, job);
+}
+
+void job_event_completed(Job *job)
+{
+ notifier_list_notify(&job->on_finalize_completed, job);
+}
+
+void job_event_pending(Job *job)
+{
+ notifier_list_notify(&job->on_pending, job);
+}
+
void job_enter_cond(Job *job, bool(*fn)(Job *job))
{
if (!job_started(job)) {