Skip to content

Commit

Permalink
lib: make bt_value_map_foreach_entry_{const_}func() return a status code
Browse files Browse the repository at this point in the history
This patch makes the bt_value_map_foreach_entry_func() and
bt_value_map_foreach_entry_const_func() types return status codes
instead of `bt_bool`.

The available status codes are `OK` (continue the loop, like returning
`BT_TRUE` before this patch), `ERROR`, `MEMORY_ERROR`, and `INTERRUPT`
(break the loop, like returning `BT_FALSE` before this patch).

When the user function returns
`BT_VALUE_MAP_FOREACH_ENTRY_FUNC_STATUS_ERROR`,
bt_value_map_foreach_entry() returns
`BT_VALUE_MAP_FOREACH_ENTRY_STATUS_USER_ERROR` (set to the new global
status code `__BT_FUNC_STATUS_USER_ERROR`). This makes it possible to
distinguish between an internal library error and a user function error.

The purpose of this patch is to make it possible for a user function to
append an error cause to the current thread's error the same way other
user functions do: append the cause and return an error status.

For example, consider this scenario:

1. User calls bt_value_map_foreach_entry() with a user function and user
   data which contains a status member.

2. User function calls a library function which fails. The library
   function appends a cause to the current thread's error.

3. User function appends a cause to the current thread's error.

4. User function sets the user data's status member to the failing
   library function's status and returns `BT_FALSE` to interrupt the
   loop.

5. bt_value_map_foreach_entry() returns
   `BT_VALUE_MAP_FOREACH_ENTRY_STATUS_INTERRUPTED` (not an error
   status).

6. The caller of bt_value_map_foreach_entry() interprets
   `BT_VALUE_MAP_FOREACH_ENTRY_STATUS_INTERRUPTED` as an error because
   the user data's status member has an error value.

With this patch, it becomes:

1. User calls bt_value_map_foreach_entry() with a user function.

2. User function calls a library function which fails. The library
   function appends a cause to the current thread's error.

3. User function appends a cause to the current thread's error.

4. User function returns `BT_VALUE_MAP_FOREACH_ENTRY_FUNC_STATUS_ERROR`
   or `BT_VALUE_MAP_FOREACH_ENTRY_FUNC_STATUS_MEMORY_ERROR`, depending
   on the failing library function's status, which breaks the loop.

5. bt_value_map_foreach_entry() appends a cause to the current thread's
   error and returns `BT_VALUE_MAP_FOREACH_ENTRY_STATUS_USER_ERROR` or
   `BT_VALUE_MAP_FOREACH_ENTRY_STATUS_MEMORY_ERROR`.

The latter seems more natural to me.

In Python, nothing wraps bt_value_map_foreach_entry() directly, so I
just converted bt_value_map_get_keys_cb() to return the appropriate
status instead of `BT_TRUE` or `BT_FALSE`. In other words,
bt2.utils._handle_func_status() does not need any change because it will
never receive `native_bt.__BT_FUNC_STATUS_USER_ERROR`.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: I235d7957003b51630f4a2f72c1ccdef89d6173e8
Reviewed-on: https://review.lttng.org/c/babeltrace/+/2365
Reviewed-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Reviewed-by: Simon Marchi <simon.marchi@efficios.com>
Tested-by: jenkins <jenkins@lttng.org>
  • Loading branch information
eepp authored and jgalar committed Nov 15, 2019
1 parent 4253e1e commit 0589c64
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 54 deletions.
1 change: 1 addition & 0 deletions include/babeltrace2/babeltrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
#undef __BT_FUNC_STATUS_NOT_FOUND
#undef __BT_FUNC_STATUS_OK
#undef __BT_FUNC_STATUS_OVERFLOW_ERROR
#undef __BT_FUNC_STATUS_USER_ERROR
#undef __BT_IN_BABELTRACE_H
#undef __BT_UPCAST
#undef __BT_UPCAST_CONST
Expand Down
5 changes: 5 additions & 0 deletions include/babeltrace2/func-status.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@
# define __BT_FUNC_STATUS_MEMORY_ERROR -12
#endif

/* User function error */
#ifndef __BT_FUNC_STATUS_USER_ERROR
# define __BT_FUNC_STATUS_USER_ERROR -2
#endif

