Commit 31b213a1 authored by Dominik Taborsky's avatar Dominik Taborsky

events: fix the race condition while avoiding a deadlock

parent c94c860a
......@@ -162,7 +162,6 @@ event_t *evsched_event_create(evsched_t *sched, event_cb_t cb, void *data)
/* Initialize. */
memset(e, 0, sizeof(event_t));
e->sched = sched;
e->cb = cb;
e->data = data;
e->hpos.pos=0;
......@@ -179,19 +178,18 @@ void evsched_event_free(event_t *ev)
free(ev);
}
int evsched_schedule(event_t *ev, uint32_t dt)
int evsched_schedule(evsched_t *sched, event_t *ev, uint32_t dt)
{
if (ev == NULL || ev->sched == NULL) {
if (ev == NULL || sched == NULL) {
return KNOT_EINVAL;
}
struct timeval new_time = timeval_in(dt);
evsched_t *sched = ev->sched;
/* Lock calendar. */
pthread_mutex_lock(&sched->heap_lock);
ev->sched = sched;
ev->tv = new_time;
/* Make sure it's not already enqueued. */
......@@ -215,6 +213,7 @@ int evsched_cancel(event_t *ev)
return KNOT_EINVAL;
}
int ret = KNOT_EOK;
evsched_t *sched = ev->sched;
/* Lock calendar. */
......@@ -223,6 +222,9 @@ int evsched_cancel(event_t *ev)
int found = heap_find(&sched->heap, (heap_val_t *)ev);
if (found > 0) {
heap_delete(&sched->heap, found);
ev->sched = NULL;
} else {
ret = KNOT_ENOENT;
}
/* Unlock calendar. */
......@@ -232,7 +234,7 @@ int evsched_cancel(event_t *ev)
/* Reset event timer. */
memset(&ev->tv, 0, sizeof(struct timeval));
return KNOT_EOK;
return ret;
}
void evsched_start(evsched_t *sched)
......
......@@ -127,7 +127,7 @@ void evsched_event_free(event_t *ev);
* \retval KNOT_EOK on success.
* \retval KNOT_EINVAL
*/
int evsched_schedule(event_t *ev, uint32_t dt);
int evsched_schedule(evsched_t *sched, event_t *ev, uint32_t dt);
/*!
* \brief Cancel a scheduled event.
......
......@@ -146,7 +146,7 @@ static void reschedule(zone_events_t *events)
time_t diff = time_until(event_get_time(events, type));
evsched_schedule(events->event, diff * 1000);
evsched_schedule(events->sched, events->event, diff * 1000);
}
/*!
......@@ -210,10 +210,12 @@ static void event_dispatch(event_t *event)
zone_events_t *events = event->data;
pthread_mutex_lock(&events->mx);
event->sched = NULL;
if (!events->running && !events->frozen) {
events->running = true;
worker_pool_assign(events->pool, &events->task);
}
pthread_cond_broadcast(&events->cancel);
pthread_mutex_unlock(&events->mx);
}
......@@ -246,6 +248,7 @@ int zone_events_setup(struct zone *zone, worker_pool_t *workers,
return KNOT_ENOMEM;
}
zone->events.sched = scheduler;
zone->events.event = event;
zone->events.pool = workers;
zone->events.timers_db = timers_db;
......@@ -259,10 +262,21 @@ void zone_events_deinit(zone_t *zone)
return;
}
evsched_cancel(zone->events.event);
evsched_event_free(zone->events.event);
zone_events_t *events = &zone->events;
pthread_mutex_lock(&events->mx);
events->frozen = true;
/* Cancel current event. */
int ret = evsched_cancel(events->event);
if (ret == KNOT_ENOENT) {
/* The event was not cancelled, wait until we stopped */
while (events->event->sched != NULL) {
pthread_cond_wait(&events->cancel, &events->mx);
}
}
evsched_event_free(events->event);
pthread_mutex_unlock(&events->mx);
pthread_mutex_destroy(&zone->events.mx);
pthread_mutex_destroy(&events->mx);
memset(&zone->events, 0, sizeof(zone->events));
}
......@@ -336,10 +350,17 @@ void zone_events_freeze(zone_t *zone)
/* Prevent new events being enqueued. */
pthread_mutex_lock(&events->mx);
events->frozen = true;
pthread_mutex_unlock(&events->mx);
/* Cancel current event. */
evsched_cancel(events->event);
int ret = evsched_cancel(events->event);
if (ret == KNOT_ENOENT) {
/* The event was not cancelled, wait until we stopped */
while (events->event->sched != NULL) {
pthread_cond_wait(&events->cancel, &events->mx);
}
}
pthread_mutex_unlock(&events->mx);
}
void zone_events_start(zone_t *zone)
......
......@@ -47,9 +47,11 @@ typedef enum zone_event_type {
typedef struct zone_events {
pthread_mutex_t mx; //!< Mutex protecting the struct.
pthread_cond_t cancel;
bool running; //!< Some zone event is being run.
bool frozen; //!< Terminated, don't schedule new events.
evsched_t *sched;
event_t *event; //!< Scheduler event.
worker_pool_t *pool; //!< Server worker pool.
knot_db_t *timers_db; //!< Persistent zone timers database.
......@@ -86,6 +88,8 @@ int zone_events_setup(struct zone *zone, worker_pool_t *workers,
/*!
* \brief Deinitialize zone events.
*
* \warning It is expected that the worker threads are suspended and cleared.
*
* \param zone Zone whose events we want to deinitialize.
*/
void zone_events_deinit(struct zone *zone);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment