lookip: Disconnect asynchronously to avoid dead-locking watcher unregistration

While it really would be desirable to allow stream destruction during on_read()
callbacks, this does not work anymore since e49b2998. Until we have a proper
solution for this issue, use asynchronous disconnects for the only user doing
so.

Fixes #518.
This commit is contained in:
Martin Willi 2014-02-17 09:44:14 +01:00
parent 1f9e4d029e
commit 961409b668
2 changed files with 32 additions and 6 deletions

View File

@ -87,10 +87,21 @@ static void entry_destroy(entry_t *entry)
} }
/** /**
* Disconnect a stream, remove connection entry * Data for async disconnect job
*/ */
static void disconnect(private_lookip_socket_t *this, stream_t *stream) typedef struct {
/** socket ref */
private_lookip_socket_t *this;
/** stream to disconnect */
stream_t *stream;
} disconnect_data_t;
/**
* Disconnect a stream asynchronously, remove connection entry
*/
static job_requeue_t disconnect_async(disconnect_data_t *data)
{ {
private_lookip_socket_t *this = data->this;
enumerator_t *enumerator; enumerator_t *enumerator;
entry_t *entry; entry_t *entry;
@ -98,7 +109,7 @@ static void disconnect(private_lookip_socket_t *this, stream_t *stream)
enumerator = this->connected->create_enumerator(this->connected); enumerator = this->connected->create_enumerator(this->connected);
while (enumerator->enumerate(enumerator, &entry)) while (enumerator->enumerate(enumerator, &entry))
{ {
if (entry->stream == stream) if (entry->stream == data->stream)
{ {
this->connected->remove_at(this->connected, enumerator); this->connected->remove_at(this->connected, enumerator);
if (entry->up || entry->down) if (entry->up || entry->down)
@ -113,6 +124,22 @@ static void disconnect(private_lookip_socket_t *this, stream_t *stream)
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
} }
/**
* Queue async disconnect job
*/
static void disconnect(private_lookip_socket_t *this, stream_t *stream)
{
disconnect_data_t *data;
INIT(data,
.this = this,
.stream = stream,
);
lib->processor->queue_job(lib->processor,
(job_t*)callback_job_create(disconnect_async, data, free, NULL));
}
/** /**
* Callback function for listener up/down events * Callback function for listener up/down events
*/ */

View File

@ -39,9 +39,8 @@ typedef stream_t*(*stream_constructor_t)(char *uri);
/** /**
* Callback function prototype, called when stream is ready. * Callback function prototype, called when stream is ready.
* *
* It is allowed to destroy the stream during the callback, but only if it has * It is not allowed to destroy the stream nor to call on_read()/on_write/()
* no other active on_read()/on_write() callback and returns FALSE. It is not * during the callback.
* allowed to to call on_read()/on_write/() during the callback.
* *
* As select() may return even if a read()/write() would actually block, it is * As select() may return even if a read()/write() would actually block, it is
* recommended to use the non-blocking calls and handle return values * recommended to use the non-blocking calls and handle return values