All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] atmodem/atutil.h: cb_data ref/unref possibility
@ 2018-10-25  5:46 Giacinto Cifelli
  2018-10-25 16:13 ` Denis Kenzior
  0 siblings, 1 reply; 3+ messages in thread
From: Giacinto Cifelli @ 2018-10-25  5:46 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 3093 bytes --]

the cb_data can be used by creating the structure with cb_data_new,
and then there are two possibilities:
- use it in a single callback function, and destroy it with a call to
  g_free.
  Example:
  - calling function:
    struct cb_data *cbd = cb_data_new(cb, data);
    if (g_at_chat_send(chat, buf, NULL, at_cgatt_cb, cbd, g_free) > 0)
	return;
    g_free(cbd);
  - called function (here at_cgatt_cb):
	static void at_cgatt_cb(gboolean ok, GAtResult *result,
						gpointer user_data)
	{
		struct cb_data *cbd = user_data;
		ofono_gprs_cb_t cb = cbd->cb;
		struct ofono_error error;

		decode_at_error(&error,
				g_at_result_final_response(result));

		cb(&error, cbd->data);
	}
    note the absence of explicit g_free(cbd);

- pass it through a train of callback functions, adding a reference at
  each pass cb_data_ref, and removing it with cb_data_unref.
  the use of cb_data_ref would replace a new object creation, while the
  use of cb_data_unref the use of g_free.
  Example:
  - calling function:
	struct cb_data *cbd = cb_data_new(cb, data);
	// no cb_ref at the creation
	if (g_at_chat_send(chat, buf, NULL,
				at_lte_set_default_attach_info_cb,
				cbd, cb_data_unref) > 0)
		goto end;
	cb_data_unref(cbd);
  - called function 1 (at_lte_set_default_attach_info_cb):
	static void at_lte_set_default_attach_info_cb(gboolean ok,
				GAtResult *result, gpointer user_data)
	{
		struct cb_data *cbd = user_data;

		cbd = cb_data_ref(cbd);
		if (g_at_chat_send(chat, buf, NULL,
				at_cgatt_cb, cbd, cb_data_unref) > 0)
			return;
		cb_data_unref(cbd);
	}
  - called function 2 (at_cgatt_cb):
    like above. no call to g_free or cb_data_unref. The terminal function
    doesn't need to know about the reference scheme.

v2: fixed prototype for cb_data_unref to be compatible with g_free
---
 drivers/atmodem/atutil.h | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/atmodem/atutil.h b/drivers/atmodem/atutil.h
index f1389a94..aa8b619c 100644
--- a/drivers/atmodem/atutil.h
+++ b/drivers/atmodem/atutil.h
@@ -104,6 +104,7 @@ char *at_util_get_cgdcont_command(guint cid, enum ofono_gprs_proto proto,
 							const char *apn);
 
 struct cb_data {
+	gint ref_count;
 	void *cb;
 	void *data;
 	void *user;
@@ -114,12 +115,37 @@ static inline struct cb_data *cb_data_new(void *cb, void *data)
 	struct cb_data *ret;
 
 	ret = g_new0(struct cb_data, 1);
+	ret->ref_count = 1;
 	ret->cb = cb;
 	ret->data = data;
 
 	return ret;
 }
 
+static inline struct cb_data *cb_data_ref(struct cb_data *cbd)
+{
+	if (cbd == NULL)
+		return NULL;
+
+	g_atomic_int_inc(&cbd->ref_count);
+
+	return cbd;
+}
+
+static inline void cb_data_unref(gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	gboolean is_zero;
+
+	if (cbd == NULL)
+		return;
+
+	is_zero = g_atomic_int_dec_and_test(&cbd->ref_count);
+
+	if (is_zero == TRUE)
+		g_free(cbd);
+}
+
 static inline int at_util_convert_signal_strength(int strength)
 {
 	int result;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] atmodem/atutil.h: cb_data ref/unref possibility
  2018-10-25  5:46 [PATCH v2] atmodem/atutil.h: cb_data ref/unref possibility Giacinto Cifelli
@ 2018-10-25 16:13 ` Denis Kenzior
  2018-10-25 16:36   ` Giacinto Cifelli
  0 siblings, 1 reply; 3+ messages in thread
From: Denis Kenzior @ 2018-10-25 16:13 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 4146 bytes --]

Hi Giacinto,

On 10/25/2018 12:46 AM, Giacinto Cifelli wrote:
> the cb_data can be used by creating the structure with cb_data_new,
> and then there are two possibilities:
> - use it in a single callback function, and destroy it with a call to
>    g_free.
>    Example:
>    - calling function:
>      struct cb_data *cbd = cb_data_new(cb, data);
>      if (g_at_chat_send(chat, buf, NULL, at_cgatt_cb, cbd, g_free) > 0)
> 	return;
>      g_free(cbd);
>    - called function (here at_cgatt_cb):
> 	static void at_cgatt_cb(gboolean ok, GAtResult *result,
> 						gpointer user_data)
> 	{
> 		struct cb_data *cbd = user_data;
> 		ofono_gprs_cb_t cb = cbd->cb;
> 		struct ofono_error error;
> 
> 		decode_at_error(&error,
> 				g_at_result_final_response(result));
> 
> 		cb(&error, cbd->data);
> 	}
>      note the absence of explicit g_free(cbd);
> 
> - pass it through a train of callback functions, adding a reference at
>    each pass cb_data_ref, and removing it with cb_data_unref.
>    the use of cb_data_ref would replace a new object creation, while the
>    use of cb_data_unref the use of g_free.
>    Example:
>    - calling function:
> 	struct cb_data *cbd = cb_data_new(cb, data);
> 	// no cb_ref at the creation
> 	if (g_at_chat_send(chat, buf, NULL,
> 				at_lte_set_default_attach_info_cb,
> 				cbd, cb_data_unref) > 0)
> 		goto end;
> 	cb_data_unref(cbd);
>    - called function 1 (at_lte_set_default_attach_info_cb):
> 	static void at_lte_set_default_attach_info_cb(gboolean ok,
> 				GAtResult *result, gpointer user_data)
> 	{
> 		struct cb_data *cbd = user_data;
> 
> 		cbd = cb_data_ref(cbd);
> 		if (g_at_chat_send(chat, buf, NULL,
> 				at_cgatt_cb, cbd, cb_data_unref) > 0)
> 			return;
> 		cb_data_unref(cbd);
> 	}
>    - called function 2 (at_cgatt_cb):
>      like above. no call to g_free or cb_data_unref. The terminal function
>      doesn't need to know about the reference scheme.
> 

This is a nice summary of a very common pattern.  I left it in the 
commit description, but perhaps you might want to break this out into a 
separate document (and make it even more digestible) so that we can 
point people to it more easily.

Perhaps something like doc/common-patterns.txt?

> v2: fixed prototype for cb_data_unref to be compatible with g_free
> ---
>   drivers/atmodem/atutil.h | 26 ++++++++++++++++++++++++++
>   1 file changed, 26 insertions(+)
> 
> diff --git a/drivers/atmodem/atutil.h b/drivers/atmodem/atutil.h
> index f1389a94..aa8b619c 100644
> --- a/drivers/atmodem/atutil.h
> +++ b/drivers/atmodem/atutil.h
> @@ -104,6 +104,7 @@ char *at_util_get_cgdcont_command(guint cid, enum ofono_gprs_proto proto,
>   							const char *apn);
>   
>   struct cb_data {
> +	gint ref_count;
>   	void *cb;
>   	void *data;
>   	void *user;
> @@ -114,12 +115,37 @@ static inline struct cb_data *cb_data_new(void *cb, void *data)
>   	struct cb_data *ret;
>   
>   	ret = g_new0(struct cb_data, 1);
> +	ret->ref_count = 1;
>   	ret->cb = cb;
>   	ret->data = data;
>   
>   	return ret;
>   }
>   
> +static inline struct cb_data *cb_data_ref(struct cb_data *cbd)
> +{
> +	if (cbd == NULL)
> +		return NULL;

I removed this part.  For all private/semi-private APIs I want us to 
crash early.  If someone is making the mistake of passing a NULL to 
cb_data_ref then I don't want it to remain hidden until the bug 
manifests itself in harder to detect ways.

> +
> +	g_atomic_int_inc(&cbd->ref_count);

And I removed g_atomic stuff as well...

> +
> +	return cbd;
> +}
> +
> +static inline void cb_data_unref(gpointer user_data)
> +{
> +	struct cb_data *cbd = user_data;
> +	gboolean is_zero;
> +
> +	if (cbd == NULL)
> +		return;
> +
> +	is_zero = g_atomic_int_dec_and_test(&cbd->ref_count);
> +
> +	if (is_zero == TRUE)
> +		g_free(cbd);
> +}
> +
>   static inline int at_util_convert_signal_strength(int strength)
>   {
>   	int result;
> 

Applied as commit eed785a4d7a2529a5c1ddee8ba20b1c4e2aa7f99.  Please 
eyeball and make sure I didn't screw anything up.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] atmodem/atutil.h: cb_data ref/unref possibility
  2018-10-25 16:13 ` Denis Kenzior
