Give processor_t more control over the lifecycle of a job

Jobs are now destroyed by the processor, but they are allowed to
reschedule themselves.  That is, parts of the reschedule functionality
already provided by callback_job_t is moved to the processor.  Not yet
fully supported is JOB_REQUEUE_DIRECT and canceling jobs.

Note: job_t.destroy() is now called not only for queued jobs but also
after execution or cancellation of jobs.  job_t.status can be used to
decide what to do in said method.
This commit is contained in:
Tobias Brunner
2012-06-25 17:10:28 +02:00
parent 18d21a57df
commit 7fec83af28
26 changed files with 237 additions and 170 deletions
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009 Tobias Brunner
* Copyright (C) 2009-2012 Tobias Brunner
* Copyright (C) 2007-2011 Martin Willi
* Copyright (C) 2011 revosec AG
* Hochschule fuer Technik Rapperswil
@@ -56,7 +56,7 @@ struct private_callback_job_t {
thread_t *thread;
/**
* mutex to access jobs interna
* mutex to access private job data
*/
mutex_t *mutex;
@@ -71,9 +71,9 @@ struct private_callback_job_t {
private_callback_job_t *parent;
/**
* TRUE if the job got cancelled
* TRUE if the job got canceled
*/
bool cancelled;
bool canceled;
/**
* condvar to synchronize the cancellation/destruction of the job
@@ -103,10 +103,10 @@ static void unregister(private_callback_job_t *this)
if (this->parent)
{
this->parent->mutex->lock(this->parent->mutex);
if (this->parent->cancelled && !this->cancelled)
if (this->parent->canceled && !this->canceled)
{
/* if the parent has been cancelled but we have not yet, we do not
* unregister until we got cancelled by the parent. */
/* if the parent has been canceled but we have not yet, we do not
* unregister until we got canceled by the parent. */
this->parent->mutex->unlock(this->parent->mutex);
this->destroyable->wait(this->destroyable, this->mutex);
this->parent->mutex->lock(this->parent->mutex);
@@ -144,7 +144,7 @@ METHOD(callback_job_t, cancel, void,
semaphore_t *terminated = NULL;
this->mutex->lock(this->mutex);
this->cancelled = TRUE;
this->canceled = TRUE;
/* terminate children */
while (this->children->get_first(this->children, (void**)&child) == SUCCESS)
{
@@ -177,12 +177,10 @@ METHOD(callback_job_t, cancel, void,
}
}
METHOD(job_t, execute, void,
METHOD(job_t, execute, job_requeue_t,
private_callback_job_t *this)
{
bool cleanup = FALSE, requeue = FALSE;
thread_cleanup_push((thread_cleanup_t)destroy, this);
bool requeue = FALSE;
this->mutex->lock(this->mutex);
this->thread = thread_current();
@@ -191,10 +189,9 @@ METHOD(job_t, execute, void,
while (TRUE)
{
this->mutex->lock(this->mutex);
if (this->cancelled)
if (this->canceled)
{
this->mutex->unlock(this->mutex);
cleanup = TRUE;
break;
}
this->mutex->unlock(this->mutex);
@@ -210,7 +207,6 @@ METHOD(job_t, execute, void,
case JOB_REQUEUE_NONE:
default:
{
cleanup = TRUE;
break;
}
}
@@ -219,14 +215,10 @@ METHOD(job_t, execute, void,
this->mutex->lock(this->mutex);
this->thread = NULL;
this->mutex->unlock(this->mutex);
/* manually create a cancellation point to avoid that a cancelled thread
* goes back into the thread pool */
/* manually create a cancellation point to avoid that a canceled thread
* goes back into the thread pool at all */
thread_cancellation_point();
if (requeue)
{
lib->processor->queue_job(lib->processor, &this->public.job);
}
thread_cleanup_pop(cleanup);
return requeue ? JOB_REQUEUE_FAIR : JOB_REQUEUE_NONE;
}
METHOD(job_t, get_priority, job_priority_t,
@@ -27,33 +27,6 @@ typedef struct callback_job_t callback_job_t;
#include <library.h>
#include <processing/jobs/job.h>
typedef enum job_requeue_t job_requeue_t;
/**
* Job requeueing policy.
*
* The job requeueing policy defines how a job is handled when the callback
* function returns.
*/
enum job_requeue_t {
/**
* Do not requeue job, destroy it
*/
JOB_REQUEUE_NONE,
/**
* Reque the job fairly, meaning it has to requeue as any other job
*/
JOB_REQUEUE_FAIR,
/**
* Reexecute the job directly, without the need of requeueing it
*/
JOB_REQUEUE_DIRECT,
};
/**
* The callback function to use for the callback job.
*
+48 -5
View File
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -24,6 +25,8 @@
typedef struct job_t job_t;
typedef enum job_priority_t job_priority_t;
typedef enum job_requeue_t job_requeue_t;
typedef enum job_status_t job_status_t;
#include <library.h>
@@ -47,19 +50,57 @@ enum job_priority_t {
*/
extern enum_name_t *job_priority_names;
/**
* Job requeueing policy.
*
* The job requeueing policy defines how a job is handled after it has been
* executed.
*/
enum job_requeue_t {
/** Do not requeue job, destroy it */
JOB_REQUEUE_NONE = 0,
/** Requeue the job fairly, i.e. it is inserted at the end of the queue */
JOB_REQUEUE_FAIR,
/** Reexecute the job directly, without the need of requeueing it */
JOB_REQUEUE_DIRECT,
/** For jobs that rescheduled themselves via scheduler_t */
JOB_REQUEUE_SCHEDULED,
};
/**
* Job status
*/
enum job_status_t {
/** The job is queued and has not yet been executed */
JOB_STATUS_QUEUED = 0,
/** During execution */
JOB_STATUS_EXECUTING,
/** If the job got canceled */
JOB_STATUS_CANCELED,
/** The job was executed successfully */
JOB_STATUS_DONE,
};
/**
* Job interface as it is stored in the job queue.
*/
struct job_t {
/**
* Status of this job, is modified exclusively by the processor/scheduler
*/
job_status_t status;
/**
* Execute a job.
*
* The processing facility executes a job using this method. Jobs are
* one-shot, they destroy themself after execution, so don't use a job
* once it has been executed.
* one-shot, they are destroyed after execution (depending on the return
* value here), so don't use a job once it has been queued.
*
* @return policy how to requeue the job
*/
void (*execute) (job_t *this);
job_requeue_t (*execute) (job_t *this);
/**
* Get the priority of a job.
@@ -71,8 +112,10 @@ struct job_t {
/**
* Destroy a job.
*
* Is only called whenever a job was not executed (e.g. due daemon shutdown).
* After execution, jobs destroy themself.
* Is called after a job is executed or got canceled. It is also called
* for queued jobs that were never executed.
*
* Use the status of a job to decide what to do during destruction.
*/
void (*destroy) (job_t *this);
};