From 1a0ece3e873e3864269ed7eaed957dc10c56d25f Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Sun, 7 Apr 2013 23:17:37 +0300 Subject: [PATCH] istream API change: Added support for multiple destroy callbacks. --- src/lib-http/http-client-connection.c | 5 ++-- .../imap-urlauth-connection.c | 2 +- src/lib-storage/index/index-mail.c | 7 +++-- src/lib/iostream-private.h | 8 ++++-- src/lib/iostream-temp.c | 2 +- src/lib/iostream.c | 10 +++++-- src/lib/istream.c | 28 ++++++++++++++----- src/lib/istream.h | 9 +++--- src/lib/json-parser.c | 2 +- 9 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/lib-http/http-client-connection.c b/src/lib-http/http-client-connection.c index 4e801d4445..ed33008239 100644 --- a/src/lib-http/http-client-connection.c +++ b/src/lib-http/http-client-connection.c @@ -370,7 +370,7 @@ http_client_connection_return_response(struct http_client_connection *conn, actual payload stream. */ conn->incoming_payload = response->payload = i_stream_create_limit(response->payload, (uoff_t)-1); - i_stream_set_destroy_callback(response->payload, + i_stream_add_destroy_callback(response->payload, http_client_payload_destroyed, req); /* the callback may add its own I/O, so we need to remove @@ -391,7 +391,8 @@ http_client_connection_return_response(struct http_client_connection *conn, if (retrying) { /* retrying, don't destroy the request */ if (response->payload != NULL) { - i_stream_unset_destroy_callback(conn->incoming_payload); + i_stream_remove_destroy_callback(conn->incoming_payload, + http_client_payload_destroyed); i_stream_unref(&conn->incoming_payload); conn->conn.io = io_add(conn->conn.fd_in, IO_READ, http_client_connection_input, diff --git a/src/lib-imap-urlauth/imap-urlauth-connection.c b/src/lib-imap-urlauth/imap-urlauth-connection.c index ef4122b310..3a4835d502 100644 --- a/src/lib-imap-urlauth/imap-urlauth-connection.c +++ b/src/lib-imap-urlauth/imap-urlauth-connection.c @@ -604,7 +604,7 @@ imap_urlauth_fetch_reply_set_literal_stream(struct imap_urlauth_connection *conn data = buffer_get_data(conn->literal_buf, &size); i_assert(size == conn->literal_size); reply->input = i_stream_create_from_data(data, size); - i_stream_set_destroy_callback(reply->input, + i_stream_add_destroy_callback(reply->input, literal_stream_destroy, conn->literal_buf); } diff --git a/src/lib-storage/index/index-mail.c b/src/lib-storage/index/index-mail.c index 00a77d8996..2fb2fcb074 100644 --- a/src/lib-storage/index/index-mail.c +++ b/src/lib-storage/index/index-mail.c @@ -948,7 +948,7 @@ int index_mail_init_stream(struct index_mail *mail, /* do this only once in case a plugin changes the stream. otherwise the check would break. */ data->destroy_callback_set = TRUE; - i_stream_set_destroy_callback(data->stream, + i_stream_add_destroy_callback(data->stream, index_mail_stream_destroy_callback, mail); } @@ -1260,11 +1260,12 @@ static void index_mail_close_streams_full(struct index_mail *mail, bool closing) i_stream_unref(&data->filter_stream); if (data->stream != NULL) { data->destroying_stream = TRUE; - if (!closing) { + if (!closing && data->destroy_callback_set) { /* we're replacing the stream with a new one. it's allowed to have references until the mail is closed (but we can't really check that) */ - i_stream_unset_destroy_callback(data->stream); + i_stream_remove_destroy_callback(data->stream, + index_mail_stream_destroy_callback); } i_stream_unref(&data->stream); if (closing) { diff --git a/src/lib/iostream-private.h b/src/lib/iostream-private.h index 49c03484e3..870a995311 100644 --- a/src/lib/iostream-private.h +++ b/src/lib/iostream-private.h @@ -3,6 +3,11 @@ /* This file is private to input stream and output stream implementations */ +struct iostream_destroy_callback { + void (*callback)(void *context); + void *context; +}; + struct iostream_private { int refcount; char *name; @@ -12,8 +17,7 @@ struct iostream_private { void (*set_max_buffer_size)(struct iostream_private *stream, size_t max_size); - void (*destroy_callback)(void *context); - void *destroy_context; + ARRAY(struct iostream_destroy_callback) destroy_callbacks; }; void io_stream_init(struct iostream_private *stream); diff --git a/src/lib/iostream-temp.c b/src/lib/iostream-temp.c index 4f1f88cdd7..83681a679f 100644 --- a/src/lib/iostream-temp.c +++ b/src/lib/iostream-temp.c @@ -253,7 +253,7 @@ struct istream *iostream_temp_finish(struct ostream **output, tstream->buf->used); i_stream_set_name(input, t_strdup_printf( "(Temp file in %s)", tstream->temp_path_prefix)); - i_stream_set_destroy_callback(input, iostream_temp_buf_destroyed, + i_stream_add_destroy_callback(input, iostream_temp_buf_destroyed, tstream->buf); tstream->buf = NULL; } diff --git a/src/lib/iostream.c b/src/lib/iostream.c index 50b334aa40..66ad38fe76 100644 --- a/src/lib/iostream.c +++ b/src/lib/iostream.c @@ -1,6 +1,7 @@ /* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "array.h" #include "iostream-private.h" static void @@ -31,14 +32,19 @@ void io_stream_ref(struct iostream_private *stream) void io_stream_unref(struct iostream_private *stream) { + const struct iostream_destroy_callback *dc; + i_assert(stream->refcount > 0); if (--stream->refcount != 0) return; stream->close(stream, FALSE); stream->destroy(stream); - if (stream->destroy_callback != NULL) - stream->destroy_callback(stream->destroy_context); + if (array_is_created(&stream->destroy_callbacks)) { + array_foreach(&stream->destroy_callbacks, dc) + dc->callback(dc->context); + array_free(&stream->destroy_callbacks); + } i_free(stream->name); i_free(stream); diff --git a/src/lib/istream.c b/src/lib/istream.c index bd42094296..1bbb28d724 100644 --- a/src/lib/istream.c +++ b/src/lib/istream.c @@ -2,6 +2,7 @@ #include "lib.h" #include "ioloop.h" +#include "array.h" #include "str.h" #include "istream-private.h" @@ -53,22 +54,35 @@ void i_stream_unref(struct istream **stream) *stream = NULL; } -#undef i_stream_set_destroy_callback -void i_stream_set_destroy_callback(struct istream *stream, +#undef i_stream_add_destroy_callback +void i_stream_add_destroy_callback(struct istream *stream, istream_callback_t *callback, void *context) { struct iostream_private *iostream = &stream->real_stream->iostream; + struct iostream_destroy_callback *dc; - iostream->destroy_callback = callback; - iostream->destroy_context = context; + if (!array_is_created(&iostream->destroy_callbacks)) + i_array_init(&iostream->destroy_callbacks, 2); + dc = array_append_space(&iostream->destroy_callbacks); + dc->callback = callback; + dc->context = context; } -void i_stream_unset_destroy_callback(struct istream *stream) +void i_stream_remove_destroy_callback(struct istream *stream, + void (*callback)()) { struct iostream_private *iostream = &stream->real_stream->iostream; + const struct iostream_destroy_callback *dcs; + unsigned int i, count; - iostream->destroy_callback = NULL; - iostream->destroy_context = NULL; + dcs = array_get(&iostream->destroy_callbacks, &count); + for (i = 0; i < count; i++) { + if (dcs[i].callback == callback) { + array_delete(&iostream->destroy_callbacks, i, 1); + return; + } + } + i_unreached(); } int i_stream_get_fd(struct istream *stream) diff --git a/src/lib/istream.h b/src/lib/istream.h index b21db077c8..2a4b9ae96b 100644 --- a/src/lib/istream.h +++ b/src/lib/istream.h @@ -52,15 +52,16 @@ void i_stream_ref(struct istream *stream); /* Unreferences the stream and sets stream pointer to NULL. */ void i_stream_unref(struct istream **stream); /* Call the given callback function when stream is destroyed. */ -void i_stream_set_destroy_callback(struct istream *stream, +void i_stream_add_destroy_callback(struct istream *stream, istream_callback_t *callback, void *context) ATTR_NULL(3); -#define i_stream_set_destroy_callback(stream, callback, context) \ - i_stream_set_destroy_callback(stream + \ +#define i_stream_add_destroy_callback(stream, callback, context) \ + i_stream_add_destroy_callback(stream + \ CALLBACK_TYPECHECK(callback, void (*)(typeof(context))), \ (istream_callback_t *)callback, context) /* Remove the destroy callback. */ -void i_stream_unset_destroy_callback(struct istream *stream); +void i_stream_remove_destroy_callback(struct istream *stream, + void (*callback)()); /* Return file descriptor for stream, or -1 if none is available. */ int i_stream_get_fd(struct istream *stream); diff --git a/src/lib/json-parser.c b/src/lib/json-parser.c index 01556f5a6a..8d3cab9fac 100644 --- a/src/lib/json-parser.c +++ b/src/lib/json-parser.c @@ -596,7 +596,7 @@ json_try_parse_stream_start(struct json_parser *parser, parser->state = parser->state == JSON_STATE_OBJECT_VALUE ? JSON_STATE_OBJECT_SKIP_STRING : JSON_STATE_ARRAY_SKIP_STRING; parser->strinput = i_stream_create_jsonstr(parser->input); - i_stream_set_destroy_callback(parser->strinput, + i_stream_add_destroy_callback(parser->strinput, json_strinput_destroyed, parser); *input_r = parser->strinput; -- 2.47.3