summaryrefslogtreecommitdiff
path: root/src/charon/bus
diff options
context:
space:
mode:
authorRene Mayrhofer <rene@mayrhofer.eu.org>2007-06-03 17:46:37 +0000
committerRene Mayrhofer <rene@mayrhofer.eu.org>2007-06-03 17:46:37 +0000
commit62bf8ed9e48c18169c43ae6c44f345f401bd4393 (patch)
tree61a58c5c24278a9013b23b2cea5605a1ee142cdb /src/charon/bus
parent59dbcced8de77b3b861cd2307543226f0abc10a6 (diff)
downloadvyos-strongswan-62bf8ed9e48c18169c43ae6c44f345f401bd4393.tar.gz
vyos-strongswan-62bf8ed9e48c18169c43ae6c44f345f401bd4393.zip
- Update to new upstream release.
Diffstat (limited to 'src/charon/bus')
-rw-r--r--src/charon/bus/bus.c73
-rw-r--r--src/charon/bus/bus.h11
2 files changed, 79 insertions, 5 deletions
diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c
index 740663d5c..5f46cd29e 100644
--- a/src/charon/bus/bus.c
+++ b/src/charon/bus/bus.c
@@ -185,6 +185,28 @@ static void add_listener(private_bus_t *this, bus_listener_t *listener)
}
/**
+ * Implementation of bus_t.remove_listener.
+ */
+static void remove_listener(private_bus_t *this, bus_listener_t *listener)
+{
+ iterator_t *iterator;
+ bus_listener_t *current;
+
+ pthread_mutex_lock(&this->mutex);
+ iterator = this->listeners->create_iterator(this->listeners, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current == listener)
+ {
+ iterator->remove(iterator);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&this->mutex);
+}
+
+/**
* Get the listener object for the calling thread
*/
static active_listener_t *get_active_listener(private_bus_t *this)
@@ -216,6 +238,32 @@ static active_listener_t *get_active_listener(private_bus_t *this)
return found;
}
+typedef struct cancel_info_t cancel_info_t;
+
+/**
+ * cancellation info to cancel a listening operation cleanly
+ */
+struct cancel_info_t {
+ /**
+ * mutex to unlock on cancellation
+ */
+ pthread_mutex_t *mutex;
+
+ /**
+ * listener to unregister
+ */
+ active_listener_t *listener;
+};
+
+/**
+ * disable a listener to cleanly clean up
+ */
+static void unregister(cancel_info_t *info)
+{
+ info->listener->state = UNREGISTERED;
+ pthread_mutex_unlock(info->mutex);
+}
+
/**
* Implementation of bus_t.listen.
*/
@@ -223,14 +271,24 @@ static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
ike_sa_t **ike_sa, char** format, va_list* args)
{
active_listener_t *listener;
+ int oldstate;
+ cancel_info_t info;
pthread_mutex_lock(&this->mutex);
listener = get_active_listener(this);
/* go "listening", say hello to a thread which have a signal for us */
listener->state = LISTENING;
pthread_cond_broadcast(&listener->cond);
- /* wait until it has us delivered a signal, and go back to "registered" */
+ /* wait until it has us delivered a signal, and go back to "registered".
+ * we allow cancellation here, but must cleanly disable the listener. */
+ info.mutex = &this->mutex;
+ info.listener = listener;
+ pthread_cleanup_push((void*)unregister, &info);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
pthread_cond_wait(&listener->cond, &this->mutex);
+ pthread_setcancelstate(oldstate, NULL);
+ pthread_cleanup_pop(0);
+
pthread_mutex_unlock(&this->mutex);
/* return signal values */
@@ -299,7 +357,6 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level,
while (iterator->iterate(iterator, (void**)&listener))
{
va_list args_copy;
-
va_copy(args_copy, args);
if (!listener->signal(listener, signal, level, thread,
ike_sa, format, args_copy))
@@ -315,8 +372,11 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level,
iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
while (iterator->iterate(iterator, (void**)&active_listener))
{
- /* wait until it is back */
- while (active_listener->state == REGISTERED)
+ /* wait until all threads are registered. But if the thread raising
+ * the signal is the same as the one that listens, we skip it.
+ * Otherwise we would deadlock. */
+ while (active_listener->id != pthread_self() &&
+ active_listener->state == REGISTERED)
{
pthread_cond_wait(&active_listener->cond, &this->mutex);
}
@@ -339,7 +399,9 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level,
iterator->reset(iterator);
while (iterator->iterate(iterator, (void**)&active_listener))
{
- while (active_listener->state == REGISTERED)
+ /* do not wait for ourself, it won't happen (see above) */
+ while (active_listener->id != pthread_self() &&
+ active_listener->state == REGISTERED)
{
pthread_cond_wait(&active_listener->cond, &this->mutex);
}
@@ -380,6 +442,7 @@ bus_t *bus_create()
private_bus_t *this = malloc_thing(private_bus_t);
this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
+ this->public.remove_listener = (void(*)(bus_t*,bus_listener_t*))remove_listener;
this->public.listen = (signal_t(*)(bus_t*,level_t*,int*,ike_sa_t**,char**,va_list*))listen_;
this->public.set_listen_state = (void(*)(bus_t*,bool))set_listen_state;
this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h
index 200525fb7..4b46c7e82 100644
--- a/src/charon/bus/bus.h
+++ b/src/charon/bus/bus.h
@@ -266,6 +266,14 @@ struct bus_t {
void (*add_listener) (bus_t *this, bus_listener_t *listener);
/**
+ * @brief Unregister a listener from the bus.
+ *
+ * @param this bus
+ * @param listener listener to unregister.
+ */
+ void (*remove_listener) (bus_t *this, bus_listener_t *listener);
+
+ /**
* @brief Listen actively on the bus.
*
* As we are fully multithreaded, we must provide a mechanism
@@ -275,6 +283,9 @@ struct bus_t {
* it processes a signal, registration is required. This is done through
* the set_listen_state() method, see below.
*
+ * The listen() function is (has) a thread cancellation point, so might
+ * want to register cleanup handlers.
+ *
* @param this bus
* @param level verbosity level of the signal
* @param thread receives thread number emitted the signal