proper thread cancellation when using the charon->interfaces

This commit is contained in:
Martin Willi
2007-05-23 09:08:13 +00:00
parent 0f6b068259
commit 76042f8471
8 changed files with 100 additions and 5 deletions
+60 -1
View File
@@ -184,6 +184,28 @@ static void add_listener(private_bus_t *this, bus_listener_t *listener)
pthread_mutex_unlock(&this->mutex);
}
/**
* 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
*/
@@ -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 */
@@ -384,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;
+11
View File
@@ -265,6 +265,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.
*
@@ -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