Re: [ubus PATCH] libubus: remove global variables

2023-03-05 Thread Hauke Mehrtens

Hi Simon,

On 1/5/23 15:30, Simon Tate wrote:

Remove the use of global blob_buf and blob_attr variables to allow
for better thread safety with a ctx per thread on client invoke
and sends.

Add the same variables to within each calling function's scope,
encapsulating the memory usage there.

Fixes a multithreaded use case and has been verified 10,000
threads multiple times running invokes and send events.


I like this approach. The disadvantage is that we have more mallocs in 
the code now. Before the global b variable had a pointer to the heap 
which was reused, now we always start with a small buffer on the heap 
and then have to realloc to increase it and free it up when the function 
terminates.


The OpenWrt applications do not make much use of pthreads, but if your 
application is such a change is helpful. I think we can effort the extra 
overhead of the extra mallocs and frees.


I also found there many style problems and some problems in error paths 
in the code.



Signed-off-by: Simon Tate 
---
  cli.c  | 38 --
  libubus-internal.h |  2 +-
  libubus-io.c   | 10 ---
  libubus-obj.c  | 63 ++-
  libubus-req.c  | 44 +-
  libubus-sub.c  | 13 ++---
  libubus.c  | 67 ++
  7 files changed, 161 insertions(+), 76 deletions(-)

diff --git a/cli.c b/cli.c
index 81591ec..e6d7a1b 100644
--- a/cli.c
+++ b/cli.c
@@ -16,7 +16,6 @@
  #include 
  #include "libubus.h"
  
-static struct blob_buf b;

  static int listen_timeout;
  static int timeout = 30;
  static bool simple_output = false;
@@ -140,18 +139,29 @@ static int ubus_cli_call(struct ubus_context *ctx, int 
argc, char **argv)
if (argc < 2 || argc > 3)
return -2;
  
+	struct blob_buf b = { 0 };

blob_buf_init(, 0);
if (argc == 3 && !blobmsg_add_json_from_string(, argv[2])) {
if (!simple_output)
fprintf(stderr, "Failed to parse message data\n");
-   return -1;
+   ret = -1;
+   goto error;
}
  
  	ret = ubus_lookup_id(ctx, argv[0], );

-   if (ret)
-   return ret;
+   if (ret) {
+   goto error;
+   }


Please do not use brackets for only one statement. This is part of the 
Linux kernel code style which is used here. There are multiple places 
where you do not have to add them.



+
+   ret = ubus_invoke(ctx, id, argv[1], b.head, receive_call_result_data, 
NULL, timeout * 1000);
+   if (ret) {
+   goto error;
+   }
  
-	return ubus_invoke(ctx, id, argv[1], b.head, receive_call_result_data, NULL, timeout * 1000);

+error:
+   blob_buf_free();
+
+   return ret;
  }
  
  struct cli_listen_data {

@@ -265,15 +275,23 @@ static int ubus_cli_send(struct ubus_context *ctx, int 
argc, char **argv)
if (argc < 1 || argc > 2)
return -2;
  
+	int ret = UBUS_STATUS_OK;


Initialization is not needed here.
Please move the "int ret;" to the beginning of the function.


+
+   struct blob_buf b = { 0 };
blob_buf_init(, 0);
  
  	if (argc == 2 && !blobmsg_add_json_from_string(, argv[1])) {

if (!simple_output)
fprintf(stderr, "Failed to parse message data\n");
-   return -1;
+   ret = -1;
+   goto error;
}
  
-	return ubus_send_event(ctx, argv[0], b.head);

+   ret = ubus_send_event(ctx, argv[0], b.head);
+
+error:
+   blob_buf_free();
+   return ret;
  }
  
  struct cli_wait_data {

@@ -428,6 +446,7 @@ ubus_cli_get_monitor_data(struct blob_attr *data)
struct blob_attr *tb[UBUS_ATTR_MAX];
int i;
  
+	struct blob_buf b = { 0 };

blob_buf_init(, 0);
blob_parse(data, tb, policy, UBUS_ATTR_MAX);
  
@@ -454,7 +473,10 @@ ubus_cli_get_monitor_data(struct blob_attr *data)

}
}
  
-	return blobmsg_format_json(b.head, true);

+   char* ret = blobmsg_format_json(b.head, true);
+
+   blob_buf_free();
+   return ret;
  }
  
  static void

diff --git a/libubus-internal.h b/libubus-internal.h
index 24477a0..5b23668 100644
--- a/libubus-internal.h
+++ b/libubus-internal.h
@@ -17,7 +17,7 @@
  extern struct blob_buf b;
  extern const struct ubus_method watch_method;
  
-struct blob_attr **ubus_parse_msg(struct blob_attr *msg, size_t len);