/* General error */
#ifndef __BT_FUNC_STATUS_ERROR
# define __BT_FUNC_STATUS_ERROR -1
Expand Down
15 changes: 13 additions & 2 deletions include/babeltrace2/value-const.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,22 @@ bt_bool bt_value_map_is_empty(const bt_value *map_obj)
extern const bt_value *bt_value_map_borrow_entry_value_const(
const bt_value *map_obj, const char *key);

typedef bt_bool (* bt_value_map_foreach_entry_const_func)(const char *key,
const bt_value *object, void *data);
typedef enum bt_value_map_foreach_entry_const_func_status {
BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK = __BT_FUNC_STATUS_OK,
BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_ERROR = __BT_FUNC_STATUS_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_INTERRUPT = __BT_FUNC_STATUS_INTERRUPTED,
} bt_value_map_foreach_entry_const_func_status;

typedef bt_value_map_foreach_entry_const_func_status
(* bt_value_map_foreach_entry_const_func)(const char *key,
const bt_value *object, void *data);

typedef enum bt_value_map_foreach_entry_const_status {
BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK = __BT_FUNC_STATUS_OK,
BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_ERROR = __BT_FUNC_STATUS_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_USER_ERROR = __BT_FUNC_STATUS_USER_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_INTERRUPTED = __BT_FUNC_STATUS_INTERRUPTED,
} bt_value_map_foreach_entry_const_status;

Expand Down
15 changes: 13 additions & 2 deletions include/babeltrace2/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,22 @@ extern bt_value *bt_value_map_create(void);
extern bt_value *bt_value_map_borrow_entry_value(
bt_value *map_obj, const char *key);

typedef bt_bool (* bt_value_map_foreach_entry_func)(const char *key,
bt_value *object, void *data);
typedef enum bt_value_map_foreach_entry_func_status {
BT_VALUE_MAP_FOREACH_ENTRY_FUNC_STATUS_OK = __BT_FUNC_STATUS_OK,
BT_VALUE_MAP_FOREACH_ENTRY_FUNC_STATUS_ERROR = __BT_FUNC_STATUS_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_FUNC_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_FUNC_STATUS_INTERRUPT = __BT_FUNC_STATUS_INTERRUPTED,
} bt_value_map_foreach_entry_func_status;

typedef bt_value_map_foreach_entry_func_status
(* bt_value_map_foreach_entry_func)(const char *key,
bt_value *object, void *data);

typedef enum bt_value_map_foreach_entry_status {
BT_VALUE_MAP_FOREACH_ENTRY_STATUS_OK = __BT_FUNC_STATUS_OK,
BT_VALUE_MAP_FOREACH_ENTRY_STATUS_ERROR = __BT_FUNC_STATUS_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_STATUS_MEMORY_ERROR = __BT_FUNC_STATUS_MEMORY_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_STATUS_USER_ERROR = __BT_FUNC_STATUS_USER_ERROR,
BT_VALUE_MAP_FOREACH_ENTRY_STATUS_INTERRUPTED = __BT_FUNC_STATUS_INTERRUPTED,
} bt_value_map_foreach_entry_status;

Expand Down
13 changes: 6 additions & 7 deletions src/bindings/python/bt2/bt2/native_bt_value.i.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,16 @@ struct bt_value_map_get_keys_data {
struct bt_value *keys;
};

static int bt_value_map_get_keys_cb(const char *key, const struct bt_value *object, void *data)
static bt_value_map_foreach_entry_const_func_status bt_value_map_get_keys_cb(
const char *key, const struct bt_value *object, void *data)
{
bt_value_array_append_element_status status;
int status;
struct bt_value_map_get_keys_data *priv_data = data;

status = bt_value_array_append_string_element(priv_data->keys, key);
if (status != __BT_FUNC_STATUS_OK) {
return BT_FALSE;
}

return BT_TRUE;
BT_ASSERT(status == __BT_FUNC_STATUS_OK ||
status == __BT_FUNC_STATUS_MEMORY_ERROR);
return status;
}

static struct bt_value *bt_value_map_get_keys(const struct bt_value *map_obj)
Expand Down
5 changes: 3 additions & 2 deletions src/cli/babeltrace2.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,13 +330,14 @@ void print_map_value(const char *key, const bt_value *object, FILE *fp,
}

