diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-06-03 17:46:37 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-06-03 17:46:37 +0000 |
commit | 62bf8ed9e48c18169c43ae6c44f345f401bd4393 (patch) | |
tree | 61a58c5c24278a9013b23b2cea5605a1ee142cdb /src/charon/bus | |
parent | 59dbcced8de77b3b861cd2307543226f0abc10a6 (diff) | |
download | vyos-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.c | 73 | ||||
-rw-r--r-- | src/charon/bus/bus.h | 11 |
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**)¤t)) + { + 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 |