+void ubus_parse_msg(struct blob_attr *msg, size_t len, struct blob_attr 
**attrbuf, size_t attrbuf_len);
  bool ubus_validate_hdr(struct ubus_msghdr *hdr);
  void ubus_handle_data(struct uloop_fd *u, unsigned int events);
  int ubus_send_msg(struct ubus_context *ctx, uint32_t seq,
diff --git a/libubus-io.c b/libubus-io.c
index 3561ac4..143d3be 100644
--- a/libubus-io.c
+++ b/libubus-io.c
@@ -41,12 +41,10 @@ static const struct blob_attr_info 
ubus_policy[UBUS_ATTR_MAX] = {

[ubus PATCH] libubus: remove global variables

2023-01-05 Thread Simon Tate
Remove the use of global blob_buf and blob_attr variables to allow
for better thread safety with a ctx per thread on client invoke
and sends.

Add the same variables to within each calling function's scope,
encapsulating the memory usage there.

Fixes a multithreaded use case and has been verified 10,000
threads multiple times running invokes and send events.

Signed-off-by: Simon Tate 
---
 cli.c  | 38 --
 libubus-internal.h |  2 +-
 libubus-io.c   | 10 ---
 libubus-obj.c  | 63 ++-
 libubus-req.c  | 44 +-
 libubus-sub.c  | 13 ++---
 libubus.c  | 67 ++
 7 files changed, 161 insertions(+), 76 deletions(-)

diff --git a/cli.c b/cli.c
index 81591ec..e6d7a1b 100644
--- a/cli.c
+++ b/cli.c
@@ -16,7 +16,6 @@
 #include 
 #include "libubus.h"
 
-static struct blob_buf b;
 static int listen_timeout;
 static int timeout = 30;
 static bool simple_output = false;
@@ -140,18 +139,29 @@ static int ubus_cli_call(struct ubus_context *ctx, int 
argc, char **argv)
if (argc < 2 || argc > 3)
return -2;
 
+   struct blob_buf b = { 0 };
blob_buf_init(, 0);
if (argc == 3 && !blobmsg_add_json_from_string(, argv[2])) {
if (!simple_output)
fprintf(stderr, "Failed to parse message data\n");
-   return -1;
+   ret = -1;
+   goto error;
}
 
ret = ubus_lookup_id(ctx, argv[0], );
-   if (ret)
-   return ret;
+   if (ret) {
+   goto error;
+   }
+
+   ret = ubus_invoke(ctx, id, argv[1], b.head, receive_call_result_data, 
NULL, timeout * 1000);
+   if (ret) {
+   goto error;
+   }
 
-   return ubus_invoke(ctx, id, argv[1], b.head, receive_call_result_data, 
NULL, timeout * 1000);
+error:
+   blob_buf_free();
+
+   return ret;
 }
 
 struct cli_listen_data {
@@ -265,15 +275,23 @@ static int ubus_cli_send(struct ubus_context *ctx, int 
argc, char **argv)
if (argc < 1 || argc > 2)
return -2;
 
+   int ret = UBUS_STATUS_OK;
+
+   struct blob_buf b = { 0 };
blob_buf_init(, 0);
 
if (argc == 2 && !blobmsg_add_json_from_string(, argv[1])) {
if (!simple_output)
fprintf(stderr, "Failed to parse message data\n");
-   return -1;
+   ret = -1;
+   goto error;
}
 
-   return ubus_send_event(ctx, argv[0], b.head);
+   ret = ubus_send_event(ctx, argv[0], b.head);
+
+error:
+   blob_buf_free();
+   return ret;
 }
 
 struct cli_wait_data {
@@ -428,6 +446,7 @@ ubus_cli_get_monitor_data(struct blob_attr *data)
struct blob_attr *tb[UBUS_ATTR_MAX];
int i;
 
+   struct blob_buf b = { 0 };
blob_buf_init(, 0);
blob_parse(data, tb, policy, UBUS_ATTR_MAX);
 
@@ -454,7 +473,10 @@ ubus_cli_get_monitor_data(struct blob_attr *data)
}
}
 
-   return blobmsg_format_json(b.head, true);
+   char* ret = blobmsg_format_json(b.head, true);
+
+   blob_buf_free();
+   return ret;
 }
 
 static void
diff --git a/libubus-internal.h b/libubus-internal.h
index 24477a0..5b23668 100644
--- a/libubus-internal.h
+++ b/libubus-internal.h
@@ -17,7 +17,7 @@
 extern struct blob_buf b;
 extern const struct ubus_method watch_method;
 
-struct blob_attr **ubus_parse_msg(struct blob_attr *msg, size_t len);
+void ubus_parse_msg(struct blob_attr *msg, size_t len, struct blob_attr 
**attrbuf, size_t attrbuf_len);
 bool ubus_validate_hdr(struct ubus_msghdr *hdr);
 void ubus_handle_data(struct uloop_fd *u, unsigned int events);
 int ubus_send_msg(struct ubus_context *ctx, uint32_t seq,
diff --git a/libubus-io.c b/libubus-io.c
index 3561ac4..143d3be 100644
--- a/libubus-io.c
+++ b/libubus-io.c
@@ -41,12 +41,10 @@ static const struct blob_attr_info 
ubus_policy[UBUS_ATTR_MAX] = {
[UBUS_ATTR_SUBSCRIBERS] = { .type = BLOB_ATTR_NESTED },
 };
 
-static struct blob_attr *attrbuf[UBUS_ATTR_MAX];
 
-__hidden struct blob_attr **ubus_parse_msg(struct blob_attr *msg, size_t len)
+__hidden void ubus_parse_msg(struct blob_attr *msg, size_t len, struct 
blob_attr **attrbuf, size_t attrbuf_len)
 {
-   blob_parse_untrusted(msg, len, attrbuf, ubus_policy, UBUS_ATTR_MAX);
-   return attrbuf;
+   blob_parse_untrusted(msg, len, attrbuf, ubus_policy, attrbuf_len);
 }
 
 static void wait_data(int fd, bool write)
@@ -137,6 +135,8 @@ int __hidden ubus_send_msg(struct ubus_context *ctx, 
uint32_t seq,
hdr.seq = cpu_to_be16(seq);
hdr.peer = cpu_to_be32(peer);
 
+   struct blob_buf b = {0};
+
if (!msg) {
blob_buf_init(, 0);
msg = b.head;
@@ -152,6 +152,8 @@ int __hidden ubus_send_msg(struct ubus_context *ctx, 
uint32_t seq,
if (fd >= 0)