static
bt_bool collect_map_keys(const char *key, const bt_value *object, void *data)
bt_value_map_foreach_entry_const_func_status collect_map_keys(
const char *key, const bt_value *object, void *data)
{
GPtrArray *map_keys = data;

g_ptr_array_add(map_keys, (gpointer *) key);

return BT_TRUE;
return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK;
}

static
Expand Down
2 changes: 2 additions & 0 deletions src/common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,8 @@ const char *bt_common_func_status_string(int status)
return "UNKNOWN_OBJECT";
case __BT_FUNC_STATUS_MEMORY_ERROR:
return "MEMORY_ERROR";
case __BT_FUNC_STATUS_USER_ERROR:
return "USER_ERROR";
case __BT_FUNC_STATUS_ERROR:
return "ERROR";
case __BT_FUNC_STATUS_OK:
Expand Down
1 change: 1 addition & 0 deletions src/lib/func-status.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*/
#define BT_FUNC_STATUS_AGAIN __BT_FUNC_STATUS_AGAIN
#define BT_FUNC_STATUS_END __BT_FUNC_STATUS_END
#define BT_FUNC_STATUS_USER_ERROR __BT_FUNC_STATUS_USER_ERROR
#define BT_FUNC_STATUS_ERROR __BT_FUNC_STATUS_ERROR
#define BT_FUNC_STATUS_INTERRUPTED __BT_FUNC_STATUS_INTERRUPTED
#define BT_FUNC_STATUS_UNKNOWN_OBJECT __BT_FUNC_STATUS_UNKNOWN_OBJECT
Expand Down
78 changes: 51 additions & 27 deletions src/lib/value.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "common/common.h"
#include "compat/glib.h"
#include "lib/assert-pre.h"
#include "lib/assert-post.h"
#include "lib/value.h"
#include "common/assert.h"
#include "func-status.h"
Expand Down Expand Up @@ -1271,7 +1272,7 @@ enum bt_value_map_foreach_entry_status bt_value_map_foreach_entry(
struct bt_value *map_obj, bt_value_map_foreach_entry_func func,
void *data)
{
enum bt_value_map_foreach_entry_status ret = BT_FUNC_STATUS_OK;
int status = BT_FUNC_STATUS_OK;
gpointer key, element_obj;
GHashTableIter iter;
struct bt_value_map *typed_map_obj = BT_VALUE_TO_MAP(map_obj);
Expand All @@ -1286,16 +1287,40 @@ enum bt_value_map_foreach_entry_status bt_value_map_foreach_entry(
while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));

if (!func(key_str, element_obj, data)) {
BT_LOGT("User interrupted the loop: key=\"%s\", "
"value-addr=%p, data=%p",
key_str, element_obj, data);
ret = BT_FUNC_STATUS_INTERRUPTED;
status = func(key_str, element_obj, data);
BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(status);
if (status != BT_FUNC_STATUS_OK) {
if (status < 0) {
BT_LIB_LOGE_APPEND_CAUSE(
"User function failed while iterating "
"map value entries: "
"status=%s, key=\"%s\", "
"value-addr=%p, data=%p",
bt_common_func_status_string(status),
key_str, element_obj, data);

if (status == BT_FUNC_STATUS_ERROR) {
/*
* User function error becomes a
* user error from this
* function's caller's
* perspective.
*/
status = BT_FUNC_STATUS_USER_ERROR;
}
} else {
BT_ASSERT(status == BT_FUNC_STATUS_INTERRUPTED);
BT_LOGT("User interrupted the loop: status=%s, "
"key=\"%s\", value-addr=%p, data=%p",
bt_common_func_status_string(status),
key_str, element_obj, data);
}

break;
}
}

return ret;
return status;
}

