* [PATCH v2] qmimodem: include shutdown in callback cleanup queue
@ 2017-03-30 13:51 Lukasz Nowak
2017-03-30 13:51 ` Lukasz Nowak
0 siblings, 1 reply; 3+ messages in thread
From: Lukasz Nowak @ 2017-03-30 13:51 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 360 bytes --]
From: Lukasz Nowak <lnowak@tycoint.com>
Changes since v1:
- fixed callback->timeout not being saved in qmi_device_shutdown()
Lukasz Nowak (1):
qmimodem: include shutdown in callback cleanup queue
drivers/qmimodem/qmi.c | 401 ++++++++++++++++++++++---------------------------
1 file changed, 180 insertions(+), 221 deletions(-)
--
2.7.4
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v2] qmimodem: include shutdown in callback cleanup queue
2017-03-30 13:51 [PATCH v2] qmimodem: include shutdown in callback cleanup queue Lukasz Nowak
@ 2017-03-30 13:51 ` Lukasz Nowak
2017-04-03 18:19 ` Denis Kenzior
0 siblings, 1 reply; 3+ messages in thread
From: Lukasz Nowak @ 2017-03-30 13:51 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 19083 bytes --]
From: Lukasz Nowak <lnowak@tycoint.com>
Create a unified callback_data structure, used for all timeout callbacks.
This allows to maintain a single callback_queue, which cancels any active
timeouts, and frees callback data memory when a usb device is hot unplugged.
---
drivers/qmimodem/qmi.c | 401 ++++++++++++++++++++++---------------------------
1 file changed, 180 insertions(+), 221 deletions(-)
diff --git a/drivers/qmimodem/qmi.c b/drivers/qmimodem/qmi.c
index 9b80455..ec38a87 100644
--- a/drivers/qmimodem/qmi.c
+++ b/drivers/qmimodem/qmi.c
@@ -43,11 +43,6 @@
typedef void (*qmi_message_func_t)(uint16_t message, uint16_t length,
const void *buffer, void *user_data);
-struct discovery {
- void *discover_data;
- qmi_destroy_func_t destroy;
-};
-
struct qmi_device {
int ref_count;
int fd;
@@ -58,7 +53,7 @@ struct qmi_device {
GQueue *req_queue;
GQueue *control_queue;
GQueue *service_queue;
- GQueue *discovery_queue;
+ GQueue *callback_queue;
uint8_t next_control_tid;
uint16_t next_service_tid;
qmi_debug_func_t debug_func;
@@ -154,6 +149,89 @@ void qmi_free(void *ptr)
free(ptr);
}
+struct discover_data {
+ qmi_discover_func_t func;
+};
+
+struct shutdown_data {
+ qmi_shutdown_func_t func;
+};
+
+struct service_create_data {
+ bool shared;
+ uint8_t type;
+ uint16_t major;
+ uint16_t minor;
+ qmi_create_func_t func;
+};
+
+struct service_create_shared_data {
+ struct qmi_service *service;
+ qmi_create_func_t func;
+};
+
+struct callback_data {
+ struct qmi_device *device;
+ void *user_data;
+ qmi_destroy_func_t user_destroy;
+ qmi_destroy_func_t callback_destroy;
+ guint timeout;
+ union {
+ struct discover_data discover;
+ struct shutdown_data shutdown;
+ struct service_create_data service_create;
+ struct service_create_shared_data service_create_shared;
+ } data;
+};
+
+static void callback_data_free(struct callback_data *callback)
+{
+ if (callback->timeout) {
+ g_source_remove(callback->timeout);
+ callback->timeout = 0;
+ }
+
+ if (callback->callback_destroy)
+ callback->callback_destroy(callback);
+
+ if (callback->user_destroy)
+ callback->user_destroy(callback->user_data);
+
+ g_free(callback);
+}
+
+static void service_create_shared_free(gpointer user_data)
+{
+ struct callback_data *callback = user_data;
+
+ qmi_service_unref(callback->data.service_create_shared.service);
+}
+
+static void __callback_started(struct callback_data *callback)
+{
+ struct qmi_device *device = callback->device;
+
+ g_queue_push_tail(device->callback_queue, callback);
+}
+
+static void __callback_complete(struct callback_data *callback)
+{
+ struct qmi_device *device = callback->device;
+ GList *list;
+
+ list = g_queue_find(device->callback_queue, callback);
+ if (!list)
+ return;
+
+ g_queue_delete_link(device->callback_queue, list);
+ callback_data_free(callback);
+}
+
+static void __callback_free(gpointer data, gpointer user_data)
+{
+ callback_data_free(data);
+}
+
static struct qmi_request *__request_alloc(uint8_t service,
uint8_t client, uint16_t message,
uint16_t headroom, const void *data,
@@ -219,24 +297,6 @@ static gint __request_compare(gconstpointer a, gconstpointer b)
return req->tid - tid;
}
-static void __discovery_free(gpointer data, gpointer user_data)
-{
- struct discovery *d = data;
- qmi_destroy_func_t destroy = d->destroy;
-
- destroy(d->discover_data);
-}
-
-static gint __discovery_compare(gconstpointer a, gconstpointer b)
-{
- const struct discovery *d = a;
-
- if (d->discover_data == b)
- return 0;
-
- return 1;
-}
-
static void __notify_free(gpointer data, gpointer user_data)
{
struct qmi_notify *notify = data;
@@ -868,37 +928,6 @@ static void read_watch_destroy(gpointer user_data)
device->read_watch = 0;
}
-static void __qmi_device_discovery_started(struct qmi_device *device,
- void *discover_data,
- qmi_destroy_func_t destroy)
-{
- struct discovery *d;
-
- d = g_new0(struct discovery, 1);
- d->discover_data = discover_data;
- d->destroy = destroy;
-
- g_queue_push_tail(device->discovery_queue, d);
-}
-
-static void __qmi_device_discovery_complete(struct qmi_device *device,
- void *discover_data)
-{
- GList *list;
- struct discovery *d;
-
- list = g_queue_find_custom(device->req_queue,
- discover_data, __discovery_compare);
- if (!list)
- return;
-
- d = list->data;
- g_queue_delete_link(device->discovery_queue, list);
-
- d->destroy(d->discover_data);
- __discovery_free(d, NULL);
-}
-
static void service_destroy(gpointer data)
{
struct qmi_service *service = data;
@@ -952,7 +981,7 @@ struct qmi_device *qmi_device_new(int fd)
device->req_queue = g_queue_new();
device->control_queue = g_queue_new();
device->service_queue = g_queue_new();
- device->discovery_queue = g_queue_new();
+ device->callback_queue = g_queue_new();
device->service_list = g_hash_table_new_full(g_direct_hash,
g_direct_equal, NULL, service_destroy);
@@ -989,8 +1018,8 @@ void qmi_device_unref(struct qmi_device *device)
g_queue_foreach(device->req_queue, __request_free, NULL);
g_queue_free(device->req_queue);
- g_queue_foreach(device->discovery_queue, __discovery_free, NULL);
- g_queue_free(device->discovery_queue);
+ g_queue_foreach(device->callback_queue, __callback_free, NULL);
+ g_queue_free(device->callback_queue);
if (device->write_watch > 0)
g_source_remove(device->write_watch);
@@ -1051,34 +1080,12 @@ static const void *tlv_get(const void *data, uint16_t size,
return NULL;
}
-struct discover_data {
- struct qmi_device *device;
- qmi_discover_func_t func;
- void *user_data;
- qmi_destroy_func_t destroy;
- guint timeout;
-};
-
-static void discover_data_free(gpointer user_data)
-{
- struct discover_data *data = user_data;
-
- if (data->timeout) {
- g_source_remove(data->timeout);
- data->timeout = 0;
- }
-
- if (data->destroy)
- data->destroy(data->user_data);
-
- g_free(data);
-}
-
static void discover_callback(uint16_t message, uint16_t length,
const void *buffer, void *user_data)
{
- struct discover_data *data = user_data;
- struct qmi_device *device = data->device;
+ struct callback_data *callback = user_data;
+ struct discover_data *data = &callback->data.discover;
+ struct qmi_device *device = callback->device;
const struct qmi_result_code *result_code;
const struct qmi_service_list *service_list;
const void *ptr;
@@ -1155,23 +1162,22 @@ done:
device->version_count = count;
if (data->func)
- data->func(count, list, data->user_data);
+ data->func(count, list, callback->user_data);
- __qmi_device_discovery_complete(data->device, data);
+ __callback_complete(callback);
}
static gboolean discover_reply(gpointer user_data)
{
- struct discover_data *data = user_data;
- struct qmi_device *device = data->device;
-
- data->timeout = 0;
+ struct callback_data *callback = user_data;
+ struct discover_data *data = &callback->data.discover;
+ struct qmi_device *device = callback->device;
if (data->func)
data->func(device->version_count,
- device->version_list, data->user_data);
+ device->version_list, callback->user_data);
- __qmi_device_discovery_complete(data->device, data);
+ __callback_complete(callback);
return FALSE;
}
@@ -1179,7 +1185,7 @@ static gboolean discover_reply(gpointer user_data)
bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
- struct discover_data *data;
+ struct callback_data *callback;
struct qmi_request *req;
struct qmi_control_hdr *hdr;
@@ -1188,27 +1194,27 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
__debug_device(device, "device %p discover", device);
- data = g_try_new0(struct discover_data, 1);
- if (!data)
+ callback = g_try_new0(struct callback_data, 1);
+ if (!callback)
return false;
- data->device = device;
- data->func = func;
- data->user_data = user_data;
- data->destroy = destroy;
+ callback->device = device;
+ callback->user_data = user_data;
+ callback->user_destroy = destroy;
+ callback->data.discover.func = func;
if (device->version_list) {
- data->timeout = g_timeout_add_seconds(0, discover_reply, data);
- __qmi_device_discovery_started(device, data,
- discover_data_free);
+ callback->timeout = g_timeout_add_seconds(0, discover_reply,
+ callback);
+ __callback_started(callback);
return true;
}
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_GET_VERSION_INFO, QMI_CONTROL_HDR_SIZE,
- NULL, 0, discover_callback, data, (void **) &hdr);
+ NULL, 0, discover_callback, callback, (void **) &hdr);
if (!req) {
- g_free(data);
+ g_free(callback);
return false;
}
@@ -1220,8 +1226,8 @@ bool qmi_device_discover(struct qmi_device *device, qmi_discover_func_t func,
__request_submit(device, req, hdr->transaction);
- data->timeout = g_timeout_add_seconds(5, discover_reply, data);
- __qmi_device_discovery_started(device, data, discover_data_free);
+ callback->timeout = g_timeout_add_seconds(5, discover_reply, callback);
+ __callback_started(callback);
return true;
}
@@ -1252,39 +1258,34 @@ static void release_client(struct qmi_device *device,
__request_submit(device, req, hdr->transaction);
}
-struct shutdown_data {
- struct qmi_device *device;
- qmi_shutdown_func_t func;
- void *user_data;
- qmi_destroy_func_t destroy;
-};
-
static gboolean shutdown_reply(gpointer user_data)
{
- struct shutdown_data *data = user_data;
+ struct callback_data *callback = user_data;
+ struct shutdown_data *data = &callback->data.shutdown;
if (data->func)
- data->func(data->user_data);
+ data->func(callback->user_data);
- g_free(data);
+ __callback_complete(callback);
return FALSE;
}
static gboolean shutdown_timeout(gpointer user_data)
{
- struct shutdown_data *data = user_data;
- struct qmi_device *device = data->device;
+ struct callback_data *callback = user_data;
+ struct qmi_device *device = callback->device;
if (device->release_users > 0)
return TRUE;
- return shutdown_reply(data);
+ return shutdown_reply(callback);
}
bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
+ struct callback_data *callback;
struct shutdown_data *data;
if (!device)
@@ -1292,19 +1293,24 @@ bool qmi_device_shutdown(struct qmi_device *device, qmi_shutdown_func_t func,
__debug_device(device, "device %p shutdown", device);
- data = g_try_new0(struct shutdown_data, 1);
- if (!data)
+ callback = g_try_new0(struct callback_data, 1);
+ if (!callback)
return false;
- data->device = device;
+ callback->device = device;
+ callback->user_data = user_data;
+ callback->user_destroy = destroy;
+ data = &callback->data.shutdown;
data->func = func;
- data->user_data = user_data;
- data->destroy = destroy;
if (device->release_users > 0)
- g_timeout_add_seconds(0, shutdown_timeout, data);
+ callback->timeout = g_timeout_add_seconds(0, shutdown_timeout,
+ callback);
else
- g_timeout_add_seconds(0, shutdown_reply, data);
+ callback->timeout = g_timeout_add_seconds(0, shutdown_reply,
+ callback);
+
+ __callback_started(callback);
return true;
}
@@ -1771,41 +1777,13 @@ bool qmi_result_get_uint64(struct qmi_result *result, uint8_t type,
return true;
}
-struct service_create_data {
- struct qmi_device *device;
- bool shared;
- uint8_t type;
- uint16_t major;
- uint16_t minor;
- qmi_create_func_t func;
- void *user_data;
- qmi_destroy_func_t destroy;
- guint timeout;
-};
-
-static void service_create_data_free(gpointer user_data)
-{
- struct service_create_data *data = user_data;
-
- if (data->timeout) {
- g_source_remove(data->timeout);
- data->timeout = 0;
- }
-
- if (data->destroy)
- data->destroy(data->user_data);
-
- g_free(data);
-}
-
static gboolean service_create_reply(gpointer user_data)
{
- struct service_create_data *data = user_data;
+ struct callback_data *callback = user_data;
- data->timeout = 0;
- data->func(NULL, data->user_data);
+ callback->data.service_create.func(NULL, callback->user_data);
- __qmi_device_discovery_complete(data->device, data);
+ __callback_complete(callback);
return FALSE;
}
@@ -1813,8 +1791,9 @@ static gboolean service_create_reply(gpointer user_data)
static void service_create_callback(uint16_t message, uint16_t length,
const void *buffer, void *user_data)
{
- struct service_create_data *data = user_data;
- struct qmi_device *device = data->device;
+ struct callback_data *callback = user_data;
+ struct service_create_data *data = &callback->data.service_create;
+ struct qmi_device *device = callback->device;
struct qmi_service *service = NULL;
const struct qmi_result_code *result_code;
const struct qmi_client_id *client_id;
@@ -1843,7 +1822,7 @@ static void service_create_callback(uint16_t message, uint16_t length,
goto done;
service->ref_count = 1;
- service->device = data->device;
+ service->device = callback->device;
service->shared = data->shared;
service->type = data->type;
@@ -1861,17 +1840,18 @@ static void service_create_callback(uint16_t message, uint16_t length,
GUINT_TO_POINTER(hash_id), service);
done:
- data->func(service, data->user_data);
+ data->func(service, callback->user_data);
qmi_service_unref(service);
- __qmi_device_discovery_complete(data->device, data);
+ __callback_complete(callback);
}
static void service_create_discover(uint8_t count,
const struct qmi_version *list, void *user_data)
{
- struct service_create_data *data = user_data;
- struct qmi_device *device = data->device;
+ struct callback_data *callback = user_data;
+ struct service_create_data *data = &callback->data.service_create;
+ struct qmi_device *device = callback->device;
struct qmi_request *req;
struct qmi_control_hdr *hdr;
unsigned char client_req[] = { 0x01, 0x01, 0x00, data->type };
@@ -1890,15 +1870,14 @@ static void service_create_discover(uint8_t count,
req = __request_alloc(QMI_SERVICE_CONTROL, 0x00,
QMI_CTL_GET_CLIENT_ID, QMI_CONTROL_HDR_SIZE,
client_req, sizeof(client_req),
- service_create_callback, data, (void **) &hdr);
+ service_create_callback, callback, (void **) &hdr);
if (!req) {
- if (data->timeout > 0)
- g_source_remove(data->timeout);
+ if (callback->timeout > 0)
+ g_source_remove(callback->timeout);
- data->timeout = g_timeout_add_seconds(0,
- service_create_reply, data);
- __qmi_device_discovery_started(device, data,
- service_create_data_free);
+ callback->timeout = g_timeout_add_seconds(0,
+ service_create_reply, callback);
+ __callback_started(callback);
return;
}
@@ -1915,36 +1894,39 @@ static bool service_create(struct qmi_device *device, bool shared,
uint8_t type, qmi_create_func_t func,
void *user_data, qmi_destroy_func_t destroy)
{
+ struct callback_data *callback;
struct service_create_data *data;
- data = g_try_new0(struct service_create_data, 1);
- if (!data)
+ callback = g_try_new0(struct callback_data, 1);
+ if (!callback)
return false;
- data->device = device;
+ callback->device = device;
+ callback->user_data = user_data;
+ callback->user_destroy = destroy;
+ data = &callback->data.service_create;
+ data->func = func;
data->shared = shared;
data->type = type;
- data->func = func;
- data->user_data = user_data;
- data->destroy = destroy;
if (device->version_list) {
service_create_discover(device->version_count,
- device->version_list, data);
+ device->version_list, callback);
goto done;
}
- if (qmi_device_discover(device, service_create_discover, data, NULL))
+ if (qmi_device_discover(device, service_create_discover, callback,
+ NULL))
goto done;
- g_free(data);
+ g_free(callback);
return false;
done:
- data->timeout = g_timeout_add_seconds(8, service_create_reply, data);
- __qmi_device_discovery_started(device, data,
- service_create_data_free);
+ callback->timeout = g_timeout_add_seconds(8, service_create_reply,
+ callback);
+ __callback_started(callback);
return true;
}
@@ -1962,40 +1944,15 @@ bool qmi_service_create(struct qmi_device *device,
return service_create(device, false, type, func, user_data, destroy);
}
-struct service_create_shared_data {
- struct qmi_service *service;
- struct qmi_device *device;
- qmi_create_func_t func;
- void *user_data;
- qmi_destroy_func_t destroy;
- guint timeout;
-};
-
-static void service_create_shared_data_free(gpointer user_data)
-{
- struct service_create_shared_data *data = user_data;
-
- if (data->timeout) {
- g_source_remove(data->timeout);
- data->timeout = 0;
- }
-
- qmi_service_unref(data->service);
-
- if (data->destroy)
- data->destroy(data->user_data);
-
- g_free(data);
-}
-
static gboolean service_create_shared_reply(gpointer user_data)
{
- struct service_create_shared_data *data = user_data;
+ struct callback_data *callback = user_data;
+ struct service_create_shared_data *data =
+ &callback->data.service_create_shared;
- data->timeout = 0;
- data->func(data->service, data->user_data);
+ data->func(data->service, callback->user_data);
- __qmi_device_discovery_complete(data->device, data);
+ __callback_complete(callback);
return FALSE;
}
@@ -2016,22 +1973,24 @@ bool qmi_service_create_shared(struct qmi_device *device,
service = g_hash_table_find(device->service_list,
__service_compare_shared, GUINT_TO_POINTER(type_val));
if (service) {
+ struct callback_data *callback;
struct service_create_shared_data *data;
- data = g_try_new0(struct service_create_shared_data, 1);
- if (!data)
+ callback = g_try_new0(struct callback_data, 1);
+ if (!callback)
return false;
+ callback->device = device;
+ callback->user_data = user_data;
+ callback->user_destroy = destroy;
+ callback->callback_destroy = service_create_shared_free;
+ data = &callback->data.service_create_shared;
data->service = qmi_service_ref(service);
- data->device = device;
data->func = func;
- data->user_data = user_data;
- data->destroy = destroy;
- data->timeout = g_timeout_add(0,
- service_create_shared_reply, data);
- __qmi_device_discovery_started(device, data,
- service_create_shared_data_free);
+ callback->timeout = g_timeout_add(0,
+ service_create_shared_reply, callback);
+ __callback_started(callback);
return 0;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v2] qmimodem: include shutdown in callback cleanup queue
2017-03-30 13:51 ` Lukasz Nowak
@ 2017-04-03 18:19 ` Denis Kenzior
0 siblings, 0 replies; 3+ messages in thread
From: Denis Kenzior @ 2017-04-03 18:19 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 918 bytes --]
Hi Lukasz,
On 03/30/2017 08:51 AM, Lukasz Nowak wrote:
> From: Lukasz Nowak <lnowak@tycoint.com>
>
> Create a unified callback_data structure, used for all timeout callbacks.
> This allows to maintain a single callback_queue, which cancels any active
> timeouts, and frees callback data memory when a usb device is hot unplugged.
> ---
> drivers/qmimodem/qmi.c | 401 ++++++++++++++++++++++---------------------------
> 1 file changed, 180 insertions(+), 221 deletions(-)
>
I didn't like how invasive this approach was, and also the union was a
bit ugly as it required all the weird data structures to be defined
first. They were no longer local to actual functions that utilized them.
Please check [PATCH] qmi: Optimize structure allocations. That one
should simplify things quite a bit as well. Not tested on my end, so
please let me know / fix it if it is broken.
Regards,
-Denis
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2017-04-03 18:19 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-30 13:51 [PATCH v2] qmimodem: include shutdown in callback cleanup queue Lukasz Nowak
2017-03-30 13:51 ` Lukasz Nowak
2017-04-03 18:19 ` Denis Kenzior
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.