@ 2018-10-25 16:36   ` Giacinto Cifelli
  0 siblings, 0 replies; 3+ messages in thread
From: Giacinto Cifelli @ 2018-10-25 16:36 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 5187 bytes --]

Hi Denis,


On Thu, Oct 25, 2018 at 6:13 PM Denis Kenzior <denkenz@gmail.com> wrote:
>
> Hi Giacinto,
>
> On 10/25/2018 12:46 AM, Giacinto Cifelli wrote:
> > the cb_data can be used by creating the structure with cb_data_new,
> > and then there are two possibilities:
> > - use it in a single callback function, and destroy it with a call to
> >    g_free.
> >    Example:
> >    - calling function:
> >      struct cb_data *cbd = cb_data_new(cb, data);
> >      if (g_at_chat_send(chat, buf, NULL, at_cgatt_cb, cbd, g_free) > 0)
> >       return;
> >      g_free(cbd);
> >    - called function (here at_cgatt_cb):
> >       static void at_cgatt_cb(gboolean ok, GAtResult *result,
> >                                               gpointer user_data)
> >       {
> >               struct cb_data *cbd = user_data;
> >               ofono_gprs_cb_t cb = cbd->cb;
> >               struct ofono_error error;
> >
> >               decode_at_error(&error,
> >                               g_at_result_final_response(result));
> >
> >               cb(&error, cbd->data);
> >       }
> >      note the absence of explicit g_free(cbd);
> >
> > - pass it through a train of callback functions, adding a reference at
> >    each pass cb_data_ref, and removing it with cb_data_unref.
> >    the use of cb_data_ref would replace a new object creation, while the
> >    use of cb_data_unref the use of g_free.
> >    Example:
> >    - calling function:
> >       struct cb_data *cbd = cb_data_new(cb, data);
> >       // no cb_ref at the creation
> >       if (g_at_chat_send(chat, buf, NULL,
> >                               at_lte_set_default_attach_info_cb,
> >                               cbd, cb_data_unref) > 0)
> >               goto end;
> >       cb_data_unref(cbd);
> >    - called function 1 (at_lte_set_default_attach_info_cb):
> >       static void at_lte_set_default_attach_info_cb(gboolean ok,
> >                               GAtResult *result, gpointer user_data)
> >       {
> >               struct cb_data *cbd = user_data;
> >
> >               cbd = cb_data_ref(cbd);
> >               if (g_at_chat_send(chat, buf, NULL,
> >                               at_cgatt_cb, cbd, cb_data_unref) > 0)
> >                       return;
> >               cb_data_unref(cbd);
> >       }
> >    - called function 2 (at_cgatt_cb):
> >      like above. no call to g_free or cb_data_unref. The terminal function
> >      doesn't need to know about the reference scheme.
> >
>
> This is a nice summary of a very common pattern.

yes, I felt very creative this morning :)

> I left it in the
> commit description, but perhaps you might want to break this out into a
> separate document (and make it even more digestible) so that we can
> point people to it more easily.
>
> Perhaps something like doc/common-patterns.txt?

ok, I will start such a document.

>
> > v2: fixed prototype for cb_data_unref to be compatible with g_free
> > ---
> >   drivers/atmodem/atutil.h | 26 ++++++++++++++++++++++++++
> >   1 file changed, 26 insertions(+)
> >
> > diff --git a/drivers/atmodem/atutil.h b/drivers/atmodem/atutil.h
> > index f1389a94..aa8b619c 100644
> > --- a/drivers/atmodem/atutil.h
> > +++ b/drivers/atmodem/atutil.h
> > @@ -104,6 +104,7 @@ char *at_util_get_cgdcont_command(guint cid, enum ofono_gprs_proto proto,
> >                                                       const char *apn);
> >
> >   struct cb_data {
> > +     gint ref_count;
> >       void *cb;
> >       void *data;
> >       void *user;
> > @@ -114,12 +115,37 @@ static inline struct cb_data *cb_data_new(void *cb, void *data)
> >       struct cb_data *ret;
> >
> >       ret = g_new0(struct cb_data, 1);
> > +     ret->ref_count = 1;
> >       ret->cb = cb;
> >       ret->data = data;
> >
> >       return ret;
> >   }
> >
> > +static inline struct cb_data *cb_data_ref(struct cb_data *cbd)
> > +{
> > +     if (cbd == NULL)
> > +             return NULL;
>
> I removed this part.  For all private/semi-private APIs I want us to
> crash early.  If someone is making the mistake of passing a NULL to
> cb_data_ref then I don't want it to remain hidden until the bug
> manifests itself in harder to detect ways.
>
> > +
> > +     g_atomic_int_inc(&cbd->ref_count);
>
> And I removed g_atomic stuff as well...
>
> > +
> > +     return cbd;
> > +}
> > +
> > +static inline void cb_data_unref(gpointer user_data)
> > +{
> > +     struct cb_data *cbd = user_data;
> > +     gboolean is_zero;
> > +
> > +     if (cbd == NULL)
> > +             return;
> > +
> > +     is_zero = g_atomic_int_dec_and_test(&cbd->ref_count);
> > +
> > +     if (is_zero == TRUE)
> > +             g_free(cbd);
> > +}
> > +
> >   static inline int at_util_convert_signal_strength(int strength)
> >   {
> >       int result;
> >
>
> Applied as commit eed785a4d7a2529a5c1ddee8ba20b1c4e2aa7f99.  Please
> eyeball and make sure I didn't screw anything up.

It looks ok and executes fine (with the gemaltomodem/lte.c that isn't
yet in the tree).

>
> Regards,
> -Denis

Regards,
Giacinto

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-10-25 16:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-25  5:46 [PATCH v2] atmodem/atutil.h: cb_data ref/unref possibility Giacinto Cifelli
2018-10-25 16:13 ` Denis Kenzior
2018-10-25 16:36   ` Giacinto Cifelli

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.