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;
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);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->stream == stream)
if (entry->stream == data->stream)
{
this->connected->remove_at(this->connected, enumerator);
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);
}
/**
* 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
*/

View File

@ -39,9 +39,8 @@ typedef stream_t*(*stream_constructor_t)(char *uri);
/**
* Callback function prototype, called when stream is ready.
*
* It is allowed to destroy the stream during the callback, but only if it has
* no other active on_read()/on_write() callback and returns FALSE. It is not
* allowed to to call on_read()/on_write/() during the callback.
* It is not allowed to destroy the stream nor to call on_read()/on_write/()
* during the callback.
*
* 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