enum bt_value_map_foreach_entry_const_status bt_value_map_foreach_entry_const(
Expand All @@ -1310,21 +1335,20 @@ enum bt_value_map_foreach_entry_const_status bt_value_map_foreach_entry_const(

struct extend_map_element_data {
struct bt_value *base_obj;
int status;
};

static
bt_bool extend_map_element(const char *key,
const struct bt_value *extension_obj_elem, void *data)
bt_value_map_foreach_entry_const_func_status extend_map_element(
const char *key, const struct bt_value *extension_obj_elem,
void *data)
{
bt_bool ret = BT_TRUE;
int status;
struct extend_map_element_data *extend_data = data;
struct bt_value *extension_obj_elem_copy = NULL;

/* Copy object which is to replace the current one */
extend_data->status = bt_value_copy(extension_obj_elem,
&extension_obj_elem_copy);
if (extend_data->status) {
status = bt_value_copy(extension_obj_elem, &extension_obj_elem_copy);
if (status) {
BT_LIB_LOGE_APPEND_CAUSE("Cannot copy map element: %!+v",
extension_obj_elem);
goto error;
Expand All @@ -1333,36 +1357,35 @@ bt_bool extend_map_element(const char *key,
BT_ASSERT(extension_obj_elem_copy);

/* Replace in base map value. */
extend_data->status = bt_value_map_insert_entry(
extend_data->base_obj, key,
status = bt_value_map_insert_entry(extend_data->base_obj, key,
(void *) extension_obj_elem_copy);
if (extend_data->status) {
if (status) {
BT_LIB_LOGE_APPEND_CAUSE(
"Cannot replace value in base map value: key=\"%s\", "
"%![base-map-value-]+v, %![element-value-]+v",
key, extend_data->base_obj,
extension_obj_elem_copy);
key, extend_data->base_obj, extension_obj_elem_copy);
goto error;
}

goto end;

error:
BT_ASSERT(extend_data->status != BT_FUNC_STATUS_OK);
ret = BT_FALSE;
BT_ASSERT(status < 0);

end:
BT_OBJECT_PUT_REF_AND_RESET(extension_obj_elem_copy);
return ret;
BT_ASSERT(status == BT_FUNC_STATUS_OK ||
status == BT_FUNC_STATUS_MEMORY_ERROR);
return status;
}

enum bt_value_map_extend_status bt_value_map_extend(
struct bt_value *base_map_obj,
const struct bt_value *extension_obj)
{
int status = BT_FUNC_STATUS_OK;
struct extend_map_element_data extend_data = {
.base_obj = NULL,
.status = BT_FUNC_STATUS_OK,
};

BT_ASSERT_PRE_NO_ERROR();
Expand All @@ -1379,15 +1402,16 @@ enum bt_value_map_extend_status bt_value_map_extend(
* in the base map object.
*/
extend_data.base_obj = base_map_obj;

if (bt_value_map_foreach_entry_const(extension_obj, extend_map_element,
&extend_data)) {
status = bt_value_map_foreach_entry_const(extension_obj,
extend_map_element, &extend_data);
if (status != BT_FUNC_STATUS_OK) {
BT_ASSERT(status == BT_FUNC_STATUS_MEMORY_ERROR);
BT_LIB_LOGE_APPEND_CAUSE(
"Cannot iterate on the extension object's elements: "
"%![extension-value-]+v", extension_obj);
}

return extend_data.status;
return status;
}

enum bt_value_copy_status bt_value_copy(const struct bt_value *object,
Expand Down
8 changes: 5 additions & 3 deletions src/plugins/common/param-validation/param-validation.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ enum bt_param_validation_status validate_value(
struct bt_param_validation_context *ctx);

static
bt_bool validate_map_value_entry(const char *key,
const bt_value *value, void *v_data)
bt_value_map_foreach_entry_const_func_status validate_map_value_entry(
const char *key, const bt_value *value, void *v_data)
{
struct validate_map_value_data *data = v_data;
const struct bt_param_validation_map_value_entry_descr *entry = NULL;
Expand Down Expand Up @@ -192,7 +192,9 @@ bt_bool validate_map_value_entry(const char *key,
}

/* Continue iterating if everything is good so far. */
return data->status == BT_PARAM_VALIDATION_STATUS_OK;
return data->status == BT_PARAM_VALIDATION_STATUS_OK ?
BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK :
BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_INTERRUPT;
}

static
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/text/details/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,14 +370,14 @@ gint compare_strings(const char **a, const char **b)
}

static
bt_bool map_value_foreach_add_key_to_array(const char *key,
const bt_value *object, void *data)
bt_value_map_foreach_entry_const_func_status map_value_foreach_add_key_to_array(
const char *key, const bt_value *object, void *data)
{
GPtrArray *keys = data;

BT_ASSERT_DBG(keys);
g_ptr_array_add(keys, (void *) key);
return BT_TRUE;
return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK;
}

static
Expand Down
Loading

0 comments on commit 0589c64

Please sign in to comment.