Limit the number of concurrently handled stroke messages.
This avoids clogging the thread pool with potentially blocking jobs.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2011 Tobias Brunner
|
||||||
* Copyright (C) 2008 Martin Willi
|
* Copyright (C) 2008 Martin Willi
|
||||||
* Hochschule fuer Technik Rapperswil
|
* Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -25,7 +26,10 @@
|
|||||||
|
|
||||||
#include <hydra.h>
|
#include <hydra.h>
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
|
#include <threading/mutex.h>
|
||||||
#include <threading/thread.h>
|
#include <threading/thread.h>
|
||||||
|
#include <threading/condvar.h>
|
||||||
|
#include <utils/linked_list.h>
|
||||||
#include <processing/jobs/callback_job.h>
|
#include <processing/jobs/callback_job.h>
|
||||||
|
|
||||||
#include "stroke_config.h"
|
#include "stroke_config.h"
|
||||||
@@ -35,6 +39,12 @@
|
|||||||
#include "stroke_attribute.h"
|
#include "stroke_attribute.h"
|
||||||
#include "stroke_list.h"
|
#include "stroke_list.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To avoid clogging the thread pool with (blocking) jobs, we limit the number
|
||||||
|
* of concurrently handled stroke commands.
|
||||||
|
*/
|
||||||
|
#define MAX_CONCURRENT 4
|
||||||
|
|
||||||
typedef struct stroke_job_context_t stroke_job_context_t;
|
typedef struct stroke_job_context_t stroke_job_context_t;
|
||||||
typedef struct private_stroke_socket_t private_stroke_socket_t;
|
typedef struct private_stroke_socket_t private_stroke_socket_t;
|
||||||
|
|
||||||
@@ -56,7 +66,32 @@ struct private_stroke_socket_t {
|
|||||||
/**
|
/**
|
||||||
* job accepting stroke messages
|
* job accepting stroke messages
|
||||||
*/
|
*/
|
||||||
callback_job_t *job;
|
callback_job_t *receiver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* job handling stroke messages
|
||||||
|
*/
|
||||||
|
callback_job_t *handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* queued stroke commands
|
||||||
|
*/
|
||||||
|
linked_list_t *commands;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lock for command list
|
||||||
|
*/
|
||||||
|
mutex_t *mutex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* condvar to signal the arrival or completion of commands
|
||||||
|
*/
|
||||||
|
condvar_t *condvar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the number of currently handled commands
|
||||||
|
*/
|
||||||
|
u_int handling;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* configuration backend
|
* configuration backend
|
||||||
@@ -84,7 +119,7 @@ struct private_stroke_socket_t {
|
|||||||
stroke_ca_t *ca;
|
stroke_ca_t *ca;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status information logging
|
* status information logging
|
||||||
*/
|
*/
|
||||||
stroke_list_t *list;
|
stroke_list_t *list;
|
||||||
};
|
};
|
||||||
@@ -488,6 +523,18 @@ static void stroke_job_context_destroy(stroke_job_context_t *this)
|
|||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called to signal the completion of a command
|
||||||
|
*/
|
||||||
|
static inline job_requeue_t job_processed(private_stroke_socket_t *this)
|
||||||
|
{
|
||||||
|
this->mutex->lock(this->mutex);
|
||||||
|
this->handling--;
|
||||||
|
this->condvar->signal(this->condvar);
|
||||||
|
this->mutex->unlock(this->mutex);
|
||||||
|
return JOB_REQUEUE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* process a stroke request from the socket pointed by "fd"
|
* process a stroke request from the socket pointed by "fd"
|
||||||
*/
|
*/
|
||||||
@@ -506,7 +553,7 @@ static job_requeue_t process(stroke_job_context_t *ctx)
|
|||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "reading length of stroke message failed: %s",
|
DBG1(DBG_CFG, "reading length of stroke message failed: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return JOB_REQUEUE_NONE;
|
return job_processed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read message */
|
/* read message */
|
||||||
@@ -515,14 +562,14 @@ static job_requeue_t process(stroke_job_context_t *ctx)
|
|||||||
if (bytes_read != msg_length)
|
if (bytes_read != msg_length)
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
|
DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
|
||||||
return JOB_REQUEUE_NONE;
|
return job_processed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
out = fdopen(strokefd, "w+");
|
out = fdopen(strokefd, "w+");
|
||||||
if (out == NULL)
|
if (out == NULL)
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
|
DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
|
||||||
return JOB_REQUEUE_NONE;
|
return job_processed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
|
DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
|
||||||
@@ -599,11 +646,38 @@ static job_requeue_t process(stroke_job_context_t *ctx)
|
|||||||
fclose(out);
|
fclose(out);
|
||||||
/* fclose() closes underlying FD */
|
/* fclose() closes underlying FD */
|
||||||
ctx->fd = 0;
|
ctx->fd = 0;
|
||||||
return JOB_REQUEUE_NONE;
|
return job_processed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of private_stroke_socket_t.stroke_receive.
|
* Handle queued stroke commands
|
||||||
|
*/
|
||||||
|
static job_requeue_t handle(private_stroke_socket_t *this)
|
||||||
|
{
|
||||||
|
stroke_job_context_t *ctx;
|
||||||
|
callback_job_t *job;
|
||||||
|
bool oldstate;
|
||||||
|
|
||||||
|
this->mutex->lock(this->mutex);
|
||||||
|
thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
|
||||||
|
oldstate = thread_cancelability(TRUE);
|
||||||
|
while (this->commands->get_count(this->commands) == 0 ||
|
||||||
|
this->handling >= MAX_CONCURRENT)
|
||||||
|
{
|
||||||
|
this->condvar->wait(this->condvar, this->mutex);
|
||||||
|
}
|
||||||
|
thread_cancelability(oldstate);
|
||||||
|
this->commands->remove_first(this->commands, (void**)&ctx);
|
||||||
|
this->handling++;
|
||||||
|
thread_cleanup_pop(TRUE);
|
||||||
|
job = callback_job_create_with_prio((callback_job_cb_t)process, ctx,
|
||||||
|
(void*)stroke_job_context_destroy, this->handler, JOB_PRIO_HIGH);
|
||||||
|
lib->processor->queue_job(lib->processor, (job_t*)job);
|
||||||
|
return JOB_REQUEUE_DIRECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept stroke commands and queue them to be handled
|
||||||
*/
|
*/
|
||||||
static job_requeue_t receive(private_stroke_socket_t *this)
|
static job_requeue_t receive(private_stroke_socket_t *this)
|
||||||
{
|
{
|
||||||
@@ -611,7 +685,6 @@ static job_requeue_t receive(private_stroke_socket_t *this)
|
|||||||
int strokeaddrlen = sizeof(strokeaddr);
|
int strokeaddrlen = sizeof(strokeaddr);
|
||||||
int strokefd;
|
int strokefd;
|
||||||
bool oldstate;
|
bool oldstate;
|
||||||
callback_job_t *job;
|
|
||||||
stroke_job_context_t *ctx;
|
stroke_job_context_t *ctx;
|
||||||
|
|
||||||
oldstate = thread_cancelability(TRUE);
|
oldstate = thread_cancelability(TRUE);
|
||||||
@@ -624,17 +697,18 @@ static job_requeue_t receive(private_stroke_socket_t *this)
|
|||||||
return JOB_REQUEUE_FAIR;
|
return JOB_REQUEUE_FAIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = malloc_thing(stroke_job_context_t);
|
INIT(ctx,
|
||||||
ctx->fd = strokefd;
|
.fd = strokefd,
|
||||||
ctx->this = this;
|
.this = this,
|
||||||
job = callback_job_create_with_prio((callback_job_cb_t)process,
|
);
|
||||||
ctx, (void*)stroke_job_context_destroy, this->job, JOB_PRIO_HIGH);
|
this->mutex->lock(this->mutex);
|
||||||
lib->processor->queue_job(lib->processor, (job_t*)job);
|
this->commands->insert_last(this->commands, ctx);
|
||||||
|
this->condvar->signal(this->condvar);
|
||||||
|
this->mutex->unlock(this->mutex);
|
||||||
|
|
||||||
return JOB_REQUEUE_FAIR;
|
return JOB_REQUEUE_FAIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initialize and open stroke socket
|
* initialize and open stroke socket
|
||||||
*/
|
*/
|
||||||
@@ -682,7 +756,11 @@ static bool open_socket(private_stroke_socket_t *this)
|
|||||||
METHOD(stroke_socket_t, destroy, void,
|
METHOD(stroke_socket_t, destroy, void,
|
||||||
private_stroke_socket_t *this)
|
private_stroke_socket_t *this)
|
||||||
{
|
{
|
||||||
this->job->cancel(this->job);
|
this->handler->cancel(this->handler);
|
||||||
|
this->receiver->cancel(this->receiver);
|
||||||
|
this->commands->destroy_function(this->commands, (void*)stroke_job_context_destroy);
|
||||||
|
this->condvar->destroy(this->condvar);
|
||||||
|
this->mutex->destroy(this->mutex);
|
||||||
lib->credmgr->remove_set(lib->credmgr, &this->ca->set);
|
lib->credmgr->remove_set(lib->credmgr, &this->ca->set);
|
||||||
lib->credmgr->remove_set(lib->credmgr, &this->cred->set);
|
lib->credmgr->remove_set(lib->credmgr, &this->cred->set);
|
||||||
charon->backends->remove_backend(charon->backends, &this->config->backend);
|
charon->backends->remove_backend(charon->backends, &this->config->backend);
|
||||||
@@ -722,14 +800,22 @@ stroke_socket_t *stroke_socket_create()
|
|||||||
this->control = stroke_control_create();
|
this->control = stroke_control_create();
|
||||||
this->list = stroke_list_create(this->attribute);
|
this->list = stroke_list_create(this->attribute);
|
||||||
|
|
||||||
|
this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
|
||||||
|
this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
|
||||||
|
this->commands = linked_list_create();
|
||||||
|
|
||||||
lib->credmgr->add_set(lib->credmgr, &this->ca->set);
|
lib->credmgr->add_set(lib->credmgr, &this->ca->set);
|
||||||
lib->credmgr->add_set(lib->credmgr, &this->cred->set);
|
lib->credmgr->add_set(lib->credmgr, &this->cred->set);
|
||||||
charon->backends->add_backend(charon->backends, &this->config->backend);
|
charon->backends->add_backend(charon->backends, &this->config->backend);
|
||||||
hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider);
|
hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider);
|
||||||
|
|
||||||
this->job = callback_job_create_with_prio((callback_job_cb_t)receive,
|
this->receiver = callback_job_create_with_prio((callback_job_cb_t)receive,
|
||||||
this, NULL, NULL, JOB_PRIO_CRITICAL);
|
this, NULL, NULL, JOB_PRIO_CRITICAL);
|
||||||
lib->processor->queue_job(lib->processor, (job_t*)this->job);
|
lib->processor->queue_job(lib->processor, (job_t*)this->receiver);
|
||||||
|
|
||||||
|
this->handler = callback_job_create_with_prio((callback_job_cb_t)handle,
|
||||||
|
this, NULL, NULL, JOB_PRIO_CRITICAL);
|
||||||
|
lib->processor->queue_job(lib->processor, (job_t*)this->handler);
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user