lib: add internal object pool API and use it; adapt plugins/tests
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 18 May 2018 17:32:37 +0000 (13:32 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 2 May 2019 04:05:45 +0000 (00:05 -0400)
Pooling
=======
This patch adds the `bt_object_pool` (object pool) internal API.

From <https://en.wikipedia.org/wiki/Object_pool_pattern>:

> The object pool pattern is a software creational design pattern that
> uses a set of initialized objects kept ready to use – a "pool" –
> rather than allocating and destroying them on demand. A client of the
> pool will request an object from the pool and perform operations on
> the returned object. When the client has finished, it returns the
> object to the pool rather than destroying it; this can be done
> manually or automatically.
>
> Object pools are primarily used for performance: in some
> circumstances, object pools significantly improve performance.

When initializing an object pool with bt_object_pool_initialize(), you
provide a function which can allocate a brand new object from memory, as
well as a function which can destroy and deallocate an existing object.
As of this patch, the destroy function is only used when you call
bt_object_pool_finalize() to finalize an object pool: all the objects
in the pool are destroyed.

The object pool API is:

bt_object_pool_create_object():
    Creates an object from an object pool. If the pool is empty, this
    function calls the "new" user function to allocate a new object
    before returning it. Otherwise this function returns a recycled
    object, removing it from the pool. The returned object is owned by
    the caller.

bt_object_pool_recycle_object():
    Recycles an object, that is, puts it back into the pool. The pool
    becomes the sole owner of the object to recycle.

There is not upper limit for the number of objects in the pool as of
this patch: the pool can grow infinitely, it never shrinks.

Within the library, the function naming convention for a recyclable, or
"poolable" object `bt_X` is as such:

bt_X_new():
    Allocates an object from memory. The object created by this function
    might be incomplete: the object is not always ready to use after
    calling this. This is the function which is passed as the "new"
    function when calling bt_object_pool_initialize().

bt_X_create():
    Creates an object from a pool and makes it useable, setting again
    the references that were reset during bt_X_recycle(), for example.
    Which pool to use is explicitly known by the function. It is part of
    an object received as a parameter. This could call bt_X_new()
    indirectly if the pool is empty.

bt_X_recycle():
    Resets the received object and recycles it within the appropriate
    pool. This function puts any reference which would keep the shared
    object alive even if the owner is now partially dead, part of a
    pool.

bt_X_destroy():
    Finalizes and deallocates the received object.

The following objects are recyclable as of this patch:

* `bt_event`; pool belongs to its event class, recycling happens when
  the event notification is destroyed.

* `bt_clock_value`; pool belongs to its clock class.

* `bt_packet`; pool belongs to its stream, recycling happens when its
  reference count reaches 0.

* `bt_packet_header_field`; pool belongs to a trace (more about this
  new object below).

* `bt_packet_context_field`; pool belongs to a stream class (more about
  this new object below).

* `bt_event_header_field`; pool belongs to a stream class (more about
  this new object below).

Unique objects
==============
Having a pool of event objects means that an event object must make sure
that everything under it which could be modified per instance is not
shared. In this case, the four `bt_field` objects (header, stream event
context, context, and payload) must not be shared.

Therefore this patch introduces unique objects (non-shared). By default,
bt_object_init() initializes a shared object. A function which creates a
unique object can mark it as unique thanks to bt_object_set_is_shared().
This is only used in developer mode to verify that the developer does
not call bt_get() or bt_put() on a unique object.

As a library user, you cannot create a unique object. It is created (and
destroyed) internally: you can only borrow the already-created object
from another object.

As of this patch, bt_event_create() and bt_field_create() are internal
functions. When you create an event notification with
bt_notification_event_create(), you pass the event class and packet to
use for the internal creation of the event object. Then you can borrow
the created (unique, non-shared) event with
bt_notification_event_borrow_event(), and its fields with
bt_event_borrow_header(), bt_event_borrow_stream_event_context(),
bt_event_borrow_context(), and bt_event_borrow_payload().

Then, recursively, you can borrow fields from compound fields
(structure, array, sequence, variant) and set their values.

On creation, the structure, variant, and array fields recursively create
all their subfields. This can't be done with the sequence field because
we need to know its length: subfields are created lazily when the
sequence's length increases; they are never destroyed until the sequence
field itself is destroyed (the sequence field's length is not
necessarily its field pointer array's length). A variant field has a
current field member which points to one of its subfields depending on
the current selection.

A packet object is still shared, as it needs to be shared between
multiple event objects. Its header and context fields, however, are
unique. Like the event object, the packet object creates its own unique
fields and you can borrow them with bt_packet_borrow_header() and
bt_packet_borrow_context().

Clock values are also unique (bt_clock_value_create() is now internal).
They are created when an event or an inactivity notification is created.
Once you borrow a clock value object using a clock class, you can set
its value with the new bt_clock_value_set_value() function. Clock value
objects now have the concepts of being set and frozen (like field
objects) because they are not immutable anymore.

CTF IR field API changes
========================
* bt_field_integer_*() functions now apply to both integer and
  enumeration fields, as an enumeration field is considered to be
  an integer field.

  For this to be efficient (no branches), an enumeration field is
  nothing more than an integer field and the functions just cast the
  given `struct bt_field *` object to a common integer field:

      struct bt_field_enumeration {
          struct bt_field_common_integer common;
      };

* bt_field_string_clear(): new function to clear an existing string
  field object.

  Because field objects are reused and they are not reset when an event
  is recycled (for performance), you must call bt_field_string_clear()
  before you initially call bt_field_string_append() or
  bt_field_string_append_len(). You don't need to call
  bt_field_string_clear() before initially calling
  bt_field_string_set_value().

* bt_field_sequence_get_length() returns an integer (`int64_t`), not a
  field object. It is useless for the user to have the actual length
  integer field.

* bt_field_sequence_set_length() accepts an integer (`uint64_t`), not a
  field, for the same reason as the previous point.

* bt_field_variant_get_field() is removed. This function had a dual
  role where it would select the current field using the value of
  a tag field, and then return the current field. It is a vestige of
  the CTF writer API.

  Now, you set the tag value (plain integer) with
  bt_field_variant_set_tag_signed() or
  bt_field_variant_set_tag_unsigned(), and then you can borrow the
  variant field's current (selected) field with
  bt_field_variant_borrow_current_field().

  You can still get the variant field's current tag value with
  bt_field_variant_get_tag_signed() and
  bt_field_variant_get_tag_unsigned(). Combined with
  bt_field_type_enumeration_signed_find_mappings_by_value() and
  bt_field_type_enumeration_unsigned_find_mappings_by_value(), you can
  get the variant field's tag's mappings, so really there's no value
  keeping the actual tag enumeration field.

The CTF writer field API is unchanged and still backward compatible.

Free packet header, packet context, and event header fields
===========================================================
It is possible to create a "free" packet header field (wrapper). This is
useful to fill a packet header field without creating the packet that
would create it, because in order to create this packet, you need a
stream, which is created from a stream class, and the stream class's ID
is found in the packet header field data.

The API is:

bt_trace_create_packet_header_field():
    Creates a free packet header field
    (`struct bt_packet_header_field *`).

bt_packet_header_field_borrow_field():
    Borrows the underlying field object to fill it.

bt_packet_move_header():
    Moves the free packet header field object to a given packet,
    replacing its current packet header field. After calling this, and
    on success, the object is considered to belong to the packet object:
    you can discard it.

    What happens here is that bt_packet_move_header() first recycles its
    current packet header field wrapper object to the trace's packet
    header field pool, and then replaces it with the provided object.

bt_packet_header_field_release():
    Releases the given packet header field. This function exists for
    error handling, to discard a packet header field without leaking
    when you called bt_trace_create_packet_header_field(), but you
    cannot call bt_packet_move_header().

Analogous functions exist for a packet context field:

* bt_stream_class_create_packet_context_field()
* bt_packet_context_field_borrow_field()
* bt_packet_move_context()
* bt_packet_context_field_release()

Having free packet header and packet context fields is necessary for a
`src.ctf.fs` component to work because it needs to know some field
values of both packet header and context fields before even creating a
stream object (to have a single stream for multiple data stream files,
for example), thus also before creating a packet.

Analogous functions exist for an event header field:

* bt_stream_class_create_event_header_field()
* bt_event_header_field_borrow_field()
* bt_event_move_header()
* bt_event_header_field_release()

Those three new (unique, non-shared) objects use the internal
`bt_field_wrapper` API.

Other changes
=============
* bt_clock_class_cycles_to_ns(): new public function to transform cycles
  to nanoseconds from Epoch using a specific clock class. The
  `src.ctf.fs` component used to create a clock value just to have this
  through bt_clock_value_get_value_ns_from_epoch(), and then destroy it.
  With this patch, you cannot create a free clock value anymore,
  therefore this new function satisfies the existing use case.

* BT_LIB_LOG*() now accepts the `%!o` specifier to log the details of
  an object pool.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
73 files changed:
Makefile.am
include/Makefile.am
include/babeltrace/assert-internal.h
include/babeltrace/assert-pre-internal.h
include/babeltrace/babeltrace-internal.h
include/babeltrace/babeltrace.h
include/babeltrace/ctf-ir/clock-class-internal.h
include/babeltrace/ctf-ir/clock-class.h
include/babeltrace/ctf-ir/clock-value-internal.h
include/babeltrace/ctf-ir/clock-value.h
include/babeltrace/ctf-ir/event-class-internal.h
include/babeltrace/ctf-ir/event-header-field.h [new file with mode: 0644]
include/babeltrace/ctf-ir/event-internal.h
include/babeltrace/ctf-ir/event.h
include/babeltrace/ctf-ir/field-types-internal.h
include/babeltrace/ctf-ir/field-wrapper-internal.h [new file with mode: 0644]
include/babeltrace/ctf-ir/fields-internal.h
include/babeltrace/ctf-ir/fields.h
include/babeltrace/ctf-ir/packet-context-field.h [new file with mode: 0644]
include/babeltrace/ctf-ir/packet-header-field.h [new file with mode: 0644]
include/babeltrace/ctf-ir/packet-internal.h
include/babeltrace/ctf-ir/packet.h
include/babeltrace/ctf-ir/stream-class-internal.h
include/babeltrace/ctf-ir/stream-class.h
include/babeltrace/ctf-ir/stream-internal.h
include/babeltrace/ctf-ir/trace-internal.h
include/babeltrace/ctf-ir/trace.h
include/babeltrace/ctf-writer/fields-internal.h
include/babeltrace/ctf-writer/fields.h
include/babeltrace/graph/notification-event.h
include/babeltrace/graph/notification-inactivity.h
include/babeltrace/lib-logging-internal.h
include/babeltrace/object-internal.h
include/babeltrace/object-pool-internal.h [new file with mode: 0644]
lib/Makefile.am
lib/ctf-ir/Makefile.am
lib/ctf-ir/clock-class.c
lib/ctf-ir/event-class.c
lib/ctf-ir/event-header-field.c [new file with mode: 0644]
lib/ctf-ir/event.c
lib/ctf-ir/field-types.c
lib/ctf-ir/field-wrapper.c [new file with mode: 0644]
lib/ctf-ir/fields.c
lib/ctf-ir/packet-context-field.c [new file with mode: 0644]
lib/ctf-ir/packet-header-field.c [new file with mode: 0644]
lib/ctf-ir/packet.c
lib/ctf-ir/stream-class.c
lib/ctf-ir/stream.c
lib/ctf-ir/trace.c
lib/ctf-writer/event.c
lib/ctf-writer/field-types.c
lib/ctf-writer/fields.c
lib/ctf-writer/stream.c
lib/graph/notification/event.c
lib/graph/notification/inactivity.c
lib/lib-logging.c
lib/object-pool.c [new file with mode: 0644]
lib/ref.c
lib/values.c
plugins/Makefile.am
plugins/ctf/common/btr/btr.h
plugins/ctf/common/notif-iter/notif-iter.c
plugins/ctf/common/notif-iter/notif-iter.h
plugins/ctf/fs-src/data-stream-file.c
plugins/ctf/fs-src/data-stream-file.h
plugins/ctf/fs-src/fs.c
plugins/text/Makefile.am
plugins/text/dmesg/dmesg.c
plugins/text/plugin.c
plugins/text/pretty/print.c
tests/lib/test_bt_notification_iterator.c
tests/lib/test_ctf_writer.c
tests/plugins/test-utils-muxer.c

index 98fd7d44fcb07098f9c5dc4471d9eb66c61e49db..eb6831a2b16a308835d6c5fcd7a9de081c494d1f 100644 (file)
@@ -16,9 +16,9 @@ SUBDIRS +=                    \
        plugins                 \
        cli                     \
        bindings                \
-       tests                   \
        doc                     \
-       extras
+       extras                  \
+       tests
 
 dist_doc_DATA = ChangeLog LICENSE mit-license.txt gpl-2.0.txt \
                std-ext-lib.txt README CONTRIBUTING.adoc
index 3dd6eb81abf25037cf9da7a994ae37a104696267..acadd59f6a337238072c5759d578e6b131b967cf 100644 (file)
@@ -106,10 +106,13 @@ babeltracectfirinclude_HEADERS = \
        babeltrace/ctf-ir/clock.h \
        babeltrace/ctf-ir/event-class.h \
        babeltrace/ctf-ir/event.h \
+       babeltrace/ctf-ir/event-header-field.h \
        babeltrace/ctf-ir/field-path.h \
        babeltrace/ctf-ir/field-types.h \
        babeltrace/ctf-ir/fields.h \
        babeltrace/ctf-ir/packet.h \
+       babeltrace/ctf-ir/packet-context-field.h \
+       babeltrace/ctf-ir/packet-header-field.h \
        babeltrace/ctf-ir/stream-class.h \
        babeltrace/ctf-ir/stream.h \
        babeltrace/ctf-ir/trace.h \
@@ -175,6 +178,7 @@ noinst_HEADERS = \
        babeltrace/common-internal.h \
        babeltrace/bitfield-internal.h \
        babeltrace/object-internal.h \
+       babeltrace/object-pool-internal.h \
        babeltrace/plugin/plugin-internal.h \
        babeltrace/plugin/plugin-so-internal.h \
        babeltrace/plugin/python-plugin-provider-internal.h \
@@ -202,6 +206,7 @@ noinst_HEADERS = \
        babeltrace/ctf-ir/stream-class-internal.h \
        babeltrace/ctf-ir/event-internal.h \
        babeltrace/ctf-ir/field-path-internal.h \
+       babeltrace/ctf-ir/field-wrapper-internal.h \
        babeltrace/ctf-ir/trace-internal.h \
        babeltrace/ctf-ir/clock-class-internal.h \
        babeltrace/ctf-ir/field-types-internal.h \
index 5d78f96f40668187cd68982c12caa87f8cc7be21..431230c91d9f145e1e9f0f86ef99cdaef963eab9 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <assert.h>
+#include <babeltrace/babeltrace-internal.h>
 
 #ifdef BT_DEBUG_MODE
 /*
@@ -50,7 +51,7 @@
  * In-depth explanation: https://stackoverflow.com/questions/37411809/how-to-elegantly-fix-this-unused-variable-warning/37412551#37412551
  */
 # define BT_ASSERT(_cond)      ((void) sizeof((void) (_cond), 0))
-# define BT_ASSERT_FUNC                __attribute__((unused))
+# define BT_ASSERT_FUNC                BT_UNUSED
 #endif /* BT_DEBUG_MODE */
 
 #endif /* BABELTRACE_ASSERT_INTERNAL_H */
index cc412340f69bb0d119c32b5b319fc3270e7f55ed..58364736441b7508cec33d5b1452225fcc2e5f87 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef BABELTRACE_ASSERT_PRE_INTERNAL_H
 #define BABELTRACE_ASSERT_PRE_INTERNAL_H
 
+#include <babeltrace/babeltrace-internal.h>
+
 /*
  * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
  * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
@@ -33,7 +35,7 @@
  * also need to define it before including this header.
  *
  * This is a reminder that in order to use
- * <babeltrace/assert-internal.hpp>, you also need to use logging
+ * <babeltrace/assert-pre-internal.h>, you also need to use logging
  * explicitly.
  */
 #ifndef BABELTRACE_LIB_LOGGING_INTERNAL_H
@@ -97,7 +99,7 @@
 # define BT_ASSERT_PRE_MSG     BT_LIB_LOGF
 #else
 # define BT_ASSERT_PRE(_cond, _fmt, ...)
-# define BT_ASSERT_PRE_FUNC    __attribute__((unused))
+# define BT_ASSERT_PRE_FUNC    BT_UNUSED
 # define BT_ASSERT_PRE_MSG(_fmt, ...)
 #endif /* BT_DEV_MODE */
 
index 583d949ca2ebe72d4f9874cf074affd5ec7527b3..1cf3af96331caf0e782937cb88978f4ee089e411 100644 (file)
@@ -85,4 +85,6 @@
 
 #define TOSTRING(x)    __STRINGIFY(x)
 
+#define BT_UNUSED      __attribute__((unused))
+
 #endif
index d59f36a105f23bfd5a520280a8e93f689d131f24..cd910280777577f8f879f35c0f8f1b6ce6c79124 100644 (file)
 #include <babeltrace/ctf-ir/clock-value.h>
 #include <babeltrace/ctf-ir/clock.h>
 #include <babeltrace/ctf-ir/event-class.h>
+#include <babeltrace/ctf-ir/event-header-field.h>
 #include <babeltrace/ctf-ir/event.h>
 #include <babeltrace/ctf-ir/field-path.h>
 #include <babeltrace/ctf-ir/field-types.h>
 #include <babeltrace/ctf-ir/fields.h>
+#include <babeltrace/ctf-ir/packet-context-field.h>
+#include <babeltrace/ctf-ir/packet-header-field.h>
 #include <babeltrace/ctf-ir/packet.h>
 #include <babeltrace/ctf-ir/stream-class.h>
 #include <babeltrace/ctf-ir/stream.h>
index cd4c6cb00f2ec80ad470cebc0ffa4052b0bee98a..9f4f23fe1e1ccc67d009d13bb01ed9e1a8de7a46 100644 (file)
@@ -30,6 +30,7 @@
 #include <babeltrace/ctf-ir/clock-class.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/object-pool-internal.h>
 #include <babeltrace/compat/uuid-internal.h>
 #include <babeltrace/types.h>
 #include <stdbool.h>
@@ -53,6 +54,9 @@ struct bt_clock_class {
         * class.
         */
        int frozen;
+
+       /* Pool of `struct bt_clock_value *` */
+       struct bt_object_pool cv_pool;
 };
 
 BT_HIDDEN
index bb68d2b7fc1cbdabf63fffc2ca23315b35aa31b4..e9af453c950bc0e70e0a8b15eedf8739d0fe70c5 100644 (file)
@@ -78,6 +78,8 @@ extern const unsigned char *bt_clock_class_get_uuid(
                struct bt_clock_class *clock_class);
 extern int bt_clock_class_set_uuid(struct bt_clock_class *clock_class,
                const unsigned char *uuid);
+extern int bt_clock_class_cycles_to_ns(struct bt_clock_class *clock_class,
+               uint64_t cycles, int64_t *ns);
 
 #ifdef __cplusplus
 }
index a33a71cae78d3cf7cfede107db575547b716bf7e..0f23181b733595b275621cf0cfffdae28f803ee3 100644 (file)
@@ -23,6 +23,7 @@
  * SOFTWARE.
  */
 
+#include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/object-internal.h>
 #include <stdbool.h>
 #include <stdint.h>
@@ -35,6 +36,48 @@ struct bt_clock_value {
        uint64_t value;
        bool ns_from_epoch_overflows;
        int64_t ns_from_epoch;
+       bool is_set;
+       bool frozen;
 };
 
+static inline
+void bt_clock_value_set(struct bt_clock_value *clock_value)
+{
+       BT_ASSERT(clock_value);
+       clock_value->is_set = true;
+}
+
+static inline
+void bt_clock_value_reset(struct bt_clock_value *clock_value)
+{
+       BT_ASSERT(clock_value);
+       clock_value->is_set = false;
+}
+
+BT_UNUSED
+static inline
+void _bt_clock_value_set_is_frozen(struct bt_clock_value *clock_value,
+               bool is_frozen)
+{
+       BT_ASSERT(clock_value);
+       clock_value->frozen = is_frozen;
+}
+
+#ifdef BT_DEV_MODE
+# define bt_clock_value_set_is_frozen  _bt_clock_value_set_is_frozen
+#else
+# define bt_clock_value_set_is_frozen(_x, _f)
+#endif /* BT_DEV_MODE */
+
+BT_HIDDEN
+struct bt_clock_value *bt_clock_value_create(
+               struct bt_clock_class *clock_class);
+
+BT_HIDDEN
+void bt_clock_value_recycle(struct bt_clock_value *clock_value);
+
+BT_HIDDEN
+void bt_clock_value_set_raw_value(struct bt_clock_value *clock_value,
+               uint64_t cycles);
+
 #endif /* BABELTRACE_CTF_IR_CLOCK_VALUE_INTERNAL_H */
index 706e36dfb7bfb98d4c1c5fce6f9988b9e42002b5..9fb152e8f7904cc6bb8700ddac47e3782fd8914d 100644 (file)
@@ -43,8 +43,6 @@ extern "C" {
 struct bt_clock_class;
 struct bt_clock_value;
 
-extern struct bt_clock_value *bt_clock_value_create(
-               struct bt_clock_class *clock_class, uint64_t value);
 extern struct bt_clock_class *bt_clock_value_borrow_class(
                struct bt_clock_value *clock_value);
 
@@ -55,6 +53,8 @@ struct bt_clock_class *bt_clock_value_get_class(
        return bt_get(bt_clock_value_borrow_class(clock_value));
 }
 
+extern int bt_clock_value_set_value(
+               struct bt_clock_value *clock_value, uint64_t raw_value);
 extern int bt_clock_value_get_value(
                struct bt_clock_value *clock_value, uint64_t *raw_value);
 extern int bt_clock_value_get_value_ns_from_epoch(
index a89e82dd1c3178920fa75b786188ff7eb58b6115..316408d84ae1592633dd9b6306d4f1c3c8107229 100644 (file)
@@ -38,6 +38,7 @@
 #include <babeltrace/ctf-ir/event-class.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/assert-internal.h>
+#include <babeltrace/object-pool-internal.h>
 #include <glib.h>
 
 struct bt_event_class_common {
@@ -63,6 +64,9 @@ struct bt_event_class_common {
 
 struct bt_event_class {
        struct bt_event_class_common common;
+
+       /* Pool of `struct bt_event *` */
+       struct bt_object_pool event_pool;
 };
 
 BT_HIDDEN
@@ -98,6 +102,10 @@ int bt_event_class_common_validate_single_clock_class(
                struct bt_event_class_common *event_class,
                struct bt_clock_class **expected_clock_class);
 
+BT_HIDDEN
+int bt_event_class_update_event_pool_clock_values(
+               struct bt_event_class *event_class);
+
 static inline
 const char *bt_event_class_common_get_name(
                struct bt_event_class_common *event_class)
diff --git a/include/babeltrace/ctf-ir/event-header-field.h b/include/babeltrace/ctf-ir/event-header-field.h
new file mode 100644 (file)
index 0000000..0ff6d58
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef BABELTRACE_CTF_IR_EVENT_HEADER_FIELD_H
+#define BABELTRACE_CTF_IR_EVENT_HEADER_FIELD_H
+
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bt_event_header_field;
+struct bt_field;
+
+extern
+struct bt_field *bt_event_header_field_borrow_field(
+               struct bt_event_header_field *field);
+
+extern
+void bt_event_header_field_release(struct bt_event_header_field *field);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_CTF_IR_EVENT_HEADER_FIELD_H */
index 7f37f14feb49863f9a43a5850b453b56febc09eb..dccc5726f3a84e52d49dfd0e51bb3f0522654ad5 100644 (file)
@@ -36,6 +36,7 @@
 #include <babeltrace/ctf-ir/fields.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-ir/event-class-internal.h>
+#include <babeltrace/ctf-ir/field-wrapper-internal.h>
 #include <babeltrace/ctf-ir/validation-internal.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/assert-internal.h>
@@ -46,7 +47,7 @@ struct bt_stream_pos;
 struct bt_event_common {
        struct bt_object base;
        struct bt_event_class_common *class;
-       struct bt_field_common *header_field;
+       struct bt_field_wrapper *header_field;
        struct bt_field_common *stream_event_context_field;
        struct bt_field_common *context_field;
        struct bt_field_common *payload_field;
@@ -101,7 +102,10 @@ int bt_event_common_initialize(struct bt_event_common *event,
                int (*map_clock_classes_func)(struct bt_stream_class_common *stream_class,
                        struct bt_field_type_common *packet_context_field_type,
                        struct bt_field_type_common *event_header_field_type),
-               void *(*create_field_func)(void *));
+               void *(*create_field_func)(void *),
+               void (*release_field_func)(void *),
+               void *(*create_header_field_func)(void *, void *),
+               void (*release_header_field_func)(void *));
 
 static inline
 struct bt_field_common *bt_event_common_borrow_payload(
@@ -125,39 +129,6 @@ end:
        return payload;
 }
 
-static inline
-int bt_event_common_set_payload(struct bt_event_common *event,
-               struct bt_field_common *payload)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(event, "Event");
-
-       if (payload) {
-               BT_ASSERT_PRE(bt_field_type_common_compare(payload->type,
-                       event->class->payload_field_type) == 0,
-                       "Payload field's type is different from the "
-                       "expected field type: %![event-]+_e, %![ft-]+_F, "
-                       "%![expected-ft-]+_F",
-                       event, payload->type,
-                       event->class->payload_field_type);
-       } else {
-               BT_ASSERT_PRE(!event->class->payload_field_type,
-                       "Setting no event payload field, "
-                       "but event payload field type is not NULL: ",
-                       "%![event-]+_e, %![payload-ft-]+_F",
-                       event, event->class->payload_field_type);
-       }
-
-       bt_put(event->payload_field);
-       event->payload_field = bt_get(payload);
-       BT_LOGV("Set event's payload field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "payload-field-addr=%p",
-               event, bt_event_class_common_get_name(event->class),
-               bt_event_class_common_get_id(event->class), payload);
-       return 0;
-}
-
 static inline
 struct bt_field_common *bt_event_common_borrow_header(
                struct bt_event_common *event)
@@ -174,50 +145,12 @@ struct bt_field_common *bt_event_common_borrow_header(
                goto end;
        }
 
-       header = event->header_field;
+       header = event->header_field->field;
 
 end:
        return header;
 }
 
-static inline
-int bt_event_common_set_header(struct bt_event_common *event,
-               struct bt_field_common *header)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(event, "Event");
-
-       /*
-        * Ensure the provided header's type matches the one registered to the
-        * stream class.
-        */
-       if (header) {
-               BT_ASSERT_PRE(bt_field_type_common_compare(header->type,
-                       bt_event_class_common_borrow_stream_class(event->class)->event_header_field_type) == 0,
-                       "Header field's type is different from the "
-                       "expected field type: %![event-]+_e, %![ft-]+_F, "
-                       "%![expected-ft-]+_F",
-                       event, header->type,
-                       bt_event_class_common_borrow_stream_class(event->class)->event_header_field_type);
-       } else {
-               BT_ASSERT_PRE(!bt_event_class_common_borrow_stream_class(event->class)->event_header_field_type,
-                       "Setting no event header field, "
-                       "but event header field type is not NULL: ",
-                       "%![event-]+_e, %![header-ft-]+_F",
-                       event,
-                       bt_event_class_common_borrow_stream_class(event->class)->event_header_field_type);
-       }
-
-       bt_put(event->header_field);
-       event->header_field = bt_get(header);
-       BT_LOGV("Set event's header field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "header-field-addr=%p",
-               event, bt_event_class_common_get_name(event->class),
-               bt_event_class_common_get_id(event->class), header);
-       return 0;
-}
-
 static inline
 struct bt_field_common *bt_event_common_borrow_context(
                struct bt_event_common *event)
@@ -240,38 +173,6 @@ end:
        return context;
 }
 
-static inline
-int bt_event_common_set_context(struct bt_event_common *event,
-               struct bt_field_common *context)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(event, "Event");
-
-       if (context) {
-               BT_ASSERT_PRE(bt_field_type_common_compare(context->type,
-                       event->class->context_field_type) == 0,
-                       "Context field's type is different from the "
-                       "expected field type: %![event-]+_e, %![ft-]+_F, "
-                       "%![expected-ft-]+_F",
-                       event, context->type, event->class->context_field_type);
-       } else {
-               BT_ASSERT_PRE(!event->class->context_field_type,
-                       "Setting no event context field, "
-                       "but event context field type is not NULL: ",
-                       "%![event-]+_e, %![context-ft-]+_F",
-                       event, event->class->context_field_type);
-       }
-
-       bt_put(event->context_field);
-       event->context_field = bt_get(context);
-       BT_LOGV("Set event's context field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "context-field-addr=%p",
-               event, bt_event_class_common_get_name(event->class),
-               bt_event_class_common_get_id(event->class), context);
-       return 0;
-}
-
 static inline
 struct bt_field_common *bt_event_common_borrow_stream_event_context(
                struct bt_event_common *event)
@@ -295,50 +196,43 @@ end:
 }
 
 static inline
-int bt_event_common_set_stream_event_context(struct bt_event_common *event,
-               struct bt_field_common *stream_event_context)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(event, "Event");
-
-       if (stream_event_context) {
-               BT_ASSERT_PRE(bt_field_type_common_compare(stream_event_context->type,
-                       bt_event_class_common_borrow_stream_class(event->class)->event_context_field_type) == 0,
-                       "Stream event context field's type is different from the "
-                       "expected field type: %![event-]+_e, %![ft-]+_F, "
-                       "%![expected-ft-]+_F",
-                       event, stream_event_context->type,
-                       bt_event_class_common_borrow_stream_class(event->class)->event_context_field_type);
-       } else {
-               BT_ASSERT_PRE(!bt_event_class_common_borrow_stream_class(event->class)->event_context_field_type,
-                       "Setting no stream event context field, "
-                       "but stream event context field type is not NULL: ",
-                       "%![event-]+_e, %![context-ft-]+_F",
-                       event,
-                       bt_event_class_common_borrow_stream_class(event->class)->event_context_field_type);
-       }
-
-       bt_get(stream_event_context);
-       BT_MOVE(event->stream_event_context_field, stream_event_context);
-       BT_LOGV("Set event's stream event context field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "stream-event-context-field-addr=%p",
-               event, bt_event_class_common_get_name(event->class),
-               bt_event_class_common_get_id(event->class),
-               stream_event_context);
-       return 0;
-}
-
-static inline
-void bt_event_common_finalize(struct bt_object *obj)
+void bt_event_common_finalize(struct bt_object *obj,
+               void (*field_release_func)(void *),
+               void (*header_field_release_func)(void *, struct bt_event_common *))
 {
        struct bt_event_common *event = (void *) obj;
 
        BT_LOGD("Destroying event: addr=%p, "
                "event-class-name=\"%s\", event-class-id=%" PRId64,
-               event, bt_event_class_common_get_name(event->class),
-               bt_event_class_common_get_id(event->class));
+               event,
+               event->class ? bt_event_class_common_get_name(event->class) : NULL,
+               event->class ? bt_event_class_common_get_id(event->class) : INT64_C(-1));
+
+       if (event->header_field) {
+               BT_LOGD_STR("Releasing event's header field.");
+               header_field_release_func(event->header_field, event);
+       }
+
+       if (event->stream_event_context_field) {
+               BT_LOGD_STR("Releasing event's stream event context field.");
+               field_release_func(event->stream_event_context_field);
+       }
+
+       if (event->context_field) {
+               BT_LOGD_STR("Releasing event's context field.");
+               field_release_func(event->context_field);
+       }
+
+       if (event->payload_field) {
+               BT_LOGD_STR("Releasing event's payload field.");
+               field_release_func(event->payload_field);
+       }
 
+       /*
+        * Leave this after calling header_field_release_func() because
+        * this function receives the event object and could need its
+        * class to perform some cleanup.
+        */
        if (!event->base.parent) {
                /*
                 * Event was keeping a reference to its class since it shared no
@@ -347,15 +241,22 @@ void bt_event_common_finalize(struct bt_object *obj)
                 */
                bt_put(event->class);
        }
-
-       bt_put(event->header_field);
-       BT_LOGD_STR("Putting event's stream event context field.");
-       bt_put(event->stream_event_context_field);
-       BT_LOGD_STR("Putting event's context field.");
-       bt_put(event->context_field);
-       BT_LOGD_STR("Putting event's payload field.");
-       bt_put(event->payload_field);
-       BT_LOGD_STR("Putting event's packet.");
 }
 
+BT_HIDDEN
+struct bt_event *bt_event_new(struct bt_event_class *event_class);
+
+BT_HIDDEN
+struct bt_event *bt_event_create(struct bt_event_class *event_class,
+               struct bt_packet *packet);
+
+BT_HIDDEN
+void bt_event_recycle(struct bt_event *event);
+
+BT_HIDDEN
+void bt_event_destroy(struct bt_event *event);
+
+BT_HIDDEN
+int bt_event_set_packet(struct bt_event *event, struct bt_packet *packet);
+
 #endif /* BABELTRACE_CTF_IR_EVENT_INTERNAL_H */
index 46211aaefca930ee2e9b1fbe7deeb12a9c4e7759..ababc8f01774f853d235aebf7771283b308e260b 100644 (file)
@@ -121,6 +121,7 @@ immutable, except for \link refs reference counting\endlink.
 @sa ctfirevent
 */
 struct bt_event;
+struct bt_event_header_field;
 struct bt_clock;
 struct bt_clock_value;
 struct bt_event_class;
@@ -165,8 +166,6 @@ with bt_trace_add_stream_class(), then this function fails.
 @pre \p event_class has a parent stream class.
 @postsuccessrefcountret1
 */
-extern struct bt_event *bt_event_create(struct bt_event_class *event_class);
-
 extern struct bt_event_class *bt_event_borrow_class(struct bt_event *event);
 
 /**
@@ -217,39 +216,6 @@ struct bt_packet *bt_event_get_packet(struct bt_event *event)
        return bt_get(bt_event_borrow_packet(event));
 }
 
-/**
-@brief Associates the CTF IR event \p event to the CTF IR packet
-       \p packet.
-
-The \link ctfirstreamclass CTF IR stream class\endlink of the
-parent \link ctfirstream CTF IR stream\endlink of \p packet \em must
-be the same as the parent stream class of the
-\link ctfireventclass CTF IR event class\endlink returned
-by bt_event_get_class() for \p event.
-
-You \em must call this function to create an event-packet association
-before you call bt_notification_event_create() with \p event.
-
-On success, this function also sets the parent stream object of
-\p event to the parent stream of \p packet.
-
-@param[in] event       Event to which to associate \p packet.
-@param[in] packet      Packet to associate to \p event.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{event}
-@prenotnull{packet}
-@prehot{event}
-@pre The parent stream class of \p packet is the same as the parent
-       stream class of \p event.
-@postsuccessrefcountretinc
-
-@sa bt_event_get_packet(): Returns the associated packet of a
-       given event object.
-*/
-extern int bt_event_set_packet(struct bt_event *event,
-               struct bt_packet *packet);
-
 extern struct bt_stream *bt_event_borrow_stream(struct bt_event *event);
 
 /**
@@ -278,210 +244,16 @@ struct bt_stream *bt_event_get_stream(struct bt_event *event)
 
 extern struct bt_field *bt_event_borrow_header(struct bt_event *event);
 
-/**
-@brief Returns the stream event header field of the CTF IR event
-       \p event.
-
-@param[in] event       Event of which to get the stream event header
-                       field.
-@returns               Stream event header field of \p event,
-                       or \c NULL if the stream event header
-                       field is not set or on error.
-
-@prenotnull{event}
-@postrefcountsame{event}
-@postsuccessrefcountretinc
-
-@sa bt_event_get_header(): Sets the stream event header
-       field of a given event.
-*/
-static inline
-struct bt_field *bt_event_get_header(struct bt_event *event)
-{
-       return bt_get(bt_event_borrow_header(event));
-}
-
-/**
-@brief Sets the stream event header field of the CTF IR event
-       \p event to \p header, or unsets the current stream event header field
-       from \p event.
-
-If \p header is not \c NULL, the field type of \p header, as returned by
-bt_field_get_type(), \em must be equivalent to the field type returned by
-bt_stream_class_get_event_header_type() for the parent stream class
-of \p event.
-
-@param[in] event       Event of which to set the stream event header
-                       field.
-@param[in] header      Stream event header field.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{event}
-@prehot{event}
-@pre <strong>\p header, if not \c NULL</strong>, has a field type equivalent to
-       the field type returned by bt_stream_class_get_event_header_type()
-       for the parent stream class of \p event.
-@postrefcountsame{event}
-@post <strong>On success, if \p header is not \c NULL</strong>,
-       the reference count of \p header is incremented.
-
-@sa bt_event_get_header(): Returns the stream event header field
-       of a given event.
-*/
-extern int bt_event_set_header(struct bt_event *event,
-               struct bt_field *header);
+extern int bt_event_move_header(struct bt_event *event,
+               struct bt_event_header_field *header);
 
 extern struct bt_field *bt_event_borrow_stream_event_context(
                struct bt_event *event);
 
-/**
-@brief Returns the stream event context field of the CTF IR event
-       \p event.
-
-@param[in] event       Event of which to get the stream event context
-                       field.
-@returns               Stream event context field of \p event,
-                       or \c NULL if the stream event context
-                       field is not set or on error.
-
-@prenotnull{event}
-@postrefcountsame{event}
-@postsuccessrefcountretinc
-
-@sa bt_event_set_stream_event_context(): Sets the stream event context
-       field of a given event.
-*/
-static inline
-struct bt_field *bt_event_get_stream_event_context(struct bt_event *event)
-{
-       return bt_get(bt_event_borrow_stream_event_context(event));
-}
-
-/**
-@brief Sets the stream event context field of the CTF IR event
-       \p event to \p context, or unsets the current stream event context field
-       from \p event.
-
-If \p context is not \c NULL, the field type of \p context, as returned by
-bt_field_get_type(), \em must be equivalent to the field type returned by
-bt_stream_class_get_event_context_type() for the parent stream class
-of \p event.
-
-@param[in] event       Event of which to set the stream event context field.
-@param[in] context     Stream event context field.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{event}
-@prehot{event}
-@pre <strong>\p context, if not \c NULL</strong>, has a field type equivalent to
-       the field type returned by bt_stream_class_get_event_context_type()
-       for the parent stream class of \p event.
-@postrefcountsame{event}
-@post <strong>On success, if \p context is not \c NULL</strong>, the reference
-       count of \p context is incremented.
-
-@sa bt_event_get_stream_event_context(): Returns the stream event context
-       field of a given event.
-*/
-extern int bt_event_set_stream_event_context(struct bt_event *event,
-               struct bt_field *context);
-
 extern struct bt_field *bt_event_borrow_context(struct bt_event *event);
 
-/**
-@brief Returns the event context field of the CTF IR event \p event.
-
-@param[in] event       Event of which to get the context field.
-@returns               Event context field of \p event, or \c NULL if the
-                       event context field is not set or on error.
-
-@prenotnull{event}
-@postrefcountsame{event}
-@postsuccessrefcountretinc
-
-@sa bt_event_set_context(): Sets the event context field of a given
-       event.
-*/
-static inline
-struct bt_field *bt_event_get_context(struct bt_event *event)
-{
-       return bt_get(bt_event_borrow_context(event));
-}
-
-/**
-@brief Sets the event context field of the CTF IR event \p event to \p context,
-       or unsets the current event context field from \p event.
-
-If \p context is not \c NULL, the field type of \p context, as returned by
-bt_field_get_type(), \em must be equivalent to the field type returned by
-bt_event_class_get_context_type() for the parent class of \p event.
-
-@param[in] event       Event of which to set the context field.
-@param[in] context     Event context field.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{event}
-@prehot{event}
-@pre <strong>\p context, if not \c NULL</strong>, has a field type equivalent to
-       the field type returned by bt_event_class_get_context_type() for the
-       parent class of \p event.
-@postrefcountsame{event}
-@post <strong>On success, if \p context is not \c NULL</strong>, the reference
-       count of \p context is incremented.
-
-@sa bt_event_get_context(): Returns the context field of a given event.
-*/
-extern int bt_event_set_context(struct bt_event *event,
-               struct bt_field *context);
-
 extern struct bt_field *bt_event_borrow_payload(struct bt_event *event);
 
-/**
-@brief Returns the payload field of the CTF IR event \p event.
-
-@param[in] event       Event of which to get the payload field.
-@returns               Payload field of \p event, or \c NULL if the payload
-                       field is not set or on error.
-
-@prenotnull{event}
-@postrefcountsame{event}
-@postsuccessrefcountretinc
-
-@sa bt_event_set_payload(): Sets the payload field of a given
-       event.
-*/
-static inline
-struct bt_field *bt_event_get_payload(struct bt_event *event)
-{
-       return bt_get(bt_event_borrow_payload(event));
-}
-
-/**
-@brief Sets the payload field of the CTF IR event \p event to \p payload,
-       or unsets the current event payload field from \p event.
-
-If \p payload is not \c NULL, the field type of \p payload, as returned by
-bt_field_get_type(), \em must be equivalent to the field type returned by
-bt_event_class_get_payload_type() for the parent class of \p event.
-
-@param[in] event       Event of which to set the payload field.
-@param[in] payload     Event payload field.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{event}
-@prehot{event}
-@pre <strong>\p payload, if not \c NULL</strong>, has a field type equivalent to
-       the field typereturned by bt_event_class_get_payload_type() for the
-       parent class of \p event.
-@postrefcountsame{event}
-@post <strong>On success, if \p payload is not \c NULL</strong>, the reference
-       count of \p payload is incremented.
-
-@sa bt_event_get_payload(): Returns the payload field of a given event.
-*/
-extern int bt_event_set_payload(struct bt_event *event,
-               struct bt_field *payload);
-
 /** @} */
 
 /**
@@ -493,56 +265,6 @@ extern struct bt_clock_value *bt_event_borrow_clock_value(
                struct bt_event *event,
                struct bt_clock_class *clock_class);
 
-/**
-@brief Returns the value, as of the CTF IR event \p event, of the
-       clock described by the
-       \link ctfirclockclass CTF IR clock class\endlink \p clock_class.
-
-@param[in] event       Event of which to get the value of the clock
-                       described by \p clock_class.
-@param[in] clock_class Class of the clock of which to get the value.
-@returns               Value of the clock described by \p clock_class
-                       as of \p event.
-
-@prenotnull{event}
-@prenotnull{clock_class}
-@postrefcountsame{event}
-@postrefcountsame{clock_class}
-@postsuccessrefcountretinc
-
-@sa bt_event_set_clock_value(): Sets the clock value of a given event.
-*/
-static inline
-struct bt_clock_value *bt_event_get_clock_value(
-               struct bt_event *event,
-               struct bt_clock_class *clock_class)
-{
-       return bt_get(bt_event_borrow_clock_value(event, clock_class));
-}
-
-/**
-@brief Sets the value, as of the CTF IR event \p event, of the
-       clock described by its \link ctfirclockclass CTF IR
-       clock class\endlink.
-
-@param[in] event       Event of which to set the value of the clock
-                       described by the clock class of \p clock_value.
-@param[in] clock_value Value of the clock described by its clock class
-                       as of \p event.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{event}
-@prenotnull{clock_value}
-@prehot{event}
-@postrefcountsame{event}
-
-@sa bt_event_get_clock_value(): Returns the clock value of
-       a given event.
-*/
-extern int bt_event_set_clock_value(
-               struct bt_event *event,
-               struct bt_clock_value *clock_value);
-
 /** @} */
 
 /** @} */
index 8d013b189032cadf429b1bc4002e50e8a9a2133d..a15b9c0a13e5e62b283c1d4ab8f723b90b034e69 100644 (file)
 #define BT_ASSERT_PRE_FT_HOT(_ft, _name)                               \
        BT_ASSERT_PRE_HOT((_ft), (_name), ": +%!+_F", (_ft))
 
+#define BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(_ft, _index)     \
+       (&g_array_index(((struct bt_field_type_common_structure *) (_ft))->fields, \
+               struct bt_field_type_common_structure_field, (_index)))
+
+#define BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(_ft, _index)      \
+       (&g_array_index(((struct bt_field_type_common_variant *) (_ft))->choices, \
+               struct bt_field_type_common_variant_choice, (_index)))
+
 struct bt_field_common;
 struct bt_field_type_common;
 struct bt_field_type;
@@ -118,7 +126,10 @@ struct bt_field_type_common {
 
 struct bt_field_type_common_integer {
        struct bt_field_type_common common;
+
+       /* Owned by this */
        struct bt_clock_class *mapped_clock_class;
+
        enum bt_byte_order user_byte_order;
        bt_bool is_signed;
        unsigned int size;
@@ -131,7 +142,6 @@ struct enumeration_mapping {
                uint64_t _unsigned;
                int64_t _signed;
        } range_start;
-
        union {
                uint64_t _unsigned;
                int64_t _signed;
@@ -141,9 +151,14 @@ struct enumeration_mapping {
 
 struct bt_field_type_common_enumeration {
        struct bt_field_type_common common;
+
+       /* Owned by this */
        struct bt_field_type_common_integer *container_ft;
-       GPtrArray *entries; /* Array of ptrs to struct enumeration_mapping */
-       /* Only set during validation. */
+
+       /* Array of `struct enumeration_mapping *`, owned by this */
+       GPtrArray *entries;
+
+       /* Only set during validation */
        bt_bool has_overlapping_ranges;
 };
 
@@ -155,7 +170,10 @@ enum bt_field_type_enumeration_mapping_iterator_type {
 
 struct bt_field_type_enumeration_mapping_iterator {
        struct bt_object base;
+
+       /* Owned by this */
        struct bt_field_type_common_enumeration *enumeration_ft;
+
        enum bt_field_type_enumeration_mapping_iterator_type type;
        int index;
        union {
@@ -172,37 +190,82 @@ struct bt_field_type_common_floating_point {
        unsigned int mant_dig;
 };
 
-struct structure_field_common {
-       struct bt_field_type_common common;
+struct bt_field_type_common_structure_field {
        GQuark name;
+
+       /* Owned by this */
        struct bt_field_type_common *type;
 };
 
 struct bt_field_type_common_structure {
        struct bt_field_type_common common;
        GHashTable *field_name_to_index;
-       GPtrArray *fields; /* Array of pointers to struct structure_field_common */
+
+       /*
+        * Array of `struct bt_field_type_common_structure_field`,
+        * owned by this
+        */
+       GArray *fields;
+};
+
+struct bt_field_type_common_variant_choice_range {
+       union {
+               int64_t i;
+               uint64_t u;
+       } lower;
+       union {
+               int64_t i;
+               uint64_t u;
+       } upper;
+};
+
+struct bt_field_type_common_variant_choice {
+       GQuark name;
+
+       /* Owned by this */
+       struct bt_field_type_common *type;
+
+       /* Array of `struct bt_field_type_common_variant_choice_range` */
+       GArray *ranges;
 };
 
 struct bt_field_type_common_variant {
        struct bt_field_type_common common;
        GString *tag_name;
+       bool choices_up_to_date;
+
+       /* Owned by this */
        struct bt_field_type_common_enumeration *tag_ft;
+
+       /* Owned by this */
        struct bt_field_path *tag_field_path;
-       GHashTable *field_name_to_index;
-       GPtrArray *fields; /* Array of pointers to struct structure_field_common */
+
+       GHashTable *choice_name_to_index;
+
+       /*
+        * Array of `struct bt_field_type_common_variant_choice`,
+        * owned by this */
+       GArray *choices;
 };
 
 struct bt_field_type_common_array {
        struct bt_field_type_common common;
+
+       /* Owned by this */
        struct bt_field_type_common *element_ft;
-       unsigned int length; /* Number of elements */
+
+       unsigned int length;
 };
 
 struct bt_field_type_common_sequence {
        struct bt_field_type_common common;
+
+       /* Owned by this */
        struct bt_field_type_common *element_ft;
+
        GString *length_field_name;
+
+       /* Owned by this */
        struct bt_field_path *length_field_path;
 };
 
@@ -483,17 +546,14 @@ int bt_field_type_common_variant_add_field(struct bt_field_type_common *ft,
                const char *field_name);
 
 BT_HIDDEN
-struct bt_field_type_common *
-bt_field_type_common_variant_borrow_field_type_by_name(
-               struct bt_field_type_common *ft,
-               const char *field_name);
+int bt_field_type_common_variant_update_choices(
+               struct bt_field_type_common *ft);
 
 BT_HIDDEN
 struct bt_field_type_common *
-bt_field_type_common_variant_borrow_field_type_from_tag(
+bt_field_type_common_variant_borrow_field_type_by_name(
                struct bt_field_type_common *ft,
-               struct bt_field_common *tag_field,
-               bt_field_common_create_func field_create_func);
+               const char *field_name);
 
 BT_HIDDEN
 int64_t bt_field_type_common_variant_get_field_count(
@@ -724,4 +784,9 @@ int bt_field_type_common_validate_single_clock_class(
                struct bt_field_type_common *ft,
                struct bt_clock_class **expected_clock_class);
 
+BT_HIDDEN
+int64_t bt_field_type_common_variant_find_choice_index(
+               struct bt_field_type_common *ft, uint64_t uval,
+               bool is_signed);
+
 #endif /* BABELTRACE_CTF_IR_FIELD_TYPES_INTERNAL_H */
diff --git a/include/babeltrace/ctf-ir/field-wrapper-internal.h b/include/babeltrace/ctf-ir/field-wrapper-internal.h
new file mode 100644 (file)
index 0000000..cdbfabe
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef BABELTRACE_CTF_IR_FIELD_WRAPPER_INTERNAL_H
+#define BABELTRACE_CTF_IR_FIELD_WRAPPER_INTERNAL_H
+
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-ir/fields-internal.h>
+#include <babeltrace/object-pool-internal.h>
+#include <babeltrace/object-internal.h>
+
+struct bt_field_wrapper {
+       struct bt_object base;
+
+       /* Owned by this */
+       struct bt_field_common *field;
+};
+
+BT_HIDDEN
+struct bt_field_wrapper *bt_field_wrapper_new(void *data);
+
+BT_HIDDEN
+void bt_field_wrapper_destroy(struct bt_field_wrapper *field);
+
+BT_HIDDEN
+struct bt_field_wrapper *bt_field_wrapper_create(
+               struct bt_object_pool *pool, struct bt_field_type *ft);
+
+#endif /* BABELTRACE_CTF_IR_FIELD_WRAPPER_INTERNAL_H */
index 388b0cb24b91305626c6cf91b0c72783015182ac..c616328cd4cbb61f2cd0a5a2e6be6129c9908d86 100644 (file)
 #include <glib.h>
 
 #define BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(_field, _type_id, _name)        \
-       BT_ASSERT_PRE((_field)->type->id == (_type_id),                 \
+       BT_ASSERT_PRE((_field)->type->id == ((int) (_type_id)),         \
                _name " has the wrong type ID: expected-type-id=%s, "   \
-               "%![field-]+_f", bt_common_field_type_id_string(_type_id),      \
-               (_field))
+               "%![field-]+_f",                                        \
+               bt_common_field_type_id_string((int) (_type_id)), (_field))
 
 #define BT_ASSERT_PRE_FIELD_COMMON_IS_SET(_field, _name)               \
        BT_ASSERT_PRE(bt_field_common_is_set_recursive(_field),         \
@@ -55,7 +55,8 @@
 struct bt_field;
 struct bt_field_common;
 
-typedef void (*bt_field_common_method_freeze)(struct bt_field_common *);
+typedef void (*bt_field_common_method_set_is_frozen)(struct bt_field_common *,
+               bool);
 typedef int (*bt_field_common_method_validate)(struct bt_field_common *);
 typedef struct bt_field_common *(*bt_field_common_method_copy)(
                struct bt_field_common *);
@@ -63,7 +64,7 @@ typedef bt_bool (*bt_field_common_method_is_set)(struct bt_field_common *);
 typedef void (*bt_field_common_method_reset)(struct bt_field_common *);
 
 struct bt_field_common_methods {
-       bt_field_common_method_freeze freeze;
+       bt_field_common_method_set_is_frozen set_is_frozen;
        bt_field_common_method_validate validate;
        bt_field_common_method_copy copy;
        bt_field_common_method_is_set is_set;
@@ -98,11 +99,6 @@ struct bt_field_common_integer {
        } payload;
 };
 
-struct bt_field_common_enumeration {
-       struct bt_field_common common;
-       struct bt_field_common *payload;
-};
-
 struct bt_field_common_floating_point {
        struct bt_field_common common;
        double payload;
@@ -110,24 +106,45 @@ struct bt_field_common_floating_point {
 
 struct bt_field_common_structure {
        struct bt_field_common common;
-       GPtrArray *fields; /* Array of pointers to struct bt_field_common */
+
+       /* Array of `struct bt_field_common *`, owned by this */
+       GPtrArray *fields;
 };
 
 struct bt_field_common_variant {
        struct bt_field_common common;
-       struct bt_field_common *tag;
-       struct bt_field_common *payload;
+
+       union {
+               uint64_t u;
+               int64_t i;
+       } tag_value;
+
+       /* Weak: belongs to `choices` below */
+       struct bt_field_common *current_field;
+
+       /* Array of `struct bt_field_common *`, owned by this */
+       GPtrArray *fields;
 };
 
 struct bt_field_common_array {
        struct bt_field_common common;
-       GPtrArray *elements; /* Array of pointers to struct bt_field_common */
+
+       /* Array of `struct bt_field_common *`, owned by this */
+       GPtrArray *elements;
 };
 
 struct bt_field_common_sequence {
        struct bt_field_common common;
-       struct bt_field_common *length;
-       GPtrArray *elements; /* Array of pointers to struct bt_field_common */
+
+       /*
+        * This is the true sequence field's length: its value can be
+        * less than `elements->len` below because we never shrink the
+        * array of elements to avoid reallocation.
+        */
+       uint64_t length;
+
+       /* Array of `struct bt_field_common *`, owned by this */
+       GPtrArray *elements;
 };
 
 struct bt_field_common_string {
@@ -135,8 +152,9 @@ struct bt_field_common_string {
        GString *payload;
 };
 
-BT_HIDDEN
-int64_t bt_field_sequence_get_int_length(struct bt_field *field);
+struct bt_field_enumeration {
+       struct bt_field_common_integer common;
+};
 
 BT_HIDDEN
 struct bt_field_common *bt_field_common_copy(struct bt_field_common *field);
@@ -146,20 +164,34 @@ int bt_field_common_structure_initialize(struct bt_field_common *field,
                struct bt_field_type_common *type,
                bt_object_release_func release_func,
                struct bt_field_common_methods *methods,
-               bt_field_common_create_func field_create_func);
+               bt_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func);
 
 BT_HIDDEN
 int bt_field_common_array_initialize(struct bt_field_common *field,
                struct bt_field_type_common *type,
                bt_object_release_func release_func,
-               struct bt_field_common_methods *methods);
+               struct bt_field_common_methods *methods,
+               bt_field_common_create_func field_create_func,
+               GDestroyNotify field_destroy_func);
 
 BT_HIDDEN
-int bt_field_common_generic_validate(struct bt_field_common *field);
+int bt_field_common_sequence_initialize(struct bt_field_common *field,
+               struct bt_field_type_common *type,
+               bt_object_release_func release_func,
+               struct bt_field_common_methods *methods,
+               GDestroyNotify field_destroy_func);
 
 BT_HIDDEN
-int bt_field_common_enumeration_validate_recursive(
-               struct bt_field_common *field);
+int bt_field_common_variant_initialize(struct bt_field_common *field,
+               struct bt_field_type_common *type,
+               bt_object_release_func release_func,
+               struct bt_field_common_methods *methods,
+               bt_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func);
+
+BT_HIDDEN
+int bt_field_common_generic_validate(struct bt_field_common *field);
 
 BT_HIDDEN
 int bt_field_common_structure_validate_recursive(struct bt_field_common *field);
@@ -176,9 +208,6 @@ int bt_field_common_sequence_validate_recursive(struct bt_field_common *field);
 BT_HIDDEN
 void bt_field_common_generic_reset(struct bt_field_common *field);
 
-BT_HIDDEN
-void bt_field_common_enumeration_reset_recursive(struct bt_field_common *field);
-
 BT_HIDDEN
 void bt_field_common_structure_reset_recursive(struct bt_field_common *field);
 
@@ -195,33 +224,32 @@ BT_HIDDEN
 void bt_field_common_string_reset(struct bt_field_common *field);
 
 BT_HIDDEN
-void bt_field_common_generic_freeze(struct bt_field_common *field);
-
-BT_HIDDEN
-void bt_field_common_enumeration_freeze_recursive(struct bt_field_common *field);
+void bt_field_common_generic_set_is_frozen(struct bt_field_common *field,
+               bool is_frozen);
 
 BT_HIDDEN
-void bt_field_common_structure_freeze_recursive(struct bt_field_common *field);
+void bt_field_common_structure_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen);
 
 BT_HIDDEN
-void bt_field_common_variant_freeze_recursive(struct bt_field_common *field);
+void bt_field_common_variant_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen);
 
 BT_HIDDEN
-void bt_field_common_array_freeze_recursive(struct bt_field_common *field);
+void bt_field_common_array_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen);
 
 BT_HIDDEN
-void bt_field_common_sequence_freeze_recursive(struct bt_field_common *field);
+void bt_field_common_sequence_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen);
 
 BT_HIDDEN
-void _bt_field_common_freeze_recursive(struct bt_field_common *field);
+void _bt_field_common_set_is_frozen_recursive(struct bt_field_common *field,
+               bool is_frozen);
 
 BT_HIDDEN
 bt_bool bt_field_common_generic_is_set(struct bt_field_common *field);
 
-BT_HIDDEN
-bt_bool bt_field_common_enumeration_is_set_recursive(
-               struct bt_field_common *field);
-
 BT_HIDDEN
 bt_bool bt_field_common_structure_is_set_recursive(
                struct bt_field_common *field);
@@ -235,49 +263,25 @@ bt_bool bt_field_common_array_is_set_recursive(struct bt_field_common *field);
 BT_HIDDEN
 bt_bool bt_field_common_sequence_is_set_recursive(struct bt_field_common *field);
 
-BT_HIDDEN
-void bt_field_common_integer_destroy(struct bt_object *obj);
-
-BT_HIDDEN
-void bt_field_common_enumeration_destroy_recursive(struct bt_object *obj);
-
-BT_HIDDEN
-void bt_field_common_floating_point_destroy(struct bt_object *obj);
-
-BT_HIDDEN
-void bt_field_common_structure_destroy_recursive(struct bt_object *obj);
-
-BT_HIDDEN
-void bt_field_common_variant_destroy_recursive(struct bt_object *obj);
-
-BT_HIDDEN
-void bt_field_common_array_destroy_recursive(struct bt_object *obj);
-
-BT_HIDDEN
-void bt_field_common_sequence_destroy_recursive(struct bt_object *obj);
-
-BT_HIDDEN
-void bt_field_common_string_destroy(struct bt_object *obj);
-
 #ifdef BT_DEV_MODE
-# define bt_field_common_validate_recursive    _bt_field_common_validate_recursive
-# define bt_field_common_freeze_recursive      _bt_field_common_freeze_recursive
-# define bt_field_common_is_set_recursive      _bt_field_common_is_set_recursive
-# define bt_field_common_reset_recursive       _bt_field_common_reset_recursive
-# define bt_field_common_set                   _bt_field_common_set
-# define bt_field_validate_recursive           _bt_field_validate_recursive
-# define bt_field_freeze_recursive             _bt_field_freeze_recursive
-# define bt_field_is_set_recursive             _bt_field_is_set_recursive
-# define bt_field_reset_recursive              _bt_field_reset_recursive
-# define bt_field_set                          _bt_field_set
+# define bt_field_common_validate_recursive            _bt_field_common_validate_recursive
+# define bt_field_common_set_is_frozen_recursive       _bt_field_common_set_is_frozen_recursive
+# define bt_field_common_is_set_recursive              _bt_field_common_is_set_recursive
+# define bt_field_common_reset_recursive               _bt_field_common_reset_recursive
+# define bt_field_common_set                           _bt_field_common_set
+# define bt_field_validate_recursive                   _bt_field_validate_recursive
+# define bt_field_set_is_frozen_recursive              _bt_field_set_is_frozen_recursive
+# define bt_field_is_set_recursive                     _bt_field_is_set_recursive
+# define bt_field_reset_recursive                      _bt_field_reset_recursive
+# define bt_field_set                                  _bt_field_set
 #else
 # define bt_field_common_validate_recursive(_field)    (-1)
-# define bt_field_common_freeze_recursive(_field)
+# define bt_field_common_set_is_frozen_recursive(_field, _is_frozen)
 # define bt_field_common_is_set_recursive(_field)      (BT_FALSE)
 # define bt_field_common_reset_recursive(_field)       (BT_TRUE)
 # define bt_field_common_set(_field, _val)
 # define bt_field_validate_recursive(_field)           (-1)
-# define bt_field_freeze_recursive(_field)
+# define bt_field_set_is_frozen_recursive(_field, _is_frozen)
 # define bt_field_is_set_recursive(_field)             (BT_FALSE)
 # define bt_field_reset_recursive(_field)              (BT_TRUE)
 # define bt_field_set(_field, _val)
@@ -287,8 +291,8 @@ BT_ASSERT_FUNC
 static inline bool field_type_common_has_known_id(
                struct bt_field_type_common *ft)
 {
-       return ft->id > BT_FIELD_TYPE_ID_UNKNOWN ||
-               ft->id < BT_FIELD_TYPE_ID_NR;
+       return (int) ft->id > BT_FIELD_TYPE_ID_UNKNOWN ||
+               (int) ft->id < BT_FIELD_TYPE_ID_NR;
 }
 
 static inline
@@ -369,73 +373,50 @@ struct bt_field_type_common *bt_field_common_borrow_type(
 }
 
 static inline
-int64_t bt_field_common_sequence_get_int_length(struct bt_field_common *field)
-{
-       struct bt_field_common_sequence *sequence = BT_FROM_COMMON(field);
-       int64_t ret;
-
-       BT_ASSERT(field);
-       BT_ASSERT(field->type->id == BT_FIELD_TYPE_ID_SEQUENCE);
-       if (!sequence->length) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = (int64_t) sequence->elements->len;
-
-end:
-       return ret;
-}
-
-static inline
-struct bt_field_common *bt_field_common_sequence_borrow_length(
-               struct bt_field_common *field)
+int64_t bt_field_common_sequence_get_length(struct bt_field_common *field)
 {
        struct bt_field_common_sequence *sequence = BT_FROM_COMMON(field);
 
        BT_ASSERT_PRE_NON_NULL(field, "Sequence field");
        BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_SEQUENCE,
                "Field");
-       return sequence->length;
+       return (int64_t) sequence->length;
 }
 
 static inline
 int bt_field_common_sequence_set_length(struct bt_field_common *field,
-               struct bt_field_common *length_field)
+               uint64_t length, bt_field_common_create_func field_create_func)
 {
        int ret = 0;
-       struct bt_field_common_integer *length = BT_FROM_COMMON(length_field);
        struct bt_field_common_sequence *sequence = BT_FROM_COMMON(field);
-       uint64_t sequence_length;
 
        BT_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_ASSERT_PRE_NON_NULL(length_field, "Length field");
        BT_ASSERT_PRE_FIELD_COMMON_HOT(field, "Sequence field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(length_field,
-               BT_FIELD_TYPE_ID_INTEGER, "Length field");
-       BT_ASSERT_PRE(
-               !bt_field_type_common_integer_is_signed(length->common.type),
-               "Length field's type is signed: %!+_f", length_field);
-       BT_ASSERT_PRE_FIELD_COMMON_IS_SET(length_field, "Length field");
-       sequence_length = length->payload.unsignd;
-       if (sequence->elements) {
-               g_ptr_array_free(sequence->elements, TRUE);
-               bt_put(sequence->length);
-       }
 
-       sequence->elements = g_ptr_array_sized_new((size_t) sequence_length);
-       if (!sequence->elements) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               ret = -1;
-               goto end;
+       if (length > sequence->elements->len) {
+               /* Make more room */
+               struct bt_field_type_common_sequence *sequence_ft;
+               uint64_t cur_len = sequence->elements->len;
+               uint64_t i;
+
+               g_ptr_array_set_size(sequence->elements, length);
+               sequence_ft = BT_FROM_COMMON(sequence->common.type);
+
+               for (i = cur_len; i < sequence->elements->len; i++) {
+                       struct bt_field_common *elem_field =
+                               field_create_func(sequence_ft->element_ft);
+
+                       if (!elem_field) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       BT_ASSERT(!sequence->elements->pdata[i]);
+                       sequence->elements->pdata[i] = elem_field;
+               }
        }
 
-       g_ptr_array_set_free_func(sequence->elements,
-               (GDestroyNotify) bt_put);
-       g_ptr_array_set_size(sequence->elements, (size_t) sequence_length);
-       bt_get(length_field);
-       sequence->length = length_field;
-       bt_field_common_freeze_recursive(length_field);
+       sequence->length = length;
 
 end:
        return ret;
@@ -491,239 +472,65 @@ struct bt_field_common *bt_field_common_structure_borrow_field_by_index(
        return structure->fields->pdata[index];
 }
 
-BT_ASSERT_PRE_FUNC
-static inline bool field_to_set_has_expected_type(
-               struct bt_field_common *struct_field,
-               const char *name, struct bt_field_common *value)
-{
-       bool ret = true;
-       struct bt_field_type_common *expected_field_type = NULL;
-
-       expected_field_type =
-               bt_field_type_common_structure_borrow_field_type_by_name(
-                       struct_field->type, name);
-
-       if (bt_field_type_common_compare(expected_field_type, value->type)) {
-               BT_ASSERT_PRE_MSG("Value field's type is different from the expected field type: "
-                       "%![value-ft-]+_F, %![expected-ft-]+_F", value->type,
-                       expected_field_type);
-               ret = false;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static inline
-int bt_field_common_structure_set_field_by_name(struct bt_field_common *field,
-               const char *name, struct bt_field_common *value)
-{
-       int ret = 0;
-       GQuark field_quark;
-       struct bt_field_common_structure *structure = BT_FROM_COMMON(field);
-       size_t index;
-       GHashTable *field_name_to_index;
-       struct bt_field_type_common_structure *structure_ft;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Structure field");
-       BT_ASSERT_PRE_NON_NULL(name, "Field name");
-       BT_ASSERT_PRE_NON_NULL(value, "Value field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_STRUCT,
-               "Parent field");
-       BT_ASSERT_PRE(field_to_set_has_expected_type(field, name, value),
-               "Value field's type is different from the expected field type.");
-       field_quark = g_quark_from_string(name);
-       structure_ft = BT_FROM_COMMON(field->type);
-       field_name_to_index = structure_ft->field_name_to_index;
-       if (!g_hash_table_lookup_extended(field_name_to_index,
-                       GUINT_TO_POINTER(field_quark), NULL,
-                       (gpointer *) &index)) {
-               BT_LOGV("Invalid parameter: no such field in structure field's type: "
-                       "struct-field-addr=%p, struct-ft-addr=%p, "
-                       "field-ft-addr=%p, name=\"%s\"",
-                       field, field->type, value->type, name);
-               ret = -1;
-               goto end;
-       }
-       bt_get(value);
-       BT_MOVE(structure->fields->pdata[index], value);
-
-end:
-       return ret;
-}
-
 static inline
 struct bt_field_common *bt_field_common_array_borrow_field(
-               struct bt_field_common *field, uint64_t index,
-               bt_field_common_create_func field_create_func)
+               struct bt_field_common *field, uint64_t index)
 {
-       struct bt_field_common *new_field = NULL;
-       struct bt_field_type_common *field_type = NULL;
        struct bt_field_common_array *array = BT_FROM_COMMON(field);
 
        BT_ASSERT_PRE_NON_NULL(field, "Array field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_ARRAY, "Field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_ARRAY,
+               "Field");
        BT_ASSERT_PRE(index < array->elements->len,
                "Index is out of bound: %![array-field-]+_f, "
                "index=%" PRIu64 ", count=%u", field,
                index, array->elements->len);
-
-       field_type = bt_field_type_common_array_borrow_element_field_type(
-               field->type);
-       if (array->elements->pdata[(size_t) index]) {
-               new_field = array->elements->pdata[(size_t) index];
-               goto end;
-       }
-
-       /* We don't want to modify this field if it's frozen */
-       BT_ASSERT_PRE_FIELD_COMMON_HOT(field, "Array field");
-       new_field = field_create_func(field_type);
-       array->elements->pdata[(size_t) index] = new_field;
-
-end:
-       return new_field;
+       return array->elements->pdata[(size_t) index];
 }
 
 static inline
 struct bt_field_common *bt_field_common_sequence_borrow_field(
-               struct bt_field_common *field, uint64_t index,
-               bt_field_common_create_func field_create_func)
+               struct bt_field_common *field, uint64_t index)
 {
-       struct bt_field_common *new_field = NULL;
-       struct bt_field_type_common *field_type = NULL;
        struct bt_field_common_sequence *sequence = BT_FROM_COMMON(field);
 
        BT_ASSERT_PRE_NON_NULL(field, "Sequence field");
        BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_SEQUENCE,
                "Field");
-       BT_ASSERT_PRE_NON_NULL(sequence->elements, "Sequence field's element array");
-       BT_ASSERT_PRE(index < sequence->elements->len,
+       BT_ASSERT_PRE(index < sequence->length,
                "Index is out of bound: %![seq-field-]+_f, "
                "index=%" PRIu64 ", count=%u", field, index,
                sequence->elements->len);
-       field_type = bt_field_type_common_sequence_borrow_element_field_type(
-               field->type);
-       if (sequence->elements->pdata[(size_t) index]) {
-               new_field = sequence->elements->pdata[(size_t) index];
-               goto end;
-       }
-
-       /* We don't want to modify this field if it's frozen */
-       BT_ASSERT_PRE_FIELD_COMMON_HOT(field, "Sequence field");
-       new_field = field_create_func(field_type);
-       sequence->elements->pdata[(size_t) index] = new_field;
-
-end:
-       return new_field;
+       return sequence->elements->pdata[(size_t) index];
 }
 
 static inline
-struct bt_field_common *bt_field_common_enumeration_borrow_container(
-               struct bt_field_common *field,
-               bt_field_common_create_func field_create_func)
+int bt_field_variant_common_set_tag(struct bt_field_common *variant_field,
+               uint64_t tag_uval, bool is_signed)
 {
-       struct bt_field_common_enumeration *enumeration = BT_FROM_COMMON(field);
-
-       BT_ASSERT_PRE_NON_NULL(field, "Enumeration field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_ENUM, "Field");
-
-       if (!enumeration->payload) {
-               struct bt_field_type_common_enumeration *enumeration_type;
-
-               /* We don't want to modify this field if it's frozen */
-               BT_ASSERT_PRE_FIELD_COMMON_HOT(field, "Enumeration field");
-
-               enumeration_type = BT_FROM_COMMON(field->type);
-               enumeration->payload =
-                       field_create_func(
-                               BT_TO_COMMON(enumeration_type->container_ft));
-       }
-
-       return enumeration->payload;
-}
-
-static inline
-struct bt_field_common *bt_field_common_variant_borrow_field(
-               struct bt_field_common *field,
-               struct bt_field_common *tag_field,
-               bt_field_common_create_func field_create_func)
-{
-       struct bt_field_common *new_field = NULL;
-       struct bt_field_common_variant *variant = BT_FROM_COMMON(field);
-       struct bt_field_type_common_variant *variant_type;
-       struct bt_field_type_common *field_type;
-       struct bt_field_common *tag_enum = NULL;
-       struct bt_field_common_integer *tag_enum_integer =
-               BT_FROM_COMMON(field);
-       int64_t tag_enum_value;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Variant field");
-       BT_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field, BT_FIELD_TYPE_ID_VARIANT,
-               "Variant field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(tag_field, BT_FIELD_TYPE_ID_ENUM,
-               "Tag field");
-       variant_type = BT_FROM_COMMON(field->type);
-       tag_enum = bt_field_common_enumeration_borrow_container(tag_field,
-               field_create_func);
-       BT_ASSERT_PRE_NON_NULL(tag_enum, "Tag field's container");
-       tag_enum_integer = BT_FROM_COMMON(tag_enum);
-       BT_ASSERT_PRE(bt_field_common_validate_recursive(tag_field) == 0,
-               "Tag field is invalid: %!+_f", tag_field);
-       tag_enum_value = tag_enum_integer->payload.signd;
+       int ret = 0;
+       int64_t choice_index;
+       struct bt_field_common_variant *variant = BT_FROM_COMMON(variant_field);
 
-       /*
-        * If the variant currently has a tag and a payload, and if the
-        * requested tag value is the same as the current one, return
-        * the current payload instead of creating a fresh one.
-        */
-       if (variant->tag && variant->payload) {
-               struct bt_field_common *cur_tag_container = NULL;
-               struct bt_field_common_integer *cur_tag_enum_integer;
-               int64_t cur_tag_value;
-
-               cur_tag_container =
-                       bt_field_common_enumeration_borrow_container(
-                               variant->tag, field_create_func);
-               BT_ASSERT(cur_tag_container);
-               cur_tag_enum_integer = BT_FROM_COMMON(cur_tag_container);
-               cur_tag_value = cur_tag_enum_integer->payload.signd;
-
-               if (cur_tag_value == tag_enum_value) {
-                       new_field = variant->payload;
-                       goto end;
-               }
-       }
+       BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+               BT_FIELD_TYPE_ID_VARIANT, "Field");
 
-       /* We don't want to modify this field if it's frozen */
-       BT_ASSERT_PRE_FIELD_COMMON_HOT(field, "Variant field");
-       field_type = bt_field_type_common_variant_borrow_field_type_signed(
-               variant_type, tag_enum_value);
-
-       /* It's the caller's job to make sure the tag's value is valid */
-       BT_ASSERT_PRE(field_type,
-               "Variant field's type does not contain a field type for "
-               "this tag value: tag-value-signed=%" PRId64 ", "
-               "%![var-ft-]+_F, %![tag-field-]+_f", tag_enum_value,
-               variant_type, tag_field);
-
-       new_field = field_create_func(field_type);
-       if (!new_field) {
-               BT_LOGW("Cannot create field: "
-                       "variant-field-addr=%p, variant-ft-addr=%p, "
-                       "field-ft-addr=%p", field, field->type, field_type);
+       /* Find matching index in variant field's type */
+       choice_index = bt_field_type_common_variant_find_choice_index(
+               variant_field->type, tag_uval, is_signed);
+       if (choice_index < 0) {
+               ret = -1;
                goto end;
        }
 
-       bt_put(variant->tag);
-       bt_put(variant->payload);
-       variant->tag = bt_get(tag_field);
-       variant->payload = new_field;
+       /* Select corresponding field */
+       BT_ASSERT(choice_index < variant->fields->len);
+       variant->current_field = variant->fields->pdata[choice_index];
+       variant->tag_value.u = tag_uval;
 
 end:
-       return new_field;
+       return ret;
 }
 
 static inline
@@ -735,172 +542,63 @@ struct bt_field_common *bt_field_common_variant_borrow_current_field(
        BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
        BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(variant_field,
                BT_FIELD_TYPE_ID_VARIANT, "Field");
-       return variant->payload;
+       BT_ASSERT_PRE(variant->current_field,
+               "Variant field has no current field: %!+_f", variant_field);
+       return variant->current_field;
 }
 
 static inline
-struct bt_field_common *bt_field_common_variant_borrow_tag(
-               struct bt_field_common *variant_field)
+int bt_field_common_variant_get_tag_signed(struct bt_field_common *variant_field,
+       int64_t *tag)
 {
        struct bt_field_common_variant *variant = BT_FROM_COMMON(variant_field);
 
        BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
        BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(variant_field,
                BT_FIELD_TYPE_ID_VARIANT, "Field");
-       return variant->tag;
-}
-
-static inline
-int bt_field_common_integer_signed_get_value(struct bt_field_common *field,
-               int64_t *value)
-{
-       struct bt_field_common_integer *integer = BT_FROM_COMMON(field);
-
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_FIELD_COMMON_IS_SET(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_INTEGER, "Field");
-       BT_ASSERT_PRE(bt_field_type_common_integer_is_signed(field->type),
-               "Field's type is unsigned: %!+_f", field);
-       *value = integer->payload.signd;
-       return 0;
-}
-
-BT_ASSERT_PRE_FUNC
-static inline bool value_is_in_range_signed(unsigned int size, int64_t value)
-{
-       bool ret = true;
-       int64_t min_value, max_value;
-
-       min_value = -(1ULL << (size - 1));
-       max_value = (1ULL << (size - 1)) - 1;
-       if (value < min_value || value > max_value) {
-               BT_LOGF("Value is out of bounds: value=%" PRId64 ", "
-                       "min-value=%" PRId64 ", max-value=%" PRId64,
-                       value, min_value, max_value);
-               ret = false;
-       }
-
-       return ret;
-}
-
-static inline
-int bt_field_common_integer_signed_set_value(struct bt_field_common *field,
-               int64_t value)
-{
-       int ret = 0;
-       struct bt_field_common_integer *integer = BT_FROM_COMMON(field);
-       struct bt_field_type_common_integer *integer_type;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_COMMON_HOT(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_INTEGER, "Field");
-       integer_type = BT_FROM_COMMON(field->type);
-       BT_ASSERT_PRE(bt_field_type_common_integer_is_signed(field->type),
-               "Field's type is unsigned: %!+_f", field);
-       BT_ASSERT_PRE(value_is_in_range_signed(integer_type->size, value),
-               "Value is out of bounds: value=%" PRId64 ", %![field-]+_f",
-               value, field);
-       integer->payload.signd = value;
-       bt_field_common_set(field, true);
-       return ret;
-}
-
-static inline
-int bt_field_common_integer_unsigned_get_value(struct bt_field_common *field,
-               uint64_t *value)
-{
-       struct bt_field_common_integer *integer = BT_FROM_COMMON(field);
-
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_FIELD_COMMON_IS_SET(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_INTEGER, "Field");
-       BT_ASSERT_PRE(!bt_field_type_common_integer_is_signed(field->type),
-               "Field's type is signed: %!+_f", field);
-       *value = integer->payload.unsignd;
+       BT_ASSERT_PRE(variant->current_field,
+               "Variant field has no current field: %!+_f", variant_field);
+       *tag = variant->tag_value.i;
        return 0;
 }
 
-BT_ASSERT_PRE_FUNC
-static inline bool value_is_in_range_unsigned(unsigned int size, uint64_t value)
-{
-       bool ret = true;
-       int64_t max_value;
-
-       max_value = (size == 64) ? UINT64_MAX : ((uint64_t) 1 << size) - 1;
-       if (value > max_value) {
-               BT_LOGF("Value is out of bounds: value=%" PRIu64 ", "
-                       "max-value=%" PRIu64,
-                       value, max_value);
-               ret = false;
-       }
-
-       return ret;
-}
-
 static inline
-int bt_field_common_integer_unsigned_set_value(struct bt_field_common *field,
-               uint64_t value)
+int bt_field_common_variant_get_tag_unsigned(struct bt_field_common *variant_field,
+       uint64_t *tag)
 {
-       struct bt_field_common_integer *integer = BT_FROM_COMMON(field);
-       struct bt_field_type_common_integer *integer_type;
+       struct bt_field_common_variant *variant = BT_FROM_COMMON(variant_field);
 
-       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_COMMON_HOT(field, "Integer field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_INTEGER, "Field");
-       integer_type = BT_FROM_COMMON(field->type);
-       BT_ASSERT_PRE(!bt_field_type_common_integer_is_signed(field->type),
-               "Field's type is signed: %!+_f", field);
-       BT_ASSERT_PRE(value_is_in_range_unsigned(integer_type->size, value),
-               "Value is out of bounds: value=%" PRIu64 ", %![field-]+_f",
-               value, field);
-       integer->payload.unsignd = value;
-       bt_field_common_set(field, true);
+       BT_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+               BT_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_ASSERT_PRE(variant->current_field,
+               "Variant field has no current field: %!+_f", variant_field);
+       *tag = variant->tag_value.u;
        return 0;
 }
 
 static inline
 struct bt_field_type_enumeration_mapping_iterator *
 bt_field_common_enumeration_get_mappings(struct bt_field_common *field,
-               bt_field_common_create_func field_create_func)
+               bt_field_common_create_func field_create_func,
+               uint64_t uval)
 {
-       int ret;
-       struct bt_field_common *container = NULL;
+       struct bt_field_type_common_enumeration *enum_type = NULL;
        struct bt_field_type_common_integer *integer_type = NULL;
        struct bt_field_type_enumeration_mapping_iterator *iter = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(field, "Enumeration field");
-       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_FIELD_TYPE_ID_ENUM, "Field");
-       container = bt_field_common_enumeration_borrow_container(field,
-               field_create_func);
-       BT_ASSERT_PRE(container,
-               "Enumeration field has no container field: %!+_f", field);
-       BT_ASSERT(container->type);
-       integer_type = BT_FROM_COMMON(container->type);
-       BT_ASSERT_PRE_FIELD_COMMON_IS_SET(container,
-               "Enumeration field's payload field");
+       BT_ASSERT(field);
+       BT_ASSERT(field->type->id == BT_FIELD_TYPE_ID_ENUM);
+       BT_ASSERT(field->payload_set);
+       enum_type = BT_FROM_COMMON(field->type);
+       integer_type = enum_type->container_ft;
 
        if (!integer_type->is_signed) {
-               uint64_t value;
-
-               ret = bt_field_common_integer_unsigned_get_value(container,
-                       &value);
-               BT_ASSERT(ret == 0);
                iter = bt_field_type_common_enumeration_unsigned_find_mappings_by_value(
-                               field->type, value);
+                               field->type, uval);
        } else {
-               int64_t value;
-
-               ret = bt_field_common_integer_signed_get_value(container, &value);
-               BT_ASSERT(ret == 0);
                iter = bt_field_type_common_enumeration_signed_find_mappings_by_value(
-                               field->type, value);
+                               field->type, (int64_t) uval);
        }
 
        return iter;
@@ -1021,6 +719,26 @@ int bt_field_common_string_append_len(struct bt_field_common *field,
        return 0;
 }
 
+static inline
+int bt_field_common_string_clear(struct bt_field_common *field)
+{
+       struct bt_field_common_string *string_field = BT_FROM_COMMON(field);
+
+       BT_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_ASSERT_PRE_FIELD_COMMON_HOT(field, "String field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(field,
+               BT_FIELD_TYPE_ID_STRING, "Field");
+
+       if (string_field->payload) {
+               g_string_set_size(string_field->payload, 0);
+       } else {
+               string_field->payload = g_string_new(NULL);
+       }
+
+       bt_field_common_set(field, true);
+       return 0;
+}
+
 static inline
 int _bt_field_validate_recursive(struct bt_field *field)
 {
@@ -1028,9 +746,10 @@ int _bt_field_validate_recursive(struct bt_field *field)
 }
 
 static inline
-void _bt_field_freeze_recursive(struct bt_field *field)
+void _bt_field_set_is_frozen_recursive(struct bt_field *field, bool is_frozen)
 {
-       return _bt_field_common_freeze_recursive((void *) field);
+       return _bt_field_common_set_is_frozen_recursive((void *) field,
+                       is_frozen);
 }
 
 static inline
@@ -1051,4 +770,139 @@ void _bt_field_set(struct bt_field *field, bool value)
        _bt_field_common_set((void *) field, value);
 }
 
+static inline
+void bt_field_common_finalize(struct bt_field_common *field)
+{
+       BT_ASSERT(field);
+       BT_LOGD_STR("Putting field's type.");
+       bt_put(field->type);
+}
+
+static inline
+void bt_field_common_integer_finalize(struct bt_field_common *field)
+{
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common integer field object: addr=%p", field);
+       bt_field_common_finalize(field);
+}
+
+static inline
+void bt_field_common_floating_point_finalize(struct bt_field_common *field)
+{
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common floating point number field object: addr=%p", field);
+       bt_field_common_finalize(field);
+}
+
+static inline
+void bt_field_common_structure_finalize_recursive(struct bt_field_common *field)
+{
+       struct bt_field_common_structure *structure = BT_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common structure field object: addr=%p", field);
+       bt_field_common_finalize(field);
+
+       if (structure->fields) {
+               g_ptr_array_free(structure->fields, TRUE);
+       }
+}
+
+static inline
+void bt_field_common_variant_finalize_recursive(struct bt_field_common *field)
+{
+       struct bt_field_common_variant *variant = BT_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common variant field object: addr=%p", field);
+       bt_field_common_finalize(field);
+
+       if (variant->fields) {
+               g_ptr_array_free(variant->fields, TRUE);
+       }
+}
+
+static inline
+void bt_field_common_array_finalize_recursive(struct bt_field_common *field)
+{
+       struct bt_field_common_array *array = BT_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common array field object: addr=%p", field);
+       bt_field_common_finalize(field);
+
+       if (array->elements) {
+               g_ptr_array_free(array->elements, TRUE);
+       }
+}
+
+static inline
+void bt_field_common_sequence_finalize_recursive(struct bt_field_common *field)
+{
+       struct bt_field_common_sequence *sequence = BT_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common sequence field object: addr=%p", field);
+       bt_field_common_finalize(field);
+
+       if (sequence->elements) {
+               g_ptr_array_free(sequence->elements, TRUE);
+       }
+}
+
+static inline
+void bt_field_common_string_finalize(struct bt_field_common *field)
+{
+       struct bt_field_common_string *string = BT_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common string field object: addr=%p", field);
+       bt_field_common_finalize(field);
+
+       if (string->payload) {
+               g_string_free(string->payload, TRUE);
+       }
+}
+
+BT_ASSERT_PRE_FUNC
+static inline bool value_is_in_range_signed(unsigned int size, int64_t value)
+{
+       bool ret = true;
+       int64_t min_value, max_value;
+
+       min_value = -(1ULL << (size - 1));
+       max_value = (1ULL << (size - 1)) - 1;
+       if (value < min_value || value > max_value) {
+               BT_LOGF("Value is out of bounds: value=%" PRId64 ", "
+                       "min-value=%" PRId64 ", max-value=%" PRId64,
+                       value, min_value, max_value);
+               ret = false;
+       }
+
+       return ret;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline bool value_is_in_range_unsigned(unsigned int size, uint64_t value)
+{
+       bool ret = true;
+       int64_t max_value;
+
+       max_value = (size == 64) ? UINT64_MAX : ((uint64_t) 1 << size) - 1;
+       if (value > max_value) {
+               BT_LOGF("Value is out of bounds: value=%" PRIu64 ", "
+                       "max-value=%" PRIu64,
+                       value, max_value);
+               ret = false;
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_field *bt_field_create_recursive(struct bt_field_type *type);
+
+BT_HIDDEN
+void bt_field_destroy_recursive(struct bt_field *field);
+
 #endif /* BABELTRACE_CTF_IR_FIELDS_INTERNAL_H */
index ab0ba546d87e33f410f9e00ff9c99fa4178c9e32..7d811c96fcd511c568ba48a4150e093f57f048d3 100644 (file)
@@ -145,26 +145,6 @@ struct bt_field_type_enumeration_mapping_iterator;
 @{
 */
 
-/**
-@brief  Creates an uninitialized @field described by the @ft
-       \p field_type.
-
-On success, \p field_type becomes the parent of the created field
-object.
-
-On success, this function creates an \em uninitialized field: it has
-no value. You need to set the value of the created field with one of the
-its specific setters.
-
-@param[in] field_type  Field type which describes the field to create.
-@returns               Created field object, or \c NULL on error.
-
-@prenotnull{field_type}
-@postsuccessrefcountret1
-@postsuccessfrozen{field_type}
-*/
-extern struct bt_field *bt_field_create(struct bt_field_type *field_type);
-
 extern struct bt_field_type *bt_field_borrow_type(struct bt_field *field);
 
 /**
@@ -360,22 +340,6 @@ extern bt_bool bt_field_is_variant(struct bt_field *field);
 @{
 */
 
-/**
-@brief Creates a \em deep copy of the @field \p field.
-
-You can copy a frozen field: the resulting copy is <em>not frozen</em>.
-
-@param[in] field       Field to copy.
-@returns               Deep copy of \p field on success,
-                       or \c NULL on error.
-
-@prenotnull{field}
-@postrefcountsame{field}
-@postsuccessrefcountret1
-@post <strong>On success</strong>, the returned field is not frozen.
-*/
-extern struct bt_field *bt_field_copy(struct bt_field *field);
-
 /** @} */
 
 /** @} */
@@ -590,63 +554,6 @@ extern int bt_field_floating_point_set_value(
 
 /** @} */
 
-/**
-@defgroup ctfirenumfield CTF IR enumeration field
-@ingroup ctfirfields
-@brief CTF IR enumeration field.
-
-@code
-#include <babeltrace/ctf-ir/fields.h>
-@endcode
-
-A CTF IR <strong><em>enumeration field</em></strong> is a @field which
-holds a @intfield, and which is described by a @enumft.
-
-To set the current integral value of an enumeration field, you need to
-get its wrapped @intfield with bt_field_enumeration_get_container(),
-and then set the integral value with either
-bt_field_integer_signed_set_value() or
-bt_field_integer_unsigned_set_value().
-
-Once you set the integral value of an enumeration field by following the
-previous paragraph, you can get the mappings containing this value in
-their range with bt_field_enumeration_get_mappings(). This function
-returns a @enumftiter.
-
-@sa ctfirenumfieldtype
-@sa ctfirfields
-
-@addtogroup ctfirenumfield
-@{
-*/
-
-extern struct bt_field *bt_field_enumeration_borrow_container(
-               struct bt_field *enum_field);
-
-/**
-@brief  Returns the @intfield, potentially creating it, wrapped by the
-       @enumfield \p enum_field.
-
-This function creates the @intfield to return if it does not currently
-exist.
-
-@param[in] enum_field  Enumeration field of which to get the wrapped
-                       integer field.
-@returns               Integer field wrapped by \p enum_field, or
-                       \c NULL on error.
-
-@prenotnull{enum_field}
-@preisenumfield{enum_field}
-@postrefcountsame{enum_field}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field *bt_field_enumeration_get_container(
-               struct bt_field *enum_field)
-{
-       return bt_get(bt_field_enumeration_borrow_container(enum_field));
-}
-
 /**
 @brief Returns a @enumftiter on all the mappings of the field type of
        \p enum_field which contain the current integral value of the
@@ -815,6 +722,8 @@ extern int bt_field_string_append_len(
                struct bt_field *string_field, const char *value,
                unsigned int length);
 
+extern int bt_field_string_clear(struct bt_field *string_field);
+
 /** @} */
 
 /**
@@ -846,116 +755,9 @@ field with bt_field_structure_set_field_by_name().
 extern struct bt_field *bt_field_structure_borrow_field_by_name(
                struct bt_field *struct_field, const char *name);
 
-/**
-@brief  Returns the @field named \p name, potentially creating it,
-       in the @structfield \p struct_field.
-
-This function creates the @field to return if it does not currently
-exist.
-
-@param[in] struct_field        Structure field of which to get the field
-                       named \p name.
-@param[in] name                Name of the field to get from \p struct_field.
-@returns               Field named \p name in \p struct_field, or
-                       \c NULL on error.
-
-@prenotnull{struct_field}
-@prenotnull{name}
-@preisstructfield{struct_field}
-@postrefcountsame{struct_field}
-@postsuccessrefcountretinc
-
-@sa bt_field_structure_get_field_by_index(): Returns the field of a
-       given structure field by index.
-@sa bt_field_structure_set_field_by_name(): Sets the field of a
-       given structure field by name.
-*/
-static inline
-struct bt_field *bt_field_structure_get_field_by_name(
-               struct bt_field *struct_field, const char *name)
-{
-       return bt_get(bt_field_structure_borrow_field_by_name(struct_field,
-               name));
-}
-
 extern struct bt_field *bt_field_structure_borrow_field_by_index(
                struct bt_field *struct_field, uint64_t index);
 
-/**
-@brief  Returns the @field at index \p index in the @structfield
-       \p struct_field.
-
-@param[in] struct_field        Structure field of which to get the field
-                       at index \p index.
-@param[in] index       Index of the field to get in \p struct_field.
-@returns               Field at index \p index in \p struct_field, or
-                       \c NULL on error.
-
-@prenotnull{struct_field}
-@preisstructfield{struct_field}
-@pre \p index is lesser than the number of fields contained in the
-       parent field type of \p struct_field (see
-       bt_field_type_structure_get_field_count()).
-@postrefcountsame{struct_field}
-@postsuccessrefcountretinc
-
-@sa bt_field_structure_get_field_by_name(): Returns the field of a
-       given structure field by name.
-@sa bt_field_structure_set_field_by_name(): Sets the field of a
-       given structure field by name.
-*/
-static inline
-struct bt_field *bt_field_structure_get_field_by_index(
-               struct bt_field *struct_field, uint64_t index)
-{
-       return bt_get(bt_field_structure_borrow_field_by_index(struct_field,
-               index));
-}
-
-/**
-@brief Sets the field of the @structfield \p struct_field named \p name
-       to the @field \p field.
-
-If \p struct_field already contains a field named \p name, then it may
-either be replaced by \p field and its reference count is decremented,
-or \p field's value is assigned to it.
-
-The field type of \p field, as returned by bt_field_get_type(),
-\em must be equivalent to the field type returned by
-bt_field_type_structure_get_field_type_by_name() with the field
-type of \p struct_field and the same name, \p name.
-
-bt_trace_get_packet_header_type() for the parent trace class of
-\p packet.
-
-@param[in] struct_field        Structure field of which to set the field
-                       named \p name.
-@param[in] name                Name of the field to set in \p struct_field.
-@param[in] field       Field named \p name to set in \p struct_field.
-@returns               0 on success, or -1 on error.
-
-@prenotnull{struct_field}
-@prenotnull{name}
-@prenotnull{field}
-@prehot{struct_field}
-@preisstructfield{struct_field}
-@pre \p field has a field type equivalent to the field type returned by
-       bt_field_type_structure_get_field_type_by_name() for the
-       field type of \p struct_field with the name \p name.
-@postrefcountsame{struct_field}
-@post <strong>On success, the field in \p struct_field named \p name</strong>
-       may either be replaced by \p field or have the same value as \p field.
-@postsuccessrefcountinc{field}
-
-@sa bt_field_structure_get_field_by_index(): Returns the field of a
-       given structure field by index.
-@sa bt_field_structure_get_field_by_name(): Returns the field of a
-       given structure field by name.
-*/
-extern int bt_field_structure_set_field_by_name(
-               struct bt_field *struct_field,
-               const char *name, struct bt_field *field);
-
 /** @} */
 
 /**
@@ -984,33 +786,6 @@ first get the field with bt_field_array_get_field().
 extern struct bt_field *bt_field_array_borrow_field(
                struct bt_field *array_field, uint64_t index);
 
-/**
-@brief  Returns the @field at index \p index, potentially creating it,
-       in the @arrayfield \p array_field.
-
-This function creates the @field to return if it does not currently
-exist.
-
-@param[in] array_field Array field of which to get the field
-                       at index \p index.
-@param[in] index       Index of the field to get in \p array_field.
-@returns               Field at index \p index in \p array_field, or
-                       \c NULL on error.
-
-@prenotnull{array_field}
-@preisarrayfield{array_field}
-@pre \p index is lesser than bt_field_type_array_get_length() called
-       on the field type of \p array_field.
-@postrefcountsame{array_field}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field *bt_field_array_get_field(
-               struct bt_field *array_field, uint64_t index)
-{
-       return bt_get(bt_field_array_borrow_field(array_field, index));
-}
-
 /** @} */
 
 /**
@@ -1042,68 +817,7 @@ it contains.
 extern struct bt_field *bt_field_sequence_borrow_field(
                struct bt_field *sequence_field, uint64_t index);
 
-/**
-@brief  Returns the @field at index \p index, potentially creating it,
-       in the @seqfield \p sequence_field.
-
-This function creates the @field to return if it does not currently
-exist.
-
-@param[in] sequence_field      Sequence field of which to get the field
-                               at index \p index.
-@param[in] index               Index of the field to get in
-                               \p sequence_field.
-@returns                       Field at index \p index in
-                               \p sequence_field, or \c NULL on error.
-
-@prenotnull{sequence_field}
-@preisseqfield{sequence_field}
-@pre \p sequence_field has a length field previously set with
-       bt_field_sequence_set_length().
-@pre \p index is lesser than the current integral value of the current
-       length field of \p sequence_field (see
-       bt_field_sequence_get_length()).
-@postrefcountsame{sequence_field}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field *bt_field_sequence_get_field(
-               struct bt_field *sequence_field, uint64_t index)
-{
-       return bt_get(bt_field_sequence_borrow_field(sequence_field, index));
-}
-
-extern struct bt_field *bt_field_sequence_borrow_length(
-               struct bt_field *sequence_field);
-
-/**
-@brief  Returns the length @intfield of the @seqfield \p sequence_field.
-
-The current integral value of the returned length field indicates the
-number of fields contained in \p sequence_field.
-
-@param[in] sequence_field      Sequence field of which to get the
-                               length field.
-@returns                       Length field of \p sequence_field, or
-                               \c NULL on error.
-
-@prenotnull{sequence_field}
-@preisseqfield{sequence_field}
-@pre \p sequence_field has a length field previously set with
-       bt_field_sequence_set_length().
-@postrefcountsame{sequence_field}
-@postsuccessrefcountretinc
-@post <strong>On success</strong>, the returned field is a @intfield.
-
-@sa bt_field_sequence_set_length(): Sets the length field of a given
-       sequence field.
-*/
-static inline
-struct bt_field *bt_field_sequence_get_length(
-               struct bt_field *sequence_field)
-{
-       return bt_get(bt_field_sequence_borrow_length(sequence_field));
-}
+extern int64_t bt_field_sequence_get_length(struct bt_field *sequence_field);
 
 /**
 @brief Sets the length @intfield of the @seqfield \p sequence_field
@@ -1129,7 +843,7 @@ fields contained in \p sequence_field.
        given sequence field.
 */
 extern int bt_field_sequence_set_length(struct bt_field *sequence_field,
-               struct bt_field *length_field);
+               uint64_t length);
 
 /** @} */
 
@@ -1158,96 +872,21 @@ field again.
 @{
 */
 
-extern struct bt_field *bt_field_variant_borrow_field(
-               struct bt_field *variant_field,
-               struct bt_field *tag_field);
+extern int bt_field_variant_set_tag_signed(struct bt_field *variant_field,
+               int64_t tag);
 
-/**
-@brief  Returns the @field, potentially creating it, selected by the
-       tag @intfield \p tag_field in the @varfield \p variant_field.
-
-This function creates the @field to return if it does not currently
-exist.
-
-Once you call this function, you can call
-bt_field_variant_get_current_field() to get the same field again,
-and you can call bt_field_variant_get_tag() to get \p tag_field.
-
-@param[in] variant_field       Variant field of which to get the field
-                               selected by \p tag_field.
-@param[in] tag_field           Tag field.
-@returns                       Field selected by \p tag_field in
-                               \p variant_field, or \c NULL on error.
-
-@prenotnull{variant_field}
-@prenotnull{tag_field}
-@preisvarfield{variant_field}
-@preisenumfield{tag_field}
-@postrefcountsame{variant_field}
-@postsuccessrefcountinc{tag_field}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field *bt_field_variant_get_field(
-               struct bt_field *variant_field,
-               struct bt_field *tag_field)
-{
-       return bt_get(bt_field_variant_borrow_field(variant_field, tag_field));
-}
+extern int bt_field_variant_set_tag_unsigned(struct bt_field *variant_field,
+               uint64_t tag);
 
-extern struct bt_field *bt_field_variant_borrow_current_field(
-               struct bt_field *variant_field);
+extern int bt_field_variant_get_tag_signed(struct bt_field *variant_field,
+               int64_t *tag);
 
-/**
-@brief  Returns the currently selected @field of the @varfield
-       \p variant_field.
-
-@param[in] variant_field       Variant field of which to get the
-                               currently selected field.
-@returns                       Currently selected field of
-                               \p variant_field, or \c NULL if there's
-                               no selected field or on error.
-
-@prenotnull{variant_field}
-@preisvarfield{variant_field}
-@pre \p variant_field contains has a current selected field previously
-       set with bt_field_variant_get_field().
-@postrefcountsame{variant_field}
-@postsuccessrefcountretinc
-*/
-static inline
-struct bt_field *bt_field_variant_get_current_field(
-               struct bt_field *variant_field)
-{
-       return bt_get(bt_field_variant_borrow_current_field(variant_field));
-}
+extern int bt_field_variant_get_tag_unsigned(struct bt_field *variant_field,
+               uint64_t *tag);
 
-extern struct bt_field *bt_field_variant_borrow_tag(
+extern struct bt_field *bt_field_variant_borrow_current_field(
                struct bt_field *variant_field);
 
-/**
-@brief  Returns the tag @enumfield of the @varfield \p variant_field.
-
-@param[in] variant_field       Variant field of which to get the
-                               tag field.
-@returns                       Tag field of \p variant_field, or
-                               \c NULL on error.
-
-@prenotnull{variant_field}
-@preisvarfield{variant_field}
-@pre \p variant_field contains has a current selected field previously
-       set with bt_field_variant_get_field().
-@postrefcountsame{variant_field}
-@postsuccessrefcountretinc
-@post <strong>On success</strong>, the returned field is a @enumfield.
-*/
-static inline
-struct bt_field *bt_field_variant_get_tag(
-               struct bt_field *variant_field)
-{
-       return bt_get(bt_field_variant_borrow_tag(variant_field));
-}
-
 /** @} */
 
 #ifdef __cplusplus
diff --git a/include/babeltrace/ctf-ir/packet-context-field.h b/include/babeltrace/ctf-ir/packet-context-field.h
new file mode 100644 (file)
index 0000000..02fad68
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef BABELTRACE_CTF_IR_PACKET_CONTEXT_FIELD_H
+#define BABELTRACE_CTF_IR_PACKET_CONTEXT_FIELD_H
+
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bt_packet_context_field;
+struct bt_field;
+
+extern
+struct bt_field *bt_packet_context_field_borrow_field(
+               struct bt_packet_context_field *field);
+
+extern
+void bt_packet_context_field_release(struct bt_packet_context_field *field);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_CTF_IR_PACKET_CONTEXT_FIELD_H */
diff --git a/include/babeltrace/ctf-ir/packet-header-field.h b/include/babeltrace/ctf-ir/packet-header-field.h
new file mode 100644 (file)
index 0000000..9494d02
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef BABELTRACE_CTF_IR_PACKET_HEADER_FIELD_H
+#define BABELTRACE_CTF_IR_PACKET_HEADER_FIELD_H
+
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bt_packet_header_field;
+struct bt_field;
+
+extern
+struct bt_field *bt_packet_header_field_borrow_field(
+               struct bt_packet_header_field *field);
+
+extern
+void bt_packet_header_field_release(struct bt_packet_header_field *field);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_CTF_IR_PACKET_HEADER_FIELD_H */
index 9f66fb14f89b88f7401dc70d8a193a96d6ed6165..4cbf0ac88a5b5c88fb02be6f3b11ad628e668bcb 100644 (file)
 #include <babeltrace/assert-internal.h>
 #include <babeltrace/ctf-ir/fields.h>
 #include <babeltrace/ctf-ir/stream.h>
+#include <babeltrace/ctf-ir/field-wrapper-internal.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/babeltrace-internal.h>
 
 struct bt_packet {
        struct bt_object base;
-       struct bt_field *header;
-       struct bt_field *context;
+       struct bt_field_wrapper *header;
+       struct bt_field_wrapper *context;
        struct bt_stream *stream;
        int frozen;
 };
@@ -45,7 +46,16 @@ void _bt_packet_freeze(struct bt_packet *packet);
 #ifdef BT_DEV_MODE
 # define bt_packet_freeze      _bt_packet_freeze
 #else
-# define bt_packet_freeze
+# define bt_packet_freeze(_packet)
 #endif /* BT_DEV_MODE */
 
+BT_HIDDEN
+struct bt_packet *bt_packet_new(struct bt_stream *stream);
+
+BT_HIDDEN
+void bt_packet_recycle(struct bt_packet *packet);
+
+BT_HIDDEN
+void bt_packet_destroy(struct bt_packet *packet);
+
 #endif /* BABELTRACE_CTF_IR_PACKET_INTERNAL_H */
index ef3b83eab7f7454f138336bbcc1709cfe69abcde..e87a5f806dc86cf23553dcd05c993c66a1706758 100644 (file)
@@ -97,6 +97,8 @@ except for \link refs reference counting\endlink.
 @sa ctfirpacket
 */
 struct bt_packet;
+struct bt_packet_header_field;
+struct bt_packet_context_field;
 struct bt_stream;
 
 /**
@@ -118,11 +120,9 @@ bt_packet_set_header() and bt_packet_set_context().
 @prenotnull{stream}
 @postsuccessrefcountret1
 */
-extern struct bt_packet *bt_packet_create(
-               struct bt_stream *stream);
+extern struct bt_packet *bt_packet_create(struct bt_stream *stream);
 
-extern struct bt_stream *bt_packet_borrow_stream(
-               struct bt_packet *packet);
+extern struct bt_stream *bt_packet_borrow_stream(struct bt_packet *packet);
 
 /**
 @brief Returns the parent CTF IR stream of the CTF IR packet \p packet.
@@ -154,111 +154,16 @@ struct bt_stream *bt_packet_get_stream(
 extern
 struct bt_field *bt_packet_borrow_header(struct bt_packet *packet);
 
-/**
-@brief Returns the trace packet header field of the CTF IR packet
-       \p packet.
-
-@param[in] packet      Packet of which to get the trace packet header
-                       field.
-@returns               Trace packet header field of \p packet,
-                       or \c NULL if the trace packet header
-                       field is not set or on error.
-
-@prenotnull{packet}
-@postrefcountsame{packet}
-@postsuccessrefcountretinc
-
-@sa bt_packet_set_header(): Sets the trace packet header
-       field of a given packet.
-*/
-static inline
-struct bt_field *bt_packet_get_header(struct bt_packet *packet)
-{
-       return bt_get(bt_packet_borrow_header(packet));
-}
-
-/**
-@brief Sets the trace packet header field of the CTF IR packet \p packet to
-       \p header, or unsets the current trace packet header field from
-       \p packet.
-
-If \p header is not \c NULL, the field type of \p header, as returned by
-bt_field_get_type(), \em must be equivalent to the field type returned by
-bt_trace_get_packet_header_type() for the parent trace class of
-\p packet.
-
-@param[in] packet      Packet of which to set the trace packet header field.
-@param[in] header      Trace packet header field.
-@returns               0 on success, or a negative value on error.
-
-@prenotnull{packet}
-@prehot{packet}
-@pre <strong>\p header, if not \c NULL</strong>, has a field type equivalent to
-       the field type returned by bt_trace_get_packet_header_type() for the
-       parent trace class of \p packet.
-@postrefcountsame{event}
-@post <strong>On success, if \p header is not \c NULL</strong>, the reference
-       count of \p header is incremented.
-
-@sa bt_packet_get_header(): Returns the trace packet header field of a given
-       packet.
-*/
-extern int bt_packet_set_header(struct bt_packet *packet,
-               struct bt_field *header);
-
-extern struct bt_field *bt_packet_borrow_context(
-               struct bt_packet *packet);
-
-/**
-@brief Returns the stream packet context field of the CTF IR packet
-       \p packet.
-
-@param[in] packet      Packet of which to get the stream packet context
-                       field.
-@returns               Stream packet context field of \p packet,
-                       or \c NULL if the stream packet context
-                       field is not set or on error.
-
-@prenotnull{packet}
-@postrefcountsame{packet}
-@postsuccessrefcountretinc
-
-@sa bt_packet_set_context(): Sets the stream packet context
-       field of a given packet.
-*/
-static inline
-struct bt_field *bt_packet_get_context(struct bt_packet *packet)
-{
-       return bt_get(bt_packet_borrow_context(packet));
-}
-
-/**
-@brief Sets the stream packet context field of the CTF IR packet \p packet to
-       \p context, or unsets the current packet context field from \p packet.
-
-If \p context is not \c NULL, the field type of \p context, as returned by
-bt_field_get_type(), \em must be equivalent to the field type returned by
-bt_stream_class_get_packet_context_type() for the parent stream class of
-\p packet.
-
-@param[in] packet      Packet of which to set the stream packet context field.
-@param[in] context     Stream packet context field.
-@returns               0 on success, or a negative value on error.
+extern
+int bt_packet_move_header(struct bt_packet *packet,
+               struct bt_packet_header_field *header);
 
-@prenotnull{packet}
-@prehot{packet}
-@pre <strong>\p context, if not \c NULL</strong>, has a field type equivalent to
-       the field type returned by bt_stream_class_get_packet_context_type()
-       for the parent stream class of \p packet.
-@postrefcountsame{packet}
-@post <strong>On success, if \p context is not \c NULL</strong>, the reference
-       count of \p context is incremented.
+extern
+struct bt_field *bt_packet_borrow_context(struct bt_packet *packet);
 
-@sa bt_packet_get_context(): Returns the stream packet context field of a
-       given packet.
-*/
-extern int bt_packet_set_context(
-               struct bt_packet *packet, struct bt_field *context);
+extern
+int bt_packet_move_context(struct bt_packet *packet,
+               struct bt_packet_context_field *context);
 
 /** @} */
 
index 9968fc54076f06f0c1e2a9e4cd59336116c9baa5..373e997599b063837561589ee9d0736deaa3e6e5 100644 (file)
@@ -34,6 +34,7 @@
 #include <babeltrace/ctf-ir/utils-internal.h>
 #include <babeltrace/ctf-ir/visitor.h>
 #include <babeltrace/object-internal.h>
+#include <babeltrace/object-pool-internal.h>
 #include <babeltrace/babeltrace-internal.h>
 #include <glib.h>
 #include <inttypes.h>
@@ -84,6 +85,12 @@ struct bt_stream_class_common {
 
 struct bt_stream_class {
        struct bt_stream_class_common common;
+
+       /* Pool of `struct bt_field_wrapper *` */
+       struct bt_object_pool event_header_field_pool;
+
+       /* Pool of `struct bt_field_wrapper *` */
+       struct bt_object_pool packet_context_field_pool;
 };
 
 struct bt_event_class_common;
index c34d3315a7d43d98d0db2972c1ab41abc27495ae..225ea45079a28c4d023194975ea9acc39adb56db 100644 (file)
@@ -142,6 +142,8 @@ except for:
 struct bt_stream_class;
 struct bt_event_class;
 struct bt_clock;
+struct bt_event_header_field;
+struct bt_packet_context_field;
 
 /**
 @name Creation and parent access functions
@@ -339,6 +341,10 @@ struct bt_field_type *bt_stream_class_get_packet_context_field_type(
                stream_class));
 }
 
+extern
+struct bt_packet_context_field *bt_stream_class_create_packet_context_field(
+               struct bt_stream_class *stream_class);
+
 /**
 @brief Sets the packet context field type of the CTF IR stream class
        \p stream_class to \p packet_context_type, or unsets the current packet
@@ -435,6 +441,9 @@ extern int bt_stream_class_set_event_header_field_type(
                struct bt_stream_class *stream_class,
                struct bt_field_type *event_header_type);
 
+extern struct bt_event_header_field *bt_stream_class_create_event_header_field(
+               struct bt_stream_class *stream_class);
+
 extern struct bt_field_type *
 bt_stream_class_borrow_event_context_field_type(
                struct bt_stream_class *stream_class);
index 78c16c1d6cb4f34df3c0e72a70eeac5b62c61c4d..245fd7816c714e2c1b63f454763b8a3f02e0361a 100644 (file)
@@ -32,6 +32,7 @@
 #include <babeltrace/ctf-ir/stream.h>
 #include <babeltrace/ctf-ir/utils-internal.h>
 #include <babeltrace/object-internal.h>
+#include <babeltrace/object-pool-internal.h>
 #include <babeltrace/babeltrace-internal.h>
 #include <glib.h>
 
@@ -58,6 +59,9 @@ struct bt_stream_common {
 
 struct bt_stream {
        struct bt_stream_common common;
+
+       /* Pool of `struct bt_packet *` */
+       struct bt_object_pool packet_pool;
 };
 
 BT_HIDDEN
index f2ca55c13ff6e992ed47f245f79c06085ea7ffaf..3d7a47f6e265b6d95ab658407914147ed557b046 100644 (file)
@@ -36,6 +36,7 @@
 #include <babeltrace/ctf-ir/attributes-internal.h>
 #include <babeltrace/ctf-ir/clock-class-internal.h>
 #include <babeltrace/object-internal.h>
+#include <babeltrace/object-pool-internal.h>
 #include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/values.h>
 #include <babeltrace/types.h>
@@ -70,6 +71,9 @@ struct bt_trace {
        GArray *is_static_listeners;
        bt_bool is_static;
        bt_bool in_remove_listener;
+
+       /* Pool of `struct bt_field_wrapper *` */
+       struct bt_object_pool packet_header_field_pool;
 };
 
 BT_HIDDEN
index e855e636fa1d8f1f9e8c065e132fc13f3304f0c4..949672266188b879f6faabe658d82c1890312a8b 100644 (file)
@@ -44,9 +44,6 @@
 extern "C" {
 #endif
 
-struct bt_field_type;
-struct bt_value;
-
 /**
 @defgroup ctfirtraceclass CTF IR trace class
 @ingroup ctfir
@@ -152,6 +149,9 @@ struct bt_trace;
 struct bt_stream;
 struct bt_stream_class;
 struct bt_clock_class;
+struct bt_field_type;
+struct bt_value;
+struct bt_packet_header_field;
 
 /**
 @brief User function type to use with
@@ -588,6 +588,9 @@ struct bt_field_type *bt_trace_get_packet_header_field_type(
        return bt_get(bt_trace_borrow_packet_header_field_type(trace_class));
 }
 
+extern struct bt_packet_header_field *bt_trace_create_packet_header_field(
+               struct bt_trace *trace);
+
 /**
 @brief Sets the packet header field type of the CTF IR trace class
        \p trace_class to \p packet_header_type, or unsets the current packet
index 47e1fd0e4eaff6e39526daecbf2542e578c9da43..d0e97471da456368ff59c773b2e0d43f41dab434 100644 (file)
 #include <stdint.h>
 #include <stddef.h>
 
-/* For bt_bool */
 #include <babeltrace/babeltrace.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-writer/fields.h>
 #include <babeltrace/ctf-writer/serialize-internal.h>
 
+struct bt_ctf_field_enumeration {
+       struct bt_field_common common;
+       struct bt_field_common_integer *container;
+};
+
+struct bt_ctf_field_variant {
+       struct bt_field_common_variant common;
+       struct bt_ctf_field_enumeration *tag;
+};
+
 BT_HIDDEN
 int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
                struct bt_ctf_stream_pos *pos,
                enum bt_ctf_byte_order native_byte_order);
 
+BT_HIDDEN
+int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field,
+               const char *name, struct bt_ctf_field *value);
+
+BT_HIDDEN
+struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container(
+               struct bt_ctf_field *field);
+
 static inline
 bt_bool bt_ctf_field_is_set_recursive(struct bt_ctf_field *field)
 {
index b00a7374d3ce2521e8ad5bd9bf1341850d17cd19..ceee0e3838426c235ccde3df09ceae04cc4e5fb4 100644 (file)
@@ -94,9 +94,6 @@ extern int bt_ctf_field_floating_point_set_value(
 extern struct bt_ctf_field *bt_ctf_field_enumeration_get_container(
                struct bt_ctf_field *enum_field);
 
-extern struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_enumeration_get_mappings(struct bt_ctf_field *enum_field);
-
 extern const char *bt_ctf_field_string_get_value(
                struct bt_ctf_field *string_field);
 
@@ -124,19 +121,12 @@ struct bt_ctf_field *bt_ctf_field_structure_get_field(
 extern struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index(
                struct bt_ctf_field *struct_field, uint64_t index);
 
-extern int bt_ctf_field_structure_set_field_by_name(
-               struct bt_ctf_field *struct_field,
-               const char *name, struct bt_ctf_field *field);
-
 extern struct bt_ctf_field *bt_ctf_field_array_get_field(
                struct bt_ctf_field *array_field, uint64_t index);
 
 extern struct bt_ctf_field *bt_ctf_field_sequence_get_field(
                struct bt_ctf_field *sequence_field, uint64_t index);
 
-extern struct bt_ctf_field *bt_ctf_field_sequence_get_length(
-               struct bt_ctf_field *sequence_field);
-
 extern int bt_ctf_field_sequence_set_length(struct bt_ctf_field *sequence_field,
                struct bt_ctf_field *length_field);
 
@@ -147,9 +137,6 @@ extern struct bt_ctf_field *bt_ctf_field_variant_get_field(
 extern struct bt_ctf_field *bt_ctf_field_variant_get_current_field(
                struct bt_ctf_field *variant_field);
 
-extern struct bt_ctf_field *bt_ctf_field_variant_get_tag(
-               struct bt_ctf_field *variant_field);
-
 #ifdef __cplusplus
 }
 #endif
index 1df54eb2a6a098bee40b265cf0b94a06b745f524..d6614fb6ad5dec10b0dc196c77e311281094974c 100644 (file)
@@ -36,38 +36,17 @@ extern "C" {
 
 struct bt_notification;
 struct bt_event;
+struct bt_event_class;
 struct bt_clock_class_priority_map;
 
-/**
- * Create an event notification.
- *
- * @param event                        The event
- * @returns                    An event notification instance
- *
- * @see #bt_notification_type
- */
 extern struct bt_notification *bt_notification_event_create(
-               struct bt_event *event,
+               struct bt_event_class *event_class,
+               struct bt_packet *packet,
                struct bt_clock_class_priority_map *clock_class_priority_map);
 
 extern struct bt_event *bt_notification_event_borrow_event(
                struct bt_notification *notification);
 
-/**
- * Get an event notification's event.
- *
- * @param notification Event notification instance
- * @returns            An event instance
- *
- * @see #bt_event
- */
-static inline
-struct bt_event *bt_notification_event_get_event(
-               struct bt_notification *notification)
-{
-       return bt_get(bt_notification_event_borrow_event(notification));
-}
-
 extern struct bt_clock_class_priority_map *
 bt_notification_event_borrow_clock_class_priority_map(
                struct bt_notification *notification);
index 34099731c2189a68a062893a102c77e834ece99a..93be8b1243c73903feeba34abda7530fb8a9d431 100644 (file)
@@ -55,19 +55,6 @@ extern struct bt_clock_value *bt_notification_inactivity_borrow_clock_value(
                struct bt_notification *notification,
                struct bt_clock_class *clock_class);
 
-static inline
-struct bt_clock_value *bt_notification_inactivity_get_clock_value(
-               struct bt_notification *notification,
-               struct bt_clock_class *clock_class)
-{
-       return bt_get(bt_notification_inactivity_borrow_clock_value(
-               notification, clock_class));
-}
-
-extern int bt_notification_inactivity_set_clock_value(
-               struct bt_notification *notification,
-               struct bt_clock_value *clock_value);
-
 #ifdef __cplusplus
 }
 #endif
index 376be0bc88535e0495eb7832246c627cde17686d..ca893d8ee2661eca16869242aba13aa0dac73610 100644 (file)
@@ -143,6 +143,9 @@ int bt_lib_log_level;
  *   `u`:
  *       Plugin. The parameter type is `struct bt_plugin *`.
  *
+ *   `o`:
+ *       Object pool. The parameter type is `struct bt_object_pool *`.
+ *
  * CTF writer category:
  *   `F`:
  *       CTF writer field type. The parameter type is `struct bt_field_type *`.
index 9d906da1ba093d7faaea5b33d7e9fd7f1d019fda..4efba28e8278f8b721c7f06a45794a307dc61ec9 100644 (file)
  * SOFTWARE.
  */
 
+#include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/ref-internal.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/assert-internal.h>
+#include <stdbool.h>
 
 /**
  * All objects publicly exposed by Babeltrace APIs must contain this structure
@@ -45,6 +47,12 @@ struct bt_object {
        bt_object_release_func parent_is_owner_listener;
        /* @see doc/ref-counting.md */
        struct bt_object *parent;
+
+       /*
+        * True if this object is shared, that is, it uses reference
+        * counting. Only used in developer mode.
+        */
+       bool is_shared;
 };
 
 static inline
@@ -138,6 +146,18 @@ void bt_object_set_parent(void *child_ptr, void *parent)
        child->parent = bt_get(parent);
 }
 
+#ifdef BT_DEV_MODE
+static inline
+void _bt_object_set_is_shared(struct bt_object *obj, bool is_shared)
+{
+       obj->is_shared = is_shared;
+}
+
+# define bt_object_set_is_shared       _bt_object_set_is_shared
+#else
+# define bt_object_set_is_shared(_obj, _is_shared)
+#endif
+
 static inline
 void bt_object_init(void *ptr, bt_object_release_func release)
 {
@@ -145,6 +165,7 @@ void bt_object_init(void *ptr, bt_object_release_func release)
 
        obj->release = release;
        obj->parent = NULL;
+       bt_object_set_is_shared(obj, true);
        bt_ref_init(&obj->ref_count, generic_release);
 }
 
diff --git a/include/babeltrace/object-pool-internal.h b/include/babeltrace/object-pool-internal.h
new file mode 100644 (file)
index 0000000..fc9d8c0
--- /dev/null
@@ -0,0 +1,182 @@
+#ifndef BABELTRACE_OBJECT_POOL_INTERNAL_H
+#define BABELTRACE_OBJECT_POOL_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This is a generic object pool to avoid memory allocation/deallocation
+ * for objects of which the lifespan is typically short, but which are
+ * created a lot.
+ *
+ * The object pool, thanks to two user functions, knows how to allocate
+ * a brand new object in memory when the pool is empty and how to
+ * destroy an object when we destroy the pool.
+ *
+ * The object pool's user is responsible for:
+ *
+ * * Setting whatever references the object needs to keep and reset some
+ *   properties _after_ calling bt_object_pool_create_object(). This is
+ *   typically done in the bt_*_create() function which calls
+ *   bt_object_pool_create_object() (which could call the user-provided
+ *   allocation function if the pool is empty) and then sets the
+ *   appropriate properties on the possibly recycled object.
+ *
+ * * Releasing whatever references the object keeps _before_ calling
+ *   bt_object_pool_recycle_object(). This is typically done in a custom
+ *   bt_*_recycle() function which does the necessary before calling
+ *   bt_object_pool_recycle_object() with an object ready to be reused
+ *   at any time.
+ */
+
+#include <glib.h>
+#include <babeltrace/object-internal.h>
+
+typedef void *(*bt_object_pool_new_object_func)(void *data);
+typedef void *(*bt_object_pool_destroy_object_func)(void *obj, void *data);
+
+struct bt_object_pool {
+       /*
+        * Container of recycled objects, owned by this. The array's size
+        * is the pool's capacity.
+        */
+       GPtrArray *objects;
+
+       /*
+        * Pool's size, that is, number of elements in the array above,
+        * starting at index 0, which exist as recycled objects.
+        */
+       size_t size;
+
+       /* User functions */
+       struct {
+               /* Allocate a new object in memory */
+               bt_object_pool_new_object_func new_object;
+
+               /* Free direct and indirect memory occupied by object */
+               bt_object_pool_destroy_object_func destroy_object;
+       } funcs;
+
+       /* User data passed to user functions */
+       void *data;
+};
+
+/*
+ * Initializes an object pool which is already allocated.
+ */
+int bt_object_pool_initialize(struct bt_object_pool *pool,
+               bt_object_pool_new_object_func new_object_func,
+               bt_object_pool_destroy_object_func destroy_object_func,
+               void *data);
+
+/*
+ * Finalizes an object pool without deallocating it.
+ */
+void bt_object_pool_finalize(struct bt_object_pool *pool);
+
+/*
+ * Creates an object from an object pool. If the pool is empty, this
+ * function calls the "new" user function to allocate a new object
+ * before returning it. Otherwise this function returns a recycled
+ * object, removing it from the pool.
+ *
+ * The returned object is owned by the caller.
+ */
+static inline
+void *bt_object_pool_create_object(struct bt_object_pool *pool)
+{
+       struct bt_object *obj;
+
+       BT_ASSERT(pool);
+
+#ifdef BT_LOGV
+       BT_LOGV("Creating object from pool: pool-addr=%p, pool-size=%zu, pool-cap=%u",
+               pool, pool->size, pool->objects->len);
+#endif
+
+       if (pool->size > 0) {
+               /* Pick one from the pool */
+               pool->size--;
+               obj = pool->objects->pdata[pool->size];
+               pool->objects->pdata[pool->size] = NULL;
+
+               if (obj->is_shared) {
+                       /* Object is shared: reset reference count to 1 */
+                       obj->ref_count.count = 1;
+               }
+               goto end;
+       }
+
+       /* Pool is empty: create a brand new object */
+#ifdef BT_LOGV
+       BT_LOGV("Pool is empty: allocating new object: pool-addr=%p",
+               pool);
+#endif
+
+       obj = pool->funcs.new_object(pool->data);
+
+end:
+#ifdef BT_LOGV
+       BT_LOGV("Created one object from pool: pool-addr=%p, obj-addr=%p",
+               pool, obj);
+#endif
+
+       return obj;
+}
+
+/*
+ * Recycles an object, that is, puts it back into the pool.
+ *
+ * The pool becomes the sole owner of the object to recycle.
+ */
+static inline
+void bt_object_pool_recycle_object(struct bt_object_pool *pool, void *obj)
+{
+       BT_ASSERT(pool);
+       BT_ASSERT(obj);
+
+#ifdef BT_LOGV
+       BT_LOGV("Recycling object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
+               pool, pool->size, pool->objects->len, obj);
+#endif
+
+       if (pool->size == pool->objects->len) {
+               /* Backing array is full: make place for recycled object */
+#ifdef BT_LOGV
+               BT_LOGV("Object pool is full: increasing object pool capacity: "
+                       "pool-addr=%p, old-pool-cap=%u, new-pool-cap=%u",
+                       pool, pool->objects->len, pool->objects->len + 1);
+#endif
+               g_ptr_array_set_size(pool->objects, pool->size + 1);
+       }
+
+       pool->objects->pdata[pool->size] = obj;
+       pool->size++;
+
+#ifdef BT_LOGV
+       BT_LOGV("Recycled object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
+               pool, pool->size, pool->objects->len, obj);
+#endif
+}
+
+#endif /* BABELTRACE_OBJECT_POOL_INTERNAL_H */
index 3425ebfbb22ece42a5b5173ffc9b141cee5caa11..121279a2b57b0a37f87bc73e3d70dacba3b46ade 100644 (file)
@@ -2,7 +2,13 @@ SUBDIRS = ctf-ir ctf-writer prio_heap plugin graph .
 
 lib_LTLIBRARIES = libbabeltrace.la libbabeltrace-ctf.la
 
-libbabeltrace_la_SOURCES = babeltrace.c values.c ref.c lib-logging.c logging.c
+libbabeltrace_la_SOURCES = \
+       babeltrace.c \
+       values.c \
+       ref.c \
+       lib-logging.c \
+       logging.c \
+       object-pool.c
 libbabeltrace_la_LDFLAGS = $(LT_NO_UNDEFINED) \
                        -version-info $(BABELTRACE_LIBRARY_VERSION)
 
index 852cb5a46b19d302ff8acc7b9029621b451ea4f9..56075a80e8ecfc56168c96b9b18a6a0cbf7fa536 100644 (file)
@@ -5,10 +5,14 @@ libctf_ir_la_SOURCES = \
        clock-class.c \
        event.c \
        event-class.c \
+       event-header-field.c \
+       field-wrapper.c \
        fields.c \
        field-types.c \
        field-path.c \
        packet.c \
+       packet-context-field.c \
+       packet-header-field.c \
        stream.c \
        stream-class.c \
        trace.c \
index 316364b9000d207b0fb750cb8222942f58e28ab5..a4fd6ed626570712f3451f9f0a73236444d3df04 100644 (file)
@@ -29,6 +29,7 @@
 #define BT_LOG_TAG "CLOCK-CLASS"
 #include <babeltrace/lib-logging-internal.h>
 
+#include <babeltrace/assert-pre-internal.h>
 #include <babeltrace/compat/uuid-internal.h>
 #include <babeltrace/ctf-ir/clock-class-internal.h>
 #include <babeltrace/ctf-ir/clock-value-internal.h>
 static
 void bt_clock_class_destroy(struct bt_object *obj);
 
+static
+struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class);
+
+static
+void bt_clock_value_destroy(struct bt_clock_value *clock_value);
+
 BT_HIDDEN
 bt_bool bt_clock_class_is_valid(struct bt_clock_class *clock_class)
 {
@@ -112,6 +119,13 @@ end:
        return is_valid;
 }
 
+static
+void bt_clock_class_free_clock_value(struct bt_clock_value *clock_value,
+               struct bt_clock_class *clock_class)
+{
+       bt_clock_value_destroy(clock_value);
+}
+
 struct bt_clock_class *bt_clock_class_create(const char *name,
                uint64_t freq)
 {
@@ -144,6 +158,17 @@ struct bt_clock_class *bt_clock_class_create(const char *name,
                }
        }
 
+       ret = bt_object_pool_initialize(&clock_class->cv_pool,
+               (bt_object_pool_new_object_func) bt_clock_value_new,
+               (bt_object_pool_destroy_object_func)
+                       bt_clock_class_free_clock_value,
+               clock_class);
+       if (ret) {
+               BT_LOGE("Failed to initialize clock value pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
        BT_LOGD("Created clock class object: addr=%p, name=\"%s\"",
                clock_class, name);
        return clock_class;
@@ -506,11 +531,12 @@ end:
        return ret;
 }
 
-static uint64_t ns_from_value(uint64_t frequency, uint64_t value)
+static inline
+uint64_t ns_from_value(uint64_t frequency, uint64_t value)
 {
        uint64_t ns;
 
-       if (frequency == 1000000000) {
+       if (frequency == UINT64_C(1000000000)) {
                ns = value;
        } else {
                double dblres = ((1e9 * (double) value) / (double) frequency);
@@ -546,70 +572,70 @@ void bt_clock_class_destroy(struct bt_object *obj)
        clock_class = container_of(obj, struct bt_clock_class, base);
        BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"",
                obj, bt_clock_class_get_name(clock_class));
+
        if (clock_class->name) {
                g_string_free(clock_class->name, TRUE);
        }
+
        if (clock_class->description) {
                g_string_free(clock_class->description, TRUE);
        }
 
+       bt_object_pool_finalize(&clock_class->cv_pool);
        g_free(clock_class);
 }
 
 static
-void bt_clock_value_destroy(struct bt_object *obj)
+void bt_clock_value_destroy(struct bt_clock_value *clock_value)
 {
-       struct bt_clock_value *value;
-
-       if (!obj) {
-               return;
-       }
-
-       value = container_of(obj, struct bt_clock_value, base);
        BT_LOGD("Destroying clock value: addr=%p, clock-class-addr=%p, "
-               "clock-class-name=\"%s\"", obj, value->clock_class,
-               bt_clock_class_get_name(value->clock_class));
-       bt_put(value->clock_class);
-       g_free(value);
+               "clock-class-name=\"%s\"", clock_value,
+               clock_value->clock_class,
+               bt_clock_class_get_name(clock_value->clock_class));
+       bt_put(clock_value->clock_class);
+       g_free(clock_value);
 }
 
-static
-void set_ns_from_epoch(struct bt_clock_value *clock_value)
+static inline
+int ns_from_epoch(struct bt_clock_class *clock_class, uint64_t value,
+               int64_t *ns_from_epoch, bool *overflows)
 {
-       struct bt_clock_class *clock_class = clock_value->clock_class;
+       int ret = 0;
        int64_t diff;
        int64_t s_ns;
        uint64_t u_ns;
        uint64_t cycles;
 
+       *overflows = false;
+
        /* Initialize nanosecond timestamp to clock's offset in seconds */
-       if (clock_class->offset_s <= (INT64_MIN / 1000000000) ||
-                       clock_class->offset_s >= (INT64_MAX / 1000000000)) {
+       if (clock_class->offset_s <= (INT64_MIN / INT64_C(1000000000)) ||
+                       clock_class->offset_s >= (INT64_MAX / INT64_C(1000000000))) {
                /*
                 * Overflow: offset in seconds converted to nanoseconds
                 * is outside the int64_t range.
                 */
-               clock_value->ns_from_epoch_overflows = true;
+               *overflows = true;
                goto end;
        }
 
-       clock_value->ns_from_epoch = clock_class->offset_s * (int64_t) 1000000000;
+       *ns_from_epoch = clock_class->offset_s * INT64_C(1000000000);
 
        /* Add offset in cycles */
        if (clock_class->offset < 0) {
-               cycles = (uint64_t) (-clock_class->offset);
+               cycles = (uint64_t) -clock_class->offset;
        } else {
                cycles = (uint64_t) clock_class->offset;
        }
 
        u_ns = ns_from_value(clock_class->frequency, cycles);
 
-       if (u_ns == -1ULL || u_ns >= INT64_MAX) {
+       if (u_ns == UINT64_C(-1) || u_ns >= INT64_MAX) {
                /*
                 * Overflow: offset in cycles converted to nanoseconds
                 * is outside the int64_t range.
                 */
-               clock_value->ns_from_epoch_overflows = true;
+               *overflows = true;
                goto end;
        }
 
@@ -617,7 +643,7 @@ void set_ns_from_epoch(struct bt_clock_value *clock_value)
        BT_ASSERT(s_ns >= 0);
 
        if (clock_class->offset < 0) {
-               if (clock_value->ns_from_epoch >= 0) {
+               if (*ns_from_epoch >= 0) {
                        /*
                         * Offset in cycles is negative so it must also
                         * be negative once converted to nanoseconds.
@@ -626,7 +652,7 @@ void set_ns_from_epoch(struct bt_clock_value *clock_value)
                        goto offset_ok;
                }
 
-               diff = clock_value->ns_from_epoch - INT64_MIN;
+               diff = *ns_from_epoch - INT64_MIN;
 
                if (s_ns >= diff) {
                        /*
@@ -634,7 +660,7 @@ void set_ns_from_epoch(struct bt_clock_value *clock_value)
                         * plus the offset in cycles converted to
                         * nanoseconds is outside the int64_t range.
                         */
-                       clock_value->ns_from_epoch_overflows = true;
+                       *overflows = true;
                        goto end;
                }
 
@@ -644,11 +670,11 @@ void set_ns_from_epoch(struct bt_clock_value *clock_value)
                 */
                s_ns = -s_ns;
        } else {
-               if (clock_value->ns_from_epoch <= 0) {
+               if (*ns_from_epoch <= 0) {
                        goto offset_ok;
                }
 
-               diff = INT64_MAX - clock_value->ns_from_epoch;
+               diff = INT64_MAX - *ns_from_epoch;
 
                if (s_ns >= diff) {
                        /*
@@ -656,23 +682,23 @@ void set_ns_from_epoch(struct bt_clock_value *clock_value)
                         * plus the offset in cycles converted to
                         * nanoseconds is outside the int64_t range.
                         */
-                       clock_value->ns_from_epoch_overflows = true;
+                       *overflows = true;
                        goto end;
                }
        }
 
 offset_ok:
-       clock_value->ns_from_epoch += s_ns;
+       *ns_from_epoch += s_ns;
 
        /* Add clock value (cycles) */
-       u_ns = ns_from_value(clock_class->frequency, clock_value->value);
+       u_ns = ns_from_value(clock_class->frequency, value);
 
        if (u_ns == -1ULL || u_ns >= INT64_MAX) {
                /*
                 * Overflow: value converted to nanoseconds is outside
                 * the int64_t range.
                 */
-               clock_value->ns_from_epoch_overflows = true;
+               *overflows = true;
                goto end;
        }
 
@@ -680,11 +706,11 @@ offset_ok:
        BT_ASSERT(s_ns >= 0);
 
        /* Clock value (cycles) is always positive */
-       if (clock_value->ns_from_epoch <= 0) {
+       if (*ns_from_epoch <= 0) {
                goto value_ok;
        }
 
-       diff = INT64_MAX - clock_value->ns_from_epoch;
+       diff = INT64_MAX - *ns_from_epoch;
 
        if (s_ns >= diff) {
                /*
@@ -692,27 +718,38 @@ offset_ok:
                 * clock value converted to nanoseconds is outside the
                 * int64_t range.
                 */
-               clock_value->ns_from_epoch_overflows = true;
+               *overflows = true;
                goto end;
        }
 
 value_ok:
-       clock_value->ns_from_epoch += s_ns;
+       *ns_from_epoch += s_ns;
 
 end:
-       if (clock_value->ns_from_epoch_overflows) {
-               clock_value->ns_from_epoch = 0;
+       if (*overflows) {
+               *ns_from_epoch = 0;
+               ret = -1;
        }
+
+       return ret;
 }
 
-struct bt_clock_value *bt_clock_value_create(
-               struct bt_clock_class *clock_class, uint64_t value)
+static
+void set_ns_from_epoch(struct bt_clock_value *clock_value)
+{
+       (void) ns_from_epoch(clock_value->clock_class,
+               clock_value->value, &clock_value->ns_from_epoch,
+               &clock_value->ns_from_epoch_overflows);
+}
+
+static
+struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class)
 {
        struct bt_clock_value *ret = NULL;
 
        BT_LOGD("Creating clock value object: clock-class-addr=%p, "
-               "clock-class-name=\"%s\", value=%" PRIu64, clock_class,
-               bt_clock_class_get_name(clock_class), value);
+               "clock-class-name=\"%s\"", clock_class,
+               bt_clock_class_get_name(clock_class));
 
        if (!clock_class) {
                BT_LOGW_STR("Invalid parameter: clock class is NULL.");
@@ -725,10 +762,9 @@ struct bt_clock_value *bt_clock_value_create(
                goto end;
        }
 
-       bt_object_init(ret, bt_clock_value_destroy);
+       bt_object_init(ret, NULL);
+       bt_object_set_is_shared((void *) ret, false);
        ret->clock_class = bt_get(clock_class);
-       ret->value = value;
-       set_ns_from_epoch(ret);
        bt_clock_class_freeze(clock_class);
        BT_LOGD("Created clock value object: clock-value-addr=%p, "
                "clock-class-addr=%p, clock-class-name=\"%s\", "
@@ -740,8 +776,95 @@ end:
        return ret;
 }
 
-int bt_clock_value_get_value(
-               struct bt_clock_value *clock_value, uint64_t *raw_value)
+BT_HIDDEN
+struct bt_clock_value *bt_clock_value_create(struct bt_clock_class *clock_class)
+{
+       struct bt_clock_value *clock_value = NULL;
+
+       BT_ASSERT(clock_class);
+       clock_value = bt_object_pool_create_object(&clock_class->cv_pool);
+       if (!clock_value) {
+               BT_LIB_LOGE("Cannot allocate one clock value from clock class's clock value pool: "
+                       "%![cc-]+K", clock_class);
+               goto error;
+       }
+
+       if (!clock_value->clock_class) {
+               clock_value->clock_class = bt_get(clock_class);
+       }
+
+       goto end;
+
+error:
+       if (clock_value) {
+               bt_clock_value_recycle(clock_value);
+               clock_value = NULL;
+       }
+
+end:
+       return clock_value;
+}
+
+BT_HIDDEN
+void bt_clock_value_recycle(struct bt_clock_value *clock_value)
+{
+       struct bt_clock_class *clock_class;
+
+       BT_ASSERT(clock_value);
+       BT_LIB_LOGD("Recycling clock value: %!+k", clock_value);
+
+       /*
+        * Those are the important ordered steps:
+        *
+        * 1. Reset the clock value object, but do NOT put its clock
+        *    class's reference. This clock class contains the pool to
+        *    which we're about to recycle this clock value object, so
+        *    we must guarantee its existence thanks to this existing
+        *    reference.
+        *
+        * 2. Move the clock class reference to our `clock_class`
+        *    variable so that we can set the clock value's clock class
+        *    member to NULL before recycling it. We CANNOT do this
+        *    after we put the clock class reference because this
+        *    bt_put() could destroy the clock class, also destroying
+        *    its clock value pool, thus also destroying our clock value
+        *    object (this would result in an invalid write access).
+        *
+        * 3. Recycle the clock value object.
+        *
+        * 4. Put our clock class reference.
+        */
+       bt_clock_value_reset(clock_value);
+       bt_clock_value_set_is_frozen(clock_value, false);
+       clock_class = clock_value->clock_class;
+       BT_ASSERT(clock_class);
+       clock_value->clock_class = NULL;
+       bt_object_pool_recycle_object(&clock_class->cv_pool, clock_value);
+       bt_put(clock_class);
+}
+
+BT_HIDDEN
+void bt_clock_value_set_raw_value(struct bt_clock_value *clock_value,
+               uint64_t cycles)
+{
+       BT_ASSERT(clock_value);
+
+       clock_value->value = cycles;
+       set_ns_from_epoch(clock_value);
+       bt_clock_value_set(clock_value);
+}
+
+int bt_clock_value_set_value(struct bt_clock_value *clock_value,
+               uint64_t raw_value)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
+       BT_ASSERT_PRE_HOT(clock_value, "Clock value", ": %!+k", clock_value);
+       bt_clock_value_set_raw_value(clock_value, raw_value);
+       return 0;
+}
+
+int bt_clock_value_get_value(struct bt_clock_value *clock_value,
+               uint64_t *raw_value)
 {
        int ret = 0;
 
@@ -953,3 +1076,33 @@ int bt_clock_class_compare(struct bt_clock_class *clock_class_a,
 end:
        return ret;
 }
+
+int bt_clock_class_cycles_to_ns(struct bt_clock_class *clock_class,
+               uint64_t cycles, int64_t *ns)
+{
+       int ret;
+       bool overflows;
+
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds");
+
+       ret = ns_from_epoch(clock_class, cycles, ns, &overflows);
+       if (ret) {
+               if (overflows) {
+                       BT_LIB_LOGW("Cannot convert cycles to nanoseconds "
+                               "from Epoch for given clock class: "
+                               "value overflow: %![cc-]+K, cycles=%" PRIu64,
+                               clock_class, cycles);
+               } else {
+                       BT_LIB_LOGW("Cannot convert cycles to nanoseconds "
+                               "from Epoch for given clock class: "
+                               "%![cc-]+K, cycles=%" PRIu64,
+                               clock_class, cycles);
+               }
+
+               goto end;
+       }
+
+end:
+       return ret;
+}
index 79cd123eac2362c490382551ffc35be07cdab81b..57402e3474133bc5e712af3bbcd5564adb952c5a 100644 (file)
 #include <babeltrace/lib-logging-internal.h>
 
 #include <babeltrace/assert-pre-internal.h>
+#include <babeltrace/ctf-ir/clock-value-internal.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-ir/field-types-internal.h>
 #include <babeltrace/ctf-ir/event-class.h>
 #include <babeltrace/ctf-ir/event-class-internal.h>
+#include <babeltrace/ctf-ir/event-internal.h>
 #include <babeltrace/ctf-ir/stream-class.h>
 #include <babeltrace/ctf-ir/stream-class-internal.h>
 #include <babeltrace/ctf-ir/trace-internal.h>
@@ -116,11 +118,21 @@ error:
 static
 void bt_event_class_destroy(struct bt_object *obj)
 {
+       struct bt_event_class *event_class = (void *) obj;
+
        BT_LOGD("Destroying event class: addr=%p", obj);
        bt_event_class_common_finalize(obj);
+       bt_object_pool_finalize(&event_class->event_pool);
        g_free(obj);
 }
 
+static
+void free_event(struct bt_event *event,
+               struct bt_event_class *event_class)
+{
+       bt_event_destroy(event);
+}
+
 struct bt_event_class *bt_event_class_create(const char *name)
 {
        int ret;
@@ -147,6 +159,16 @@ struct bt_event_class *bt_event_class_create(const char *name)
                goto error;
        }
 
+       ret = bt_object_pool_initialize(&event_class->event_pool,
+               (bt_object_pool_new_object_func) bt_event_new,
+               (bt_object_pool_destroy_object_func) free_event,
+               event_class);
+       if (ret) {
+               BT_LOGE("Failed to initialize event pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
        BT_LOGD("Created event class object: addr=%p, name=\"%s\"",
                event_class, bt_event_class_get_name(event_class));
        goto end;
@@ -303,3 +325,43 @@ int bt_event_class_common_validate_single_clock_class(
 end:
        return ret;
 }
+
+BT_HIDDEN
+int bt_event_class_update_event_pool_clock_values(
+               struct bt_event_class *event_class)
+{
+       int ret = 0;
+       uint64_t i;
+       struct bt_stream_class *stream_class =
+               bt_event_class_borrow_stream_class(event_class);
+
+       BT_ASSERT(stream_class->common.clock_class);
+
+       for (i = 0; i < event_class->event_pool.size; i++) {
+               struct bt_clock_value *cv;
+               struct bt_event *event =
+                       event_class->event_pool.objects->pdata[i];
+
+               BT_ASSERT(event);
+
+               cv = g_hash_table_lookup(event->clock_values,
+                       stream_class->common.clock_class);
+               if (cv) {
+                       continue;
+               }
+
+               cv = bt_clock_value_create(stream_class->common.clock_class);
+               if (!cv) {
+                       BT_LIB_LOGE("Cannot create clock value from clock class: "
+                               "%![cc-]+K", stream_class->common.clock_class);
+                       ret = -1;
+                       goto end;
+               }
+
+               g_hash_table_insert(event->clock_values,
+                       stream_class->common.clock_class, cv);
+       }
+
+end:
+       return ret;
+}
diff --git a/lib/ctf-ir/event-header-field.c b/lib/ctf-ir/event-header-field.c
new file mode 100644 (file)
index 0000000..40c8749
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "EVENT-HEADER-FIELD"
+#include <babeltrace/lib-logging-internal.h>
+
+#include <babeltrace/assert-pre-internal.h>
+#include <babeltrace/ctf-ir/event-header-field.h>
+#include <babeltrace/ctf-ir/fields-internal.h>
+#include <babeltrace/ctf-ir/field-wrapper-internal.h>
+#include <glib.h>
+
+struct bt_field *bt_event_header_field_borrow_field(
+               struct bt_event_header_field *header_field)
+{
+       struct bt_field_wrapper *field_wrapper = (void *) header_field;
+
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Event header field");
+       BT_ASSERT_PRE_NON_NULL(field_wrapper->field,
+               "Event header field's field object");
+       return (void *) field_wrapper->field;
+}
+
+void bt_event_header_field_release(struct bt_event_header_field *header_field)
+{
+       struct bt_field_wrapper *field_wrapper = (void *) header_field;
+
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Event header field");
+
+       /*
+        * Do not recycle because the pool could be destroyed at this
+        * point. This function is only called when there's an error
+        * anyway because the goal of an event header field wrapper is
+        * to eventually move it to an event with bt_event_move_header()
+        * after creating it.
+        */
+       bt_field_wrapper_destroy(field_wrapper);
+}
index 7e1050aee1d04a522224a11452693dd2159cf493..5cfd5e14a124515e8bbcfc943722c71c8b75e005 100644 (file)
@@ -55,9 +55,6 @@
 #include <babeltrace/assert-internal.h>
 #include <inttypes.h>
 
-static
-void bt_event_destroy(struct bt_object *obj);
-
 static
 int bt_event_common_validate_types_for_create(
                struct bt_event_class_common *event_class,
@@ -138,9 +135,13 @@ end:
 
 static
 int bt_event_common_create_fields(
+               struct bt_stream_class_common *stream_class,
                struct bt_validation_output *validation_output,
                void *(*create_field_func)(void *),
-               struct bt_field_common **header_field,
+               void (*release_field_func)(void *),
+               void *(*create_header_field_func)(void *, void *),
+               void (*release_header_field_func)(void *),
+               struct bt_field_wrapper **header_field,
                struct bt_field_common **stream_event_context_field,
                struct bt_field_common **context_field,
                struct bt_field_common **payload_field)
@@ -151,7 +152,8 @@ int bt_event_common_create_fields(
                BT_LOGD("Creating initial event header field: ft-addr=%p",
                        validation_output->event_header_type);
                *header_field =
-                       create_field_func(validation_output->event_header_type);
+                       create_header_field_func(stream_class,
+                               validation_output->event_header_type);
                if (!*header_field) {
                        BT_LOGE_STR("Cannot create initial event header field object.");
                        goto error;
@@ -194,10 +196,22 @@ int bt_event_common_create_fields(
        goto end;
 
 error:
-       BT_PUT(*header_field);
-       BT_PUT(*stream_event_context_field);
-       BT_PUT(*context_field);
-       BT_PUT(*payload_field);
+       if (*header_field) {
+               release_header_field_func(*header_field);
+       }
+
+       if (*stream_event_context_field) {
+               release_field_func(*stream_event_context_field);
+       }
+
+       if (*context_field) {
+               release_field_func(*context_field);
+       }
+
+       if (*payload_field) {
+               release_field_func(*payload_field);
+       }
+
        ret = -1;
 
 end:
@@ -212,11 +226,12 @@ int _bt_event_common_validate(struct bt_event_common *event)
 
        BT_ASSERT(event);
        if (event->header_field) {
-               ret = bt_field_common_validate_recursive(event->header_field);
+               ret = bt_field_common_validate_recursive(
+                       event->header_field->field);
                if (ret) {
                        BT_ASSERT_PRE_MSG("Invalid event's header field: "
                                "%![event-]+_e, %![field-]+_f",
-                               event, event->header_field);
+                               event, event->header_field->field);
                        goto end;
                }
        }
@@ -275,14 +290,29 @@ void _bt_event_common_freeze(struct bt_event_common *event)
                "event-class-name=\"%s\", event-class-id=%" PRId64,
                event, bt_event_class_common_get_name(event->class),
                bt_event_class_common_get_id(event->class));
-       BT_LOGD_STR("Freezing event's header field.");
-       bt_field_common_freeze_recursive(event->header_field);
-       BT_LOGD_STR("Freezing event's stream event context field.");
-       bt_field_common_freeze_recursive(event->stream_event_context_field);
-       BT_LOGD_STR("Freezing event's context field.");
-       bt_field_common_freeze_recursive(event->context_field);
-       BT_LOGD_STR("Freezing event's payload field.");
-       bt_field_common_freeze_recursive(event->payload_field);
+
+       if (event->header_field) {
+               BT_LOGD_STR("Freezing event's header field.");
+               bt_field_common_set_is_frozen_recursive(
+                       event->header_field->field, true);
+       }
+
+       if (event->stream_event_context_field) {
+               BT_LOGD_STR("Freezing event's stream event context field.");
+               bt_field_common_set_is_frozen_recursive(
+                       event->stream_event_context_field, true);
+       }
+
+       if (event->context_field) {
+               BT_LOGD_STR("Freezing event's context field.");
+               bt_field_common_set_is_frozen_recursive(event->context_field, true);
+       }
+
+       if (event->payload_field) {
+               BT_LOGD_STR("Freezing event's payload field.");
+               bt_field_common_set_is_frozen_recursive(event->payload_field, true);
+       }
+
        event->frozen = 1;
 }
 
@@ -296,12 +326,15 @@ int bt_event_common_initialize(struct bt_event_common *event,
                int (*map_clock_classes_func)(struct bt_stream_class_common *stream_class,
                        struct bt_field_type_common *packet_context_field_type,
                        struct bt_field_type_common *event_header_field_type),
-               void *(*create_field_func)(void *))
+               void *(*create_field_func)(void *),
+               void (*release_field_func)(void *),
+               void *(*create_header_field_func)(void *, void *),
+               void (*release_header_field_func)(void *))
 {
        int ret;
        struct bt_trace_common *trace = NULL;
        struct bt_stream_class_common *stream_class = NULL;
-       struct bt_field_common *event_header = NULL;
+       struct bt_field_wrapper *event_header = NULL;
        struct bt_field_common *stream_event_context = NULL;
        struct bt_field_common *event_context = NULL;
        struct bt_field_common *event_payload = NULL;
@@ -399,9 +432,12 @@ int bt_event_common_initialize(struct bt_event_common *event,
         */
        event->class = bt_get(event_class);
 
-       ret = bt_event_common_create_fields(&validation_output,
-               create_field_func, &event_header,
-               &stream_event_context, &event_context, &event_payload);
+       ret = bt_event_common_create_fields(stream_class,
+               &validation_output,
+               create_field_func, release_field_func,
+               create_header_field_func, release_header_field_func,
+               &event_header, &stream_event_context, &event_context,
+               &event_payload);
        if (ret) {
                /* bt_event_common_create_fields() logs errors */
                goto error;
@@ -416,10 +452,14 @@ int bt_event_common_initialize(struct bt_event_common *event,
        bt_validation_replace_types(trace, stream_class, event_class,
                &validation_output,
                BT_VALIDATION_FLAG_STREAM | BT_VALIDATION_FLAG_EVENT);
-       BT_MOVE(event->header_field, event_header);
-       BT_MOVE(event->stream_event_context_field, stream_event_context);
-       BT_MOVE(event->context_field, event_context);
-       BT_MOVE(event->payload_field, event_payload);
+       event->header_field = event_header;
+       event_header = NULL;
+       event->stream_event_context_field = stream_event_context;
+       stream_event_context = NULL;
+       event->context_field = event_context;
+       event_context = NULL;
+       event->payload_field = event_payload;
+       event_payload = NULL;
 
        /*
         * Put what was not moved in bt_validation_replace_types().
@@ -457,20 +497,73 @@ int bt_event_common_initialize(struct bt_event_common *event,
 error:
        bt_validation_output_put_types(&validation_output);
        bt_put(expected_clock_class);
-       bt_put(event_header);
-       bt_put(stream_event_context);
-       bt_put(event_context);
-       bt_put(event_payload);
+
+       if (event_header) {
+               release_header_field_func(event_header);
+       }
+
+       if (stream_event_context) {
+               release_field_func(stream_event_context);
+       }
+
+       if (event_context) {
+               release_field_func(event_context);
+       }
+
+       if (event_payload) {
+               release_field_func(event_payload);
+       }
+
        ret = -1;
 
 end:
        return ret;
 }
 
-struct bt_event *bt_event_create(struct bt_event_class *event_class)
+static
+void bt_event_header_field_recycle(struct bt_field_wrapper *field_wrapper,
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT(field_wrapper);
+       BT_LIB_LOGD("Recycling event header field: "
+               "addr=%p, %![sc-]+S, %![field-]+f", field_wrapper,
+               stream_class, field_wrapper->field);
+       bt_object_pool_recycle_object(
+               &stream_class->event_header_field_pool,
+               field_wrapper);
+}
+
+static
+struct bt_field_wrapper *create_event_header_field(
+               struct bt_stream_class *stream_class,
+               struct bt_field_type_common *ft)
+{
+       struct bt_field_wrapper *field_wrapper = NULL;
+
+       field_wrapper = bt_field_wrapper_create(
+               &stream_class->event_header_field_pool, (void *) ft);
+       if (!field_wrapper) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_event_header_field_recycle(field_wrapper, stream_class);
+               field_wrapper = NULL;
+       }
+
+end:
+       return field_wrapper;
+}
+
+BT_HIDDEN
+struct bt_event *bt_event_new(struct bt_event_class *event_class)
 {
        int ret;
        struct bt_event *event = NULL;
+       struct bt_stream_class *stream_class;
 
        event = g_new0(struct bt_event, 1);
        if (!event) {
@@ -479,21 +572,147 @@ struct bt_event *bt_event_create(struct bt_event_class *event_class)
        }
 
        ret = bt_event_common_initialize(BT_TO_COMMON(event),
-               BT_TO_COMMON(event_class), NULL, bt_event_destroy,
+               BT_TO_COMMON(event_class), NULL, NULL,
                (bt_validation_flag_copy_field_type_func) bt_field_type_copy,
-               true, NULL, (void *) bt_field_create);
+               true, NULL,
+               (void *) bt_field_create_recursive,
+               (void *) bt_field_destroy_recursive,
+               (void *) create_event_header_field,
+               (void *) bt_event_header_field_recycle);
        if (ret) {
                /* bt_event_common_initialize() logs errors */
                goto error;
        }
 
+       bt_object_set_is_shared((void *) event, false);
        event->clock_values = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, NULL, bt_put);
-       assert(event->clock_values);
+                       g_direct_equal, NULL,
+                       (GDestroyNotify) bt_clock_value_recycle);
+       BT_ASSERT(event->clock_values);
+       stream_class = bt_event_class_borrow_stream_class(event_class);
+       BT_ASSERT(stream_class);
+
+       if (stream_class->common.clock_class) {
+               struct bt_clock_value *clock_value;
+
+               clock_value = bt_clock_value_create(
+                       stream_class->common.clock_class);
+               if (!clock_value) {
+                       BT_LIB_LOGE("Cannot create clock value from clock class: "
+                               "%![cc-]+K", stream_class->common.clock_class);
+                       goto error;
+               }
+
+               g_hash_table_insert(event->clock_values,
+                       stream_class->common.clock_class, clock_value);
+       }
+
        goto end;
 
 error:
-       BT_PUT(event);
+       if (event) {
+               bt_event_destroy(event);
+               event = NULL;
+       }
+
+end:
+       return event;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+void _bt_event_reset_dev_mode(struct bt_event *event)
+{
+       GHashTableIter iter;
+       gpointer key, value;
+
+       BT_ASSERT(event);
+
+       if (event->common.header_field) {
+               bt_field_common_set_is_frozen_recursive(
+                       event->common.header_field->field, false);
+               bt_field_common_reset_recursive(
+                       event->common.header_field->field);
+       }
+
+       if (event->common.stream_event_context_field) {
+               bt_field_common_set_is_frozen_recursive(
+                       event->common.stream_event_context_field, false);
+               bt_field_common_reset_recursive(
+                       event->common.stream_event_context_field);
+       }
+
+       if (event->common.context_field) {
+               bt_field_common_set_is_frozen_recursive(
+                       event->common.context_field, false);
+               bt_field_common_reset_recursive(event->common.context_field);
+       }
+
+       if (event->common.payload_field) {
+               bt_field_common_set_is_frozen_recursive(
+                       event->common.payload_field, false);
+               bt_field_common_reset_recursive(event->common.payload_field);
+       }
+
+       g_hash_table_iter_init(&iter, event->clock_values);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               struct bt_clock_value *clock_value = value;
+
+               BT_ASSERT(clock_value);
+               bt_clock_value_reset(clock_value);
+               bt_clock_value_set_is_frozen(clock_value, false);
+       }
+}
+
+#ifdef BT_DEV_MODE
+# define bt_event_reset_dev_mode       _bt_event_reset_dev_mode
+#else
+# define bt_event_reset_dev_mode(_x)
+#endif
+
+static inline
+void bt_event_reset(struct bt_event *event)
+{
+       BT_ASSERT(event);
+       event->common.frozen = false;
+       bt_event_reset_dev_mode(event);
+       BT_PUT(event->packet);
+}
+
+BT_HIDDEN
+struct bt_event *bt_event_create(struct bt_event_class *event_class,
+               struct bt_packet *packet)
+{
+       int ret;
+       struct bt_event *event = NULL;
+
+       BT_ASSERT(event_class);
+       event = bt_object_pool_create_object(&event_class->event_pool);
+       if (!event) {
+               BT_LIB_LOGE("Cannot allocate one event from event class's event pool: "
+                       "%![event-class-]+E", event_class);
+               goto error;
+       }
+
+       if (!event->common.class) {
+               event->common.class = bt_get(event_class);
+       }
+
+       BT_ASSERT(packet);
+       ret = bt_event_set_packet(event, packet);
+       if (ret) {
+               BT_LIB_LOGE("Cannot set event's packet: "
+                       "%![event-]+e, %![packet-]+a", event, packet);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (event) {
+               bt_event_recycle(event);
+               event = NULL;
+       }
 
 end:
        return event;
@@ -518,34 +737,18 @@ struct bt_field *bt_event_borrow_payload(struct bt_event *event)
                bt_event_common_borrow_payload(BT_TO_COMMON(event)));
 }
 
-int bt_event_set_payload(struct bt_event *event, struct bt_field *field)
-{
-       return bt_event_common_set_payload(BT_TO_COMMON(event),
-               (void *) field);
-}
-
 struct bt_field *bt_event_borrow_header(struct bt_event *event)
 {
        return BT_FROM_COMMON(
                bt_event_common_borrow_header(BT_TO_COMMON(event)));
 }
 
-int bt_event_set_header(struct bt_event *event, struct bt_field *field)
-{
-       return bt_event_common_set_header(BT_TO_COMMON(event), (void *) field);
-}
-
 struct bt_field *bt_event_borrow_context(struct bt_event *event)
 {
        return BT_FROM_COMMON(
                bt_event_common_borrow_context(BT_TO_COMMON(event)));
 }
 
-int bt_event_set_context(struct bt_event *event, struct bt_field *field)
-{
-       return bt_event_common_set_context(BT_TO_COMMON(event), (void *) field);
-}
-
 struct bt_field *bt_event_borrow_stream_event_context(
                struct bt_event *event)
 {
@@ -553,18 +756,31 @@ struct bt_field *bt_event_borrow_stream_event_context(
                BT_TO_COMMON(event)));
 }
 
-int bt_event_set_stream_event_context(struct bt_event *event,
-               struct bt_field *field)
+static
+void release_event_header_field(struct bt_field_wrapper *field_wrapper,
+               struct bt_event_common *event_common)
 {
-       return bt_event_common_set_stream_event_context(
-               BT_TO_COMMON(event), (void *) field);
+       struct bt_event *event = BT_FROM_COMMON(event_common);
+       struct bt_event_class *event_class = bt_event_borrow_class(event);
+
+       if (!event_class) {
+               bt_field_wrapper_destroy(field_wrapper);
+       } else {
+               struct bt_stream_class *stream_class =
+                       bt_event_class_borrow_stream_class(event_class);
+
+               BT_ASSERT(stream_class);
+               bt_event_header_field_recycle(field_wrapper, stream_class);
+       }
 }
 
-void bt_event_destroy(struct bt_object *obj)
+BT_HIDDEN
+void bt_event_destroy(struct bt_event *event)
 {
-       struct bt_event *event = (void *) obj;
-
-       bt_event_common_finalize(obj);
+       BT_ASSERT(event);
+       bt_event_common_finalize((void *) event,
+               (void *) bt_field_destroy_recursive,
+               (void *) release_event_header_field);
        g_hash_table_destroy(event->clock_values);
        BT_LOGD_STR("Putting event's packet.");
        bt_put(event->packet);
@@ -594,42 +810,6 @@ end:
        return clock_value;
 }
 
-int bt_event_set_clock_value(struct bt_event *event,
-               struct bt_clock_value *value)
-{
-       struct bt_trace *trace;
-       struct bt_stream_class *stream_class;
-       struct bt_event_class *event_class;
-       struct bt_clock_class *clock_class = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_NON_NULL(value, "Clock value");
-       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_TO_COMMON(event), "Event");
-       clock_class = bt_clock_value_borrow_class(value);
-       event_class = BT_FROM_COMMON(event->common.class);
-       BT_ASSERT(event_class);
-       stream_class = bt_event_class_borrow_stream_class(event_class);
-       BT_ASSERT(stream_class);
-       trace = bt_stream_class_borrow_trace(stream_class);
-       BT_ASSERT(trace);
-       BT_ASSERT_PRE(bt_trace_common_has_clock_class(BT_TO_COMMON(trace),
-               clock_class),
-               "Clock class is not part of event's trace: "
-               "%![event-]+e, %![clock-class-]+K",
-               event, clock_class);
-       g_hash_table_insert(event->clock_values, clock_class, bt_get(value));
-       BT_LOGV("Set event's clock value: "
-               "event-addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64 ", clock-class-addr=%p, "
-               "clock-class-name=\"%s\", clock-value-addr=%p, "
-               "clock-value-cycles=%" PRIu64,
-               event, bt_event_class_common_get_name(event->common.class),
-               bt_event_class_common_get_id(event->common.class),
-               clock_class, bt_clock_class_get_name(clock_class),
-               value, value->value);
-       return 0;
-}
-
 struct bt_packet *bt_event_borrow_packet(struct bt_event *event)
 {
        struct bt_packet *packet = NULL;
@@ -649,8 +829,8 @@ end:
        return packet;
 }
 
-int bt_event_set_packet(struct bt_event *event,
-               struct bt_packet *packet)
+BT_HIDDEN
+int bt_event_set_packet(struct bt_event *event, struct bt_packet *packet)
 {
        BT_ASSERT_PRE_NON_NULL(event, "Event");
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
@@ -691,3 +871,66 @@ void _bt_event_freeze(struct bt_event *event)
        BT_LOGD_STR("Freezing event's packet.");
        bt_packet_freeze(event->packet);
 }
+
+BT_HIDDEN
+void bt_event_recycle(struct bt_event *event)
+{
+       struct bt_event_class *event_class;
+
+       BT_ASSERT(event);
+       BT_LIB_LOGD("Recycling event: %!+e", event);
+
+       /*
+        * Those are the important ordered steps:
+        *
+        * 1. Reset the event object (put any permanent reference it
+        *    has, unfreeze it and its fields in developer mode, etc.),
+        *    but do NOT put its class's reference. This event class
+        *    contains the pool to which we're about to recycle this
+        *    event object, so we must guarantee its existence thanks
+        *    to this existing reference.
+        *
+        * 2. Move the event class reference to our `event_class`
+        *    variable so that we can set the event's class member
+        *    to NULL before recycling it. We CANNOT do this after
+        *    we put the event class reference because this bt_put()
+        *    could destroy the event class, also destroying its
+        *    event pool, thus also destroying our event object (this
+        *    would result in an invalid write access).
+        *
+        * 3. Recycle the event object.
+        *
+        * 4. Put our event class reference.
+        */
+       bt_event_reset(event);
+       event_class = BT_FROM_COMMON(event->common.class);
+       BT_ASSERT(event_class);
+       event->common.class = NULL;
+       bt_object_pool_recycle_object(&event_class->event_pool, event);
+       bt_put(event_class);
+}
+
+int bt_event_move_header(struct bt_event *event,
+               struct bt_event_header_field *header_field)
+{
+       struct bt_stream_class *stream_class;
+       struct bt_field_wrapper *field_wrapper = (void *) header_field;
+
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Header field");
+       BT_ASSERT_PRE_HOT(BT_TO_COMMON(event), "Event", ": +%!+e", event);
+       stream_class = bt_event_class_borrow_stream_class(
+               bt_event_borrow_class(event));
+       BT_ASSERT_PRE(stream_class->common.event_header_field_type,
+               "Stream class has no event header field type: %!+S",
+               stream_class);
+
+       /* Recycle current header field: always exists */
+       BT_ASSERT(event->common.header_field);
+       bt_event_header_field_recycle(event->common.header_field,
+               stream_class);
+
+       /* Move new field */
+       event->common.header_field = (void *) field_wrapper;
+       return 0;
+}
index 084dc74d1f908a975bb1520fab598932cd318640..11764121f76f6274996148d20ad4284f59be005a 100644 (file)
@@ -157,21 +157,6 @@ void destroy_enumeration_mapping(struct enumeration_mapping *mapping)
        g_free(mapping);
 }
 
-static
-void destroy_structure_field_common(struct structure_field_common *field)
-{
-       if (!field) {
-               return;
-       }
-
-       BT_LOGD("Destroying structure/variant field type's field object: "
-               "addr=%p, field-ft-addr=%p, field-name=\"%s\"",
-               field, field->type, g_quark_to_string(field->name));
-       BT_LOGD_STR("Putting field type.");
-       bt_put(field->type);
-       g_free(field);
-}
-
 BT_HIDDEN
 void bt_field_type_common_initialize(struct bt_field_type_common *ft,
                bool init_bo, bt_object_release_func release_func,
@@ -282,8 +267,8 @@ void bt_field_type_common_structure_initialize(
 
        BT_LOGD_STR("Initializing common structure field type object.");
        ft->id = BT_FIELD_TYPE_ID_STRUCT;
-       struct_ft->fields = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) destroy_structure_field_common);
+       struct_ft->fields = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_field_type_common_structure_field));
        struct_ft->field_name_to_index = g_hash_table_new(NULL, NULL);
        bt_field_type_common_initialize(ft, true, release_func, methods);
        BT_LOGD("Initialized common structure field type object: addr=%p", ft);
@@ -349,9 +334,9 @@ void bt_field_type_common_variant_initialize(
                tag_ft, tag_name);
        ft->id = BT_FIELD_TYPE_ID_VARIANT;
        var_ft->tag_name = g_string_new(tag_name);
-       var_ft->field_name_to_index = g_hash_table_new(NULL, NULL);
-       var_ft->fields = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) destroy_structure_field_common);
+       var_ft->choice_name_to_index = g_hash_table_new(NULL, NULL);
+       var_ft->choices = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_field_type_common_variant_choice));
 
        if (tag_ft) {
                var_ft->tag_ft = bt_get(tag_ft);
@@ -422,19 +407,47 @@ void bt_field_type_common_string_destroy(struct bt_object *obj)
        g_free(ft);
 }
 
+static
+void bt_field_type_common_structure_field_finalize(
+               struct bt_field_type_common_structure_field *field)
+{
+       if (!field) {
+               return;
+       }
+
+       BT_LOGD("Finalizing structure field type's field: "
+               "addr=%p, field-ft-addr=%p, field-name=\"%s\"",
+               field, field->type, g_quark_to_string(field->name));
+       BT_LOGD_STR("Putting field type.");
+       bt_put(field->type);
+}
 
 BT_HIDDEN
 void bt_field_type_common_structure_destroy_recursive(struct bt_object *obj)
 {
        struct bt_field_type_common_structure *ft = (void *) obj;
+       uint64_t i;
 
        if (!ft) {
                return;
        }
 
        BT_LOGD("Destroying structure field type object: addr=%p", ft);
-       g_ptr_array_free(ft->fields, TRUE);
-       g_hash_table_destroy(ft->field_name_to_index);
+
+       if (ft->fields) {
+               for (i = 0; i < ft->fields->len; i++) {
+                       bt_field_type_common_structure_field_finalize(
+                               BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                                       ft, i));
+               }
+
+               g_array_free(ft->fields, TRUE);
+       }
+
+       if (ft->field_name_to_index) {
+               g_hash_table_destroy(ft->field_name_to_index);
+       }
+
        g_free(ft);
 }
 
@@ -471,19 +484,55 @@ void bt_field_type_common_sequence_destroy_recursive(struct bt_object *obj)
        g_free(ft);
 }
 
+static
+void bt_field_type_common_variant_choice_finalize(
+               struct bt_field_type_common_variant_choice *choice)
+{
+       if (!choice) {
+               return;
+       }
+
+       BT_LOGD("Finalizing variant field type's choice: "
+               "addr=%p, field-ft-addr=%p, field-name=\"%s\"",
+               choice, choice->type, g_quark_to_string(choice->name));
+       BT_LOGD_STR("Putting field type.");
+       bt_put(choice->type);
+
+       if (choice->ranges) {
+               g_array_free(choice->ranges, TRUE);
+       }
+}
+
 BT_HIDDEN
 void bt_field_type_common_variant_destroy_recursive(struct bt_object *obj)
 {
        struct bt_field_type_common_variant *ft = (void *) obj;
+       uint64_t i;
 
        if (!ft) {
                return;
        }
 
        BT_LOGD("Destroying variant field type object: addr=%p", ft);
-       g_ptr_array_free(ft->fields, TRUE);
-       g_hash_table_destroy(ft->field_name_to_index);
-       g_string_free(ft->tag_name, TRUE);
+
+       if (ft->choices) {
+               for (i = 0; i < ft->choices->len; i++) {
+                       bt_field_type_common_variant_choice_finalize(
+                               BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                                       ft, i));
+               }
+
+               g_array_free(ft->choices, TRUE);
+       }
+
+       if (ft->choice_name_to_index) {
+               g_hash_table_destroy(ft->choice_name_to_index);
+       }
+
+       if (ft->tag_name) {
+               g_string_free(ft->tag_name, TRUE);
+       }
+
        BT_LOGD_STR("Putting tag field type.");
        bt_put(ft->tag_ft);
        BT_LOGD_STR("Putting tag field path.");
@@ -582,13 +631,15 @@ gint compare_enumeration_mappings_unsigned(struct enumeration_mapping **a,
 }
 
 static
-int add_structure_field(GPtrArray *fields,
+int add_structure_variant_member(GArray *members,
                GHashTable *field_name_to_index,
-               struct bt_field_type_common *field_type, const char *field_name)
+               struct bt_field_type_common *field_type, const char *field_name,
+               bool is_variant)
 {
        int ret = 0;
        GQuark name_quark = g_quark_from_string(field_name);
-       struct structure_field_common *field;
+       struct bt_field_type_common **member_ft;
+       GQuark *member_name;
 
        /* Make sure structure does not contain a field of the same name */
        if (g_hash_table_lookup_extended(field_name_to_index,
@@ -599,21 +650,38 @@ int add_structure_field(GPtrArray *fields,
                goto end;
        }
 
-       field = g_new0(struct structure_field_common, 1);
-       if (!field) {
-               BT_LOGE_STR("Failed to allocate one structure/variant field type field.");
-               ret = -1;
-               goto end;
+       g_array_set_size(members, members->len + 1);
+
+       if (is_variant) {
+               struct bt_field_type_common_variant_choice *choice =
+                       &g_array_index(members,
+                               struct bt_field_type_common_variant_choice,
+                               members->len - 1);
+
+               member_ft = &choice->type;
+               member_name = &choice->name;
+               BT_ASSERT(!choice->ranges);
+               choice->ranges = g_array_new(FALSE, TRUE,
+                       sizeof(struct bt_field_type_common_variant_choice_range));
+               BT_ASSERT(choice->ranges);
+       } else {
+               struct bt_field_type_common_structure_field *field =
+                       &g_array_index(members,
+                               struct bt_field_type_common_structure_field,
+                               members->len - 1);
+
+               member_ft = &field->type;
+               member_name = &field->name;
        }
 
-       bt_get(field_type);
-       field->name = name_quark;
-       field->type = field_type;
+       *member_name = name_quark;
+       *member_ft = bt_get(field_type);
        g_hash_table_insert(field_name_to_index,
-               GUINT_TO_POINTER(name_quark), GUINT_TO_POINTER(fields->len));
-       g_ptr_array_add(fields, field);
-       BT_LOGV("Added structure/variant field type field: field-ft-addr=%p, "
-               "field-name=\"%s\"", field_type, field_name);
+               GUINT_TO_POINTER(name_quark),
+               GUINT_TO_POINTER(members->len - 1));
+       BT_LOGV("Added structure/variant field type member: member-ft-addr=%p, "
+               "member-name=\"%s\"", field_type, field_name);
+
 end:
        return ret;
 }
@@ -2149,8 +2217,8 @@ int bt_field_type_common_structure_replace_field(
        name_quark = g_quark_from_string(field_name);
 
        for (i = 0; i < struct_ft->fields->len; i++) {
-               struct structure_field_common *field = g_ptr_array_index(
-                       struct_ft->fields, i);
+               struct bt_field_type_common_structure_field *field =
+                       BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i);
 
                if (field->name == name_quark) {
                        bt_put(field->type);
@@ -2207,8 +2275,9 @@ int bt_field_type_common_structure_add_field(struct bt_field_type_common *ft,
                goto end;
        }
 
-       if (add_structure_field(struct_ft->fields,
-                       struct_ft->field_name_to_index, field_type, field_name)) {
+       if (add_structure_variant_member(struct_ft->fields,
+                       struct_ft->field_name_to_index, field_type, field_name,
+                       false)) {
                BT_LOGW("Cannot add field to structure field type: "
                        "struct-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"",
                        ft, field_type, field_name);
@@ -2256,7 +2325,7 @@ int bt_field_type_common_structure_borrow_field_by_index(
                struct bt_field_type_common **field_type, uint64_t index)
 {
        struct bt_field_type_common_structure *struct_ft = BT_FROM_COMMON(ft);
-       struct structure_field_common *field;
+       struct bt_field_type_common_structure_field *field;
 
        BT_ASSERT_PRE_NON_NULL(ft, "Field type");
        BT_ASSERT_PRE_FT_COMMON_HAS_ID(ft, BT_FIELD_TYPE_ID_STRUCT,
@@ -2265,7 +2334,7 @@ int bt_field_type_common_structure_borrow_field_by_index(
                "Index is out of bounds: index=%" PRIu64 ", "
                "count=%u, %![ft-]+_F",
                index, struct_ft->fields->len, ft);
-       field = g_ptr_array_index(struct_ft->fields, index);
+       field = BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(struct_ft, index);
 
        if (field_type) {
                *field_type = field->type;
@@ -2295,7 +2364,7 @@ bt_field_type_common_structure_borrow_field_type_by_name(
 {
        size_t index;
        GQuark name_quark;
-       struct structure_field_common *field;
+       struct bt_field_type_common_structure_field *field;
        struct bt_field_type_common_structure *struct_ft = BT_FROM_COMMON(ft);
        struct bt_field_type_common *field_type = NULL;
 
@@ -2319,7 +2388,7 @@ bt_field_type_common_structure_borrow_field_type_by_name(
                goto end;
        }
 
-       field = struct_ft->fields->pdata[index];
+       field = BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, index);
        field_type = field->type;
 
 end:
@@ -2549,8 +2618,9 @@ int bt_field_type_common_variant_add_field(struct bt_field_type_common *ft,
                }
        }
 
-       if (add_structure_field(var_ft->fields, var_ft->field_name_to_index,
-                       field_type, field_name)) {
+       if (add_structure_variant_member(var_ft->choices,
+                       var_ft->choice_name_to_index, field_type,
+                       field_name, true)) {
                BT_LOGW("Cannot add field to variant field type: "
                        "variant-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"",
                        ft, field_type, field_name);
@@ -2582,7 +2652,7 @@ bt_field_type_common_variant_borrow_field_type_by_name(
 {
        size_t index;
        GQuark name_quark;
-       struct structure_field_common *field;
+       struct bt_field_type_common_variant_choice *choice;
        struct bt_field_type_common_variant *var_ft = BT_FROM_COMMON(ft);
        struct bt_field_type_common *field_type = NULL;
 
@@ -2598,7 +2668,7 @@ bt_field_type_common_variant_borrow_field_type_by_name(
                goto end;
        }
 
-       if (!g_hash_table_lookup_extended(var_ft->field_name_to_index,
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
                        GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) {
                BT_LOGV("No such variant field type field name: "
                        "ft-addr=%p, field-name=\"%s\"",
@@ -2606,8 +2676,8 @@ bt_field_type_common_variant_borrow_field_type_by_name(
                goto end;
        }
 
-       field = g_ptr_array_index(var_ft->fields, index);
-       field_type = field->type;
+       choice = BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index);
+       field_type = choice->type;
 
 end:
        return field_type;
@@ -2621,56 +2691,6 @@ struct bt_field_type *bt_field_type_variant_borrow_field_type_by_name(
                (void *) ft, field_name);
 }
 
-BT_HIDDEN
-struct bt_field_type_common *
-bt_field_type_common_variant_borrow_field_type_from_tag(
-               struct bt_field_type_common *ft,
-               struct bt_field_common *tag_field,
-               bt_field_common_create_func field_create_func)
-{
-       int ret;
-       const char *enum_value;
-       struct bt_field_type_common *field_type = NULL;
-       struct bt_field_type_enumeration_mapping_iterator *iter = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(ft, "Variant field type");
-       BT_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
-       BT_ASSERT_PRE_FT_COMMON_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       iter = bt_field_common_enumeration_get_mappings(tag_field,
-               field_create_func);
-       ret = bt_field_type_enumeration_mapping_iterator_next(iter);
-       if (!iter || ret) {
-               BT_LOGW("Cannot get enumeration field type mapping iterator from enumeration field: "
-                       "enum-field-addr=%p", tag_field);
-               goto end;
-       }
-
-       ret = bt_field_type_enumeration_mapping_iterator_signed_get(iter,
-               &enum_value, NULL, NULL);
-       if (ret) {
-               BT_LOGW("Cannot get enumeration field type mapping iterator's current mapping: "
-                       "iter-addr=%p", iter);
-               goto end;
-       }
-
-       field_type = bt_field_type_common_variant_borrow_field_type_by_name(
-               ft, enum_value);
-
-end:
-       bt_put(iter);
-       return field_type;
-}
-
-struct bt_field_type *bt_field_type_variant_borrow_field_type_from_tag(
-               struct bt_field_type *ft,
-               struct bt_field *tag_field)
-{
-       return (void *) bt_field_type_common_variant_borrow_field_type_from_tag(
-               (void *) ft, (void *) tag_field,
-               (bt_field_common_create_func) bt_field_create);
-}
-
 BT_HIDDEN
 int64_t bt_field_type_common_variant_get_field_count(
                struct bt_field_type_common *ft)
@@ -2680,7 +2700,7 @@ int64_t bt_field_type_common_variant_get_field_count(
        BT_ASSERT_PRE_NON_NULL(ft, "Variant field type");
        BT_ASSERT_PRE_FT_COMMON_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
                "Field type");
-       return (int64_t) var_ft->fields->len;
+       return (int64_t) var_ft->choices->len;
 }
 
 int64_t bt_field_type_variant_get_field_count(struct bt_field_type *ft)
@@ -2695,23 +2715,23 @@ int bt_field_type_common_variant_borrow_field_by_index(
                struct bt_field_type_common **field_type, uint64_t index)
 {
        struct bt_field_type_common_variant *var_ft = BT_FROM_COMMON(ft);
-       struct structure_field_common *field;
+       struct bt_field_type_common_variant_choice *choice;
 
        BT_ASSERT_PRE_NON_NULL(ft, "Field type");
        BT_ASSERT_PRE_FT_COMMON_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
                "Field type");
-       BT_ASSERT_PRE(index < var_ft->fields->len,
+       BT_ASSERT_PRE(index < var_ft->choices->len,
                "Index is out of bounds: index=%" PRIu64 ", "
                "count=%u, %![ft-]+_F",
-               index, var_ft->fields->len, ft);
-       field = g_ptr_array_index(var_ft->fields, index);
+               index, var_ft->choices->len, ft);
+       choice = BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index);
 
        if (field_type) {
-               *field_type = field->type;
+               *field_type = choice->type;
        }
 
        if (field_name) {
-               *field_name = g_quark_to_string(field->name);
+               *field_name = g_quark_to_string(choice->name);
                BT_ASSERT(*field_name);
        }
 
@@ -2726,6 +2746,63 @@ int bt_field_type_variant_borrow_field_by_index(struct bt_field_type *ft,
                field_name, (void *) field_type, index);
 }
 
+BT_HIDDEN
+int64_t bt_field_type_common_variant_find_choice_index(
+               struct bt_field_type_common *ft, uint64_t uval,
+               bool is_signed)
+{
+       int64_t ret;
+       uint64_t i;
+       struct bt_field_type_common_variant *var_ft = BT_FROM_COMMON(ft);
+
+       BT_ASSERT(ft);
+       BT_ASSERT(ft->id == BT_FIELD_TYPE_ID_VARIANT);
+
+       if (bt_field_type_common_variant_update_choices(ft)) {
+               ret = INT64_C(-1);
+               goto end;
+       }
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               uint64_t range_i;
+               struct bt_field_type_common_variant_choice *choice =
+                       BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft, i);
+
+               for (range_i = 0; range_i < choice->ranges->len; range_i++) {
+                       struct bt_field_type_common_variant_choice_range *range =
+                               &g_array_index(
+                                       choice->ranges,
+                                       struct bt_field_type_common_variant_choice_range,
+                                       range_i);
+
+                       if (is_signed) {
+                               int64_t tag_ival = (int64_t) uval;
+
+                               if (tag_ival >= range->lower.i &&
+                                               tag_ival <= range->upper.i) {
+                                       goto found;
+                               }
+                       } else {
+                               if (uval >= range->lower.u &&
+                                               uval <= range->upper.u) {
+                                       goto found;
+                               }
+                       }
+               }
+       }
+
+       /* Range not found */
+       ret = INT64_C(-1);
+       goto end;
+
+found:
+       ret = (int64_t) i;
+
+end:
+       return ret;
+}
+
 struct bt_field_type *bt_field_type_array_create(
                struct bt_field_type *element_ft, unsigned int length)
 {
@@ -3379,7 +3456,7 @@ bt_field_type_common_variant_borrow_field_type_signed(
        struct bt_field_type_common *field_type = NULL;
        GQuark field_name_quark;
        gpointer index;
-       struct structure_field_common *field_entry;
+       struct bt_field_type_common_variant_choice *choice;
        struct range_overlap_query query = {
                .range_start._signed = tag_value,
                .range_end._signed = tag_value,
@@ -3394,13 +3471,14 @@ bt_field_type_common_variant_borrow_field_type_signed(
        }
 
        field_name_quark = query.mapping_name;
-       if (!g_hash_table_lookup_extended(var_ft->field_name_to_index,
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
                        GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
                goto end;
        }
 
-       field_entry = g_ptr_array_index(var_ft->fields, (size_t) index);
-       field_type = field_entry->type;
+       choice = BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
+               (size_t) index);
+       field_type = choice->type;
 
 end:
        return field_type;
@@ -3415,7 +3493,7 @@ bt_field_type_common_variant_borrow_field_type_unsigned(
        struct bt_field_type_common *field_type = NULL;
        GQuark field_name_quark;
        gpointer index;
-       struct structure_field_common *field_entry;
+       struct bt_field_type_common_variant_choice *choice;
        struct range_overlap_query query = {
                .range_start._unsigned = tag_value,
                .range_end._unsigned = tag_value,
@@ -3430,13 +3508,15 @@ bt_field_type_common_variant_borrow_field_type_unsigned(
        }
 
        field_name_quark = query.mapping_name;
-       if (!g_hash_table_lookup_extended(var_ft->field_name_to_index,
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
                GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
                goto end;
        }
 
-       field_entry = g_ptr_array_index(var_ft->fields, (size_t) index);
-       field_type = field_entry->type;
+       choice = BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
+               (size_t) index);
+       field_type = choice->type;
+
 end:
        return field_type;
 }
@@ -3527,7 +3607,7 @@ int bt_field_type_common_variant_get_field_name_index(
                goto end;
        }
 
-       if (!g_hash_table_lookup_extended(var_ft->field_name_to_index,
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
                        GUINT_TO_POINTER(name_quark),
                        NULL, (gpointer *) &index)) {
                BT_LOGV("No such variant field type field name: "
@@ -3661,27 +3741,84 @@ void bt_field_type_common_enumeration_freeze_recursive(
        bt_field_type_common_freeze(BT_TO_COMMON(enum_ft->container_ft));
 }
 
-static
-void freeze_structure_field(struct structure_field_common *field)
-{
-       BT_LOGD("Freezing structure/variant field type field: field-addr=%p, "
-               "field-ft-addr=%p, field-name=\"%s\"", field,
-               field->type, g_quark_to_string(field->name));
-       bt_field_type_common_freeze(field->type);
-}
-
 BT_HIDDEN
 void bt_field_type_common_structure_freeze_recursive(
                struct bt_field_type_common *ft)
 {
        struct bt_field_type_common_structure *struct_ft = BT_FROM_COMMON(ft);
+       uint64_t i;
 
        /* Cache the alignment */
        BT_LOGD("Freezing structure field type object: addr=%p", ft);
        ft->alignment = bt_field_type_common_get_alignment(ft);
        bt_field_type_common_generic_freeze(ft);
-       g_ptr_array_foreach(struct_ft->fields,
-               (GFunc) freeze_structure_field, NULL);
+
+       for (i = 0; i < struct_ft->fields->len; i++) {
+               struct bt_field_type_common_structure_field *field =
+                       BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i);
+
+               BT_LOGD("Freezing structure field type field: "
+                       "ft-addr=%p, name=\"%s\"",
+                       field->type, g_quark_to_string(field->name));
+               bt_field_type_common_freeze(field->type);
+       }
+}
+
+BT_HIDDEN
+int bt_field_type_common_variant_update_choices(struct bt_field_type_common *ft)
+{
+       struct bt_field_type_common_variant *var_ft = BT_FROM_COMMON(ft);
+       uint64_t i;
+       int ret = 0;
+       bool is_signed;
+
+       if (ft->frozen && var_ft->choices_up_to_date) {
+               goto end;
+       }
+
+       BT_ASSERT(var_ft->tag_ft);
+       is_signed = !!var_ft->tag_ft->container_ft->is_signed;
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_field_type_common_variant_choice *choice =
+                       BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i);
+               const char *choice_name = g_quark_to_string(choice->name);
+               struct bt_field_type_enumeration_mapping_iterator *iter =
+                       bt_field_type_common_enumeration_find_mappings_by_name(
+                               BT_TO_COMMON(var_ft->tag_ft), choice_name);
+
+               if (!iter) {
+                       ret = -1;
+                       goto end;
+               }
+
+               BT_ASSERT(choice->ranges);
+               g_array_set_size(choice->ranges, 0);
+
+               while (bt_field_type_enumeration_mapping_iterator_next(iter) == 0) {
+                       struct bt_field_type_common_variant_choice_range range;
+
+                       if (is_signed) {
+                               ret = bt_field_type_enumeration_mapping_iterator_signed_get(
+                                       iter, NULL,
+                                       &range.lower.i, &range.upper.i);
+                       } else {
+                               ret = bt_field_type_enumeration_mapping_iterator_unsigned_get(
+                                       iter, NULL,
+                                       &range.lower.u, &range.upper.u);
+                       }
+
+                       BT_ASSERT(ret == 0);
+                       g_array_append_val(choice->ranges, range);
+               }
+
+               bt_put(iter);
+       }
+
+       var_ft->choices_up_to_date = true;
+
+end:
+       return ret;
 }
 
 BT_HIDDEN
@@ -3689,11 +3826,20 @@ void bt_field_type_common_variant_freeze_recursive(
                struct bt_field_type_common *ft)
 {
        struct bt_field_type_common_variant *var_ft = BT_FROM_COMMON(ft);
+       uint64_t i;
 
        BT_LOGD("Freezing variant field type object: addr=%p", ft);
        bt_field_type_common_generic_freeze(ft);
-       g_ptr_array_foreach(var_ft->fields,
-               (GFunc) freeze_structure_field, NULL);
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_field_type_common_variant_choice *choice =
+                       BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i);
+
+               BT_LOGD("Freezing variant field type member: "
+                       "ft-addr=%p, name=\"%s\"",
+                       choice->type, g_quark_to_string(choice->name));
+               bt_field_type_common_freeze(choice->type);
+       }
 }
 
 BT_HIDDEN
@@ -3763,8 +3909,9 @@ void bt_field_type_common_structure_set_byte_order_recursive(
        struct bt_field_type_common_structure *struct_ft = BT_FROM_COMMON(ft);
 
        for (i = 0; i < struct_ft->fields->len; i++) {
-               struct structure_field_common *field = g_ptr_array_index(
-                       struct_ft->fields, i);
+               struct bt_field_type_common_structure_field *field =
+                       BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               struct_ft, i);
                struct bt_field_type_common *field_type = field->type;
 
                bt_field_type_common_set_byte_order(field_type, byte_order);
@@ -3779,10 +3926,11 @@ void bt_field_type_common_variant_set_byte_order_recursive(
        int i;
        struct bt_field_type_common_variant *var_ft = BT_FROM_COMMON(ft);
 
-       for (i = 0; i < var_ft->fields->len; i++) {
-               struct structure_field_common *field = g_ptr_array_index(
-                       var_ft->fields, i);
-               struct bt_field_type_common *field_type = field->type;
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_field_type_common_variant_choice *choice =
+                       BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft, i);
+               struct bt_field_type_common *field_type = choice->type;
 
                bt_field_type_common_set_byte_order(field_type, byte_order);
        }
@@ -4056,27 +4204,29 @@ end:
 }
 
 static
-int compare_structure_fields(struct structure_field_common *field_a,
-               struct structure_field_common *field_b)
+int compare_structure_variant_members(
+               struct bt_field_type_common *member_a_ft,
+               struct bt_field_type_common *member_b_ft,
+               GQuark member_a_name, GQuark member_b_name)
 {
        int ret = 1;
 
        /* Label */
-       if (field_a->name != field_b->name) {
+       if (member_a_name != member_b_name) {
                BT_LOGV("Structure/variant field type fields differ: different names: "
                        "field-a-name=%s, field-b-name=%s",
-                       g_quark_to_string(field_a->name),
-                       g_quark_to_string(field_b->name));
+                       g_quark_to_string(member_a_name),
+                       g_quark_to_string(member_b_name));
                goto end;
        }
 
        /* Type */
-       ret = bt_field_type_common_compare(field_a->type, field_b->type);
+       ret = bt_field_type_common_compare(member_a_ft, member_b_ft);
        if (ret == 1) {
                BT_LOGV("Structure/variant field type fields differ: different field types: "
                        "field-name=\"%s\", field-a-ft-addr=%p, field-b-ft-addr=%p",
-                       g_quark_to_string(field_a->name),
-                       field_a->type, field_b->type);
+                       g_quark_to_string(member_a_name),
+                       member_a_ft, member_b_ft);
        }
 
 end:
@@ -4114,14 +4264,17 @@ int bt_field_type_common_structure_compare_recursive(
        }
 
        for (i = 0; i < struct_ft_a->fields->len; ++i) {
-               struct structure_field_common *field_a =
-                       g_ptr_array_index(struct_ft_a->fields, i);
-               struct structure_field_common *field_b =
-                       g_ptr_array_index(struct_ft_b->fields, i);
-
-               ret = compare_structure_fields(field_a, field_b);
+               struct bt_field_type_common_structure_field *field_a =
+                       BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               struct_ft_a, i);
+               struct bt_field_type_common_structure_field *field_b =
+                       BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               struct_ft_b, i);
+
+               ret = compare_structure_variant_members(field_a->type,
+                       field_b->type, field_a->name, field_b->name);
                if (ret) {
-                       /* compare_structure_fields() logs what differs */
+                       /* compare_structure_variant_members() logs what differs */
                        BT_LOGV_STR("Structure field types differ: different fields.");
                        goto end;
                }
@@ -4165,22 +4318,25 @@ int bt_field_type_common_variant_compare_recursive(
        ret = 1;
 
        /* Fields */
-       if (var_ft_a->fields->len != var_ft_b->fields->len) {
-               BT_LOGV("Structure field types differ: different field counts: "
+       if (var_ft_a->choices->len != var_ft_b->choices->len) {
+               BT_LOGV("Variant field types differ: different field counts: "
                        "ft-a-field-count=%u, ft-b-field-count=%u",
-                       var_ft_a->fields->len, var_ft_b->fields->len);
+                       var_ft_a->choices->len, var_ft_b->choices->len);
                goto end;
        }
 
-       for (i = 0; i < var_ft_a->fields->len; ++i) {
-               struct structure_field_common *field_a =
-                       g_ptr_array_index(var_ft_a->fields, i);
-               struct structure_field_common *field_b =
-                       g_ptr_array_index(var_ft_b->fields, i);
+       for (i = 0; i < var_ft_a->choices->len; ++i) {
+               struct bt_field_type_common_variant_choice *choice_a =
+                       BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft_a, i);
+               struct bt_field_type_common_variant_choice *choice_b =
+                       BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft_b, i);
 
-               ret = compare_structure_fields(field_a, field_b);
+               ret = compare_structure_variant_members(choice_a->type,
+                       choice_b->type, choice_a->name, choice_b->name);
                if (ret) {
-                       /* compare_structure_fields() logs what differs */
+                       /* compare_structure_variant_members() logs what differs */
                        BT_LOGV_STR("Variant field types differ: different fields.");
                        goto end;
                }
@@ -4594,10 +4750,10 @@ struct bt_field_type *bt_field_type_integer_copy(
        struct bt_field_type_common_integer *int_ft = (void *) ft;
        struct bt_field_type_common_integer *copy_ft;
 
-       BT_LOGD("Copying CTF writer integer field type's: addr=%p", ft);
+       BT_LOGD("Copying integer field type's: addr=%p", ft);
        copy_ft = (void *) bt_field_type_integer_create(int_ft->size);
        if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer integer field type.");
+               BT_LOGE_STR("Cannot create integer field type.");
                goto end;
        }
 
@@ -4607,7 +4763,7 @@ struct bt_field_type *bt_field_type_integer_copy(
        copy_ft->size = int_ft->size;
        copy_ft->base = int_ft->base;
        copy_ft->encoding = int_ft->encoding;
-       BT_LOGD("Copied CTF writer integer field type: original-ft-addr=%p, copy-ft-addr=%p",
+       BT_LOGD("Copied integer field type: original-ft-addr=%p, copy-ft-addr=%p",
                ft, copy_ft);
 
 end:
@@ -4623,21 +4779,21 @@ struct bt_field_type *bt_field_type_enumeration_copy_recursive(
        struct bt_field_type_common_enumeration *copy_ft = NULL;
        struct bt_field_type_common_enumeration *container_copy_ft;
 
-       BT_LOGD("Copying CTF writer enumeration field type's: addr=%p", ft);
+       BT_LOGD("Copying enumeration field type's: addr=%p", ft);
 
        /* Copy the source enumeration's container */
-       BT_LOGD_STR("Copying CTF writer enumeration field type's container field type.");
+       BT_LOGD_STR("Copying enumeration field type's container field type.");
        container_copy_ft = BT_FROM_COMMON(bt_field_type_common_copy(
                BT_TO_COMMON(enum_ft->container_ft)));
        if (!container_copy_ft) {
-               BT_LOGE_STR("Cannot copy CTF writer enumeration field type's container field type.");
+               BT_LOGE_STR("Cannot copy enumeration field type's container field type.");
                goto end;
        }
 
        copy_ft = (void *) bt_field_type_enumeration_create(
                (void *) container_copy_ft);
        if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer enumeration field type.");
+               BT_LOGE_STR("Cannot create enumeration field type.");
                goto end;
        }
 
@@ -4657,7 +4813,7 @@ struct bt_field_type *bt_field_type_enumeration_copy_recursive(
                g_ptr_array_add(copy_ft->entries, copy_mapping);
        }
 
-       BT_LOGD("Copied CTF writer enumeration field type: original-ft-addr=%p, copy-ft-addr=%p",
+       BT_LOGD("Copied enumeration field type: original-ft-addr=%p, copy-ft-addr=%p",
                ft, copy_ft);
 
 end:
@@ -4677,17 +4833,17 @@ struct bt_field_type *bt_field_type_floating_point_copy(
        struct bt_field_type_common_floating_point *flt_ft = BT_FROM_COMMON(ft);
        struct bt_field_type_common_floating_point *copy_ft;
 
-       BT_LOGD("Copying CTF writer floating point number field type's: addr=%p", ft);
+       BT_LOGD("Copying floating point number field type's: addr=%p", ft);
        copy_ft = (void *) bt_field_type_floating_point_create();
        if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer floating point number field type.");
+               BT_LOGE_STR("Cannot create floating point number field type.");
                goto end;
        }
 
        copy_ft->user_byte_order = flt_ft->user_byte_order;
        copy_ft->exp_dig = flt_ft->exp_dig;
        copy_ft->mant_dig = flt_ft->mant_dig;
-       BT_LOGD("Copied CTF writer floating point number field type: original-ft-addr=%p, copy-ft-addr=%p",
+       BT_LOGD("Copied floating point number field type: original-ft-addr=%p, copy-ft-addr=%p",
                ft, copy_ft);
 
 end:
@@ -4704,10 +4860,10 @@ struct bt_field_type *bt_field_type_structure_copy_recursive(
        struct bt_field_type_common_structure *struct_ft = (void *) ft;
        struct bt_field_type_common_structure *copy_ft;
 
-       BT_LOGD("Copying CTF writer structure field type's: addr=%p", ft);
+       BT_LOGD("Copying structure field type's: addr=%p", ft);
        copy_ft = (void *) bt_field_type_structure_create();
        if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer structure field type.");
+               BT_LOGE_STR("Cannot create structure field type.");
                goto end;
        }
 
@@ -4718,38 +4874,36 @@ struct bt_field_type *bt_field_type_structure_copy_recursive(
                        key, value);
        }
 
+       g_array_set_size(copy_ft->fields, struct_ft->fields->len);
+
        for (i = 0; i < struct_ft->fields->len; i++) {
-               struct structure_field_common *entry, *copy_entry;
+               struct bt_field_type_common_structure_field *entry, *copy_entry;
                struct bt_field_type_common *field_ft_copy;
 
-               entry = g_ptr_array_index(struct_ft->fields, i);
-               BT_LOGD("Copying CTF writer structure field type's field: "
+               entry = BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                       struct_ft, i);
+               copy_entry = BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                       copy_ft, i);
+               BT_LOGD("Copying structure field type's field: "
                        "index=%" PRId64 ", "
                        "field-ft-addr=%p, field-name=\"%s\"",
                        i, entry, g_quark_to_string(entry->name));
-               copy_entry = g_new0(struct structure_field_common, 1);
-               if (!copy_entry) {
-                       BT_LOGE_STR("Failed to allocate one structure field type field.");
-                       goto error;
-               }
 
                field_ft_copy = (void *) bt_field_type_copy(
                        (void *) entry->type);
                if (!field_ft_copy) {
-                       BT_LOGE("Cannot copy CTF writer structure field type's field: "
+                       BT_LOGE("Cannot copy structure field type's field: "
                                "index=%" PRId64 ", "
                                "field-ft-addr=%p, field-name=\"%s\"",
                                i, entry, g_quark_to_string(entry->name));
-                       g_free(copy_entry);
                        goto error;
                }
 
                copy_entry->name = entry->name;
                copy_entry->type = field_ft_copy;
-               g_ptr_array_add(copy_ft->fields, copy_entry);
        }
 
-       BT_LOGD("Copied CTF writer structure field type: original-ft-addr=%p, copy-ft-addr=%p",
+       BT_LOGD("Copied structure field type: original-ft-addr=%p, copy-ft-addr=%p",
                ft, copy_ft);
 
 end:
@@ -4771,13 +4925,13 @@ struct bt_field_type *bt_field_type_variant_copy_recursive(
        struct bt_field_type_common_variant *var_ft = (void *) ft;
        struct bt_field_type_common_variant *copy_ft = NULL;
 
-       BT_LOGD("Copying CTF writer variant field type's: addr=%p", ft);
+       BT_LOGD("Copying variant field type's: addr=%p", ft);
        if (var_ft->tag_ft) {
-               BT_LOGD_STR("Copying CTF writer variant field type's tag field type.");
+               BT_LOGD_STR("Copying variant field type's tag field type.");
                tag_ft_copy = bt_field_type_common_copy(
                        BT_TO_COMMON(var_ft->tag_ft));
                if (!tag_ft_copy) {
-                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field type.");
+                       BT_LOGE_STR("Cannot copy variant field type's tag field type.");
                        goto end;
                }
        }
@@ -4786,36 +4940,36 @@ struct bt_field_type *bt_field_type_variant_copy_recursive(
                (void *) tag_ft_copy,
                var_ft->tag_name->len ? var_ft->tag_name->str : NULL);
        if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer variant field type.");
+               BT_LOGE_STR("Cannot create variant field type.");
                goto end;
        }
 
        /* Copy field_name_to_index */
-       g_hash_table_iter_init(&iter, var_ft->field_name_to_index);
+       g_hash_table_iter_init(&iter, var_ft->choice_name_to_index);
        while (g_hash_table_iter_next(&iter, &key, &value)) {
-               g_hash_table_insert(copy_ft->field_name_to_index,
+               g_hash_table_insert(copy_ft->choice_name_to_index,
                        key, value);
        }
 
-       for (i = 0; i < var_ft->fields->len; i++) {
-               struct structure_field_common *entry, *copy_entry;
+       g_array_set_size(copy_ft->choices, var_ft->choices->len);
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_field_type_common_variant_choice *entry, *copy_entry;
                struct bt_field_type_common *field_ft_copy;
+               uint64_t range_i;
 
-               entry = g_ptr_array_index(var_ft->fields, i);
-               BT_LOGD("Copying CTF writer variant field type's field: "
+               entry = BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, i);
+               copy_entry = BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                       copy_ft, i);
+               BT_LOGD("Copying variant field type's field: "
                        "index=%" PRId64 ", "
                        "field-ft-addr=%p, field-name=\"%s\"",
                        i, entry, g_quark_to_string(entry->name));
-               copy_entry = g_new0(struct structure_field_common, 1);
-               if (!copy_entry) {
-                       BT_LOGE_STR("Failed to allocate one variant field type field.");
-                       goto error;
-               }
 
                field_ft_copy = (void *) bt_field_type_copy(
                        (void *) entry->type);
                if (!field_ft_copy) {
-                       BT_LOGE("Cannot copy CTF writer variant field type's field: "
+                       BT_LOGE("Cannot copy variant field type's field: "
                                "index=%" PRId64 ", "
                                "field-ft-addr=%p, field-name=\"%s\"",
                                i, entry, g_quark_to_string(entry->name));
@@ -4825,19 +4979,29 @@ struct bt_field_type *bt_field_type_variant_copy_recursive(
 
                copy_entry->name = entry->name;
                copy_entry->type = field_ft_copy;
-               g_ptr_array_add(copy_ft->fields, copy_entry);
+
+               /* Copy ranges */
+               copy_entry->ranges = g_array_new(FALSE, TRUE,
+                       sizeof(struct bt_field_type_common_variant_choice_range));
+               BT_ASSERT(copy_entry->ranges);
+               g_array_set_size(copy_entry->ranges, entry->ranges->len);
+
+               for (range_i = 0; range_i < entry->ranges->len; range_i++) {
+                       copy_entry->ranges[range_i] = entry->ranges[range_i];
+               }
        }
 
        if (var_ft->tag_field_path) {
-               BT_LOGD_STR("Copying CTF writer variant field type's tag field path.");
+               BT_LOGD_STR("Copying variant field type's tag field path.");
                copy_ft->tag_field_path = bt_field_path_copy(
                        var_ft->tag_field_path);
                if (!copy_ft->tag_field_path) {
-                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field path.");
+                       BT_LOGE_STR("Cannot copy variant field type's tag field path.");
                        goto error;
                }
        }
 
+       copy_ft->choices_up_to_date = var_ft->choices_up_to_date;
        BT_LOGD("Copied variant field type: original-ft-addr=%p, copy-ft-addr=%p",
                ft, copy_ft);
 
@@ -4859,22 +5023,22 @@ struct bt_field_type *bt_field_type_array_copy_recursive(
        struct bt_field_type_common_array *array_ft = (void *) ft;
        struct bt_field_type_common_array *copy_ft = NULL;
 
-       BT_LOGD("Copying CTF writer array field type's: addr=%p", ft);
-       BT_LOGD_STR("Copying CTF writer array field type's element field type.");
+       BT_LOGD("Copying array field type's: addr=%p", ft);
+       BT_LOGD_STR("Copying array field type's element field type.");
        container_ft_copy = bt_field_type_common_copy(array_ft->element_ft);
        if (!container_ft_copy) {
-               BT_LOGE_STR("Cannot copy CTF writer array field type's element field type.");
+               BT_LOGE_STR("Cannot copy array field type's element field type.");
                goto end;
        }
 
        copy_ft = (void *) bt_field_type_array_create(
                (void *) container_ft_copy, array_ft->length);
        if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer array field type.");
+               BT_LOGE_STR("Cannot create array field type.");
                goto end;
        }
 
-       BT_LOGD("Copied CTF writer array field type: original-ft-addr=%p, copy-ft-addr=%p",
+       BT_LOGD("Copied array field type: original-ft-addr=%p, copy-ft-addr=%p",
                ft, copy_ft);
 
 end:
@@ -4890,11 +5054,11 @@ struct bt_field_type *bt_field_type_sequence_copy_recursive(
        struct bt_field_type_common_sequence *seq_ft = (void *) ft;
        struct bt_field_type_common_sequence *copy_ft = NULL;
 
-       BT_LOGD("Copying CTF writer sequence field type's: addr=%p", ft);
-       BT_LOGD_STR("Copying CTF writer sequence field type's element field type.");
+       BT_LOGD("Copying sequence field type's: addr=%p", ft);
+       BT_LOGD_STR("Copying sequence field type's element field type.");
        container_ft_copy = bt_field_type_common_copy(seq_ft->element_ft);
        if (!container_ft_copy) {
-               BT_LOGE_STR("Cannot copy CTF writer sequence field type's element field type.");
+               BT_LOGE_STR("Cannot copy sequence field type's element field type.");
                goto end;
        }
 
@@ -4903,21 +5067,21 @@ struct bt_field_type *bt_field_type_sequence_copy_recursive(
                seq_ft->length_field_name->len ?
                        seq_ft->length_field_name->str : NULL);
        if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer sequence field type.");
+               BT_LOGE_STR("Cannot create sequence field type.");
                goto end;
        }
 
        if (seq_ft->length_field_path) {
-               BT_LOGD_STR("Copying CTF writer sequence field type's length field path.");
+               BT_LOGD_STR("Copying sequence field type's length field path.");
                copy_ft->length_field_path = bt_field_path_copy(
                        seq_ft->length_field_path);
                if (!copy_ft->length_field_path) {
-                       BT_LOGE_STR("Cannot copy CTF writer sequence field type's length field path.");
+                       BT_LOGE_STR("Cannot copy sequence field type's length field path.");
                        goto error;
                }
        }
 
-       BT_LOGD("Copied CTF writer sequence field type: original-ft-addr=%p, copy-ft-addr=%p",
+       BT_LOGD("Copied sequence field type: original-ft-addr=%p, copy-ft-addr=%p",
                ft, copy_ft);
 
 end:
@@ -4935,15 +5099,15 @@ struct bt_field_type *bt_field_type_string_copy(struct bt_field_type *ft)
        struct bt_field_type_common_string *string_ft = (void *) ft;
        struct bt_field_type_common_string *copy_ft = NULL;
 
-       BT_LOGD("Copying CTF writer string field type's: addr=%p", ft);
+       BT_LOGD("Copying string field type's: addr=%p", ft);
        copy_ft = (void *) bt_field_type_string_create();
        if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer string field type.");
+               BT_LOGE_STR("Cannot create string field type.");
                goto end;
        }
 
        copy_ft->encoding = string_ft->encoding;
-       BT_LOGD("Copied CTF writer string field type: original-ft-addr=%p, copy-ft-addr=%p",
+       BT_LOGD("Copied string field type: original-ft-addr=%p, copy-ft-addr=%p",
                ft, copy_ft);
 
 end:
diff --git a/lib/ctf-ir/field-wrapper.c b/lib/ctf-ir/field-wrapper.c
new file mode 100644 (file)
index 0000000..5917f70
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "FIELD-WRAPPER"
+#include <babeltrace/lib-logging-internal.h>
+
+#include <babeltrace/ctf-ir/field-wrapper-internal.h>
+#include <babeltrace/ctf-ir/fields-internal.h>
+#include <babeltrace/object-pool-internal.h>
+#include <babeltrace/object-internal.h>
+#include <glib.h>
+
+BT_HIDDEN
+struct bt_field_wrapper *bt_field_wrapper_new(void *data)
+{
+       struct bt_field_wrapper *field_wrapper =
+               g_new0(struct bt_field_wrapper, 1);
+
+       BT_LOGD_STR("Creating empty field wrapper object.");
+
+       if (!field_wrapper) {
+               BT_LOGE("Failed to allocate one field wrapper.");
+               goto end;
+       }
+
+       bt_object_init(field_wrapper, NULL);
+       bt_object_set_is_shared((void *) field_wrapper, false);
+       BT_LOGD("Created empty field wrapper object: addr=%p",
+               field_wrapper);
+
+end:
+       return field_wrapper;
+}
+
+BT_HIDDEN
+void bt_field_wrapper_destroy(struct bt_field_wrapper *field_wrapper)
+{
+       BT_LOGD("Destroying field wrapper: addr=%p", field_wrapper);
+
+       if (field_wrapper->field) {
+               BT_LOGD_STR("Destroying field.");
+               bt_field_destroy_recursive((void *) field_wrapper->field);
+       }
+
+       BT_LOGD_STR("Putting stream class.");
+       g_free(field_wrapper);
+}
+
+BT_HIDDEN
+struct bt_field_wrapper *bt_field_wrapper_create(
+               struct bt_object_pool *pool, struct bt_field_type *ft)
+{
+       struct bt_field_wrapper *field_wrapper = NULL;
+
+       BT_ASSERT(pool);
+       BT_ASSERT(ft);
+       field_wrapper = bt_object_pool_create_object(pool);
+       if (!field_wrapper) {
+               BT_LIB_LOGE("Cannot allocate one field wrapper from field wrapper pool: "
+                       "%![pool-]+o", pool);
+               goto error;
+       }
+
+       if (!field_wrapper->field) {
+               field_wrapper->field = (void *) bt_field_create_recursive(ft);
+               if (!field_wrapper->field) {
+                       BT_LIB_LOGE("Cannot create field wrapper from field type: "
+                               "%![ft-]+F", ft);
+                       goto error;
+               }
+
+               BT_LIB_LOGD("Created initial field wrapper object: "
+                       "wrapper-addr=%p, %![field-]+f", field_wrapper,
+                       field_wrapper->field);
+       }
+
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return field_wrapper;
+}
index bd5e1bda51f504350f7bab75b7bd45626dc7f615..5c9ff0b667cd4ae7e482f0b983a042bf42134b19 100644 (file)
 #include <babeltrace/assert-internal.h>
 #include <inttypes.h>
 
-static
-struct bt_field_common *bt_field_integer_copy(struct bt_field_common *src);
-
-static
-struct bt_field_common *bt_field_enumeration_copy_recursive(
-               struct bt_field_common *src);
-
-static
-struct bt_field_common *bt_field_floating_point_copy(
-               struct bt_field_common *src);
-
-static
-struct bt_field_common *bt_field_structure_copy_recursive(
-               struct bt_field_common *src);
-
-static
-struct bt_field_common *bt_field_variant_copy_recursive(
-               struct bt_field_common *src);
-
-static
-struct bt_field_common *bt_field_array_copy_recursive(
-               struct bt_field_common *src);
-
-static
-struct bt_field_common *bt_field_sequence_copy_recursive(
-               struct bt_field_common *src);
-
-static
-struct bt_field_common *bt_field_string_copy(struct bt_field_common *src);
+#define BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(_field, _name)              \
+       BT_ASSERT_PRE((_field)->type->id == BT_FIELD_TYPE_ID_INTEGER || \
+               (_field)->type->id == BT_FIELD_TYPE_ID_ENUM,            \
+               _name " is not an integer or an enumeration field: "    \
+               "%!+f", (_field))
 
 static struct bt_field_common_methods bt_field_integer_methods = {
-       .freeze = bt_field_common_generic_freeze,
+       .set_is_frozen = bt_field_common_generic_set_is_frozen,
        .validate = bt_field_common_generic_validate,
-       .copy = bt_field_integer_copy,
+       .copy = NULL,
        .is_set = bt_field_common_generic_is_set,
        .reset = bt_field_common_generic_reset,
 };
 
 static struct bt_field_common_methods bt_field_floating_point_methods = {
-       .freeze = bt_field_common_generic_freeze,
+       .set_is_frozen = bt_field_common_generic_set_is_frozen,
        .validate = bt_field_common_generic_validate,
-       .copy = bt_field_floating_point_copy,
+       .copy = NULL,
        .is_set = bt_field_common_generic_is_set,
        .reset = bt_field_common_generic_reset,
 };
 
 static struct bt_field_common_methods bt_field_enumeration_methods = {
-       .freeze = bt_field_common_enumeration_freeze_recursive,
-       .validate = bt_field_common_enumeration_validate_recursive,
-       .copy = bt_field_enumeration_copy_recursive,
-       .is_set = bt_field_common_enumeration_is_set_recursive,
-       .reset = bt_field_common_enumeration_reset_recursive,
+       .set_is_frozen = bt_field_common_generic_set_is_frozen,
+       .validate = bt_field_common_generic_validate,
+       .copy = NULL,
+       .is_set = bt_field_common_generic_is_set,
+       .reset = bt_field_common_generic_reset,
 };
 
 static struct bt_field_common_methods bt_field_string_methods = {
-       .freeze = bt_field_common_generic_freeze,
+       .set_is_frozen = bt_field_common_generic_set_is_frozen,
        .validate = bt_field_common_generic_validate,
-       .copy = bt_field_string_copy,
+       .copy = NULL,
        .is_set = bt_field_common_generic_is_set,
        .reset = bt_field_common_string_reset,
 };
 
 static struct bt_field_common_methods bt_field_structure_methods = {
-       .freeze = bt_field_common_structure_freeze_recursive,
+       .set_is_frozen = bt_field_common_structure_set_is_frozen_recursive,
        .validate = bt_field_common_structure_validate_recursive,
-       .copy = bt_field_structure_copy_recursive,
+       .copy = NULL,
        .is_set = bt_field_common_structure_is_set_recursive,
        .reset = bt_field_common_structure_reset_recursive,
 };
 
 static struct bt_field_common_methods bt_field_sequence_methods = {
-       .freeze = bt_field_common_sequence_freeze_recursive,
+       .set_is_frozen = bt_field_common_sequence_set_is_frozen_recursive,
        .validate = bt_field_common_sequence_validate_recursive,
-       .copy = bt_field_sequence_copy_recursive,
+       .copy = NULL,
        .is_set = bt_field_common_sequence_is_set_recursive,
        .reset = bt_field_common_sequence_reset_recursive,
 };
 
 static struct bt_field_common_methods bt_field_array_methods = {
-       .freeze = bt_field_common_array_freeze_recursive,
+       .set_is_frozen = bt_field_common_array_set_is_frozen_recursive,
        .validate = bt_field_common_array_validate_recursive,
-       .copy = bt_field_array_copy_recursive,
+       .copy = NULL,
        .is_set = bt_field_common_array_is_set_recursive,
        .reset = bt_field_common_array_reset_recursive,
 };
 
 static struct bt_field_common_methods bt_field_variant_methods = {
-       .freeze = bt_field_common_variant_freeze_recursive,
+       .set_is_frozen = bt_field_common_variant_set_is_frozen_recursive,
        .validate = bt_field_common_variant_validate_recursive,
-       .copy = bt_field_variant_copy_recursive,
+       .copy = NULL,
        .is_set = bt_field_common_variant_is_set_recursive,
        .reset = bt_field_common_variant_reset_recursive,
 };
@@ -170,7 +146,44 @@ struct bt_field *(* const field_create_funcs[])(struct bt_field_type *) = {
        [BT_FIELD_TYPE_ID_STRING] =     bt_field_string_create,
 };
 
-struct bt_field *bt_field_create(struct bt_field_type *type)
+static
+void bt_field_integer_destroy(struct bt_field *field);
+
+static
+void bt_field_enumeration_destroy(struct bt_field *field);
+
+static
+void bt_field_floating_point_destroy(struct bt_field *field);
+
+static
+void bt_field_structure_destroy_recursive(struct bt_field *field);
+
+static
+void bt_field_variant_destroy_recursive(struct bt_field *field);
+
+static
+void bt_field_array_destroy_recursive(struct bt_field *field);
+
+static
+void bt_field_sequence_destroy_recursive(struct bt_field *field);
+
+static
+void bt_field_string_destroy(struct bt_field *field);
+
+static
+void (* const field_destroy_funcs[])(struct bt_field *) = {
+       [BT_FIELD_TYPE_ID_INTEGER] =    bt_field_integer_destroy,
+       [BT_FIELD_TYPE_ID_ENUM] =       bt_field_enumeration_destroy,
+       [BT_FIELD_TYPE_ID_FLOAT] =      bt_field_floating_point_destroy,
+       [BT_FIELD_TYPE_ID_STRUCT] =     bt_field_structure_destroy_recursive,
+       [BT_FIELD_TYPE_ID_VARIANT] =    bt_field_variant_destroy_recursive,
+       [BT_FIELD_TYPE_ID_ARRAY] =      bt_field_array_destroy_recursive,
+       [BT_FIELD_TYPE_ID_SEQUENCE] =   bt_field_sequence_destroy_recursive,
+       [BT_FIELD_TYPE_ID_STRING] =     bt_field_string_destroy,
+};
+
+BT_HIDDEN
+struct bt_field *bt_field_create_recursive(struct bt_field_type *type)
 {
        struct bt_field *field = NULL;
        enum bt_field_type_id type_id;
@@ -185,6 +198,7 @@ struct bt_field *bt_field_create(struct bt_field_type *type)
                goto end;
        }
 
+       bt_object_set_is_shared((void *) field, false);
        bt_field_type_freeze(type);
 
 end:
@@ -244,22 +258,15 @@ bt_bool bt_field_is_variant(struct bt_field *field)
        return bt_field_get_type_id(field) == BT_FIELD_TYPE_ID_VARIANT;
 }
 
-BT_HIDDEN
-int64_t bt_field_sequence_get_int_length(struct bt_field *field)
+int64_t bt_field_sequence_get_length(struct bt_field *field)
 {
-       return bt_field_common_sequence_get_int_length((void *) field);
+       return bt_field_common_sequence_get_length((void *) field);
 }
 
-struct bt_field *bt_field_sequence_borrow_length(struct bt_field *field)
-{
-       return (void *) bt_field_common_sequence_borrow_length((void *) field);
-}
-
-int bt_field_sequence_set_length(struct bt_field *field,
-               struct bt_field *length_field)
+int bt_field_sequence_set_length(struct bt_field *field, uint64_t length)
 {
        return bt_field_common_sequence_set_length((void *) field,
-               (void *) length_field);
+               length, (bt_field_common_create_func) bt_field_create_recursive);
 }
 
 struct bt_field *bt_field_structure_borrow_field_by_index(
@@ -276,33 +283,18 @@ struct bt_field *bt_field_structure_borrow_field_by_name(
                (void *) field, name);
 }
 
-int bt_field_structure_set_field_by_name(struct bt_field_common *field,
-               const char *name, struct bt_field_common *value)
-{
-       return bt_field_common_structure_set_field_by_name((void *) field,
-               name, (void *) value);
-}
-
 struct bt_field *bt_field_array_borrow_field(
                struct bt_field *field, uint64_t index)
 {
        return (void *) bt_field_common_array_borrow_field((void *) field,
-               index, (bt_field_common_create_func) bt_field_create);
+               index);
 }
 
 struct bt_field *bt_field_sequence_borrow_field(
                struct bt_field *field, uint64_t index)
 {
        return (void *) bt_field_common_sequence_borrow_field((void *) field,
-               index, (bt_field_common_create_func) bt_field_create);
-}
-
-struct bt_field *bt_field_variant_borrow_field(struct bt_field *field,
-               struct bt_field *tag_field)
-{
-       return (void *) bt_field_common_variant_borrow_field((void *) field,
-               (void *) tag_field,
-               (bt_field_common_create_func) bt_field_create);
+               index);
 }
 
 struct bt_field *bt_field_variant_borrow_current_field(
@@ -312,47 +304,136 @@ struct bt_field *bt_field_variant_borrow_current_field(
                (void *) variant_field);
 }
 
-struct bt_field_common *bt_field_variant_borrow_tag(
-               struct bt_field_common *variant_field)
+int bt_field_variant_set_tag_signed(struct bt_field *variant_field,
+               int64_t tag)
 {
-       return (void *) bt_field_common_variant_borrow_tag(
-               (void *) variant_field);
+       return bt_field_variant_common_set_tag((void *) variant_field,
+               (uint64_t) tag, true);
+}
+
+int bt_field_variant_set_tag_unsigned(struct bt_field *variant_field,
+               uint64_t tag)
+{
+       return bt_field_variant_common_set_tag((void *) variant_field,
+               (uint64_t) tag, false);
 }
 
-struct bt_field *bt_field_enumeration_borrow_container(struct bt_field *field)
+int bt_field_variant_get_tag_signed(struct bt_field *variant_field,
+               int64_t *tag)
 {
-       return (void *) bt_field_common_enumeration_borrow_container(
-               (void *) field, (bt_field_common_create_func) bt_field_create);
+       return bt_field_common_variant_get_tag_signed((void *) variant_field, tag);
+}
+
+int bt_field_variant_get_tag_unsigned(struct bt_field *variant_field,
+               uint64_t *tag)
+{
+       return bt_field_common_variant_get_tag_unsigned((void *) variant_field, tag);
 }
 
 struct bt_field_type_enumeration_mapping_iterator *
 bt_field_enumeration_get_mappings(struct bt_field *field)
 {
+       struct bt_field_enumeration *enum_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Enumeration field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID((struct bt_field_common *) field,
+               BT_FIELD_TYPE_ID_ENUM, "Field");
+       BT_ASSERT_PRE_FIELD_COMMON_IS_SET((struct bt_field_common *) field,
+               "Enumeration field");
        return bt_field_common_enumeration_get_mappings((void *) field,
-               (bt_field_common_create_func) bt_field_create);
+               (bt_field_common_create_func) bt_field_create_recursive,
+               enum_field->common.payload.unsignd);
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+struct bt_field_type_common_integer *get_int_enum_int_ft(
+               struct bt_field *field)
+{
+       struct bt_field_common_integer *int_field = (void *) field;
+       struct bt_field_type_common_integer *int_ft = NULL;
+
+       if (int_field->common.type->id == BT_FIELD_TYPE_ID_INTEGER) {
+               int_ft = BT_FROM_COMMON(int_field->common.type);
+       } else if (int_field->common.type->id == BT_FIELD_TYPE_ID_ENUM) {
+               struct bt_field_type_common_enumeration *enum_ft =
+                       BT_FROM_COMMON(int_field->common.type);
+               int_ft = enum_ft->container_ft;
+       }
+
+       BT_ASSERT(int_ft);
+       return int_ft;
 }
 
 int bt_field_integer_signed_get_value(struct bt_field *field, int64_t *value)
 {
-       return bt_field_common_integer_signed_get_value((void *) field, value);
+       struct bt_field_common_integer *integer = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Integer/enumeration field");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_ASSERT_PRE_FIELD_COMMON_IS_SET(BT_TO_COMMON(integer),
+               "Integer/enumeration field");
+       BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(BT_TO_COMMON(integer), "Field");
+       BT_ASSERT_PRE(bt_field_type_common_integer_is_signed(
+               BT_TO_COMMON(get_int_enum_int_ft(field))),
+               "Field's type is unsigned: %!+f", field);
+       *value = integer->payload.signd;
+       return 0;
 }
 
-int bt_field_integer_signed_set_value(struct bt_field *field,
-               int64_t value)
+int bt_field_integer_signed_set_value(struct bt_field *field, int64_t value)
 {
-       return bt_field_common_integer_signed_set_value((void *) field, value);
+       int ret = 0;
+       struct bt_field_common_integer *integer = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_ASSERT_PRE_FIELD_COMMON_HOT(BT_TO_COMMON(integer), "Integer field");
+       BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(BT_TO_COMMON(integer), "Field");
+       BT_ASSERT_PRE(bt_field_type_common_integer_is_signed(
+               BT_FROM_COMMON(get_int_enum_int_ft(field))),
+               "Field's type is unsigned: %!+f", field);
+       BT_ASSERT_PRE(value_is_in_range_signed(
+               get_int_enum_int_ft(field)->size, value),
+               "Value is out of bounds: value=%" PRId64 ", %![field-]+f",
+               value, field);
+       integer->payload.signd = value;
+       bt_field_set(field, true);
+       return ret;
 }
 
-int bt_field_integer_unsigned_get_value(struct bt_field *field,
-               uint64_t *value)
+int bt_field_integer_unsigned_get_value(struct bt_field *field, uint64_t *value)
 {
-       return bt_field_common_integer_unsigned_get_value((void *) field,
-               value);
+       struct bt_field_common_integer *integer = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_ASSERT_PRE_FIELD_COMMON_IS_SET(BT_TO_COMMON(integer), "Integer field");
+       BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(BT_TO_COMMON(integer), "Field");
+       BT_ASSERT_PRE(!bt_field_type_common_integer_is_signed(
+               BT_FROM_COMMON(get_int_enum_int_ft(field))),
+               "Field's type is signed: %!+f", field);
+       *value = integer->payload.unsignd;
+       return 0;
 }
 
-int bt_field_integer_unsigned_set_value(struct bt_field *field, uint64_t value)
+int bt_field_integer_unsigned_set_value(struct bt_field *field,
+               uint64_t value)
 {
-       return bt_field_common_integer_unsigned_set_value((void *) field, value);
+       struct bt_field_common_integer *integer = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_ASSERT_PRE_FIELD_COMMON_HOT(BT_TO_COMMON(integer), "Integer field");
+       BT_ASSERT_PRE_FIELD_IS_INT_OR_ENUM(BT_TO_COMMON(integer), "Field");
+       BT_ASSERT_PRE(!bt_field_type_common_integer_is_signed(
+               BT_FROM_COMMON(get_int_enum_int_ft(field))),
+               "Field's type is signed: %!+f", field);
+       BT_ASSERT_PRE(value_is_in_range_unsigned(
+               get_int_enum_int_ft(field)->size, value),
+               "Value is out of bounds: value=%" PRIu64 ", %![field-]+f",
+               value, field);
+       integer->payload.unsignd = value;
+       bt_field_set(field, true);
+       return 0;
 }
 
 int bt_field_floating_point_get_value(struct bt_field *field,
@@ -388,6 +469,11 @@ int bt_field_string_append_len(struct bt_field *field,
        return bt_field_common_string_append_len((void *) field, value, length);
 }
 
+int bt_field_string_clear(struct bt_field *string_field)
+{
+       return bt_field_common_string_clear((void *) string_field);
+}
+
 BT_HIDDEN
 struct bt_field_common *bt_field_common_copy(struct bt_field_common *field)
 {
@@ -408,124 +494,81 @@ end:
        return copy;
 }
 
-struct bt_field *bt_field_copy(struct bt_field *field)
-{
-       return (void *) bt_field_common_copy((void *) field);
-}
-
-static void bt_field_common_finalize(struct bt_field_common *field)
+static
+void bt_field_integer_destroy(struct bt_field *field)
 {
-       BT_ASSERT(field);
-       BT_LOGD_STR("Putting field's type.");
-       bt_put(field->type);
+       BT_LOGD("Destroying integer field object: addr=%p", field);
+       bt_field_common_integer_finalize((void *) field);
+       g_free(field);
 }
 
-BT_HIDDEN
-void bt_field_common_integer_destroy(struct bt_object *obj)
+static
+void bt_field_floating_point_destroy(struct bt_field *field)
 {
-       struct bt_field_common_integer *integer = (void *) obj;
-
-       BT_ASSERT(obj);
-       bt_field_common_finalize(BT_TO_COMMON(integer));
-       BT_LOGD("Destroying integer field object: addr=%p", obj);
-       g_free(obj);
+       BT_LOGD("Destroying floating point field object: addr=%p", field);
+       bt_field_common_floating_point_finalize((void *) field);
+       g_free(field);
 }
 
-BT_HIDDEN
-void bt_field_common_enumeration_destroy_recursive(struct bt_object *obj)
+static
+void bt_field_enumeration_destroy(struct bt_field *field)
 {
-       struct bt_field_common_enumeration *enumeration = (void *) obj;
-
-       BT_ASSERT(enumeration);
-       bt_field_common_finalize(BT_TO_COMMON(enumeration));
-       BT_LOGD("Destroying enumeration field object: addr=%p", obj);
-       BT_LOGD_STR("Putting payload field.");
-       bt_put(enumeration->payload);
-       g_free(enumeration);
+       BT_LOGD("Destroying enumeration field object: addr=%p", field);
+       bt_field_common_finalize((void *) field);
+       g_free(field);
 }
 
-BT_HIDDEN
-void bt_field_common_floating_point_destroy(struct bt_object *obj)
+static
+void bt_field_structure_destroy_recursive(struct bt_field *field)
 {
-       struct bt_field_common_floating_point *floating_point = (void *) obj;
-
-       BT_ASSERT(obj);
-       bt_field_common_finalize(BT_TO_COMMON(floating_point));
-       BT_LOGD("Destroying floating point number field object: addr=%p", obj);
-       g_free(obj);
+       BT_LOGD("Destroying structure field object: addr=%p", field);
+       bt_field_common_structure_finalize_recursive((void *) field);
+       g_free(field);
 }
 
-BT_HIDDEN
-void bt_field_common_structure_destroy_recursive(struct bt_object *obj)
+static
+void bt_field_variant_destroy_recursive(struct bt_field *field)
 {
-       struct bt_field_common_structure *structure = (void *) obj;
-
-       BT_ASSERT(obj);
-       bt_field_common_finalize(BT_TO_COMMON(structure));
-       BT_LOGD("Destroying structure field object: addr=%p", obj);
-       g_ptr_array_free(structure->fields, TRUE);
-       g_free(structure);
+       BT_LOGD("Destroying variant field object: addr=%p", field);
+       bt_field_common_variant_finalize_recursive((void *) field);
+       g_free(field);
 }
 
-BT_HIDDEN
-void bt_field_common_variant_destroy_recursive(struct bt_object *obj)
+static
+void bt_field_array_destroy_recursive(struct bt_field *field)
 {
-       struct bt_field_common_variant *variant = (void *) obj;
-
-       BT_ASSERT(obj);
-       bt_field_common_finalize(BT_TO_COMMON(variant));
-       BT_LOGD("Destroying variant field object: addr=%p", obj);
-       BT_LOGD_STR("Putting tag field.");
-       bt_put(variant->tag);
-       BT_LOGD_STR("Putting payload field.");
-       bt_put(variant->payload);
-       g_free(variant);
+       BT_LOGD("Destroying array field object: addr=%p", field);
+       bt_field_common_array_finalize_recursive((void *) field);
+       g_free(field);
 }
 
-BT_HIDDEN
-void bt_field_common_array_destroy_recursive(struct bt_object *obj)
+static
+void bt_field_sequence_destroy_recursive(struct bt_field *field)
 {
-       struct bt_field_common_array *array = (void *) obj;
-
-       BT_ASSERT(obj);
-       bt_field_common_finalize(BT_TO_COMMON(array));
-       BT_LOGD("Destroying array field object: addr=%p", obj);
-       g_ptr_array_free(array->elements, TRUE);
-       g_free(array);
+       BT_LOGD("Destroying sequence field object: addr=%p", field);
+       bt_field_common_sequence_finalize_recursive((void *) field);
+       g_free(field);
 }
 
-BT_HIDDEN
-void bt_field_common_sequence_destroy_recursive(struct bt_object *obj)
+static
+void bt_field_string_destroy(struct bt_field *field)
 {
-       struct bt_field_common_sequence *sequence = (void *) obj;
-
-       BT_ASSERT(obj);
-       bt_field_common_finalize(BT_TO_COMMON(sequence));
-       BT_LOGD("Destroying sequence field object: addr=%p", obj);
-
-       if (sequence->elements) {
-               g_ptr_array_free(sequence->elements, TRUE);
-       }
-
-       BT_LOGD_STR("Putting length field.");
-       bt_put(sequence->length);
-       g_free(sequence);
+       BT_LOGD("Destroying string field object: addr=%p", field);
+       bt_field_common_string_finalize((void *) field);
+       g_free(field);
 }
 
 BT_HIDDEN
-void bt_field_common_string_destroy(struct bt_object *obj)
+void bt_field_destroy_recursive(struct bt_field *field)
 {
-       struct bt_field_common_string *string = (void *) obj;
-
-       BT_ASSERT(obj);
-       bt_field_common_finalize(BT_TO_COMMON(string));
-       BT_LOGD("Destroying string field object: addr=%p", obj);
+       struct bt_field_common *field_common = (void *) field;
 
-       if (string->payload) {
-               g_string_free(string->payload, TRUE);
+       if (!field) {
+               return;
        }
 
-       g_free(string);
+       BT_ASSERT(field_type_common_has_known_id((void *) field_common->type));
+       field_destroy_funcs[field_common->type->id](field);
 }
 
 static
@@ -538,8 +581,7 @@ struct bt_field *bt_field_integer_create(struct bt_field_type *type)
 
        if (integer) {
                bt_field_common_initialize(BT_TO_COMMON(integer), (void *) type,
-                       bt_field_common_integer_destroy,
-                       &bt_field_integer_methods);
+                       NULL, &bt_field_integer_methods);
                BT_LOGD("Created integer field object: addr=%p, ft-addr=%p",
                        integer, type);
        } else {
@@ -552,16 +594,15 @@ struct bt_field *bt_field_integer_create(struct bt_field_type *type)
 static
 struct bt_field *bt_field_enumeration_create(struct bt_field_type *type)
 {
-       struct bt_field_common_enumeration *enumeration = g_new0(
-               struct bt_field_common_enumeration, 1);
+       struct bt_field_enumeration *enumeration = g_new0(
+               struct bt_field_enumeration, 1);
 
        BT_LOGD("Creating enumeration field object: ft-addr=%p", type);
 
        if (enumeration) {
-               bt_field_common_initialize(BT_TO_COMMON(enumeration),
-                       (void *) type,
-                       bt_field_common_enumeration_destroy_recursive,
-                       &bt_field_enumeration_methods);
+               bt_field_common_initialize(
+                       BT_TO_COMMON(BT_TO_COMMON(enumeration)),
+                       (void *) type, NULL, &bt_field_enumeration_methods);
                BT_LOGD("Created enumeration field object: addr=%p, ft-addr=%p",
                        enumeration, type);
        } else {
@@ -581,9 +622,7 @@ struct bt_field *bt_field_floating_point_create(struct bt_field_type *type)
 
        if (floating_point) {
                bt_field_common_initialize(BT_TO_COMMON(floating_point),
-                       (void *) type,
-                       bt_field_common_floating_point_destroy,
-                       &bt_field_floating_point_methods);
+                       (void *) type, NULL, &bt_field_floating_point_methods);
                BT_LOGD("Created floating point number field object: addr=%p, ft-addr=%p",
                        floating_point, type);
        } else {
@@ -598,7 +637,8 @@ int bt_field_common_structure_initialize(struct bt_field_common *field,
                struct bt_field_type_common *type,
                bt_object_release_func release_func,
                struct bt_field_common_methods *methods,
-               bt_field_common_create_func field_create_func)
+               bt_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func)
 {
        int ret = 0;
        struct bt_field_type_common_structure *structure_type =
@@ -608,16 +648,15 @@ int bt_field_common_structure_initialize(struct bt_field_common *field,
 
        BT_LOGD("Initializing common structure field object: ft-addr=%p", type);
        bt_field_common_initialize(field, type, release_func, methods);
-       structure->fields = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_put);
+       structure->fields = g_ptr_array_new_with_free_func(field_release_func);
        g_ptr_array_set_size(structure->fields, structure_type->fields->len);
 
-       /* Create all fields contained by the structure field. */
+       /* Create all fields contained in the structure field. */
        for (i = 0; i < structure_type->fields->len; i++) {
                struct bt_field_common *field;
-               struct structure_field_common *struct_field =
-                       g_ptr_array_index(structure_type->fields, i);
-
+               struct bt_field_type_common_structure_field *struct_field =
+                       BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               structure_type, i);
                field = field_create_func(struct_field->type);
                if (!field) {
                        BT_LOGE("Failed to create structure field's member: name=\"%s\", index=%zu",
@@ -651,9 +690,9 @@ struct bt_field *bt_field_structure_create(struct bt_field_type *type)
        }
 
        iret = bt_field_common_structure_initialize(BT_TO_COMMON(structure),
-               (void *) type, bt_field_common_structure_destroy_recursive,
-               &bt_field_structure_methods,
-               (bt_field_common_create_func) bt_field_create);
+               (void *) type, NULL, &bt_field_structure_methods,
+               (bt_field_common_create_func) bt_field_create_recursive,
+               (GDestroyNotify) bt_field_destroy_recursive);
        if (iret) {
                BT_PUT(structure);
                goto end;
@@ -666,25 +705,84 @@ end:
        return (void *) structure;
 }
 
+BT_HIDDEN
+int bt_field_common_variant_initialize(struct bt_field_common *field,
+               struct bt_field_type_common *type,
+               bt_object_release_func release_func,
+               struct bt_field_common_methods *methods,
+               bt_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func)
+{
+       int ret = 0;
+       struct bt_field_type_common_variant *variant_type =
+               BT_FROM_COMMON(type);
+       struct bt_field_common_variant *variant = BT_FROM_COMMON(field);
+       size_t i;
+
+       BT_LOGD("Initializing common variant field object: ft-addr=%p", type);
+       bt_field_common_initialize(field, type, release_func, methods);
+       ret = bt_field_type_common_variant_update_choices(type);
+       if (ret) {
+               BT_LOGE("Cannot update common variant field type choices: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+       variant->fields = g_ptr_array_new_with_free_func(field_release_func);
+       g_ptr_array_set_size(variant->fields, variant_type->choices->len);
+
+       /* Create all fields contained in the variant field. */
+       for (i = 0; i < variant_type->choices->len; i++) {
+               struct bt_field_common *field;
+               struct bt_field_type_common_variant_choice *var_choice =
+                       BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               variant_type, i);
+
+               field = field_create_func(var_choice->type);
+               if (!field) {
+                       BT_LOGE("Failed to create variant field's member: name=\"%s\", index=%zu",
+                               g_quark_to_string(var_choice->name), i);
+                       ret = -1;
+                       goto end;
+               }
+
+               g_ptr_array_index(variant->fields, i) = field;
+       }
+
+       BT_LOGD("Initialized common variant field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
 static
 struct bt_field *bt_field_variant_create(struct bt_field_type *type)
 {
        struct bt_field_common_variant *variant = g_new0(
                struct bt_field_common_variant, 1);
+       int iret;
 
        BT_LOGD("Creating variant field object: ft-addr=%p", type);
 
-       if (variant) {
-               bt_field_common_initialize(BT_TO_COMMON(variant),
-                       (void *) type,
-                       bt_field_common_variant_destroy_recursive,
-                       &bt_field_variant_methods);
-               BT_LOGD("Created variant field object: addr=%p, ft-addr=%p",
-                       variant, type);
-       } else {
+       if (!variant) {
                BT_LOGE_STR("Failed to allocate one variant field.");
+               goto end;
+       }
+
+       iret = bt_field_common_variant_initialize(BT_TO_COMMON(variant),
+               (void *) type, NULL, &bt_field_variant_methods,
+               (bt_field_common_create_func) bt_field_create_recursive,
+               (GDestroyNotify) bt_field_destroy_recursive);
+       if (iret) {
+               BT_PUT(variant);
+               goto end;
        }
 
+       BT_LOGD("Created variant field object: addr=%p, ft-addr=%p",
+               variant, type);
+
+end:
        return (void *) variant;
 }
 
@@ -692,12 +790,15 @@ BT_HIDDEN
 int bt_field_common_array_initialize(struct bt_field_common *field,
                struct bt_field_type_common *type,
                bt_object_release_func release_func,
-               struct bt_field_common_methods *methods)
+               struct bt_field_common_methods *methods,
+               bt_field_common_create_func field_create_func,
+               GDestroyNotify field_destroy_func)
 {
        struct bt_field_type_common_array *array_type = BT_FROM_COMMON(type);
        struct bt_field_common_array *array = BT_FROM_COMMON(field);
        unsigned int array_length;
        int ret = 0;
+       uint64_t i;
 
        BT_LOGD("Initializing common array field object: ft-addr=%p", type);
        BT_ASSERT(type);
@@ -709,8 +810,18 @@ int bt_field_common_array_initialize(struct bt_field_common *field,
                goto end;
        }
 
-       g_ptr_array_set_free_func(array->elements, (GDestroyNotify) bt_put);
+       g_ptr_array_set_free_func(array->elements, field_destroy_func);
        g_ptr_array_set_size(array->elements, array_length);
+
+       for (i = 0; i < array_length; i++) {
+               array->elements->pdata[i] = field_create_func(
+                       array_type->element_ft);
+               if (!array->elements->pdata[i]) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
        BT_LOGD("Initialized common array field object: addr=%p, ft-addr=%p",
                field, type);
 
@@ -734,9 +845,9 @@ struct bt_field *bt_field_array_create(struct bt_field_type *type)
        }
 
        ret = bt_field_common_array_initialize(BT_TO_COMMON(array),
-               (void *) type,
-               bt_field_common_array_destroy_recursive,
-               &bt_field_array_methods);
+               (void *) type, NULL, &bt_field_array_methods,
+               (bt_field_common_create_func) bt_field_create_recursive,
+               (GDestroyNotify) bt_field_destroy_recursive);
        if (ret) {
                BT_PUT(array);
                goto end;
@@ -749,25 +860,60 @@ end:
        return (void *) array;
 }
 
+BT_HIDDEN
+int bt_field_common_sequence_initialize(struct bt_field_common *field,
+               struct bt_field_type_common *type,
+               bt_object_release_func release_func,
+               struct bt_field_common_methods *methods,
+               GDestroyNotify field_destroy_func)
+{
+       struct bt_field_common_sequence *sequence = BT_FROM_COMMON(field);
+       int ret = 0;
+
+       BT_LOGD("Initializing common sequence field object: ft-addr=%p", type);
+       BT_ASSERT(type);
+       bt_field_common_initialize(field, type, release_func, methods);
+       sequence->elements = g_ptr_array_new();
+       if (!sequence->elements) {
+               ret = -1;
+               goto end;
+       }
+
+       g_ptr_array_set_free_func(sequence->elements, field_destroy_func);
+       BT_LOGD("Initialized common sequence field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
 static
 struct bt_field *bt_field_sequence_create(struct bt_field_type *type)
 {
-       struct bt_field_common_sequence *sequence = g_new0(
-               struct bt_field_common_sequence, 1);
+       struct bt_field_common_sequence *sequence =
+               g_new0(struct bt_field_common_sequence, 1);
+       int ret;
 
        BT_LOGD("Creating sequence field object: ft-addr=%p", type);
+       BT_ASSERT(type);
 
-       if (sequence) {
-               bt_field_common_initialize(BT_TO_COMMON(sequence),
-                       (void *) type,
-                       bt_field_common_sequence_destroy_recursive,
-                       &bt_field_sequence_methods);
-               BT_LOGD("Created sequence field object: addr=%p, ft-addr=%p",
-                       sequence, type);
-       } else {
+       if (!sequence) {
                BT_LOGE_STR("Failed to allocate one sequence field.");
+               goto end;
        }
 
+       ret = bt_field_common_sequence_initialize(BT_TO_COMMON(sequence),
+               (void *) type, NULL, &bt_field_sequence_methods,
+               (GDestroyNotify) bt_field_destroy_recursive);
+       if (ret) {
+               BT_PUT(sequence);
+               goto end;
+       }
+
+       BT_LOGD("Created sequence field object: addr=%p, ft-addr=%p",
+               sequence, type);
+
+end:
        return (void *) sequence;
 }
 
@@ -781,9 +927,7 @@ struct bt_field *bt_field_string_create(struct bt_field_type *type)
 
        if (string) {
                bt_field_common_initialize(BT_TO_COMMON(string),
-                       (void *) type,
-                       bt_field_common_string_destroy,
-                       &bt_field_string_methods);
+                       (void *) type, NULL, &bt_field_string_methods);
                BT_LOGD("Created string field object: addr=%p, ft-addr=%p",
                        string, type);
        } else {
@@ -799,28 +943,6 @@ int bt_field_common_generic_validate(struct bt_field_common *field)
        return (field && field->payload_set) ? 0 : -1;
 }
 
-BT_HIDDEN
-int bt_field_common_enumeration_validate_recursive(
-               struct bt_field_common *field)
-{
-       int ret;
-       struct bt_field_common_enumeration *enumeration = BT_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       if (!enumeration->payload) {
-               BT_ASSERT_PRE_MSG("Invalid enumeration field: payload is not set: "
-                       "%!+_f", field);
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_field_common_validate_recursive(enumeration->payload);
-
-end:
-       return ret;
-}
-
 BT_HIDDEN
 int bt_field_common_structure_validate_recursive(struct bt_field_common *field)
 {
@@ -860,13 +982,15 @@ int bt_field_common_variant_validate_recursive(struct bt_field_common *field)
        struct bt_field_common_variant *variant = BT_FROM_COMMON(field);
 
        BT_ASSERT(field);
-       ret = bt_field_common_validate_recursive(variant->payload);
-       if (ret) {
-               BT_ASSERT_PRE_MSG("Invalid variant field's payload field: "
-                       "%![variant-field-]+_f, %![payload-field-]+_f",
-                       field, variant->payload);
+
+       if (!variant->current_field) {
+               ret = -1;
+               goto end;
        }
 
+       ret = bt_field_common_validate_recursive(variant->current_field);
+
+end:
        return ret;
 }
 
@@ -925,20 +1049,6 @@ void bt_field_common_generic_reset(struct bt_field_common *field)
        field->payload_set = false;
 }
 
-BT_HIDDEN
-void bt_field_common_enumeration_reset_recursive(struct bt_field_common *field)
-{
-       struct bt_field_common_enumeration *enumeration = BT_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       if (!enumeration->payload) {
-               return;
-       }
-
-       bt_field_common_reset_recursive(enumeration->payload);
-}
-
 BT_HIDDEN
 void bt_field_common_structure_reset_recursive(struct bt_field_common *field)
 {
@@ -969,8 +1079,7 @@ void bt_field_common_variant_reset_recursive(struct bt_field_common *field)
        struct bt_field_common_variant *variant = BT_FROM_COMMON(field);
 
        BT_ASSERT(field);
-       BT_PUT(variant->tag);
-       BT_PUT(variant->payload);
+       variant->current_field = NULL;
 }
 
 BT_HIDDEN
@@ -1000,15 +1109,18 @@ BT_HIDDEN
 void bt_field_common_sequence_reset_recursive(struct bt_field_common *field)
 {
        struct bt_field_common_sequence *sequence = BT_FROM_COMMON(field);
+       uint64_t i;
 
        BT_ASSERT(field);
 
-       if (sequence->elements) {
-               g_ptr_array_free(sequence->elements, TRUE);
-               sequence->elements = NULL;
+       for (i = 0; i < sequence->elements->len; i++) {
+               if (sequence->elements->pdata[i]) {
+                       bt_field_common_reset_recursive(
+                               sequence->elements->pdata[i]);
+               }
        }
 
-       BT_PUT(sequence->length);
+       sequence->length = 0;
 }
 
 BT_HIDDEN
@@ -1024,367 +1136,60 @@ void bt_field_common_string_reset(struct bt_field_common *field)
        }
 }
 
-static
-struct bt_field_common *bt_field_integer_copy(struct bt_field_common *src)
-{
-       struct bt_field_common_integer *integer_src = (void *) src;
-       struct bt_field_common_integer *integer_dst;
-
-       BT_LOGD("Copying integer field: src-field-addr=%p", src);
-       integer_dst = (void *) bt_field_create((void *) src->type);
-       if (!integer_dst) {
-               goto end;
-       }
-
-       integer_dst->payload = integer_src->payload;
-       BT_LOGD_STR("Copied integer field.");
-
-end:
-       return BT_TO_COMMON(integer_dst);
-}
-
-static
-struct bt_field_common *bt_field_enumeration_copy_recursive(
-               struct bt_field_common *src)
-{
-       struct bt_field_common_enumeration *enum_src = BT_FROM_COMMON(src);
-       struct bt_field_common_enumeration *enum_dst;
-
-       BT_LOGD("Copying enumeration field: src-field-addr=%p", src);
-       enum_dst = (void *) bt_field_create((void *) src->type);
-       if (!enum_dst) {
-               goto error;
-       }
-
-       if (enum_src->payload) {
-               BT_LOGD_STR("Copying enumeration field's payload field.");
-               enum_dst->payload = (void *)
-                       bt_field_copy((void *) enum_src->payload);
-               if (!enum_dst->payload) {
-                       BT_LOGE_STR("Cannot copy enumeration field's payload field.");
-                       goto error;
-               }
-       }
-
-       BT_LOGD_STR("Copied enumeration field.");
-       goto end;
-
-error:
-       BT_PUT(enum_dst);
-
-end:
-       return BT_TO_COMMON(enum_dst);
-}
-
-static
-struct bt_field_common *bt_field_floating_point_copy(
-               struct bt_field_common *src)
-{
-       struct bt_field_common_floating_point *float_src = BT_FROM_COMMON(src);
-       struct bt_field_common_floating_point *float_dst;
-
-       BT_LOGD("Copying floating point number field: src-field-addr=%p", src);
-       float_dst = (void *) bt_field_create((void *) src->type);
-       if (!float_dst) {
-               goto end;
-       }
-
-       float_dst->payload = float_src->payload;
-       BT_LOGD_STR("Copied floating point number field.");
-
-end:
-       return BT_TO_COMMON(float_dst);
-}
-
-static
-struct bt_field_common *bt_field_structure_copy_recursive(
-               struct bt_field_common *src)
-{
-       int64_t i;
-       struct bt_field_common_structure *struct_src = BT_FROM_COMMON(src);
-       struct bt_field_common_structure *struct_dst;
-
-       BT_LOGD("Copying structure field: src-field-addr=%p", src);
-       struct_dst = (void *) bt_field_create((void *) src->type);
-       if (!struct_dst) {
-               goto error;
-       }
-
-       g_ptr_array_set_size(struct_dst->fields, struct_src->fields->len);
-
-       for (i = 0; i < struct_src->fields->len; i++) {
-               struct bt_field_common *field =
-                       g_ptr_array_index(struct_src->fields, i);
-               struct bt_field_common *field_copy = NULL;
-
-               if (field) {
-                       BT_LOGD("Copying structure field's field: src-field-addr=%p"
-                               "index=%" PRId64, field, i);
-                       field_copy = (void *) bt_field_copy((void *) field);
-                       if (!field_copy) {
-                               BT_LOGE("Cannot copy structure field's field: "
-                                       "src-field-addr=%p, index=%" PRId64,
-                                       field, i);
-                               goto error;
-                       }
-               }
-
-               BT_MOVE(g_ptr_array_index(struct_dst->fields, i), field_copy);
-       }
-
-       BT_LOGD_STR("Copied structure field.");
-       goto end;
-
-error:
-       BT_PUT(struct_dst);
-
-end:
-       return BT_TO_COMMON(struct_dst);
-}
-
-static
-struct bt_field_common *bt_field_variant_copy_recursive(
-               struct bt_field_common *src)
-{
-       struct bt_field_common_variant *variant_src = BT_FROM_COMMON(src);
-       struct bt_field_common_variant *variant_dst;
-
-       BT_LOGD("Copying variant field: src-field-addr=%p", src);
-       variant_dst = (void *) bt_field_create((void *) src->type);
-       if (!variant_dst) {
-               goto end;
-       }
-
-       if (variant_src->tag) {
-               BT_LOGD_STR("Copying variant field's tag field.");
-               variant_dst->tag = (void *) bt_field_copy(
-                       (void *) variant_src->tag);
-               if (!variant_dst->tag) {
-                       BT_LOGE_STR("Cannot copy variant field's tag field.");
-                       goto error;
-               }
-       }
-       if (variant_src->payload) {
-               BT_LOGD_STR("Copying variant field's payload field.");
-               variant_dst->payload = (void *) bt_field_copy(
-                       (void *) variant_src->payload);
-               if (!variant_dst->payload) {
-                       BT_LOGE_STR("Cannot copy variant field's payload field.");
-                       goto error;
-               }
-       }
-
-       BT_LOGD_STR("Copied variant field.");
-       goto end;
-
-error:
-       BT_PUT(variant_dst);
-
-end:
-       return BT_TO_COMMON(variant_dst);
-}
-
-static
-struct bt_field_common *bt_field_array_copy_recursive(
-               struct bt_field_common *src)
-{
-       int64_t i;
-       struct bt_field_common_array *array_src = BT_FROM_COMMON(src);
-       struct bt_field_common_array *array_dst;
-
-       BT_LOGD("Copying array field: src-field-addr=%p", src);
-       array_dst = (void *) bt_field_create((void *) src->type);
-       if (!array_dst) {
-               goto error;
-       }
-
-       g_ptr_array_set_size(array_dst->elements, array_src->elements->len);
-       for (i = 0; i < array_src->elements->len; i++) {
-               struct bt_field_common *field =
-                       g_ptr_array_index(array_src->elements, i);
-               struct bt_field_common *field_copy = NULL;
-
-               if (field) {
-                       BT_LOGD("Copying array field's element field: field-addr=%p, "
-                               "index=%" PRId64, field, i);
-                       field_copy = (void *) bt_field_copy((void *) field);
-                       if (!field_copy) {
-                               BT_LOGE("Cannot copy array field's element field: "
-                                       "src-field-addr=%p, index=%" PRId64,
-                                       field, i);
-                               goto error;
-                       }
-               }
-
-               g_ptr_array_index(array_dst->elements, i) = field_copy;
-       }
-
-       BT_LOGD_STR("Copied array field.");
-       goto end;
-
-error:
-       BT_PUT(array_dst);
-
-end:
-       return BT_TO_COMMON(array_dst);
-}
-
-static
-struct bt_field_common *bt_field_sequence_copy_recursive(
-               struct bt_field_common *src)
-{
-       int ret = 0;
-       int64_t i;
-       struct bt_field_common_sequence *sequence_src = BT_FROM_COMMON(src);
-       struct bt_field_common_sequence *sequence_dst;
-       struct bt_field_common *src_length;
-       struct bt_field_common *dst_length;
-
-       BT_LOGD("Copying sequence field: src-field-addr=%p", src);
-       sequence_dst = (void *) bt_field_create((void *) src->type);
-       if (!sequence_dst) {
-               goto error;
-       }
-
-       src_length = bt_field_common_sequence_borrow_length(src);
-       if (!src_length) {
-               /* no length set yet: keep destination sequence empty */
-               goto end;
-       }
-
-       /* copy source length */
-       BT_LOGD_STR("Copying sequence field's length field.");
-       dst_length = (void *) bt_field_copy((void *) src_length);
-       if (!dst_length) {
-               BT_LOGE_STR("Cannot copy sequence field's length field.");
-               goto error;
-       }
-
-       /* this will initialize the destination sequence's internal array */
-       ret = bt_field_common_sequence_set_length(
-               BT_TO_COMMON(sequence_dst), dst_length);
-       bt_put(dst_length);
-       if (ret) {
-               BT_LOGE("Cannot set sequence field copy's length field: "
-                       "dst-length-field-addr=%p", dst_length);
-               goto error;
-       }
-
-       BT_ASSERT(sequence_dst->elements->len == sequence_src->elements->len);
-
-       for (i = 0; i < sequence_src->elements->len; i++) {
-               struct bt_field_common *field =
-                       g_ptr_array_index(sequence_src->elements, i);
-               struct bt_field_common *field_copy = NULL;
-
-               if (field) {
-                       BT_LOGD("Copying sequence field's element field: field-addr=%p, "
-                               "index=%" PRId64, field, i);
-                       field_copy = (void *) bt_field_copy((void *) field);
-                       if (!field_copy) {
-                               BT_LOGE("Cannot copy sequence field's element field: "
-                                       "src-field-addr=%p, index=%" PRId64,
-                                       field, i);
-                               goto error;
-                       }
-               }
-
-               g_ptr_array_index(sequence_dst->elements, i) = field_copy;
-       }
-
-       BT_LOGD_STR("Copied sequence field.");
-       goto end;
-
-error:
-       BT_PUT(sequence_dst);
-
-end:
-       return BT_TO_COMMON(sequence_dst);
-}
-
-static
-struct bt_field_common *bt_field_string_copy(struct bt_field_common *src)
-{
-       struct bt_field_common_string *string_src = BT_FROM_COMMON(src);
-       struct bt_field_common_string *string_dst;
-
-       BT_LOGD("Copying string field: src-field-addr=%p", src);
-       string_dst = (void *) bt_field_create((void *) src->type);
-       if (!string_dst) {
-               goto error;
-       }
-
-       if (string_src->payload) {
-               string_dst->payload = g_string_new(string_src->payload->str);
-               if (!string_dst->payload) {
-                       BT_LOGE_STR("Failed to allocate a GString.");
-                       goto error;
-               }
-       }
-
-       BT_LOGD_STR("Copied string field.");
-       goto end;
-
-error:
-       BT_PUT(string_dst);
-
-end:
-       return BT_TO_COMMON(string_dst);
-}
-
 BT_HIDDEN
-void bt_field_common_generic_freeze(struct bt_field_common *field)
+void bt_field_common_generic_set_is_frozen(struct bt_field_common *field,
+               bool is_frozen)
 {
-       field->frozen = true;
+       field->frozen = is_frozen;
 }
 
 BT_HIDDEN
-void bt_field_common_enumeration_freeze_recursive(struct bt_field_common *field)
+void bt_field_common_structure_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen)
 {
-       struct bt_field_common_enumeration *enum_field = BT_FROM_COMMON(field);
-
-       BT_LOGD("Freezing enumeration field object: addr=%p", field);
-       BT_LOGD("Freezing enumeration field object's contained payload field: payload-field-addr=%p", enum_field->payload);
-       bt_field_common_freeze_recursive(enum_field->payload);
-       bt_field_common_generic_freeze(field);
-}
-
-BT_HIDDEN
-void bt_field_common_structure_freeze_recursive(struct bt_field_common *field)
-{
-       int64_t i;
+       uint64_t i;
        struct bt_field_common_structure *structure_field =
                BT_FROM_COMMON(field);
 
        BT_LOGD("Freezing structure field object: addr=%p", field);
 
        for (i = 0; i < structure_field->fields->len; i++) {
-               struct bt_field_common *field =
+               struct bt_field_common *struct_field =
                        g_ptr_array_index(structure_field->fields, i);
 
                BT_LOGD("Freezing structure field's field: field-addr=%p, index=%" PRId64,
-                       field, i);
-               bt_field_common_freeze_recursive(field);
+                       struct_field, i);
+               bt_field_common_set_is_frozen_recursive(struct_field,
+                       is_frozen);
        }
 
-       bt_field_common_generic_freeze(field);
+       bt_field_common_generic_set_is_frozen(field, is_frozen);
 }
 
 BT_HIDDEN
-void bt_field_common_variant_freeze_recursive(struct bt_field_common *field)
+void bt_field_common_variant_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen)
 {
+       uint64_t i;
        struct bt_field_common_variant *variant_field = BT_FROM_COMMON(field);
 
        BT_LOGD("Freezing variant field object: addr=%p", field);
-       BT_LOGD("Freezing variant field object's tag field: tag-field-addr=%p", variant_field->tag);
-       bt_field_common_freeze_recursive(variant_field->tag);
-       BT_LOGD("Freezing variant field object's payload field: payload-field-addr=%p", variant_field->payload);
-       bt_field_common_freeze_recursive(variant_field->payload);
-       bt_field_common_generic_freeze(field);
+
+       for (i = 0; i < variant_field->fields->len; i++) {
+               struct bt_field_common *var_field =
+                       g_ptr_array_index(variant_field->fields, i);
+
+               BT_LOGD("Freezing variant field's field: field-addr=%p, index=%" PRId64,
+                       var_field, i);
+               bt_field_common_set_is_frozen_recursive(var_field, is_frozen);
+       }
+
+       bt_field_common_generic_set_is_frozen(field, is_frozen);
 }
 
 BT_HIDDEN
-void bt_field_common_array_freeze_recursive(struct bt_field_common *field)
+void bt_field_common_array_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen)
 {
        int64_t i;
        struct bt_field_common_array *array_field = BT_FROM_COMMON(field);
@@ -1398,39 +1203,38 @@ void bt_field_common_array_freeze_recursive(struct bt_field_common *field)
                BT_LOGD("Freezing array field object's element field: "
                        "element-field-addr=%p, index=%" PRId64,
                        elem_field, i);
-               bt_field_common_freeze_recursive(elem_field);
+               bt_field_common_set_is_frozen_recursive(elem_field, is_frozen);
        }
 
-       bt_field_common_generic_freeze(field);
+       bt_field_common_generic_set_is_frozen(field, is_frozen);
 }
 
 BT_HIDDEN
-void bt_field_common_sequence_freeze_recursive(struct bt_field_common *field)
+void bt_field_common_sequence_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen)
 {
        int64_t i;
        struct bt_field_common_sequence *sequence_field =
                BT_FROM_COMMON(field);
 
        BT_LOGD("Freezing sequence field object: addr=%p", field);
-       BT_LOGD("Freezing sequence field object's length field: length-field-addr=%p",
-               sequence_field->length);
-       bt_field_common_freeze_recursive(sequence_field->length);
 
-       for (i = 0; i < sequence_field->elements->len; i++) {
+       for (i = 0; i < sequence_field->length; i++) {
                struct bt_field_common *elem_field =
                        g_ptr_array_index(sequence_field->elements, i);
 
                BT_LOGD("Freezing sequence field object's element field: "
                        "element-field-addr=%p, index=%" PRId64,
                        elem_field, i);
-               bt_field_common_freeze_recursive(elem_field);
+               bt_field_common_set_is_frozen_recursive(elem_field, is_frozen);
        }
 
-       bt_field_common_generic_freeze(field);
+       bt_field_common_generic_set_is_frozen(field, is_frozen);
 }
 
 BT_HIDDEN
-void _bt_field_common_freeze_recursive(struct bt_field_common *field)
+void _bt_field_common_set_is_frozen_recursive(struct bt_field_common *field,
+               bool is_frozen)
 {
        if (!field) {
                goto end;
@@ -1440,10 +1244,11 @@ void _bt_field_common_freeze_recursive(struct bt_field_common *field)
                goto end;
        }
 
-       BT_LOGD("Freezing field object: addr=%p", field);
+       BT_LOGD("Setting field object's frozen state: addr=%p, is-frozen=%d",
+               field, is_frozen);
        BT_ASSERT(field_type_common_has_known_id(field->type));
-       BT_ASSERT(field->methods->freeze);
-       field->methods->freeze(field);
+       BT_ASSERT(field->methods->set_is_frozen);
+       field->methods->set_is_frozen(field, is_frozen);
 
 end:
        return;
@@ -1455,25 +1260,6 @@ bt_bool bt_field_common_generic_is_set(struct bt_field_common *field)
        return field && field->payload_set;
 }
 
-BT_HIDDEN
-bt_bool bt_field_common_enumeration_is_set_recursive(
-               struct bt_field_common *field)
-{
-       bt_bool is_set = BT_FALSE;
-       struct bt_field_common_enumeration *enumeration = BT_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       if (!enumeration->payload) {
-               goto end;
-       }
-
-       is_set = bt_field_common_is_set_recursive(enumeration->payload);
-
-end:
-       return is_set;
-}
-
 BT_HIDDEN
 bt_bool bt_field_common_structure_is_set_recursive(
                struct bt_field_common *field)
@@ -1500,9 +1286,16 @@ BT_HIDDEN
 bt_bool bt_field_common_variant_is_set_recursive(struct bt_field_common *field)
 {
        struct bt_field_common_variant *variant = BT_FROM_COMMON(field);
+       bt_bool is_set = BT_FALSE;
 
        BT_ASSERT(field);
-       return bt_field_common_is_set_recursive(variant->payload);
+
+       if (variant->current_field) {
+               is_set = bt_field_common_is_set_recursive(
+                       variant->current_field);
+       }
+
+       return is_set;
 }
 
 BT_HIDDEN
diff --git a/lib/ctf-ir/packet-context-field.c b/lib/ctf-ir/packet-context-field.c
new file mode 100644 (file)
index 0000000..598f1cf
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PACKET-CONTEXT-FIELD"
+#include <babeltrace/lib-logging-internal.h>
+
+#include <babeltrace/assert-pre-internal.h>
+#include <babeltrace/ctf-ir/packet-context-field.h>
+#include <babeltrace/ctf-ir/fields-internal.h>
+#include <babeltrace/ctf-ir/field-wrapper-internal.h>
+#include <glib.h>
+
+struct bt_field *bt_packet_context_field_borrow_field(
+               struct bt_packet_context_field *context_field)
+{
+       struct bt_field_wrapper *field_wrapper = (void *) context_field;
+
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Packet context field");
+       BT_ASSERT_PRE_NON_NULL(field_wrapper->field,
+               "Packet context field's field object");
+       return (void *) field_wrapper->field;
+}
+
+void bt_packet_context_field_release(struct bt_packet_context_field *context_field)
+{
+       struct bt_field_wrapper *field_wrapper = (void *) context_field;
+
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Packet context field");
+
+       /*
+        * Do not recycle because the pool could be destroyed at this
+        * point. This function is only called when there's an error
+        * anyway because the goal of a packet context field wrapper is
+        * to eventually move it to a packet with bt_packet_move_context()
+        * after creating it.
+        */
+       bt_field_wrapper_destroy(field_wrapper);
+}
diff --git a/lib/ctf-ir/packet-header-field.c b/lib/ctf-ir/packet-header-field.c
new file mode 100644 (file)
index 0000000..58d2716
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PACKET-HEADER-FIELD"
+#include <babeltrace/lib-logging-internal.h>
+
+#include <babeltrace/assert-pre-internal.h>
+#include <babeltrace/ctf-ir/packet-header-field.h>
+#include <babeltrace/ctf-ir/field-wrapper-internal.h>
+#include <babeltrace/ctf-ir/fields-internal.h>
+#include <glib.h>
+
+struct bt_field *bt_packet_header_field_borrow_field(
+               struct bt_packet_header_field *header_field)
+{
+       struct bt_field_wrapper *field_wrapper = (void *) header_field;
+
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Event header field");
+       BT_ASSERT_PRE_NON_NULL(field_wrapper->field,
+               "Event header field's field object");
+       return (void *) field_wrapper->field;
+}
+
+void bt_packet_header_field_release(struct bt_packet_header_field *header_field)
+{
+       struct bt_field_wrapper *field_wrapper = (void *) header_field;
+
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Event header field");
+
+       /*
+        * Do not recycle because the pool could be destroyed at this
+        * point. This function is only called when there's an error
+        * anyway because the goal of a packet header field wrapper is
+        * to eventually move it to a packet with
+        * bt_packet_move_header() after creating it.
+        */
+       bt_field_wrapper_destroy(field_wrapper);
+}
index 1bc5a0890e41cbe7d071eeeda2ddd580650287bf..232d5bd8f2ba36002e9df72ac6f2bf2501ca4a93 100644 (file)
@@ -31,6 +31,7 @@
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-ir/packet.h>
 #include <babeltrace/ctf-ir/packet-internal.h>
+#include <babeltrace/ctf-ir/field-wrapper-internal.h>
 #include <babeltrace/ctf-ir/trace.h>
 #include <babeltrace/ctf-ir/stream-class-internal.h>
 #include <babeltrace/ctf-ir/stream-class.h>
@@ -48,122 +49,161 @@ struct bt_stream *bt_packet_borrow_stream(struct bt_packet *packet)
        return packet->stream;
 }
 
-struct bt_field *bt_packet_borrow_header(
-               struct bt_packet *packet)
+struct bt_field *bt_packet_borrow_header(struct bt_packet *packet)
 {
        BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       return packet->header;
+       return packet->header ? (void *) packet->header->field : NULL;
 }
 
-BT_ASSERT_PRE_FUNC
-static inline bool validate_field_to_set(struct bt_field *field,
-               struct bt_field_type_common *expected_ft)
+struct bt_field *bt_packet_borrow_context(struct bt_packet *packet)
 {
-       bool ret = true;
-
-       if (!field) {
-               if (expected_ft) {
-                       BT_ASSERT_PRE_MSG("Setting no field, but expected "
-                               "field type is not NULL: "
-                               "%![field-]+f, %![expected-ft-]+F",
-                               field, expected_ft);
-                       ret = false;
-                       goto end;
-               }
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
+       return packet->context ? (void *) packet->context->field : NULL;
+}
 
-               goto end;
+BT_HIDDEN
+void _bt_packet_freeze(struct bt_packet *packet)
+{
+       if (!packet || packet->frozen) {
+               return;
        }
 
-       if (bt_field_type_compare(bt_field_borrow_type(field),
-                       BT_FROM_COMMON(expected_ft)) != 0) {
-               BT_ASSERT_PRE_MSG("Field type is different from expected "
-                       " field type: %![field-ft-]+F, %![expected-ft-]+F",
-                       bt_field_borrow_type(field), expected_ft);
-               ret = false;
-               goto end;
+       BT_LOGD("Freezing packet: addr=%p", packet);
+
+       if (packet->header) {
+               BT_LOGD_STR("Freezing packet's header field.");
+               bt_field_set_is_frozen_recursive((void *) packet->header->field, true);
        }
 
-end:
-       return ret;
+       if (packet->context) {
+               BT_LOGD_STR("Freezing packet's context field.");
+               bt_field_set_is_frozen_recursive((void *) packet->context->field, true);
+       }
+
+       packet->frozen = 1;
 }
 
-int bt_packet_set_header(struct bt_packet *packet,
-               struct bt_field *header)
+static inline
+void bt_packet_reset(struct bt_packet *packet)
 {
-       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_HOT(packet, "Packet", ": +%!+a", packet);
-       BT_ASSERT_PRE(validate_field_to_set(header,
-               bt_stream_class_borrow_trace(
-                       BT_FROM_COMMON(packet->stream->common.stream_class))->common.packet_header_field_type),
-               "Invalid packet header field: "
-               "%![packet-]+a, %![field-]+f", packet, header);
-       bt_put(packet->header);
-       packet->header = bt_get(header);
-       BT_LOGV("Set packet's header field: packet-addr=%p, packet-header-addr=%p",
-               packet, header);
-       return 0;
+       BT_ASSERT(packet);
+       packet->frozen = false;
+
+       if (packet->header) {
+               bt_field_set_is_frozen_recursive(
+                       (void *) packet->header->field, false);
+               bt_field_reset_recursive((void *) packet->header->field);
+       }
+
+       if (packet->context) {
+               bt_field_set_is_frozen_recursive(
+                       (void *) packet->context->field, false);
+               bt_field_reset_recursive((void *) packet->context->field);
+       }
 }
 
-struct bt_field *bt_packet_borrow_context(struct bt_packet *packet)
+static
+void bt_packet_header_field_recycle(struct bt_field_wrapper *header_field,
+               struct bt_trace *trace)
 {
-       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       return packet->context;
+       BT_ASSERT(header_field);
+       BT_LIB_LOGD("Recycling packet header field: "
+               "addr=%p, %![trace-]+t, %![field-]+f", header_field,
+               trace, header_field->field);
+       bt_object_pool_recycle_object(&trace->packet_header_field_pool,
+               header_field);
 }
 
-int bt_packet_set_context(struct bt_packet *packet,
-               struct bt_field *context)
+static
+void bt_packet_context_field_recycle(struct bt_field_wrapper *context_field,
+               struct bt_stream_class *stream_class)
 {
-       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_HOT(packet, "Packet", ": +%!+a", packet);
-       BT_ASSERT_PRE(validate_field_to_set(context,
-               BT_FROM_COMMON(packet->stream->common.stream_class->packet_context_field_type)),
-               "Invalid packet context field: "
-               "%![packet-]+a, %![field-]+f", packet, context);
-       bt_put(packet->context);
-       packet->context = bt_get(context);
-       BT_LOGV("Set packet's context field: packet-addr=%p, packet-context-addr=%p",
-               packet, context);
-       return 0;
+       BT_ASSERT(context_field);
+       BT_LIB_LOGD("Recycling packet context field: "
+               "addr=%p, %![sc-]+S, %![field-]+f", context_field,
+               stream_class, context_field->field);
+       bt_object_pool_recycle_object(&stream_class->packet_context_field_pool,
+               context_field);
 }
 
 BT_HIDDEN
-void _bt_packet_freeze(struct bt_packet *packet)
+void bt_packet_recycle(struct bt_packet *packet)
 {
-       if (!packet || packet->frozen) {
-               return;
-       }
+       struct bt_stream *stream;
 
-       BT_LOGD("Freezing packet: addr=%p", packet);
-       BT_LOGD_STR("Freezing packet's header field.");
-       bt_field_freeze_recursive(packet->header);
-       BT_LOGD_STR("Freezing packet's context field.");
-       bt_field_freeze_recursive(packet->context);
-       packet->frozen = 1;
+       BT_ASSERT(packet);
+       BT_LIB_LOGD("Recycling packet: %!+a", packet);
+
+       /*
+        * Those are the important ordered steps:
+        *
+        * 1. Reset the packet object (put any permanent reference it
+        *    has, unfreeze it and its fields in developer mode, etc.),
+        *    but do NOT put its stream's reference. This stream
+        *    contains the pool to which we're about to recycle this
+        *    packet object, so we must guarantee its existence thanks
+        *    to this existing reference.
+        *
+        * 2. Move the stream reference to our `stream`
+        *    variable so that we can set the packet's stream member
+        *    to NULL before recycling it. We CANNOT do this after
+        *    we put the stream reference because this bt_put()
+        *    could destroy the stream, also destroying its
+        *    packet pool, thus also destroying our packet object (this
+        *    would result in an invalid write access).
+        *
+        * 3. Recycle the packet object.
+        *
+        * 4. Put our stream reference.
+        */
+       bt_packet_reset(packet);
+       stream = packet->stream;
+       BT_ASSERT(stream);
+       packet->stream = NULL;
+       bt_object_pool_recycle_object(&stream->packet_pool, packet);
+       bt_put(stream);
 }
 
-static
-void bt_packet_destroy(struct bt_object *obj)
+BT_HIDDEN
+void bt_packet_destroy(struct bt_packet *packet)
 {
-       struct bt_packet *packet = (void *) obj;
-
        BT_LOGD("Destroying packet: addr=%p", packet);
-       BT_LOGD_STR("Putting packet's header field.");
-       bt_put(packet->header);
-       BT_LOGD_STR("Putting packet's context field.");
-       bt_put(packet->context);
+       BT_LOGD_STR("Destroying packet's header field.");
+
+       if (packet->header) {
+               if (packet->stream) {
+                       BT_LOGD_STR("Recycling packet's header field.");
+                       bt_packet_header_field_recycle(packet->header,
+                               bt_stream_class_borrow_trace(
+                                       bt_stream_borrow_class(packet->stream)));
+               } else {
+                       bt_field_wrapper_destroy(packet->header);
+               }
+       }
+
+       if (packet->context) {
+               if (packet->stream) {
+                       BT_LOGD_STR("Recycling packet's context field.");
+                       bt_packet_context_field_recycle(packet->context,
+                               bt_stream_borrow_class(packet->stream));
+               } else {
+                       bt_field_wrapper_destroy(packet->context);
+               }
+       }
+
        BT_LOGD_STR("Putting packet's stream.");
        bt_put(packet->stream);
        g_free(packet);
 }
 
-struct bt_packet *bt_packet_create(
-               struct bt_stream *stream)
+BT_HIDDEN
+struct bt_packet *bt_packet_new(struct bt_stream *stream)
 {
        struct bt_packet *packet = NULL;
        struct bt_stream_class *stream_class = NULL;
        struct bt_trace *trace = NULL;
 
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       BT_ASSERT(stream);
        BT_LOGD("Creating packet object: stream-addr=%p, "
                "stream-name=\"%s\", stream-class-addr=%p, "
                "stream-class-name=\"%s\", stream-class-id=%" PRId64,
@@ -181,16 +221,17 @@ struct bt_packet *bt_packet_create(
                goto end;
        }
 
-       bt_object_init(packet, bt_packet_destroy);
+       bt_object_init(packet, (bt_object_release_func) bt_packet_recycle);
        packet->stream = bt_get(stream);
 
        if (trace->common.packet_header_field_type) {
                BT_LOGD("Creating initial packet header field: ft-addr=%p",
                        trace->common.packet_header_field_type);
-               packet->header = bt_field_create(
-                       BT_FROM_COMMON(trace->common.packet_header_field_type));
+               packet->header = bt_field_wrapper_create(
+                       &trace->packet_header_field_pool,
+                       (void *) trace->common.packet_header_field_type);
                if (!packet->header) {
-                       BT_LOGE_STR("Cannot create initial packet header field object.");
+                       BT_LOGE("Cannot create packet header field wrapper.");
                        BT_PUT(packet);
                        goto end;
                }
@@ -199,10 +240,11 @@ struct bt_packet *bt_packet_create(
        if (stream->common.stream_class->packet_context_field_type) {
                BT_LOGD("Creating initial packet context field: ft-addr=%p",
                        stream->common.stream_class->packet_context_field_type);
-               packet->context = bt_field_create(
-                       BT_FROM_COMMON(stream->common.stream_class->packet_context_field_type));
+               packet->context = bt_field_wrapper_create(
+                       &stream_class->packet_context_field_pool,
+                       (void *) stream->common.stream_class->packet_context_field_type);
                if (!packet->context) {
-                       BT_LOGE_STR("Cannot create initial packet header field object.");
+                       BT_LOGE("Cannot create packet context field wrapper.");
                        BT_PUT(packet);
                        goto end;
                }
@@ -213,3 +255,82 @@ struct bt_packet *bt_packet_create(
 end:
        return packet;
 }
+
+struct bt_packet *bt_packet_create(struct bt_stream *stream)
+{
+       struct bt_packet *packet = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       packet = bt_object_pool_create_object(&stream->packet_pool);
+       if (!packet) {
+               BT_LIB_LOGE("Cannot allocate one packet from stream's packet pool: "
+                       "%![stream-]+s", stream);
+               goto error;
+       }
+
+       if (!packet->stream) {
+               packet->stream = bt_get(stream);
+       }
+
+       goto end;
+
+error:
+       if (packet) {
+               bt_packet_recycle(packet);
+               packet = NULL;
+       }
+
+end:
+       return packet;
+}
+
+int bt_packet_move_header(struct bt_packet *packet,
+               struct bt_packet_header_field *header_field)
+{
+       struct bt_trace *trace;
+       struct bt_field_wrapper *field_wrapper = (void *) header_field;
+
+       BT_ASSERT_PRE_NON_NULL(packet, "Event");
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Header field");
+       BT_ASSERT_PRE_HOT(packet, "Packet", ": +%!+a", packet);
+       trace = bt_stream_class_borrow_trace(
+               bt_stream_borrow_class(packet->stream));
+       BT_ASSERT_PRE(trace->common.packet_header_field_type,
+               "Trace has no packet header field type: %!+t",
+               trace);
+
+       /* TODO: compare field types (precondition) */
+
+       /* Recycle current header field: always exists */
+       BT_ASSERT(packet->header);
+       bt_packet_header_field_recycle(packet->header, trace);
+
+       /* Move new field */
+       packet->header = field_wrapper;
+       return 0;
+}
+
+int bt_packet_move_context(struct bt_packet *packet,
+               struct bt_packet_context_field *context_field)
+{
+       struct bt_stream_class *stream_class;
+       struct bt_field_wrapper *field_wrapper = (void *) context_field;
+
+       BT_ASSERT_PRE_NON_NULL(packet, "Event");
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Context field");
+       BT_ASSERT_PRE_HOT(packet, "Packet", ": +%!+a", packet);
+       stream_class = bt_stream_borrow_class(packet->stream);
+       BT_ASSERT_PRE(stream_class->common.packet_context_field_type,
+               "Stream class has no packet context field type: %!+S",
+               stream_class);
+
+       /* TODO: compare field types (precondition) */
+
+       /* Recycle current context field: always exists */
+       BT_ASSERT(packet->context);
+       bt_packet_context_field_recycle(packet->context, stream_class);
+
+       /* Move new field */
+       packet->context = field_wrapper;
+       return 0;
+}
index 2bb8b2903887fdbfa0495c8702f9eb93fa3044e4..c414f79d96c808be2ba5433adfd043d39009fc72 100644 (file)
@@ -39,6 +39,7 @@
 #include <babeltrace/ctf-ir/visitor-internal.h>
 #include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/ctf-ir/utils-internal.h>
+#include <babeltrace/ctf-ir/field-wrapper-internal.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/align-internal.h>
@@ -115,10 +116,36 @@ void bt_stream_class_destroy(struct bt_object *obj)
        BT_LOGD("Destroying stream class: addr=%p, name=\"%s\", id=%" PRId64,
                stream_class, bt_stream_class_get_name(stream_class),
                bt_stream_class_get_id(stream_class));
+
+       /*
+        * IMPORTANT: Finalize the common stream class BEFORE finalizing
+        * the pools because otherwise this scenario is possible:
+        *
+        * 1. Event header field object pool is finalized, thus
+        *    destroying its internal array and state.
+        *
+        * 2. Stream class is finalized: each event class is destroyed.
+        *
+        * 3. Destroying an event class finalizes its event pool,
+        *    destroying each contained event.
+        *
+        * 4. Destroying an event makes it recycle its event header
+        *    field to its stream class's event header field pool. But
+        *    said pool is already destroyed.
+        */
        bt_stream_class_common_finalize(BT_TO_COMMON(stream_class));
+       bt_object_pool_finalize(&stream_class->event_header_field_pool);
+       bt_object_pool_finalize(&stream_class->packet_context_field_pool);
        g_free(stream_class);
 }
 
+static
+void free_field_wrapper(struct bt_field_wrapper *field_wrapper,
+               struct bt_stream_class *stream_class)
+{
+       bt_field_wrapper_destroy((void *) field_wrapper);
+}
+
 struct bt_stream_class *bt_stream_class_create(const char *name)
 {
        struct bt_stream_class *stream_class = NULL;
@@ -138,6 +165,26 @@ struct bt_stream_class *bt_stream_class_create(const char *name)
                goto error;
        }
 
+       ret = bt_object_pool_initialize(&stream_class->event_header_field_pool,
+               (bt_object_pool_new_object_func) bt_field_wrapper_new,
+               (bt_object_pool_destroy_object_func) free_field_wrapper,
+               stream_class);
+       if (ret) {
+               BT_LOGE("Failed to initialize event header field pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
+       ret = bt_object_pool_initialize(&stream_class->packet_context_field_pool,
+               (bt_object_pool_new_object_func) bt_field_wrapper_new,
+               (bt_object_pool_destroy_object_func) free_field_wrapper,
+               stream_class);
+       if (ret) {
+               BT_LOGE("Failed to initialize packet context field pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
        BT_LOGD("Created stream class object: addr=%p, name=\"%s\"",
                stream_class, name);
        return stream_class;
@@ -147,6 +194,72 @@ error:
        return NULL;
 }
 
+struct bt_event_header_field *bt_stream_class_create_event_header_field(
+               struct bt_stream_class *stream_class)
+{
+       struct bt_field_wrapper *field_wrapper;
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE(stream_class->common.frozen,
+               "Stream class is not part of a trace: %!+S", stream_class);
+       BT_ASSERT_PRE(stream_class->common.event_header_field_type,
+               "Stream class has no event header field type: %!+S",
+               stream_class);
+       field_wrapper = bt_field_wrapper_create(
+               &stream_class->event_header_field_pool,
+               (void *) stream_class->common.event_header_field_type);
+       if (!field_wrapper) {
+               BT_LIB_LOGE("Cannot allocate one event header field from stream class: "
+                       "%![sc-]+S", stream_class);
+               goto error;
+       }
+
+       BT_ASSERT(field_wrapper->field);
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return (void *) field_wrapper;
+}
+
+struct bt_packet_context_field *bt_stream_class_create_packet_context_field(
+               struct bt_stream_class *stream_class)
+{
+       struct bt_field_wrapper *field_wrapper;
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE(stream_class->common.frozen,
+               "Stream class is not part of a trace: %!+S", stream_class);
+       BT_ASSERT_PRE(stream_class->common.packet_context_field_type,
+               "Stream class has no packet context field type: %!+S",
+               stream_class);
+       field_wrapper = bt_field_wrapper_create(
+               &stream_class->packet_context_field_pool,
+               (void *) stream_class->common.packet_context_field_type);
+       if (!field_wrapper) {
+               BT_LIB_LOGE("Cannot allocate one packet context field from stream class: "
+                       "%![sc-]+S", stream_class);
+               goto error;
+       }
+
+       BT_ASSERT(field_wrapper->field);
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return (void *) field_wrapper;
+}
+
 struct bt_trace *bt_stream_class_borrow_trace(struct bt_stream_class *stream_class)
 {
        return BT_FROM_COMMON(bt_stream_class_common_borrow_trace(
@@ -465,6 +578,8 @@ int bt_stream_class_add_event_class(
 {
        struct bt_trace *trace;
        int ret = 0;
+       uint64_t i;
+       struct bt_clock_class *old_clock_class;
 
        if (!stream_class) {
                BT_LOGW("Invalid parameter: stream class is NULL: "
@@ -473,6 +588,7 @@ int bt_stream_class_add_event_class(
                goto end;
        }
 
+       old_clock_class = stream_class->common.clock_class;
        trace = BT_FROM_COMMON(bt_stream_class_common_borrow_trace(
                BT_TO_COMMON(stream_class)));
        if (trace && trace->is_static) {
@@ -498,6 +614,28 @@ int bt_stream_class_add_event_class(
                (void) bt_trace_object_modification(&obj, trace);
        }
 
+       if (!old_clock_class && stream_class->common.clock_class) {
+               /*
+                * Adding this event class updated the stream class's
+                * single clock class: make sure all the events which
+                * exist in event pools have an existing clock value for
+                * this clock class so that any created event object in
+                * the future (from a pool or not) has this clock value
+                * available.
+                */
+               for (i = 0; i < stream_class->common.event_classes->len; i++) {
+                       struct bt_event_class *event_class =
+                               stream_class->common.event_classes->pdata[i];
+
+                       BT_ASSERT(event_class);
+                       ret = bt_event_class_update_event_pool_clock_values(
+                               event_class);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+       }
+
 end:
        return ret;
 }
index 70030454d6956c3cdbf68668ce5dc118e23f80d1..4eb05a8b6365019e05818c7e6652ce2d18d21af3 100644 (file)
@@ -36,6 +36,7 @@
 #include <babeltrace/ctf-ir/stream-class-internal.h>
 #include <babeltrace/ctf-ir/trace.h>
 #include <babeltrace/ctf-ir/trace-internal.h>
+#include <babeltrace/ctf-ir/packet-internal.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/compiler-internal.h>
 #include <babeltrace/align-internal.h>
@@ -80,6 +81,7 @@ void bt_stream_destroy(struct bt_object *obj)
 
        BT_LOGD("Destroying stream object: addr=%p, name=\"%s\"",
                stream, bt_stream_get_name(stream));
+       bt_object_pool_finalize(&stream->packet_pool);
        bt_stream_common_finalize((void *) obj);
        g_free(stream);
 }
@@ -173,6 +175,12 @@ end:
        return ret;
 }
 
+static
+void bt_stream_free_packet(struct bt_packet *packet, struct bt_stream *stream)
+{
+       bt_packet_destroy(packet);
+}
+
 static
 struct bt_stream *bt_stream_create_with_id_no_check(
                struct bt_stream_class *stream_class,
@@ -226,6 +234,15 @@ struct bt_stream *bt_stream_create_with_id_no_check(
                goto error;
        }
 
+       ret = bt_object_pool_initialize(&stream->packet_pool,
+               (bt_object_pool_new_object_func) bt_packet_new,
+               (bt_object_pool_destroy_object_func) bt_stream_free_packet,
+               stream);
+       if (ret) {
+               BT_LOGE("Failed to initialize packet pool: ret=%d", ret);
+               goto error;
+       }
+
        g_ptr_array_add(trace->common.streams, stream);
        BT_LOGD("Created stream object: addr=%p", stream);
        goto end;
index 77b8c67b0d7035f737e8b3490306c861f520e859..eb4211cf8885d739b45bf3ce0c8ad922b2c1b643 100644 (file)
@@ -39,6 +39,7 @@
 #include <babeltrace/ctf-ir/event-class-internal.h>
 #include <babeltrace/ctf-writer/functor-internal.h>
 #include <babeltrace/ctf-writer/clock-internal.h>
+#include <babeltrace/ctf-ir/field-wrapper-internal.h>
 #include <babeltrace/ctf-ir/field-types-internal.h>
 #include <babeltrace/ctf-ir/attributes-internal.h>
 #include <babeltrace/ctf-ir/validation-internal.h>
@@ -103,6 +104,7 @@ void bt_trace_destroy(struct bt_object *obj)
                g_ptr_array_free(trace->listeners, TRUE);
        }
 
+       bt_object_pool_finalize(&trace->packet_header_field_pool);
        bt_trace_common_finalize(BT_TO_COMMON(trace));
        g_free(trace);
 }
@@ -188,6 +190,13 @@ void bt_trace_common_finalize(struct bt_trace_common *trace)
        bt_put(trace->packet_header_field_type);
 }
 
+static
+void free_packet_header_field(struct bt_field_wrapper *field_wrapper,
+               struct bt_trace *trace)
+{
+       bt_field_wrapper_destroy(field_wrapper);
+}
+
 struct bt_trace *bt_trace_create(void)
 {
        struct bt_trace *trace = NULL;
@@ -220,6 +229,16 @@ struct bt_trace *bt_trace_create(void)
                goto error;
        }
 
+       ret = bt_object_pool_initialize(&trace->packet_header_field_pool,
+               (bt_object_pool_new_object_func) bt_field_wrapper_new,
+               (bt_object_pool_destroy_object_func) free_packet_header_field,
+               trace);
+       if (ret) {
+               BT_LOGE("Failed to initialize packet header field pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
        BT_LOGD("Created trace object: addr=%p", trace);
        return trace;
 
@@ -1966,3 +1985,35 @@ int bt_trace_remove_is_static_listener(
 end:
        return ret;
 }
+
+struct bt_packet_header_field *bt_trace_create_packet_header_field(
+               struct bt_trace *trace)
+{
+       struct bt_field_wrapper *field_wrapper;
+
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE(trace->common.packet_header_field_type,
+               "Trace has no packet header field type: %!+t",
+               trace);
+       field_wrapper = bt_field_wrapper_create(
+               &trace->packet_header_field_pool,
+               (void *) trace->common.packet_header_field_type);
+       if (!field_wrapper) {
+               BT_LIB_LOGE("Cannot allocate one packet header field from trace: "
+                       "%![trace-]+t", trace);
+               goto error;
+       }
+
+       BT_ASSERT(field_wrapper->field);
+       bt_trace_common_freeze(BT_TO_COMMON(trace));
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return (void *) field_wrapper;
+}
index 86d64d1620b016731fc5a4baebfa047836fd27b9..2e94fe5550eb846da7fc1c63417653c4bc976112 100644 (file)
@@ -62,6 +62,47 @@ int map_clock_classes_func(struct bt_stream_class_common *stream_class,
        return ret;
 }
 
+static
+void destroy_event_header_field(struct bt_field_wrapper *field_wrapper)
+{
+       BT_ASSERT(field_wrapper);
+       bt_put(field_wrapper->field);
+       bt_field_wrapper_destroy(field_wrapper);
+}
+
+static
+struct bt_field_wrapper *create_event_header_field(
+               struct bt_stream_class *stream_class,
+               struct bt_field_type_common *ft)
+{
+       struct bt_field_wrapper *field_wrapper = NULL;
+       struct bt_ctf_field *field = bt_ctf_field_create((void *) ft);
+
+       if (!field) {
+               goto error;
+       }
+
+       field_wrapper = bt_field_wrapper_new(NULL);
+       if (!field_wrapper) {
+               goto error;
+       }
+
+       field_wrapper->field = (void *) field;
+       field = NULL;
+       goto end;
+
+error:
+       bt_put(field);
+
+       if (field_wrapper) {
+               destroy_event_header_field(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return field_wrapper;
+}
+
 struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
 {
        int ret;
@@ -91,7 +132,10 @@ struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
                (bt_validation_flag_copy_field_type_func)
                        bt_ctf_field_type_copy,
                false, map_clock_classes_func,
-               (void *) bt_ctf_field_create);
+               (void *) bt_ctf_field_create,
+               (void *) bt_put,
+               (void *) create_event_header_field,
+               (void *) destroy_event_header_field);
        if (ret) {
                /* bt_event_common_initialize() logs errors */
                goto error;
@@ -133,7 +177,7 @@ int bt_ctf_event_set_payload(struct bt_ctf_event *event, const char *name,
        BT_ASSERT_PRE_NON_NULL(field, "Payload field");
        BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_TO_COMMON(event), "Event");
        return bt_ctf_field_structure_set_field_by_name(
-               BT_FROM_COMMON(event->common.payload_field), name, field);
+               (void *) event->common.payload_field, name, field);
 }
 
 struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event,
@@ -160,34 +204,16 @@ struct bt_ctf_field *bt_ctf_event_get_payload_field(
        return bt_get(bt_event_common_borrow_payload(BT_TO_COMMON(event)));
 }
 
-int bt_ctf_event_set_payload_field(struct bt_ctf_event *event,
-               struct bt_ctf_field *field)
-{
-       return bt_event_common_set_payload(BT_TO_COMMON(event), (void *) field);
-}
-
 struct bt_ctf_field *bt_ctf_event_get_header(struct bt_ctf_event *event)
 {
        return bt_get(bt_event_common_borrow_header(BT_TO_COMMON(event)));
 }
 
-int bt_ctf_event_set_header(struct bt_ctf_event *event,
-               struct bt_ctf_field *field)
-{
-       return bt_event_common_set_header(BT_TO_COMMON(event), (void *) field);
-}
-
 struct bt_ctf_field *bt_ctf_event_get_context(struct bt_ctf_event *event)
 {
        return bt_get(bt_event_common_borrow_context(BT_TO_COMMON(event)));
 }
 
-int bt_ctf_event_set_context(struct bt_ctf_event *event,
-               struct bt_ctf_field *field)
-{
-       return bt_event_common_set_context(BT_TO_COMMON(event), (void *) field);
-}
-
 struct bt_ctf_field *bt_ctf_event_get_stream_event_context(
                struct bt_ctf_event *event)
 {
@@ -195,17 +221,20 @@ struct bt_ctf_field *bt_ctf_event_get_stream_event_context(
                BT_TO_COMMON(event)));
 }
 
-int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event,
-               struct bt_ctf_field *field)
+static
+void release_event_header_field(struct bt_field_wrapper *field_wrapper,
+               struct bt_event_common *event_common)
 {
-       return bt_event_common_set_stream_event_context(
-               BT_TO_COMMON(event), (void *) field);
+       BT_ASSERT(field_wrapper);
+       BT_PUT(field_wrapper->field);
+       bt_field_wrapper_destroy(field_wrapper);
 }
 
 static
 void bt_ctf_event_destroy(struct bt_object *obj)
 {
-       bt_event_common_finalize(obj);
+       bt_event_common_finalize(obj, (void *) bt_put,
+               (void *) release_event_header_field);
        g_free(obj);
 }
 
@@ -260,3 +289,144 @@ void _bt_ctf_event_freeze(struct bt_ctf_event *event)
 {
        _bt_event_common_freeze(BT_TO_COMMON(event));
 }
+
+int bt_ctf_event_set_header(struct bt_ctf_event *event,
+               struct bt_ctf_field *header)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_TO_COMMON(event), "Event");
+
+       /*
+        * Ensure the provided header's type matches the one registered to the
+        * stream class.
+        */
+       if (header) {
+               BT_ASSERT_PRE(bt_field_type_common_compare(
+                       ((struct bt_field_common *) header)->type,
+                       bt_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type) == 0,
+                       "Header field's type is different from the "
+                       "expected field type: %![event-]+we, %![ft-]+wF, "
+                       "%![expected-ft-]+wF",
+                       event, ((struct bt_field_common *) header)->type,
+                       bt_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
+       } else {
+               BT_ASSERT_PRE(!bt_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type,
+                       "Setting no event header field, "
+                       "but event header field type is not NULL: ",
+                       "%![event-]+we, %![header-ft-]+wF",
+                       event,
+                       bt_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
+       }
+
+       bt_put(event->common.header_field->field);
+       event->common.header_field->field = bt_get(header);
+       BT_LOGV("Set event's header field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "header-field-addr=%p",
+               event, bt_event_class_common_get_name(event->common.class),
+               bt_event_class_common_get_id(event->common.class), header);
+       return 0;
+}
+
+int bt_ctf_event_common_set_payload(struct bt_ctf_event *event,
+               struct bt_ctf_field *payload)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_TO_COMMON(event), "Event");
+
+       if (payload) {
+               BT_ASSERT_PRE(bt_field_type_common_compare(
+                       ((struct bt_field_common *) payload)->type,
+                       event->common.class->payload_field_type) == 0,
+                       "Payload field's type is different from the "
+                       "expected field type: %![event-]+we, %![ft-]+wF, "
+                       "%![expected-ft-]+wF",
+                       event,
+                       ((struct bt_field_common *) payload)->type,
+                       event->common.class->payload_field_type);
+       } else {
+               BT_ASSERT_PRE(!event->common.class->payload_field_type,
+                       "Setting no event payload field, "
+                       "but event payload field type is not NULL: ",
+                       "%![event-]+we, %![payload-ft-]+wF",
+                       event, event->common.class->payload_field_type);
+       }
+
+       bt_put(event->common.payload_field);
+       event->common.payload_field = bt_get(payload);
+       BT_LOGV("Set event's payload field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "payload-field-addr=%p",
+               event, bt_event_class_common_get_name(event->common.class),
+               bt_event_class_common_get_id(event->common.class), payload);
+       return 0;
+}
+
+int bt_ctf_event_set_context(struct bt_ctf_event *event,
+               struct bt_ctf_field *context)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_TO_COMMON(event), "Event");
+
+       if (context) {
+               BT_ASSERT_PRE(bt_field_type_common_compare(
+                       ((struct bt_field_common *) context)->type,
+                       event->common.class->context_field_type) == 0,
+                       "Context field's type is different from the "
+                       "expected field type: %![event-]+we, %![ft-]+wF, "
+                       "%![expected-ft-]+wF",
+                       event, ((struct bt_field_common *) context)->type,
+                       event->common.class->context_field_type);
+       } else {
+               BT_ASSERT_PRE(!event->common.class->context_field_type,
+                       "Setting no event context field, "
+                       "but event context field type is not NULL: ",
+                       "%![event-]+we, %![context-ft-]+wF",
+                       event, event->common.class->context_field_type);
+       }
+
+       bt_put(event->common.context_field);
+       event->common.context_field = bt_get(context);
+       BT_LOGV("Set event's context field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "context-field-addr=%p",
+               event, bt_event_class_common_get_name(event->common.class),
+               bt_event_class_common_get_id(event->common.class), context);
+       return 0;
+}
+
+int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event,
+               struct bt_ctf_field *stream_event_context)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_ASSERT_PRE_EVENT_COMMON_HOT(BT_TO_COMMON(event), "Event");
+
+       if (stream_event_context) {
+               BT_ASSERT_PRE(bt_field_type_common_compare(
+                       ((struct bt_field_common *) stream_event_context)->type,
+                       bt_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type) == 0,
+                       "Stream event context field's type is different from the "
+                       "expected field type: %![event-]+we, %![ft-]+wF, "
+                       "%![expected-ft-]+wF",
+                       event,
+                       ((struct bt_field_common *) stream_event_context)->type,
+                       bt_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
+       } else {
+               BT_ASSERT_PRE(!bt_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type,
+                       "Setting no stream event context field, "
+                       "but stream event context field type is not NULL: ",
+                       "%![event-]+we, %![context-ft-]+wF",
+                       event,
+                       bt_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
+       }
+
+       bt_put(event->common.stream_event_context_field);
+       event->common.stream_event_context_field = bt_get(stream_event_context);
+       BT_LOGV("Set event's stream event context field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "stream-event-context-field-addr=%p",
+               event, bt_event_class_common_get_name(event->common.class),
+               bt_event_class_common_get_id(event->common.class),
+               stream_event_context);
+       return 0;
+}
index f8d3ff29ce5a630cfe25cf0cb90dc608c82698a4..7fbb0bf88ef92cb71a83c3d234c971676b85b9fc 100644 (file)
@@ -33,6 +33,7 @@
 #include <babeltrace/ctf-writer/field-types.h>
 #include <babeltrace/ctf-writer/field-types-internal.h>
 #include <babeltrace/ctf-writer/fields.h>
+#include <babeltrace/ctf-writer/fields-internal.h>
 #include <babeltrace/ctf-writer/clock-internal.h>
 #include <babeltrace/object-internal.h>
 #include <babeltrace/ref.h>
@@ -390,7 +391,9 @@ int bt_ctf_field_type_structure_serialize_recursive(
        g_string_append(context->string, "struct {\n");
 
        for (i = 0; i < structure->fields->len; i++) {
-               struct structure_field_common *field = structure->fields->pdata[i];
+               struct bt_field_type_common_structure_field *field =
+                       BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               structure, i);
 
                BT_LOGD("Serializing CTF writer structure field type's field metadata: "
                        "index=%zu, "
@@ -460,9 +463,10 @@ int bt_ctf_field_type_variant_serialize_recursive(
        }
 
        context->current_indentation_level++;
-       for (i = 0; i < variant->fields->len; i++) {
-               struct structure_field_common *field =
-                       variant->fields->pdata[i];
+       for (i = 0; i < variant->choices->len; i++) {
+               struct bt_field_type_common_variant_choice *field =
+                       BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               variant, i);
 
                BT_LOGD("Serializing CTF writer variant field type's field metadata: "
                        "index=%zu, "
@@ -976,9 +980,55 @@ struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag(
                struct bt_ctf_field_type *ft,
                struct bt_ctf_field *tag_field)
 {
-       return bt_get(bt_field_type_common_variant_borrow_field_type_from_tag(
-               (void *) ft, (void *) tag_field,
-               (bt_field_common_create_func) bt_field_create));
+       int ret;
+       int64_t choice_index;
+       struct bt_ctf_field *container;
+       struct bt_field_type_common_variant *var_ft = (void *) ft;
+       struct bt_ctf_field_type *ret_ft = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT_PRE_FT_COMMON_HAS_ID(ft, BT_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       BT_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(
+               (struct bt_field_common *) tag_field,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field");
+       BT_ASSERT_PRE_FIELD_COMMON_IS_SET((struct bt_field_common *) tag_field,
+               "Tag field");
+
+       container = bt_ctf_field_enumeration_borrow_container(tag_field);
+       BT_ASSERT(container);
+
+       if (var_ft->tag_ft->container_ft->is_signed) {
+               int64_t val;
+
+               ret = bt_ctf_field_integer_signed_get_value(container,
+                       &val);
+               BT_ASSERT(ret == 0);
+               choice_index = bt_field_type_common_variant_find_choice_index(
+                       (void *) ft, (uint64_t) val, true);
+       } else {
+               uint64_t val;
+
+               ret = bt_ctf_field_integer_unsigned_get_value(container,
+                       &val);
+               BT_ASSERT(ret == 0);
+               choice_index = bt_field_type_common_variant_find_choice_index(
+                       (void *) ft, val, false);
+       }
+
+       if (choice_index < 0) {
+               BT_LIB_LOGW("Cannot find variant field type's field: "
+                       "%![var-ft-]+wF, %![tag-field-]+wf", ft, tag_field);
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_variant_get_field_by_index(ft, NULL,
+               &ret_ft, choice_index);
+       BT_ASSERT(ret == 0);
+
+end:
+       return ret_ft;
 }
 
 int64_t bt_ctf_field_type_variant_get_field_count(struct bt_ctf_field_type *ft)
@@ -1312,20 +1362,20 @@ struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
                        key, value);
        }
 
+       g_array_set_size(copy_ft->fields, struct_ft->fields->len);
+
        for (i = 0; i < struct_ft->fields->len; i++) {
-               struct structure_field_common *entry, *copy_entry;
+               struct bt_field_type_common_structure_field *entry, *copy_entry;
                struct bt_field_type_common *field_ft_copy;
 
-               entry = g_ptr_array_index(struct_ft->fields, i);
+               entry = BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                       struct_ft, i);
+               copy_entry = BT_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                       copy_ft, i);
                BT_LOGD("Copying CTF writer structure field type's field: "
                        "index=%" PRId64 ", "
                        "field-ft-addr=%p, field-name=\"%s\"",
                        i, entry, g_quark_to_string(entry->name));
-               copy_entry = g_new0(struct structure_field_common, 1);
-               if (!copy_entry) {
-                       BT_LOGE_STR("Failed to allocate one structure field type field.");
-                       goto error;
-               }
 
                field_ft_copy = (void *) bt_ctf_field_type_copy(
                        (void *) entry->type);
@@ -1334,13 +1384,11 @@ struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
                                "index=%" PRId64 ", "
                                "field-ft-addr=%p, field-name=\"%s\"",
                                i, entry, g_quark_to_string(entry->name));
-                       g_free(copy_entry);
                        goto error;
                }
 
                copy_entry->name = entry->name;
                copy_entry->type = field_ft_copy;
-               g_ptr_array_add(copy_ft->fields, copy_entry);
        }
 
        BT_LOGD("Copied CTF writer structure field type: original-ft-addr=%p, copy-ft-addr=%p",
@@ -1385,26 +1433,26 @@ struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
        }
 
        /* Copy field_name_to_index */
-       g_hash_table_iter_init(&iter, var_ft->field_name_to_index);
+       g_hash_table_iter_init(&iter, var_ft->choice_name_to_index);
        while (g_hash_table_iter_next(&iter, &key, &value)) {
-               g_hash_table_insert(copy_ft->field_name_to_index,
+               g_hash_table_insert(copy_ft->choice_name_to_index,
                        key, value);
        }
 
-       for (i = 0; i < var_ft->fields->len; i++) {
-               struct structure_field_common *entry, *copy_entry;
+       g_array_set_size(copy_ft->choices, var_ft->choices->len);
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_field_type_common_variant_choice *entry, *copy_entry;
                struct bt_field_type_common *field_ft_copy;
+               uint64_t range_i;
 
-               entry = g_ptr_array_index(var_ft->fields, i);
+               entry = BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, i);
+               copy_entry = BT_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                       copy_ft, i);
                BT_LOGD("Copying CTF writer variant field type's field: "
                        "index=%" PRId64 ", "
                        "field-ft-addr=%p, field-name=\"%s\"",
                        i, entry, g_quark_to_string(entry->name));
-               copy_entry = g_new0(struct structure_field_common, 1);
-               if (!copy_entry) {
-                       BT_LOGE_STR("Failed to allocate one variant field type field.");
-                       goto error;
-               }
 
                field_ft_copy = (void *) bt_ctf_field_type_copy(
                        (void *) entry->type);
@@ -1419,7 +1467,16 @@ struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
 
                copy_entry->name = entry->name;
                copy_entry->type = field_ft_copy;
-               g_ptr_array_add(copy_ft->fields, copy_entry);
+
+               /* Copy ranges */
+               copy_entry->ranges = g_array_new(FALSE, TRUE,
+                       sizeof(struct bt_field_type_common_variant_choice_range));
+               BT_ASSERT(copy_entry->ranges);
+               g_array_set_size(copy_entry->ranges, entry->ranges->len);
+
+               for (range_i = 0; range_i < entry->ranges->len; range_i++) {
+                       copy_entry->ranges[range_i] = entry->ranges[range_i];
+               }
        }
 
        if (var_ft->tag_field_path) {
@@ -1432,7 +1489,8 @@ struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
                }
        }
 
-       BT_LOGD("Copied variant field type: original-ft-addr=%p, copy-ft-addr=%p",
+       copy_ft->choices_up_to_date = var_ft->choices_up_to_date;
+       BT_LOGD("Copied CTF writer variant field type: original-ft-addr=%p, copy-ft-addr=%p",
                ft, copy_ft);
 
 end:
index 1a0526d2546fcd096ded90c75d59b7f00699bd1c..11baf31b76c4c7bf1ee3fc6cf90bec5947813c61 100644 (file)
@@ -42,7 +42,7 @@
 #include <stdlib.h>
 
 static struct bt_field_common_methods bt_ctf_field_integer_methods = {
-       .freeze = bt_field_common_generic_freeze,
+       .set_is_frozen = bt_field_common_generic_set_is_frozen,
        .validate = bt_field_common_generic_validate,
        .copy = NULL,
        .is_set = bt_field_common_generic_is_set,
@@ -50,23 +50,37 @@ static struct bt_field_common_methods bt_ctf_field_integer_methods = {
 };
 
 static struct bt_field_common_methods bt_ctf_field_floating_point_methods = {
-       .freeze = bt_field_common_generic_freeze,
+       .set_is_frozen = bt_field_common_generic_set_is_frozen,
        .validate = bt_field_common_generic_validate,
        .copy = NULL,
        .is_set = bt_field_common_generic_is_set,
        .reset = bt_field_common_generic_reset,
 };
 
+static
+void bt_ctf_field_enumeration_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen);
+
+static
+int bt_ctf_field_enumeration_validate_recursive(struct bt_field_common *field);
+
+static
+bt_bool bt_ctf_field_enumeration_is_set_recursive(
+               struct bt_field_common *field);
+
+static
+void bt_ctf_field_enumeration_reset_recursive(struct bt_field_common *field);
+
 static struct bt_field_common_methods bt_ctf_field_enumeration_methods = {
-       .freeze = bt_field_common_enumeration_freeze_recursive,
-       .validate = bt_field_common_enumeration_validate_recursive,
+       .set_is_frozen = bt_ctf_field_enumeration_set_is_frozen_recursive,
+       .validate = bt_ctf_field_enumeration_validate_recursive,
        .copy = NULL,
-       .is_set = bt_field_common_enumeration_is_set_recursive,
-       .reset = bt_field_common_enumeration_reset_recursive,
+       .is_set = bt_ctf_field_enumeration_is_set_recursive,
+       .reset = bt_ctf_field_enumeration_reset_recursive,
 };
 
 static struct bt_field_common_methods bt_ctf_field_string_methods = {
-       .freeze = bt_field_common_generic_freeze,
+       .set_is_frozen = bt_field_common_generic_set_is_frozen,
        .validate = bt_field_common_generic_validate,
        .copy = NULL,
        .is_set = bt_field_common_generic_is_set,
@@ -74,7 +88,7 @@ static struct bt_field_common_methods bt_ctf_field_string_methods = {
 };
 
 static struct bt_field_common_methods bt_ctf_field_structure_methods = {
-       .freeze = bt_field_common_structure_freeze_recursive,
+       .set_is_frozen = bt_field_common_structure_set_is_frozen_recursive,
        .validate = bt_field_common_structure_validate_recursive,
        .copy = NULL,
        .is_set = bt_field_common_structure_is_set_recursive,
@@ -82,7 +96,7 @@ static struct bt_field_common_methods bt_ctf_field_structure_methods = {
 };
 
 static struct bt_field_common_methods bt_ctf_field_sequence_methods = {
-       .freeze = bt_field_common_sequence_freeze_recursive,
+       .set_is_frozen = bt_field_common_sequence_set_is_frozen_recursive,
        .validate = bt_field_common_sequence_validate_recursive,
        .copy = NULL,
        .is_set = bt_field_common_sequence_is_set_recursive,
@@ -90,19 +104,32 @@ static struct bt_field_common_methods bt_ctf_field_sequence_methods = {
 };
 
 static struct bt_field_common_methods bt_ctf_field_array_methods = {
-       .freeze = bt_field_common_array_freeze_recursive,
+       .set_is_frozen = bt_field_common_array_set_is_frozen_recursive,
        .validate = bt_field_common_array_validate_recursive,
        .copy = NULL,
        .is_set = bt_field_common_array_is_set_recursive,
        .reset = bt_field_common_array_reset_recursive,
 };
 
+static
+void bt_ctf_field_variant_set_is_frozen_recursive(struct bt_field_common *field,
+               bool is_frozen);
+
+static
+int bt_ctf_field_variant_validate_recursive(struct bt_field_common *field);
+
+static
+bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_field_common *field);
+
+static
+void bt_ctf_field_variant_reset_recursive(struct bt_field_common *field);
+
 static struct bt_field_common_methods bt_ctf_field_variant_methods = {
-       .freeze = bt_field_common_variant_freeze_recursive,
-       .validate = bt_field_common_variant_validate_recursive,
+       .set_is_frozen = bt_ctf_field_variant_set_is_frozen_recursive,
+       .validate = bt_ctf_field_variant_validate_recursive,
        .copy = NULL,
-       .is_set = bt_field_common_variant_is_set_recursive,
-       .reset = bt_field_common_variant_reset_recursive,
+       .is_set = bt_ctf_field_variant_is_set_recursive,
+       .reset = bt_ctf_field_variant_reset_recursive,
 };
 
 static
@@ -145,6 +172,80 @@ typedef int (*bt_ctf_field_serialize_recursive_func)(
                struct bt_field_common *, struct bt_ctf_stream_pos *,
                enum bt_ctf_byte_order);
 
+static
+void bt_ctf_field_integer_destroy(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer integer field object: addr=%p", field);
+       bt_field_common_integer_finalize((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer floating point field object: addr=%p",
+               field);
+       bt_field_common_floating_point_finalize((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_enumeration_destroy_recursive(struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_enumeration *enumeration = BT_FROM_COMMON(field);
+
+       BT_LOGD("Destroying CTF writer enumeration field object: addr=%p",
+               field);
+       BT_LOGD_STR("Putting container field.");
+       bt_put(enumeration->container);
+       bt_field_common_finalize((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_structure_destroy_recursive(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer structure field object: addr=%p", field);
+       bt_field_common_structure_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_variant_destroy_recursive(struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_variant *variant = BT_FROM_COMMON(field);
+
+       BT_LOGD("Destroying CTF writer variant field object: addr=%p", field);
+       BT_LOGD_STR("Putting tag field.");
+       bt_put(variant->tag);
+       bt_field_common_variant_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_array_destroy_recursive(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer array field object: addr=%p", field);
+       bt_field_common_array_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_sequence_destroy_recursive(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer sequence field object: addr=%p", field);
+       bt_field_common_sequence_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_string_destroy(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer string field object: addr=%p", field);
+       bt_field_common_string_finalize((void *) field);
+       g_free(field);
+}
+
 BT_HIDDEN
 int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
                struct bt_ctf_stream_pos *pos,
@@ -243,14 +344,14 @@ int bt_ctf_field_enumeration_serialize_recursive(struct bt_field_common *field,
                struct bt_ctf_stream_pos *pos,
                enum bt_ctf_byte_order native_byte_order)
 {
-       struct bt_field_common_enumeration *enumeration = BT_FROM_COMMON(field);
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
 
        BT_LOGV("Serializing enumeration field: addr=%p, pos-offset=%" PRId64 ", "
                "native-bo=%s", field, pos->offset,
                bt_common_byte_order_string((int) native_byte_order));
        BT_LOGV_STR("Serializing enumeration field's payload field.");
-       return bt_ctf_field_serialize_recursive((void *) enumeration->payload,
-               pos, native_byte_order);
+       return bt_ctf_field_serialize_recursive(
+               (void *) enumeration->container, pos, native_byte_order);
 }
 
 static
@@ -365,7 +466,7 @@ int bt_ctf_field_variant_serialize_recursive(struct bt_field_common *field,
                bt_common_byte_order_string((int) native_byte_order));
        BT_LOGV_STR("Serializing variant field's payload field.");
        return bt_ctf_field_serialize_recursive(
-               (void *) variant->payload, pos, native_byte_order);
+               (void *) variant->current_field, pos, native_byte_order);
 }
 
 static
@@ -513,17 +614,31 @@ enum bt_ctf_field_type_id bt_ctf_field_get_type_id(struct bt_ctf_field *field)
        return (int) field_common->type->id;
 }
 
-struct bt_ctf_field *bt_ctf_field_sequence_get_length(
-               struct bt_ctf_field *field)
-{
-       return bt_get(bt_field_common_sequence_borrow_length((void *) field));
-}
-
 int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field,
                struct bt_ctf_field *length_field)
 {
+       int ret;
+       struct bt_field_common *common_length_field = (void *) length_field;
+       uint64_t length;
+
+       BT_ASSERT_PRE_NON_NULL(length_field, "Length field");
+       BT_ASSERT_PRE_FIELD_COMMON_IS_SET((void *) length_field, "Length field");
+       BT_ASSERT_PRE(common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER ||
+                       common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM,
+               "Length field must be an integer or enumeration field: %!+wf",
+               length_field);
+
+       if (common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
+               struct bt_ctf_field_enumeration *enumeration = (void *)
+                       length_field;
+
+               length_field = (void *) enumeration->container;
+       }
+
+       ret = bt_ctf_field_integer_unsigned_get_value(length_field, &length);
+       BT_ASSERT(ret == 0);
        return bt_field_common_sequence_set_length((void *) field,
-               (void *) length_field);
+               length, (bt_field_common_create_func) bt_ctf_field_create);
 }
 
 struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index(
@@ -540,33 +655,78 @@ struct bt_ctf_field *bt_ctf_field_structure_get_field_by_name(
                (void *) field, name));
 }
 
-int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field,
-               const char *name, struct bt_ctf_field *value)
-{
-       return bt_field_common_structure_set_field_by_name((void *) field,
-               name, (void *) value);
-}
-
 struct bt_ctf_field *bt_ctf_field_array_get_field(
                struct bt_ctf_field *field, uint64_t index)
 {
-       return bt_get(bt_field_common_array_borrow_field((void *) field, index,
-               (bt_field_common_create_func) bt_ctf_field_create));
+       return bt_get(
+               bt_field_common_array_borrow_field((void *) field, index));
 }
 
 struct bt_ctf_field *bt_ctf_field_sequence_get_field(
                struct bt_ctf_field *field, uint64_t index)
 {
-       return bt_get(bt_field_common_sequence_borrow_field((void *) field,
-               index, (bt_field_common_create_func) bt_ctf_field_create));
+       return bt_get(
+               bt_field_common_sequence_borrow_field((void *) field, index));
 }
 
 struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field,
                struct bt_ctf_field *tag_field)
 {
-       return bt_get(bt_field_common_variant_borrow_field((void *) field,
-               (void *) tag_field,
-               (bt_field_common_create_func) bt_ctf_field_create));
+       struct bt_ctf_field_variant *variant_field = (void *) field;
+       struct bt_ctf_field_enumeration *enum_field = (void *) tag_field;
+       struct bt_field_type_common_variant *variant_ft;
+       struct bt_field_type_common_enumeration *tag_ft;
+       struct bt_ctf_field *current_field = NULL;
+       bt_bool is_signed;
+       uint64_t tag_uval;
+       int ret;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Variant field");
+       BT_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
+       BT_ASSERT_PRE_FIELD_COMMON_IS_SET((void *) tag_field, "Tag field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(
+               (struct bt_field_common *) tag_field,
+               BT_FIELD_TYPE_ID_ENUM, "Tag field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(
+               (struct bt_field_common *) field,
+               BT_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_ASSERT_PRE(
+               bt_field_common_validate_recursive((void *) tag_field) == 0,
+               "Tag field is invalid: %!+wf", tag_field);
+       variant_ft = BT_FROM_COMMON(variant_field->common.common.type);
+       BT_ASSERT_PRE(bt_field_type_common_compare(
+               BT_TO_COMMON(variant_ft->tag_ft), enum_field->common.type) == 0,
+               "Unexpected tag field's type: %![expected-ft-]+wF, "
+               "%![tag-ft-]+wF", variant_ft->tag_ft,
+               enum_field->common.type);
+       tag_ft = BT_FROM_COMMON(enum_field->common.type);
+       is_signed = tag_ft->container_ft->is_signed;
+
+       if (is_signed) {
+               int64_t tag_ival;
+
+               ret = bt_ctf_field_integer_signed_get_value(
+                       (void *) enum_field->container, &tag_ival);
+               tag_uval = (uint64_t) tag_ival;
+       } else {
+               ret = bt_ctf_field_integer_unsigned_get_value(
+                       (void *) enum_field->container, &tag_uval);
+       }
+
+       BT_ASSERT(ret == 0);
+       ret = bt_field_variant_common_set_tag((void *) field, tag_uval,
+               is_signed);
+       if (ret) {
+               goto end;
+       }
+
+       bt_put(variant_field->tag);
+       variant_field->tag = bt_get(tag_field);
+       current_field = bt_ctf_field_variant_get_current_field(field);
+       BT_ASSERT(current_field);
+
+end:
+       return current_field;
 }
 
 struct bt_ctf_field *bt_ctf_field_variant_get_current_field(
@@ -576,41 +736,102 @@ struct bt_ctf_field *bt_ctf_field_variant_get_current_field(
                (void *) variant_field));
 }
 
-struct bt_ctf_field *bt_ctf_field_variant_get_tag(
-               struct bt_ctf_field *variant_field)
+BT_HIDDEN
+struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container(
+               struct bt_ctf_field *field)
 {
-       return bt_get(bt_field_common_variant_borrow_tag(
-               (void *) variant_field));
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Enumeration field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID((struct bt_field_common *) field,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Field");
+       BT_ASSERT(enumeration->container);
+       return (void *) enumeration->container;
 }
 
-struct bt_ctf_field *bt_ctf_field_enumeration_get_container(struct bt_ctf_field *field)
+struct bt_ctf_field *bt_ctf_field_enumeration_get_container(
+               struct bt_ctf_field *field)
 {
-       return bt_get(bt_field_common_enumeration_borrow_container(
-               (void *) field,
-               (bt_field_common_create_func) bt_ctf_field_create));
+       return bt_get(bt_ctf_field_enumeration_borrow_container(field));
 }
 
-int bt_ctf_field_integer_signed_get_value(struct bt_ctf_field *field, int64_t *value)
+int bt_ctf_field_integer_signed_get_value(struct bt_ctf_field *field,
+               int64_t *value)
 {
-       return bt_field_common_integer_signed_get_value((void *) field, value);
+       struct bt_field_common_integer *integer = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_ASSERT_PRE_FIELD_COMMON_IS_SET(BT_TO_COMMON(integer), "Integer field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(BT_TO_COMMON(integer),
+               BT_FIELD_TYPE_ID_INTEGER, "Field");
+       BT_ASSERT_PRE(bt_field_type_common_integer_is_signed(
+               integer->common.type),
+               "Field's type is unsigned: %!+_f", field);
+       *value = integer->payload.signd;
+       return 0;
 }
 
 int bt_ctf_field_integer_signed_set_value(struct bt_ctf_field *field,
                int64_t value)
 {
-       return bt_field_common_integer_signed_set_value((void *) field, value);
+       int ret = 0;
+       struct bt_field_common_integer *integer = (void *) field;
+       struct bt_field_type_common_integer *integer_type;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_ASSERT_PRE_FIELD_COMMON_HOT(BT_TO_COMMON(integer), "Integer field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(BT_TO_COMMON(integer),
+               BT_FIELD_TYPE_ID_INTEGER, "Field");
+       integer_type = BT_FROM_COMMON(integer->common.type);
+       BT_ASSERT_PRE(
+               bt_field_type_common_integer_is_signed(integer->common.type),
+               "Field's type is unsigned: %!+wf", field);
+       BT_ASSERT_PRE(value_is_in_range_signed(integer_type->size, value),
+               "Value is out of bounds: value=%" PRId64 ", %![field-]+wf",
+               value, field);
+       integer->payload.signd = value;
+       bt_field_common_set(BT_TO_COMMON(integer), true);
+       return ret;
 }
 
 int bt_ctf_field_integer_unsigned_get_value(struct bt_ctf_field *field,
                uint64_t *value)
 {
-       return bt_field_common_integer_unsigned_get_value((void *) field,
-               value);
+       struct bt_field_common_integer *integer = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_ASSERT_PRE_FIELD_COMMON_IS_SET(BT_TO_COMMON(integer), "Integer field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(BT_TO_COMMON(integer),
+               BT_FIELD_TYPE_ID_INTEGER, "Field");
+       BT_ASSERT_PRE(
+               !bt_field_type_common_integer_is_signed(integer->common.type),
+               "Field's type is signed: %!+wf", field);
+       *value = integer->payload.unsignd;
+       return 0;
 }
 
-int bt_ctf_field_integer_unsigned_set_value(struct bt_ctf_field *field, uint64_t value)
+int bt_ctf_field_integer_unsigned_set_value(struct bt_ctf_field *field,
+               uint64_t value)
 {
-       return bt_field_common_integer_unsigned_set_value((void *) field, value);
+       struct bt_field_common_integer *integer = (void *) field;
+       struct bt_field_type_common_integer *integer_type;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_ASSERT_PRE_FIELD_COMMON_HOT(BT_TO_COMMON(integer), "Integer field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(BT_TO_COMMON(integer),
+               BT_FIELD_TYPE_ID_INTEGER, "Field");
+       integer_type = BT_FROM_COMMON(integer->common.type);
+       BT_ASSERT_PRE(
+               !bt_field_type_common_integer_is_signed(integer->common.type),
+               "Field's type is signed: %!+wf", field);
+       BT_ASSERT_PRE(value_is_in_range_unsigned(integer_type->size, value),
+               "Value is out of bounds: value=%" PRIu64 ", %![field-]+wf",
+               value, field);
+       integer->payload.unsignd = value;
+       bt_field_common_set(BT_TO_COMMON(integer), true);
+       return 0;
 }
 
 int bt_ctf_field_floating_point_get_value(struct bt_ctf_field *field,
@@ -661,7 +882,7 @@ struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type)
 
        if (integer) {
                bt_field_common_initialize(BT_TO_COMMON(integer), (void *) type,
-                       bt_field_common_integer_destroy,
+                       (bt_object_release_func) bt_ctf_field_integer_destroy,
                        &bt_ctf_field_integer_methods);
                integer->common.spec.writer.serialize_func =
                        (bt_ctf_field_serialize_recursive_func) bt_ctf_field_integer_serialize;
@@ -678,24 +899,36 @@ static
 struct bt_ctf_field *bt_ctf_field_enumeration_create(
                struct bt_ctf_field_type *type)
 {
-       struct bt_field_common_enumeration *enumeration = g_new0(
-               struct bt_field_common_enumeration, 1);
+       struct bt_field_type_common_enumeration *enum_ft = (void *) type;
+       struct bt_ctf_field_enumeration *enumeration = g_new0(
+               struct bt_ctf_field_enumeration, 1);
 
        BT_LOGD("Creating CTF writer enumeration field object: ft-addr=%p", type);
 
-       if (enumeration) {
-               bt_field_common_initialize(BT_TO_COMMON(enumeration),
-                       (void *) type,
-                       bt_field_common_enumeration_destroy_recursive,
-                       &bt_ctf_field_enumeration_methods);
-               enumeration->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_enumeration_serialize_recursive;
-               BT_LOGD("Created CTF writer enumeration field object: addr=%p, ft-addr=%p",
-                       enumeration, type);
-       } else {
+       if (!enumeration) {
                BT_LOGE_STR("Failed to allocate one enumeration field.");
+               goto end;
        }
 
+       bt_field_common_initialize(BT_TO_COMMON(enumeration),
+               (void *) type,
+               (bt_object_release_func)
+                       bt_ctf_field_enumeration_destroy_recursive,
+               &bt_ctf_field_enumeration_methods);
+       enumeration->container = (void *) bt_ctf_field_create(
+               BT_FROM_COMMON(enum_ft->container_ft));
+       if (!enumeration->container) {
+               BT_PUT(enumeration);
+               goto end;
+       }
+
+       enumeration->common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func)
+                       bt_ctf_field_enumeration_serialize_recursive;
+       BT_LOGD("Created CTF writer enumeration field object: addr=%p, ft-addr=%p",
+               enumeration, type);
+
+end:
        return (void *) enumeration;
 }
 
@@ -711,7 +944,8 @@ struct bt_ctf_field *bt_ctf_field_floating_point_create(
        if (floating_point) {
                bt_field_common_initialize(BT_TO_COMMON(floating_point),
                        (void *) type,
-                       bt_field_common_floating_point_destroy,
+                       (bt_object_release_func)
+                               bt_ctf_field_floating_point_destroy,
                        &bt_ctf_field_floating_point_methods);
                floating_point->common.spec.writer.serialize_func =
                        (bt_ctf_field_serialize_recursive_func) bt_ctf_field_floating_point_serialize;
@@ -740,9 +974,12 @@ struct bt_ctf_field *bt_ctf_field_structure_create(
        }
 
        iret = bt_field_common_structure_initialize(BT_TO_COMMON(structure),
-               (void *) type, bt_field_common_structure_destroy_recursive,
+               (void *) type,
+               (bt_object_release_func)
+                       bt_ctf_field_structure_destroy_recursive,
                &bt_ctf_field_structure_methods,
-               (bt_field_common_create_func) bt_ctf_field_create);
+               (bt_field_common_create_func) bt_ctf_field_create,
+               (GDestroyNotify) bt_put);
        structure->common.spec.writer.serialize_func =
                (bt_ctf_field_serialize_recursive_func) bt_ctf_field_structure_serialize_recursive;
        if (iret) {
@@ -760,24 +997,32 @@ end:
 static
 struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type)
 {
-       struct bt_field_common_variant *variant = g_new0(
-               struct bt_field_common_variant, 1);
+       struct bt_field_type_common_variant *var_ft = (void *) type;
+       struct bt_ctf_field_variant *variant = g_new0(
+               struct bt_ctf_field_variant, 1);
 
        BT_LOGD("Creating CTF writer variant field object: ft-addr=%p", type);
 
-       if (variant) {
-               bt_field_common_initialize(BT_TO_COMMON(variant),
-                       (void *) type,
-                       bt_field_common_variant_destroy_recursive,
-                       &bt_ctf_field_variant_methods);
-               variant->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_variant_serialize_recursive;
-               BT_LOGD("Created CTF writer variant field object: addr=%p, ft-addr=%p",
-                       variant, type);
-       } else {
+       if (!variant) {
                BT_LOGE_STR("Failed to allocate one variant field.");
+               goto end;
        }
 
+       bt_field_common_variant_initialize(BT_TO_COMMON(BT_TO_COMMON(variant)),
+               (void *) type,
+               (bt_object_release_func)
+                       bt_ctf_field_variant_destroy_recursive,
+               &bt_ctf_field_variant_methods,
+               (bt_field_common_create_func) bt_ctf_field_create,
+               (GDestroyNotify) bt_put);
+       variant->tag = (void *) bt_ctf_field_create(
+               BT_FROM_COMMON(var_ft->tag_ft));
+       variant->common.common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_variant_serialize_recursive;
+       BT_LOGD("Created CTF writer variant field object: addr=%p, ft-addr=%p",
+               variant, type);
+
+end:
        return (void *) variant;
 }
 
@@ -798,8 +1043,11 @@ struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type)
 
        ret = bt_field_common_array_initialize(BT_TO_COMMON(array),
                (void *) type,
-               bt_field_common_array_destroy_recursive,
-               &bt_ctf_field_array_methods);
+               (bt_object_release_func)
+                       bt_ctf_field_array_destroy_recursive,
+               &bt_ctf_field_array_methods,
+               (bt_field_common_create_func) bt_ctf_field_create,
+               (GDestroyNotify) bt_put);
        array->common.spec.writer.serialize_func =
                (bt_ctf_field_serialize_recursive_func) bt_ctf_field_array_serialize_recursive;
        if (ret) {
@@ -823,10 +1071,12 @@ struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *type
        BT_LOGD("Creating CTF writer sequence field object: ft-addr=%p", type);
 
        if (sequence) {
-               bt_field_common_initialize(BT_TO_COMMON(sequence),
+               bt_field_common_sequence_initialize(BT_TO_COMMON(sequence),
                        (void *) type,
-                       bt_field_common_sequence_destroy_recursive,
-                       &bt_ctf_field_sequence_methods);
+                       (bt_object_release_func)
+                               bt_ctf_field_sequence_destroy_recursive,
+                       &bt_ctf_field_sequence_methods,
+                       (GDestroyNotify) bt_put);
                sequence->common.spec.writer.serialize_func =
                        (bt_ctf_field_serialize_recursive_func) bt_ctf_field_sequence_serialize_recursive;
                BT_LOGD("Created CTF writer sequence field object: addr=%p, ft-addr=%p",
@@ -849,7 +1099,8 @@ struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type)
        if (string) {
                bt_field_common_initialize(BT_TO_COMMON(string),
                        (void *) type,
-                       bt_field_common_string_destroy,
+                       (bt_object_release_func)
+                               bt_ctf_field_string_destroy,
                        &bt_ctf_field_string_methods);
                string->common.spec.writer.serialize_func =
                        (bt_ctf_field_serialize_recursive_func) bt_ctf_field_string_serialize;
@@ -861,3 +1112,192 @@ struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type)
 
        return (void *) string;
 }
+
+static
+void bt_ctf_field_enumeration_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               bt_field_common_set_is_frozen_recursive(
+                       (void *) enumeration->container, is_frozen);
+       }
+
+       bt_field_common_generic_set_is_frozen((void *) field, is_frozen);
+}
+
+static
+int bt_ctf_field_enumeration_validate_recursive(struct bt_field_common *field)
+{
+       int ret = -1;
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               ret = bt_field_common_validate_recursive(
+                       (void *) enumeration->container);
+       }
+
+       return ret;
+}
+
+static
+bt_bool bt_ctf_field_enumeration_is_set_recursive(struct bt_field_common *field)
+{
+       bt_bool is_set = BT_FALSE;
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               is_set = bt_field_common_is_set_recursive(
+                       (void *) enumeration->container);
+       }
+
+       return is_set;
+}
+
+static
+void bt_ctf_field_enumeration_reset_recursive(struct bt_field_common *field)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               bt_field_common_reset_recursive(
+                       (void *) enumeration->container);
+       }
+
+       bt_field_common_generic_reset((void *) field);
+}
+
+static
+void bt_ctf_field_variant_set_is_frozen_recursive(
+               struct bt_field_common *field, bool is_frozen)
+{
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               bt_field_common_set_is_frozen_recursive(
+                       (void *) variant->tag, is_frozen);
+       }
+
+       bt_field_common_variant_set_is_frozen_recursive((void *) field,
+               is_frozen);
+}
+
+static
+int bt_ctf_field_variant_validate_recursive(struct bt_field_common *field)
+{
+       int ret;
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               ret = bt_field_common_validate_recursive(
+                       (void *) variant->tag);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = bt_field_common_variant_validate_recursive((void *) field);
+
+end:
+       return ret;
+}
+
+static
+bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_field_common *field)
+{
+       bt_bool is_set;
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               is_set = bt_field_common_is_set_recursive(
+                       (void *) variant->tag);
+               if (is_set) {
+                       goto end;
+               }
+       }
+
+       is_set = bt_field_common_variant_is_set_recursive((void *) field);
+
+end:
+       return is_set;
+}
+
+static
+void bt_ctf_field_variant_reset_recursive(struct bt_field_common *field)
+{
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               bt_field_common_reset_recursive(
+                       (void *) variant->tag);
+       }
+
+       bt_field_common_variant_reset_recursive((void *) field);
+}
+
+BT_ASSERT_PRE_FUNC
+static inline bool field_to_set_has_expected_type(
+               struct bt_field_common *struct_field,
+               const char *name, struct bt_field_common *value)
+{
+       bool ret = true;
+       struct bt_field_type_common *expected_field_type = NULL;
+
+       expected_field_type =
+               bt_field_type_common_structure_borrow_field_type_by_name(
+                       struct_field->type, name);
+
+       if (bt_field_type_common_compare(expected_field_type, value->type)) {
+               BT_ASSERT_PRE_MSG("Value field's type is different from the expected field type: "
+                       "%![value-ft-]+_F, %![expected-ft-]+_F", value->type,
+                       expected_field_type);
+               ret = false;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field,
+               const char *name, struct bt_ctf_field *value)
+{
+       int ret = 0;
+       GQuark field_quark;
+       struct bt_field_common *common_field = (void *) field;
+       struct bt_field_common_structure *structure =
+               BT_FROM_COMMON(common_field);
+       struct bt_field_common *common_value = (void *) value;
+       size_t index;
+       GHashTable *field_name_to_index;
+       struct bt_field_type_common_structure *structure_ft;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Parent field");
+       BT_ASSERT_PRE_NON_NULL(name, "Field name");
+       BT_ASSERT_PRE_NON_NULL(value, "Value field");
+       BT_ASSERT_PRE_FIELD_COMMON_HAS_TYPE_ID(common_field,
+               BT_FIELD_TYPE_ID_STRUCT, "Parent field");
+       BT_ASSERT_PRE(field_to_set_has_expected_type(common_field,
+               name, common_value),
+               "Value field's type is different from the expected field type.");
+       field_quark = g_quark_from_string(name);
+       structure_ft = BT_FROM_COMMON(common_field->type);
+       field_name_to_index = structure_ft->field_name_to_index;
+       if (!g_hash_table_lookup_extended(field_name_to_index,
+                       GUINT_TO_POINTER(field_quark), NULL,
+                       (gpointer *) &index)) {
+               BT_LOGV("Invalid parameter: no such field in structure field's type: "
+                       "struct-field-addr=%p, struct-ft-addr=%p, "
+                       "field-ft-addr=%p, name=\"%s\"",
+                       field, common_field->type, common_value->type, name);
+               ret = -1;
+               goto end;
+       }
+       bt_get(value);
+       BT_MOVE(structure->fields->pdata[index], value);
+
+end:
+       return ret;
+}
index ec269e17ff97b0db5d8c3b8dfbdaf4d14447cb0b..e0ced0e959fb8ce5722e73dc2a8a449f9e15b255 100644 (file)
@@ -512,7 +512,7 @@ int visit_field_update_clock_value(struct bt_ctf_field *field, uint64_t *val)
        case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
        {
                uint64_t i;
-               int64_t len = bt_field_common_sequence_get_int_length(
+               int64_t len = bt_field_common_sequence_get_length(
                        (void *) field);
 
                if (len < 0) {
@@ -1248,7 +1248,7 @@ static int auto_populate_event_header(struct bt_ctf_stream *stream,
                stream, bt_ctf_stream_get_name(stream), event);
 
        id_field = bt_ctf_field_structure_get_field_by_name(
-               (void *) event->common.header_field, "id");
+               (void *) event->common.header_field->field, "id");
        event_class_id = bt_event_class_common_get_id(event->common.class);
        BT_ASSERT(event_class_id >= 0);
 
@@ -1272,7 +1272,7 @@ static int auto_populate_event_header(struct bt_ctf_stream *stream,
         * 3. The "timestamp" field is not set.
         */
        timestamp_field = bt_ctf_field_structure_get_field_by_name(
-                       (void *) event->common.header_field, "timestamp");
+                       (void *) event->common.header_field->field, "timestamp");
        if (timestamp_field && stream_class->clock &&
                        bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER &&
                        !bt_ctf_field_is_set_recursive(timestamp_field)) {
@@ -1365,10 +1365,8 @@ int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
 
        /* Make sure the various scopes of the event are set */
        BT_LOGV_STR("Validating event to append.");
-       ret = bt_event_common_validate(BT_TO_COMMON(event));
-       if (ret) {
-               goto error;
-       }
+       BT_ASSERT_PRE(bt_event_common_validate(BT_TO_COMMON(event)) == 0,
+               "Invalid event: %!+we", event);
 
        /* Save the new event and freeze it */
        BT_LOGV_STR("Freezing the event to append.");
@@ -1688,12 +1686,12 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                if (event->common.header_field) {
                        BT_LOGV_STR("Serializing event's header field.");
                        ret = bt_ctf_field_serialize_recursive(
-                               (void *) event->common.header_field,
+                               (void *) event->common.header_field->field,
                                &stream->pos, native_byte_order);
                        if (ret) {
                                BT_LOGW("Cannot serialize event's header field: "
                                        "field-addr=%p",
-                                       event->common.header_field);
+                                       event->common.header_field->field);
                                goto end;
                        }
                }
index 97186a4c8df132cc6743d5a7bc9d01b5f21b147c..486a8b1018eb248780b3de2979ba75cc76f05ea2 100644 (file)
@@ -49,129 +49,33 @@ void bt_notification_event_destroy(struct bt_object *obj)
                        (struct bt_notification_event *) obj;
 
        BT_LOGD("Destroying event notification: addr=%p", notification);
-       BT_LOGD_STR("Putting event.");
-       BT_PUT(notification->event);
+       BT_LOGD_STR("Recycling event.");
+       bt_event_recycle(notification->event);
+       notification->event = NULL;
        BT_LOGD_STR("Putting clock class priority map.");
        BT_PUT(notification->cc_prio_map);
        g_free(notification);
 }
 
-BT_ASSERT_PRE_FUNC static inline
-bt_bool validate_clock_classes(struct bt_notification_event *notif)
-{
-       /*
-        * For each clock class found in the notification's clock class
-        * priority map, make sure the event has a clock value set for
-        * this clock class. Also make sure that those clock classes
-        * are part of the trace to which the event belongs.
-        */
-       bt_bool is_valid = BT_TRUE;
-
-       int trace_cc_count;
-       int cc_prio_map_cc_count;
-       size_t cc_prio_map_cc_i, trace_cc_i;
-       struct bt_clock_value *clock_value = NULL;
-       struct bt_clock_class *clock_class = NULL;
-       struct bt_event_class *event_class = NULL;
-       struct bt_stream_class *stream_class = NULL;
-       struct bt_trace *trace = NULL;
-
-       event_class = bt_event_borrow_class(notif->event);
-       BT_ASSERT(event_class);
-       stream_class = bt_event_class_borrow_stream_class(event_class);
-       BT_ASSERT(stream_class);
-       trace = bt_stream_class_borrow_trace(stream_class);
-       BT_ASSERT(trace);
-       trace_cc_count = bt_trace_get_clock_class_count(trace);
-       BT_ASSERT(trace_cc_count >= 0);
-       cc_prio_map_cc_count =
-               bt_clock_class_priority_map_get_clock_class_count(
-                       notif->cc_prio_map);
-       BT_ASSERT(cc_prio_map_cc_count >= 0);
-
-       for (cc_prio_map_cc_i = 0; cc_prio_map_cc_i < cc_prio_map_cc_count;
-                       cc_prio_map_cc_i++) {
-               bt_bool found_in_trace = BT_FALSE;
-
-               clock_class =
-                       bt_clock_class_priority_map_get_clock_class_by_index(
-                               notif->cc_prio_map, cc_prio_map_cc_i);
-               BT_ASSERT(clock_class);
-               clock_value = bt_event_get_clock_value(notif->event,
-                       clock_class);
-               if (!clock_value) {
-                       BT_ASSERT_PRE_MSG("Event has no clock value for a clock class which exists in the notification's clock class priority map: "
-                               "notif-addr=%p, event-addr=%p, "
-                               "event-class-addr=%p, event-class-name=\"%s\", "
-                               "event-class-id=%" PRId64 ", "
-                               "cc-prio-map-addr=%p, "
-                               "clock-class-addr=%p, clock-class-name=\"%s\"",
-                               notif, notif->event, event_class,
-                               bt_event_class_get_name(event_class),
-                               bt_event_class_get_id(event_class),
-                               notif->cc_prio_map, clock_class,
-                               bt_clock_class_get_name(clock_class));
-                       is_valid = BT_FALSE;
-                       goto end;
-               }
-
-               for (trace_cc_i = 0; trace_cc_i < trace_cc_count;
-                               trace_cc_i++) {
-                       struct bt_clock_class *trace_clock_class =
-                               bt_trace_get_clock_class_by_index(trace,
-                                       trace_cc_i);
-
-                       BT_ASSERT(trace_clock_class);
-                       bt_put(trace_clock_class);
-
-                       if (trace_clock_class == clock_class) {
-                               found_in_trace = BT_TRUE;
-                               break;
-                       }
-               }
-
-               if (!found_in_trace) {
-                       BT_ASSERT_PRE_MSG("A clock class found in the event notification's clock class priority map does not exist in the notification's event's trace: "
-                               "notif-addr=%p, trace-addr=%p, "
-                               "trace-name=\"%s\", cc-prio-map-addr=%p, "
-                               "clock-class-addr=%p, clock-class-name=\"%s\"",
-                               notif, trace, bt_trace_get_name(trace),
-                               notif->cc_prio_map, clock_class,
-                               bt_clock_class_get_name(clock_class));
-                       is_valid = BT_FALSE;
-                       goto end;
-               }
-
-               BT_PUT(clock_value);
-               BT_PUT(clock_class);
-       }
-
-end:
-       bt_put(clock_value);
-       bt_put(clock_class);
-       return is_valid;
-}
-
 BT_ASSERT_PRE_FUNC
-static inline bool event_has_trace(struct bt_event *event)
+static inline bool event_class_has_trace(struct bt_event_class *event_class)
 {
-       struct bt_event_class *event_class;
        struct bt_stream_class *stream_class;
 
-       event_class = bt_event_borrow_class(event);
-       BT_ASSERT(event_class);
        stream_class = bt_event_class_borrow_stream_class(event_class);
        BT_ASSERT(stream_class);
        return bt_stream_class_borrow_trace(stream_class) != NULL;
 }
 
-struct bt_notification *bt_notification_event_create(struct bt_event *event,
+struct bt_notification *bt_notification_event_create(
+               struct bt_event_class *event_class,
+               struct bt_packet *packet,
                struct bt_clock_class_priority_map *cc_prio_map)
 {
        struct bt_notification_event *notification = NULL;
-       struct bt_event_class *event_class;
 
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
 
        if (cc_prio_map) {
                /* Function's reference, released at the end */
@@ -185,20 +89,16 @@ struct bt_notification *bt_notification_event_create(struct bt_event *event,
        }
 
        BT_ASSERT(cc_prio_map);
-       event_class = bt_event_borrow_class(event);
-       BT_ASSERT(event_class);
        BT_LOGD("Creating event notification object: "
-               "event-addr=%p, event-class-addr=%p, "
+               "event-class-addr=%p, "
                "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
                "cc-prio-map-addr=%p",
-               event, event_class,
+               event_class,
                bt_event_class_get_name(event_class),
                bt_event_class_get_id(event_class), cc_prio_map);
 
-       BT_ASSERT_PRE(bt_event_borrow_packet(event),
-               "Event has no packet: %!+e", event);
-       BT_ASSERT_PRE(event_has_trace(event),
-               "Event has no trace: %!+e", event);
+       BT_ASSERT_PRE(event_class_has_trace(event_class),
+               "Event class is not part of a trace: %!+E", event_class);
        notification = g_new0(struct bt_notification_event, 1);
        if (!notification) {
                BT_LOGE_STR("Failed to allocate one event notification.");
@@ -207,19 +107,21 @@ struct bt_notification *bt_notification_event_create(struct bt_event *event,
 
        bt_notification_init(&notification->parent, BT_NOTIFICATION_TYPE_EVENT,
                bt_notification_event_destroy);
-       notification->event = bt_get(event);
+       notification->event = bt_event_create(event_class, packet);
+       if (!notification->event) {
+               BT_LIB_LOGE("Cannot create event from event class: "
+                       "%![event-class-]+E", event_class);
+               goto error;
+       }
+
        notification->cc_prio_map = bt_get(cc_prio_map);
-       BT_ASSERT_PRE(validate_clock_classes(notification),
-               "Invalid clock classes: %![event-]+e", event);
-       BT_LOGD_STR("Freezing event notification's event.");
-       bt_event_freeze(notification->event);
        BT_LOGD_STR("Freezing event notification's clock class priority map.");
        bt_clock_class_priority_map_freeze(notification->cc_prio_map);
        BT_LOGD("Created event notification object: "
                "event-addr=%p, event-class-addr=%p, "
                "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
                "cc-prio-map-addr=%p, notif-addr=%p",
-               event, event_class,
+               notification->event, event_class,
                bt_event_class_get_name(event_class),
                bt_event_class_get_id(event_class), cc_prio_map,
                notification);
index b774d307673d358236e28e1c461edfb842adb10a..2575c14432f829b7d290932d9be2dca4511821a1 100644 (file)
@@ -56,6 +56,7 @@ struct bt_notification *bt_notification_inactivity_create(
 {
        struct bt_notification_inactivity *notification;
        struct bt_notification *ret_notif = NULL;
+       uint64_t i;
 
        if (cc_prio_map) {
                /* Function's reference, released at the end */
@@ -81,12 +82,28 @@ struct bt_notification *bt_notification_inactivity_create(
                bt_notification_inactivity_destroy);
        ret_notif = &notification->parent;
        notification->clock_values = g_hash_table_new_full(g_direct_hash,
-               g_direct_equal, bt_put, bt_put);
+               g_direct_equal, NULL, (GDestroyNotify) bt_clock_value_recycle);
        if (!notification->clock_values) {
                BT_LOGE_STR("Failed to allocate a GHashTable.");
                goto error;
        }
 
+       for (i = 0; i < cc_prio_map->entries->len; i++) {
+               struct bt_clock_value *clock_value;
+               struct bt_clock_class *clock_class =
+                       cc_prio_map->entries->pdata[i];
+
+               clock_value = bt_clock_value_create(clock_class);
+               if (!clock_value) {
+                       BT_LIB_LOGE("Cannot create clock value from clock class: "
+                               "%![cc-]+K", clock_class);
+                       goto error;
+               }
+
+               g_hash_table_insert(notification->clock_values,
+                       clock_class, clock_value);
+       }
+
        notification->cc_prio_map = bt_get(cc_prio_map);
        BT_LOGD_STR("Freezing inactivity notification's clock class priority map.");
        bt_clock_class_priority_map_freeze(cc_prio_map);
@@ -124,7 +141,7 @@ struct bt_clock_value *bt_notification_inactivity_borrow_clock_value(
        struct bt_notification_inactivity *inactivity_notification;
 
        BT_ASSERT_PRE_NON_NULL(notification, "Notification");
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock_class");
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
        BT_ASSERT_PRE_NOTIF_IS_TYPE(notification,
                BT_NOTIFICATION_TYPE_INACTIVITY);
        inactivity_notification = container_of(notification,
@@ -132,53 +149,3 @@ struct bt_clock_value *bt_notification_inactivity_borrow_clock_value(
        return g_hash_table_lookup(
                inactivity_notification->clock_values, clock_class);
 }
-
-BT_ASSERT_PRE_FUNC
-static inline bool cc_prio_map_contains_clock_class(
-               struct bt_clock_class_priority_map *cc_prio_map,
-               struct bt_clock_class *clock_class)
-{
-       int ret = 0;
-       uint64_t prio;
-
-       ret = bt_clock_class_priority_map_get_clock_class_priority(
-               cc_prio_map, clock_class, &prio);
-       return ret == 0;
-}
-
-int bt_notification_inactivity_set_clock_value(
-               struct bt_notification *notification,
-               struct bt_clock_value *clock_value)
-{
-       struct bt_notification_inactivity *inactivity_notification;
-
-       BT_ASSERT_PRE_NON_NULL(notification, "Notification");
-       BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value");
-       BT_ASSERT_PRE_HOT(notification, "Notification",
-               ": +%!+n", notification);
-       BT_ASSERT_PRE_NOTIF_IS_TYPE(notification,
-               BT_NOTIFICATION_TYPE_INACTIVITY);
-       inactivity_notification = container_of(notification,
-                       struct bt_notification_inactivity, parent);
-       BT_ASSERT_PRE(cc_prio_map_contains_clock_class(
-               inactivity_notification->cc_prio_map, clock_value->clock_class),
-               "Clock value's class is not mapped to a priority within the scope of the inactivity notification: "
-               "notif-addr=%p, cc-prio-map-addr=%p, "
-               "clock-class-addr=%p, clock-class-name=\"%s\", "
-               "clock-value-addr=%p",
-               inactivity_notification,
-               inactivity_notification->cc_prio_map,
-               clock_value->clock_class,
-               bt_clock_class_get_name(clock_value->clock_class), clock_value);
-       g_hash_table_insert(inactivity_notification->clock_values,
-               clock_value->clock_class, bt_get(clock_value));
-       BT_LOGV("Set inactivity notification's clock value: "
-               "notif-addr=%p, cc-prio-map-addr=%p, "
-               "clock-class-addr=%p, clock-class-name=\"%s\", "
-               "clock-value-addr=%p",
-               inactivity_notification,
-               inactivity_notification->cc_prio_map,
-               clock_value->clock_class,
-               bt_clock_class_get_name(clock_value->clock_class), clock_value);
-       return 0;
-}
index d50d9770d38a888b0f6fc2ecd0d8ddffc89a5967..214c2e3ae2c36f91ce357fcf4adf1b4d054ed861 100644 (file)
@@ -32,9 +32,9 @@
 #include <glib.h>
 #include <babeltrace/common-internal.h>
 #include <babeltrace/lib-logging-internal.h>
-#include <babeltrace/object-internal.h>
 #include <babeltrace/ref-internal.h>
 #include <babeltrace/values-internal.h>
+#include <babeltrace/object-pool-internal.h>
 #include <babeltrace/ctf-ir/field-types-internal.h>
 #include <babeltrace/ctf-ir/fields-internal.h>
 #include <babeltrace/ctf-ir/event-class-internal.h>
@@ -138,6 +138,16 @@ static inline void format_ref_count(char **buf_ch, bool extended,
        BUF_APPEND(", %sref-count=%lu", prefix, obj->ref_count.count);
 }
 
+static inline void format_object_pool(char **buf_ch, bool extended,
+               const char *prefix, struct bt_object_pool *pool)
+{
+       BUF_APPEND(", %ssize=%zu", PRFIELD(pool->size));
+
+       if (pool->objects) {
+               BUF_APPEND(", %scap=%u", PRFIELD(pool->objects->len));
+       }
+}
+
 static inline void format_field_type_common(char **buf_ch, bool extended,
                const char *prefix, struct bt_field_type_common *field_type)
 {
@@ -228,10 +238,9 @@ static inline void format_field_type_common(char **buf_ch, bool extended,
                struct bt_field_type_common_variant *variant =
                        BT_FROM_COMMON(field_type);
 
-               BUF_APPEND(", %stag-name=\"%s\", %stag-ft-addr=%p, "
-                       "%sfield-count=%u",
+               BUF_APPEND(", %stag-name=\"%s\", %sfield-count=%u",
                        PRFIELD(variant->tag_name->str),
-                       PRFIELD(variant->tag_ft), PRFIELD(variant->fields->len));
+                       PRFIELD(variant->choices->len));
                break;
        }
        default:
@@ -261,6 +270,8 @@ static inline void format_field_common_integer_extended(char **buf_ch,
                BT_FROM_COMMON(field->type);
        const char *fmt = NULL;
 
+       BT_ASSERT(field_type);
+
        if (field_type->base == 8) {
                fmt = ", %svalue=%" PRIo64;
        } else if (field_type->base == 16) {
@@ -291,8 +302,13 @@ static inline void format_field_common(char **buf_ch, bool extended,
                BUF_APPEND(", %sis-frozen=%d", PRFIELD(field->frozen));
        }
 
-       BUF_APPEND(", %stype-addr=%p, %stype-id=%s",
-               PRFIELD(field->type),
+       BUF_APPEND(", %stype-addr=%p", PRFIELD(field->type));
+
+       if (!field->type) {
+               return;
+       }
+
+       BUF_APPEND(", %stype-id=%s",
                PRFIELD(bt_common_field_type_id_string(field->type->id)));
 
        if (!extended || field->type->id == BT_FIELD_TYPE_ID_UNKNOWN ||
@@ -314,25 +330,17 @@ static inline void format_field_common(char **buf_ch, bool extended,
                BUF_APPEND(", %svalue=%f", PRFIELD(flt->payload));
                break;
        }
-       case BT_FIELD_TYPE_ID_ENUM:
-       {
-               struct bt_field_common_enumeration *enm =
-                       BT_FROM_COMMON(field);
-
-               if (enm->payload) {
-                       format_field_common_integer_extended(buf_ch, prefix,
-                               enm->payload);
-               }
-               break;
-       }
        case BT_FIELD_TYPE_ID_STRING:
        {
                struct bt_field_common_string *str =
                        BT_FROM_COMMON(field);
 
-               BT_ASSERT(str->payload);
-               BUF_APPEND(", %spartial-value=\"%.32s\"",
-                       PRFIELD(str->payload->str));
+               if (str->payload) {
+                       BT_ASSERT(str->payload);
+                       BUF_APPEND(", %spartial-value=\"%.32s\"",
+                               PRFIELD(str->payload->str));
+
+               }
                break;
        }
        case BT_FIELD_TYPE_ID_SEQUENCE:
@@ -340,7 +348,12 @@ static inline void format_field_common(char **buf_ch, bool extended,
                struct bt_field_common_sequence *seq =
                        BT_FROM_COMMON(field);
 
-               BUF_APPEND(", %slength-field-addr=%p", PRFIELD(seq->length));
+               BUF_APPEND(", %slength=%" PRIu64, PRFIELD(seq->length));
+
+               if (seq->elements) {
+                       BUF_APPEND(", %sallocated-length=%u",
+                               PRFIELD(seq->elements->len));
+               }
                break;
        }
        case BT_FIELD_TYPE_ID_VARIANT:
@@ -348,8 +361,8 @@ static inline void format_field_common(char **buf_ch, bool extended,
                struct bt_field_common_variant *variant =
                        BT_FROM_COMMON(field);
 
-               BUF_APPEND(", %stag-field-addr=%p, %svalue-field-addr=%p",
-                       PRFIELD(variant->tag), PRFIELD(variant->payload));
+               BUF_APPEND(", %scur-field-addr=%p",
+                       PRFIELD(variant->current_field));
                break;
        }
        default:
@@ -360,13 +373,77 @@ static inline void format_field_common(char **buf_ch, bool extended,
 static inline void format_field(char **buf_ch, bool extended,
                const char *prefix, struct bt_field *field)
 {
+       struct bt_field_common *common_field = (void *) field;
+
        format_field_common(buf_ch, extended, prefix, (void *) field);
+
+       if (!extended) {
+               return;
+       }
+
+       if (!common_field->type) {
+               return;
+       }
+
+       switch (common_field->type->id) {
+       case BT_FIELD_TYPE_ID_ENUM:
+       {
+               struct bt_field_common_integer *integer = (void *) field;
+               struct bt_field_type_common_enumeration *enum_ft =
+                       BT_FROM_COMMON(common_field->type);
+
+               if (enum_ft->container_ft) {
+                       if (enum_ft->container_ft->is_signed) {
+                               BUF_APPEND(", %svalue=%" PRId64,
+                                       PRFIELD(integer->payload.signd));
+                       } else {
+                               BUF_APPEND(", %svalue=%" PRIu64,
+                                       PRFIELD(integer->payload.unsignd));
+                       }
+               }
+               break;
+       }
+       default:
+               break;
+       }
 }
 
 static inline void format_writer_field(char **buf_ch, bool extended,
                const char *prefix, struct bt_ctf_field *field)
 {
+       struct bt_field_common *common_field = (void *) field;
+
        format_field_common(buf_ch, extended, prefix, (void *) field);
+
+       if (!extended) {
+               return;
+       }
+
+       if (!common_field->type) {
+               return;
+       }
+
+       switch (common_field->type->id) {
+       case BT_FIELD_TYPE_ID_ENUM:
+       {
+               struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+               if (enumeration->container) {
+                       format_writer_field(buf_ch, extended, prefix,
+                               (void *) enumeration->container);
+               }
+               break;
+       }
+       case BT_FIELD_TYPE_ID_VARIANT:
+       {
+               struct bt_ctf_field_variant *variant = (void *) field;
+
+               BUF_APPEND(", %stag-field-addr=%p", PRFIELD(variant->tag));
+               break;
+       }
+       default:
+               break;
+       }
 }
 
 static inline void format_field_path(char **buf_ch, bool extended,
@@ -374,10 +451,12 @@ static inline void format_field_path(char **buf_ch, bool extended,
 {
        uint64_t i;
 
-       BT_ASSERT(field_path->indexes);
-       BUF_APPEND(", %sindex-count=%u", PRFIELD(field_path->indexes->len));
+       if (field_path->indexes) {
+               BT_ASSERT(field_path->indexes);
+               BUF_APPEND(", %sindex-count=%u", PRFIELD(field_path->indexes->len));
+       }
 
-       if (!extended) {
+       if (!extended || !field_path->indexes) {
                return;
        }
 
@@ -409,22 +488,40 @@ static inline void format_trace_common(char **buf_ch, bool extended,
                BUF_APPEND_UUID(trace->uuid);
        }
 
-       BUF_APPEND(", %sclock-class-count=%u, %sstream-class-count=%u, "
-               "%sstream-count=%u, %spacket-header-ft-addr=%p",
-               PRFIELD(trace->clock_classes->len),
-               PRFIELD(trace->stream_classes->len),
-               PRFIELD(trace->streams->len),
+       if (trace->clock_classes) {
+               BUF_APPEND(", %sclock-class-count=%u",
+                       PRFIELD(trace->clock_classes->len));
+       }
+
+       if (trace->stream_classes) {
+               BUF_APPEND(", %sstream-class-count=%u",
+                       PRFIELD(trace->stream_classes->len));
+       }
+
+       if (trace->streams) {
+               BUF_APPEND(", %sstream-count=%u",
+                       PRFIELD(trace->streams->len));
+       }
+
+       BUF_APPEND(", %spacket-header-ft-addr=%p",
                PRFIELD(trace->packet_header_field_type));
 }
 
 static inline void format_trace(char **buf_ch, bool extended,
                const char *prefix, struct bt_trace *trace)
 {
+       char tmp_prefix[64];
+
        format_trace_common(buf_ch, extended, prefix, BT_TO_COMMON(trace));
 
-       if (extended) {
-               BUF_APPEND(", %sis-static=%d", PRFIELD(trace->is_static));
+       if (!extended) {
+               return;
        }
+
+       BUF_APPEND(", %sis-static=%d", PRFIELD(trace->is_static));
+       SET_TMP_PREFIX("phf-pool-");
+       format_object_pool(buf_ch, extended, prefix,
+               &trace->packet_header_field_pool);
 }
 
 static inline void format_writer_trace(char **buf_ch, bool extended,
@@ -453,9 +550,14 @@ static inline void format_stream_class_common(char **buf_ch, bool extended,
        }
 
        BUF_APPEND(", %sis-frozen=%d", PRFIELD(stream_class->frozen));
-       BUF_APPEND(", %sevent-class-count=%u, %spacket-context-ft-addr=%p, "
+
+       if (stream_class->event_classes) {
+               BUF_APPEND(", %sevent-class-count=%u",
+                       PRFIELD(stream_class->event_classes->len));
+       }
+
+       BUF_APPEND(", %spacket-context-ft-addr=%p, "
                "%sevent-header-ft-addr=%p, %sevent-context-ft-addr=%p",
-               PRFIELD(stream_class->event_classes->len),
                PRFIELD(stream_class->packet_context_field_type),
                PRFIELD(stream_class->event_header_field_type),
                PRFIELD(stream_class->event_context_field_type));
@@ -472,8 +574,18 @@ static inline void format_stream_class_common(char **buf_ch, bool extended,
 static inline void format_stream_class(char **buf_ch, bool extended,
                const char *prefix, struct bt_stream_class *stream_class)
 {
+       char tmp_prefix[64];
+
        format_stream_class_common(buf_ch, extended, prefix,
                BT_TO_COMMON(stream_class), (format_func) format_trace);
+
+       if (!extended) {
+               return;
+       }
+
+       SET_TMP_PREFIX("ehf-pool-");
+       format_object_pool(buf_ch, extended, prefix,
+               &stream_class->event_header_field_pool);
 }
 
 static inline void format_writer_stream_class(char **buf_ch, bool extended,
@@ -544,9 +656,18 @@ static inline void format_event_class_common(char **buf_ch, bool extended,
 static inline void format_event_class(char **buf_ch, bool extended,
                const char *prefix, struct bt_event_class *event_class)
 {
+       char tmp_prefix[64];
+
        format_event_class_common(buf_ch, extended, prefix,
                BT_TO_COMMON(event_class), (format_func) format_stream_class,
                (format_func) format_trace);
+
+       if (!extended) {
+               return;
+       }
+
+       SET_TMP_PREFIX("event-pool-");
+       format_object_pool(buf_ch, extended, prefix, &event_class->event_pool);
 }
 
 static inline void format_writer_event_class(char **buf_ch, bool extended,
@@ -603,9 +724,13 @@ static inline void format_stream_common(char **buf_ch, bool extended,
 static inline void format_stream(char **buf_ch, bool extended,
                const char *prefix, struct bt_stream *stream)
 {
+       char tmp_prefix[64];
+
        format_stream_common(buf_ch, extended, prefix, BT_TO_COMMON(stream),
                (format_func) format_stream_class,
                (format_func) format_trace);
+       SET_TMP_PREFIX("packet-pool-");
+       format_object_pool(buf_ch, extended, prefix, &stream->packet_pool);
 }
 
 static inline void format_writer_stream(char **buf_ch, bool extended,
@@ -633,6 +758,28 @@ static inline void format_writer_stream(char **buf_ch, bool extended,
                PRFIELD(stream->flushed_packet_count),
                PRFIELD(stream->discarded_events),
                PRFIELD(stream->size), PRFIELD(stream->last_ts_end));
+
+       if (stream->events) {
+               BUF_APPEND(", %sevent-count=%u", PRFIELD(stream->events->len));
+       }
+
+       BUF_APPEND(", %sheader-field-addr=%p, %scontext-field-addr=%p"
+               ", %sfd=%d, %smmap-offset=%zu, "
+               "%smmap-base-offset=%zu, %spacket-size=%" PRIu64 ", "
+               "%soffset=%" PRId64 ", "
+               "%sflushed-packet-count=%u, "
+               "%sdiscarded-event-count=%" PRIu64 ", "
+               "%ssize=%" PRIu64 ", %slast-ts-end=%" PRIu64,
+               PRFIELD(stream->packet_header),
+               PRFIELD(stream->packet_context),
+               PRFIELD(stream->pos.fd),
+               PRFIELD((size_t) stream->pos.mmap_offset),
+               PRFIELD((size_t) stream->pos.mmap_base_offset),
+               PRFIELD(stream->pos.packet_size),
+               PRFIELD(stream->pos.offset),
+               PRFIELD(stream->flushed_packet_count),
+               PRFIELD(stream->discarded_events),
+               PRFIELD(stream->size), PRFIELD(stream->last_ts_end));
 }
 
 static inline void format_packet(char **buf_ch, bool extended,
@@ -649,7 +796,7 @@ static inline void format_packet(char **buf_ch, bool extended,
        BUF_APPEND(", %sis-frozen=%d, %sheader-field-addr=%p, "
                "%scontext-field-addr=%p",
                PRFIELD(packet->frozen),
-               PRFIELD(packet->header),
+               PRFIELD(packet->header ? packet->header->field : NULL),
                PRFIELD(packet->context));
        stream = bt_packet_borrow_stream(packet);
        if (!stream) {
@@ -687,11 +834,16 @@ static inline void format_event_common(char **buf_ch, bool extended,
                "%sstream-context-field-addr=%p, "
                "%scontext-field-addr=%p, %spayload-field-addr=%p, ",
                PRFIELD(event->frozen),
-               PRFIELD(event->header_field),
+               PRFIELD(event->header_field ? event->header_field->field : NULL),
                PRFIELD(event->stream_event_context_field),
                PRFIELD(event->context_field),
                PRFIELD(event->payload_field));
        BUF_APPEND(", %sevent-class-addr=%p", PRFIELD(event->class));
+
+       if (!event->class) {
+               return;
+       }
+
        SET_TMP_PREFIX("event-class-");
        format_event_class_func(buf_ch, false, tmp_prefix, event->class);
        stream_class = bt_event_class_common_borrow_stream_class(event->class);
@@ -725,8 +877,10 @@ static inline void format_event(char **buf_ch, bool extended,
                return;
        }
 
-       BUF_APPEND(", %sclock-value-count=%u",
-               PRFIELD(g_hash_table_size(event->clock_values)));
+       if (event->clock_values) {
+               BUF_APPEND(", %sclock-value-count=%u",
+                       PRFIELD(g_hash_table_size(event->clock_values)));
+       }
 
        packet = bt_event_borrow_packet(event);
        if (!packet) {
@@ -758,6 +912,8 @@ static inline void format_writer_event(char **buf_ch, bool extended,
 static inline void format_clock_class(char **buf_ch, bool extended,
                const char *prefix, struct bt_clock_class *clock_class)
 {
+       char tmp_prefix[64];
+
        BUF_APPEND(", %sname=\"%s\", %sfreq=%" PRIu64,
                PRFIELD(clock_class->name->str),
                PRFIELD(clock_class->frequency));
@@ -781,6 +937,9 @@ static inline void format_clock_class(char **buf_ch, bool extended,
        if (clock_class->uuid_set) {
                BUF_APPEND_UUID(clock_class->uuid);
        }
+
+       SET_TMP_PREFIX("cv-pool-");
+       format_object_pool(buf_ch, extended, prefix, &clock_class->cv_pool);
 }
 
 static inline void format_clock_value(char **buf_ch, bool extended,
@@ -795,6 +954,8 @@ static inline void format_clock_value(char **buf_ch, bool extended,
                return;
        }
 
+       BUF_APPEND(", %sis-frozen=%d, %sis-set=%d",
+               PRFIELD(clock_value->frozen), PRFIELD(clock_value->is_set));
        BUF_APPEND(", %sclock-class-addr=%p",
                PRFIELD(clock_value->clock_class));
        SET_TMP_PREFIX("clock-class-");
@@ -991,7 +1152,7 @@ static inline void format_component_class(char **buf_ch, bool extended,
 
        BUF_APPEND(", %stype=%s, %sname=\"%s\"",
                PRFIELD(bt_component_class_type_string(comp_class->type)),
-               PRFIELD(comp_class->name->str));
+               PRFIELD(comp_class->name ? comp_class->name->str : NULL));
 
        if (comp_class->description) {
                BUF_APPEND(", %spartial-descr=\"%.32s\"",
@@ -1024,9 +1185,15 @@ static inline void format_component(char **buf_ch, bool extended,
                return;
        }
 
-       BUF_APPEND(", %sinput-port-count=%u, %soutput-port-count=%u",
-               PRFIELD(component->input_ports ? component->input_ports->len : 0),
-               PRFIELD(component->output_ports ? component->output_ports->len : 0));
+       if (component->input_ports) {
+               BUF_APPEND(", %sinput-port-count=%u",
+                       PRFIELD(component->input_ports->len));
+       }
+
+       if (component->output_ports) {
+               BUF_APPEND(", %soutput-port-count=%u",
+                       PRFIELD(component->output_ports->len));
+       }
 }
 
 static inline void format_port(char **buf_ch, bool extended,
@@ -1079,9 +1246,15 @@ static inline void format_graph(char **buf_ch, bool extended,
                return;
        }
 
-       BUF_APPEND(", %scomp-count=%u, %sconn-count=%u",
-               PRFIELD(graph->components->len),
-               PRFIELD(graph->connections->len));
+       if (graph->components) {
+               BUF_APPEND(", %scomp-count=%u",
+                       PRFIELD(graph->components->len));
+       }
+
+       if (graph->connections) {
+               BUF_APPEND(", %sconn-count=%u",
+                       PRFIELD(graph->connections->len));
+       }
 }
 
 static inline void format_notification_iterator(char **buf_ch,
@@ -1367,6 +1540,9 @@ static inline void handle_conversion_specifier_bt(void *priv_data,
                case 'g':
                        format_graph(buf_ch, extended, prefix, obj);
                        break;
+               case 'o':
+                       format_object_pool(buf_ch, extended, prefix, obj);
+                       break;
                default:
                        abort();
                }
diff --git a/lib/object-pool.c b/lib/object-pool.c
new file mode 100644 (file)
index 0000000..2ac1e57
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "OBJECT-POOL"
+#include <babeltrace/lib-logging-internal.h>
+
+#include <stdint.h>
+#include <babeltrace/assert-internal.h>
+#include <babeltrace/object-pool-internal.h>
+
+int bt_object_pool_initialize(struct bt_object_pool *pool,
+               bt_object_pool_new_object_func new_object_func,
+               bt_object_pool_destroy_object_func destroy_object_func,
+               void *data)
+{
+       int ret = 0;
+
+       BT_ASSERT(new_object_func);
+       BT_ASSERT(destroy_object_func);
+       BT_LOGD("Initializing object pool: addr=%p, data-addr=%p",
+               pool, data);
+       pool->objects = g_ptr_array_new();
+       if (!pool->objects) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       pool->funcs.new_object = new_object_func;
+       pool->funcs.destroy_object = destroy_object_func;
+       pool->data = data;
+       pool->size = 0;
+       BT_LIB_LOGD("Initialized object pool: %!+o", pool);
+       goto end;
+
+error:
+       if (pool) {
+               bt_object_pool_finalize(pool);
+       }
+
+       ret = -1;
+
+end:
+       return ret;
+}
+
+void bt_object_pool_finalize(struct bt_object_pool *pool)
+{
+       uint64_t i;
+
+       BT_ASSERT(pool);
+       BT_LIB_LOGD("Finalizing object pool: %!+o", pool);
+
+       if (pool->objects) {
+               for (i = 0; i < pool->size; i++) {
+                       void *obj = pool->objects->pdata[i];
+
+                       if (obj) {
+                               pool->funcs.destroy_object(obj, pool->data);
+                       }
+               }
+
+               g_ptr_array_free(pool->objects, TRUE);
+               pool->objects = NULL;
+       }
+}
index 02d2c4e9bf914fe3467600d81ea4d5abd13058d9..e59187c6d706c0ef49d96bcd8a09d366b489e217 100644 (file)
--- a/lib/ref.c
+++ b/lib/ref.c
@@ -27,6 +27,7 @@
 #define BT_LOG_TAG "REF"
 #include <babeltrace/lib-logging-internal.h>
 
+#include <babeltrace/assert-pre-internal.h>
 #include <babeltrace/ref-internal.h>
 #include <babeltrace/object-internal.h>
 
@@ -38,6 +39,8 @@ void *bt_get(void *ptr)
                goto end;
        }
 
+       BT_ASSERT_PRE(obj->is_shared, "Object is not shared: addr=%p", obj);
+
        if (unlikely(!obj->ref_count.release)) {
                goto end;
        }
@@ -66,6 +69,8 @@ void bt_put(void *ptr)
                return;
        }
 
+       BT_ASSERT_PRE(obj->is_shared, "Object is not shared: addr=%p", obj);
+
        if (unlikely(!obj->ref_count.release)) {
                return;
        }
index 1d5adfa98b7918bd374fecdfd2c95c17fea9dc6b..4719e4514ed33bbc8363606c931028bc3edff04a 100644 (file)
@@ -80,6 +80,7 @@ struct bt_value bt_value_null_instance = {
                },
                .release = NULL,
                .parent = NULL,
+               .is_shared = true,
        },
        .type = BT_VALUE_TYPE_NULL,
        .frozen = BT_TRUE,
index 04acb6ec3cdf14b02c5cf3f877c100a5e7ffb169..7b4ca384e00fbee90e3ff05ab4d4180255d71ee6 100644 (file)
@@ -1,5 +1,5 @@
-SUBDIRS = ctf text utils
-#libctfcopytrace
+SUBDIRS = text utils ctf
+# libctfcopytrace
 
 if ENABLE_DEBUG_INFO
 #SUBDIRS += lttng-utils
index c4f400911159059b8b12b70268d5879acba02480..dbfef72a69a79b6f81023d8a9942edd5544b0d14 100644 (file)
@@ -53,7 +53,7 @@
  */
 enum bt_btr_status {
        /** Out of memory. */
-       BT_BTR_STATUS_ENOMEM =  -5,
+       BT_BTR_STATUS_ENOMEM =          -5,
        /**
         * The binary stream reader reached the end of the user-provided
         * buffer, but data is still needed to finish decoding the
@@ -66,10 +66,10 @@ enum bt_btr_status {
        BT_BTR_STATUS_EOF =             1,
 
        /** Invalid argument. */
-       BT_BTR_STATUS_INVAL =   -3,
+       BT_BTR_STATUS_INVAL =           -3,
 
        /** General error. */
-       BT_BTR_STATUS_ERROR =   -1,
+       BT_BTR_STATUS_ERROR =           -1,
 
        /** Everything okay. */
        BT_BTR_STATUS_OK =              0,
index 67785e3600fdfcdf985e73dd950ddbd65b1ab439..7128e184ba3821272e1d689415b9c0c795a06843 100644 (file)
@@ -54,7 +54,7 @@ struct stack_entry {
         *   * sequence
         *   * variant
         *
-        * Field is owned by this.
+        * Field is borrowed.
         */
        struct bt_field *base;
 
@@ -135,27 +135,45 @@ struct bt_notif_iter {
        /*
         * Current dynamic scope field pointer.
         *
-        * This is set when a dynamic scope field is first created by
-        * btr_compound_begin_cb(). It points to one of the fields in
-        * dscopes below.
+        * This is set by read_dscope_begin_state() and contains the
+        * value of one of the pointers in `dscopes` below.
         */
-       struct bt_field **cur_dscope_field;
+       struct bt_field *cur_dscope_field;
 
        /* Trace and classes (owned by this) */
        struct {
                struct bt_trace *trace;
                struct bt_stream_class *stream_class;
                struct bt_event_class *event_class;
+               struct bt_clock_class_priority_map *cc_prio_map;
        } meta;
 
+       /* Current packet header field wrapper (NULL if not created yet) */
+       struct bt_packet_header_field *packet_header_field;
+
+       /* Current packet header field wrapper (NULL if not created yet) */
+       struct bt_packet_context_field *packet_context_field;
+
+       /* Current event header field (NULL if not created yet) */
+       struct bt_event_header_field *event_header_field;
+
        /* Current packet (NULL if not created yet) */
        struct bt_packet *packet;
 
        /* Current stream (NULL if not set yet) */
        struct bt_stream *stream;
 
+       /* Current event (NULL if not created yet) */
+       struct bt_event *event;
+
+       /* Current event notification (NULL if not created yet) */
+       struct bt_notification *event_notif;
+
        /*
-        * Current timestamp_end field (to consider before switching packets).
+        * Current `timestamp_end` field (to consider before switching
+        * packets). If it's set, it's a field which is within
+        * `dscopes.stream_packet_context` below, which is in `packet`
+        * above.
         */
        struct bt_field *cur_timestamp_end;
 
@@ -312,10 +330,7 @@ enum bt_btr_status btr_timestamp_end_cb(void *value,
 static
 void stack_entry_free_func(gpointer data)
 {
-       struct stack_entry *entry = data;
-
-       bt_put(entry->base);
-       g_free(entry);
+       g_free(data);
 }
 
 static
@@ -370,7 +385,7 @@ int stack_push(struct stack *stack, struct bt_field *base)
                goto end;
        }
 
-       entry->base = bt_get(base);
+       entry->base = base;
        g_ptr_array_add(stack->entries, entry);
 
 end:
@@ -558,13 +573,12 @@ enum bt_notif_iter_status read_dscope_begin_state(
                struct bt_notif_iter *notit,
                struct bt_field_type *dscope_field_type,
                enum state done_state, enum state continue_state,
-               struct bt_field **dscope_field)
+               struct bt_field *dscope_field)
 {
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
        enum bt_btr_status btr_status;
        size_t consumed_bits;
 
-       bt_put(*dscope_field);
        notit->cur_dscope_field = dscope_field;
        BT_LOGV("Starting BTR: notit-addr=%p, btr-addr=%p, ft-addr=%p",
                notit, notit->btr, dscope_field_type);
@@ -654,26 +668,38 @@ end:
 }
 
 static
-void put_event_dscopes(struct bt_notif_iter *notit)
+void release_event_dscopes(struct bt_notif_iter *notit)
 {
-       BT_LOGV_STR("Putting event header field.");
-       BT_PUT(notit->dscopes.stream_event_header);
-       BT_LOGV_STR("Putting stream event context field.");
-       BT_PUT(notit->dscopes.stream_event_context);
-       BT_LOGV_STR("Putting event context field.");
-       BT_PUT(notit->dscopes.event_context);
-       BT_LOGV_STR("Putting event payload field.");
-       BT_PUT(notit->dscopes.event_payload);
+       notit->dscopes.stream_event_header = NULL;
+
+       if (notit->event_header_field) {
+               bt_event_header_field_release(notit->event_header_field);
+               notit->event_header_field = NULL;
+       }
+
+       notit->dscopes.stream_event_context = NULL;
+       notit->dscopes.event_context = NULL;
+       notit->dscopes.event_payload = NULL;
 }
 
 static
-void put_all_dscopes(struct bt_notif_iter *notit)
+void release_all_dscopes(struct bt_notif_iter *notit)
 {
-       BT_LOGV_STR("Putting packet header field.");
-       BT_PUT(notit->dscopes.trace_packet_header);
-       BT_LOGV_STR("Putting packet context field.");
-       BT_PUT(notit->dscopes.stream_packet_context);
-       put_event_dscopes(notit);
+       notit->dscopes.trace_packet_header = NULL;
+
+       if (notit->packet_header_field) {
+               bt_packet_header_field_release(notit->packet_header_field);
+               notit->packet_header_field = NULL;
+       }
+
+       notit->dscopes.stream_packet_context = NULL;
+
+       if (notit->packet_context_field) {
+               bt_packet_context_field_release(notit->packet_context_field);
+               notit->packet_context_field = NULL;
+       }
+
+       release_event_dscopes(notit);
 }
 
 static
@@ -697,6 +723,28 @@ enum bt_notif_iter_status read_packet_header_begin_state(
                goto end;
        }
 
+       /*
+        * Create free packet header field from trace. This field is
+        * going to be moved to the packet once we create it. We cannot
+        * create the packet now because:
+        *
+        * 1. A packet is created from a stream.
+        * 2. A stream is created from a stream class.
+        * 3. We need the packet header field's content to know the ID
+        *    of the stream class to select.
+        */
+       BT_ASSERT(!notit->packet_header_field);
+       notit->packet_header_field = bt_trace_create_packet_header_field(
+               notit->meta.trace);
+       if (!notit->packet_header_field) {
+               BT_LOGE_STR("Cannot create packet header field wrapper from trace.");
+               ret = BT_NOTIF_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       notit->dscopes.trace_packet_header =
+               bt_packet_header_field_borrow_field(notit->packet_header_field);
+       BT_ASSERT(notit->dscopes.trace_packet_header);
        BT_LOGV("Decoding packet header field:"
                "notit-addr=%p, trace-addr=%p, trace-name=\"%s\", ft-addr=%p",
                notit, notit->meta.trace,
@@ -704,7 +752,7 @@ enum bt_notif_iter_status read_packet_header_begin_state(
        ret = read_dscope_begin_state(notit, packet_header_type,
                STATE_AFTER_TRACE_PACKET_HEADER,
                STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE,
-               &notit->dscopes.trace_packet_header);
+               notit->dscopes.trace_packet_header);
        if (ret < 0) {
                BT_LOGW("Cannot decode packet header field: "
                        "notit-addr=%p, trace-addr=%p, "
@@ -726,20 +774,6 @@ enum bt_notif_iter_status read_packet_header_continue_state(
                        STATE_AFTER_TRACE_PACKET_HEADER);
 }
 
-static inline
-bool is_struct_type(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) ==
-                       BT_FIELD_TYPE_ID_STRUCT;
-}
-
-static inline
-bool is_variant_type(struct bt_field_type *field_type)
-{
-       return bt_field_type_get_type_id(field_type) ==
-                       BT_FIELD_TYPE_ID_VARIANT;
-}
-
 static
 struct stream_class_field_path_cache *
 create_stream_class_field_path_cache_entry(
@@ -918,7 +952,7 @@ enum bt_notif_iter_status set_current_stream_class(
                goto single_stream_class;
        }
 
-       BT_ASSERT(is_struct_type(packet_header_type));
+       BT_ASSERT(bt_field_type_is_structure(packet_header_type));
 
        // TODO: optimalize!
        stream_id_field_type =
@@ -932,13 +966,12 @@ enum bt_notif_iter_status set_current_stream_class(
                BT_ASSERT(notit->dscopes.trace_packet_header);
 
                // TODO: optimalize!
-               stream_id_field = bt_field_structure_get_field_by_name(
+               stream_id_field = bt_field_structure_borrow_field_by_name(
                                notit->dscopes.trace_packet_header, "stream_id");
                BT_ASSERT(stream_id_field);
                ret = bt_field_integer_unsigned_get_value(
                                stream_id_field, &stream_id);
                BT_ASSERT(!ret);
-               BT_PUT(stream_id_field);
        } else {
 single_stream_class:
                /* Only one stream: pick the first stream class */
@@ -1018,6 +1051,112 @@ end:
        return status;
 }
 
+static inline
+uint64_t get_cur_stream_instance_id(struct bt_notif_iter *notit)
+{
+       struct bt_field *stream_instance_id_field = NULL;
+       uint64_t stream_instance_id = -1ULL;
+       int ret;
+
+       if (!notit->dscopes.trace_packet_header) {
+               goto end;
+       }
+
+       stream_instance_id_field = bt_field_structure_borrow_field_by_name(
+               notit->dscopes.trace_packet_header, "stream_instance_id");
+       if (!stream_instance_id_field) {
+               goto end;
+       }
+
+       ret = bt_field_integer_unsigned_get_value(stream_instance_id_field,
+               &stream_instance_id);
+       if (ret) {
+               stream_instance_id = -1ULL;
+               goto end;
+       }
+
+end:
+       return stream_instance_id;
+}
+
+static inline
+enum bt_notif_iter_status set_current_stream(struct bt_notif_iter *notit)
+{
+       enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
+       struct bt_stream *stream = NULL;
+
+       BT_LOGV("Calling user function (get stream): notit-addr=%p, "
+               "stream-class-addr=%p, stream-class-name=\"%s\", "
+               "stream-class-id=%" PRId64,
+               notit, notit->meta.stream_class,
+               bt_stream_class_get_name(notit->meta.stream_class),
+               bt_stream_class_get_id(notit->meta.stream_class));
+       stream = bt_get(notit->medium.medops.borrow_stream(
+               notit->meta.stream_class, get_cur_stream_instance_id(notit),
+               notit->medium.data));
+       BT_LOGV("User function returned: stream-addr=%p", stream);
+       if (!stream) {
+               BT_LOGW_STR("User function failed to return a stream object for the given stream class.");
+               status = BT_NOTIF_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       if (notit->stream && stream != notit->stream) {
+               BT_LOGW("User function returned a different stream than the previous one for the same sequence of packets.");
+               status = BT_NOTIF_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_MOVE(notit->stream, stream);
+
+end:
+       bt_put(stream);
+       return status;
+}
+
+static inline
+enum bt_notif_iter_status set_current_packet(struct bt_notif_iter *notit)
+{
+       enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
+       struct bt_packet *packet = NULL;
+
+       BT_LOGV("Creating packet for packet notification: "
+               "notit-addr=%p", notit);
+       BT_LOGV("Creating packet from stream: "
+               "notit-addr=%p, stream-addr=%p, "
+               "stream-class-addr=%p, "
+               "stream-class-name=\"%s\", "
+               "stream-class-id=%" PRId64,
+               notit, notit->stream, notit->meta.stream_class,
+               bt_stream_class_get_name(notit->meta.stream_class),
+               bt_stream_class_get_id(notit->meta.stream_class));
+
+       /* Create packet */
+       BT_ASSERT(notit->stream);
+       packet = bt_packet_create(notit->stream);
+       if (!packet) {
+               BT_LOGE("Cannot create packet from stream: "
+                       "notit-addr=%p, stream-addr=%p, "
+                       "stream-class-addr=%p, "
+                       "stream-class-name=\"%s\", "
+                       "stream-class-id=%" PRId64,
+                       notit, notit->stream, notit->meta.stream_class,
+                       bt_stream_class_get_name(notit->meta.stream_class),
+                       bt_stream_class_get_id(notit->meta.stream_class));
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_PUT(packet);
+       status = BT_NOTIF_ITER_STATUS_ERROR;
+
+end:
+       BT_MOVE(notit->packet, packet);
+       return status;
+}
+
 static
 enum bt_notif_iter_status after_packet_header_state(
                struct bt_notif_iter *notit)
@@ -1025,10 +1164,13 @@ enum bt_notif_iter_status after_packet_header_state(
        enum bt_notif_iter_status status;
 
        status = set_current_stream_class(notit);
-       if (status == BT_NOTIF_ITER_STATUS_OK) {
-               notit->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
+       if (status != BT_NOTIF_ITER_STATUS_OK) {
+               goto end;
        }
 
+       notit->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
+
+end:
        return status;
 }
 
@@ -1053,6 +1195,27 @@ enum bt_notif_iter_status read_packet_context_begin_state(
                goto end;
        }
 
+       /*
+        * Create free packet context field from stream class. This
+        * field is going to be moved to the packet once we create it.
+        * We cannot create the packet now because a packet is created
+        * from a stream, and this API must be able to return the packet
+        * header and context fields without creating a stream
+        * (bt_notif_iter_get_packet_header_context_fields()).
+        */
+       BT_ASSERT(!notit->packet_context_field);
+       notit->packet_context_field =
+               bt_stream_class_create_packet_context_field(
+                       notit->meta.stream_class);
+       if (!notit->packet_context_field) {
+               BT_LOGE_STR("Cannot create packet context field wrapper from stream class.");
+               status = BT_NOTIF_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       notit->dscopes.stream_packet_context =
+               bt_packet_context_field_borrow_field(notit->packet_context_field);
+       BT_ASSERT(notit->dscopes.stream_packet_context);
        BT_LOGV("Decoding packet context field: "
                "notit-addr=%p, stream-class-addr=%p, "
                "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", "
@@ -1064,7 +1227,7 @@ enum bt_notif_iter_status read_packet_context_begin_state(
        status = read_dscope_begin_state(notit, packet_context_type,
                STATE_AFTER_STREAM_PACKET_CONTEXT,
                STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
-               &notit->dscopes.stream_packet_context);
+               notit->dscopes.stream_packet_context);
        if (status < 0) {
                BT_LOGW("Cannot decode packet context field: "
                        "notit-addr=%p, stream-class-addr=%p, "
@@ -1101,9 +1264,9 @@ enum bt_notif_iter_status set_current_packet_content_sizes(
                goto end;
        }
 
-       packet_size_field = bt_field_structure_get_field_by_name(
+       packet_size_field = bt_field_structure_borrow_field_by_name(
                notit->dscopes.stream_packet_context, "packet_size");
-       content_size_field = bt_field_structure_get_field_by_name(
+       content_size_field = bt_field_structure_borrow_field_by_name(
                notit->dscopes.stream_packet_context, "content_size");
        if (packet_size_field) {
                int ret = bt_field_integer_unsigned_get_value(
@@ -1161,8 +1324,6 @@ enum bt_notif_iter_status set_current_packet_content_sizes(
                "notit-addr=%p, packet-size=%" PRIu64 ", content-size=%" PRIu64,
                notit, packet_size, content_size);
 end:
-       BT_PUT(packet_size_field);
-       BT_PUT(content_size_field);
        return status;
 }
 
@@ -1213,6 +1374,8 @@ enum bt_notif_iter_status read_event_header_begin_state(
                }
        }
 
+       release_event_dscopes(notit);
+       BT_ASSERT(notit->meta.stream_class);
        event_header_type = bt_stream_class_borrow_event_header_field_type(
                notit->meta.stream_class);
        if (!event_header_type) {
@@ -1220,7 +1383,18 @@ enum bt_notif_iter_status read_event_header_begin_state(
                goto end;
        }
 
-       put_event_dscopes(notit);
+       BT_ASSERT(!notit->event_header_field);
+       notit->event_header_field = bt_stream_class_create_event_header_field(
+               notit->meta.stream_class);
+       if (!notit->event_header_field) {
+               BT_LOGE_STR("Cannot create event header field wrapper from trace.");
+               status = BT_NOTIF_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       notit->dscopes.stream_event_header =
+               bt_event_header_field_borrow_field(notit->event_header_field);
+       BT_ASSERT(notit->dscopes.stream_event_header);
        BT_LOGV("Decoding event header field: "
                "notit-addr=%p, stream-class-addr=%p, "
                "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", "
@@ -1232,7 +1406,7 @@ enum bt_notif_iter_status read_event_header_begin_state(
        status = read_dscope_begin_state(notit, event_header_type,
                STATE_AFTER_STREAM_EVENT_HEADER,
                STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
-               &notit->dscopes.stream_event_header);
+               notit->dscopes.stream_event_header);
        if (status < 0) {
                BT_LOGW("Cannot decode event header field: "
                        "notit-addr=%p, stream-class-addr=%p, "
@@ -1283,7 +1457,7 @@ enum bt_notif_iter_status set_current_event_class(struct bt_notif_iter *notit)
        }
 
        /* Is there any "id"/"v" field in the event header? */
-       BT_ASSERT(is_struct_type(event_header_type));
+       BT_ASSERT(bt_field_type_is_structure(event_header_type));
        id_field_type = bt_field_type_structure_borrow_field_type_by_name(
                event_header_type, "id");
        v_field_type = bt_field_type_structure_borrow_field_type_by_name(
@@ -1303,19 +1477,19 @@ enum bt_notif_iter_status set_current_event_class(struct bt_notif_iter *notit)
                struct bt_field *v_struct_id_field = NULL;
 
                // TODO: optimalize!
-               v_field = bt_field_structure_get_field_by_name(
+               v_field = bt_field_structure_borrow_field_by_name(
                        notit->dscopes.stream_event_header, "v");
                BT_ASSERT(v_field);
 
                v_struct_field =
-                       bt_field_variant_get_current_field(v_field);
+                       bt_field_variant_borrow_current_field(v_field);
                if (!v_struct_field) {
                        goto end_v_field_type;
                }
 
                // TODO: optimalize!
-               v_struct_id_field =
-                       bt_field_structure_get_field_by_name(v_struct_field, "id");
+               v_struct_id_field = bt_field_structure_borrow_field_by_name(
+                       v_struct_field, "id");
                if (!v_struct_id_field) {
                        goto end_v_field_type;
                }
@@ -1330,41 +1504,24 @@ enum bt_notif_iter_status set_current_event_class(struct bt_notif_iter *notit)
                                event_id = -1ULL;
                        }
                }
-
-end_v_field_type:
-               BT_PUT(v_field);
-               BT_PUT(v_struct_field);
-               BT_PUT(v_struct_id_field);
        }
 
+end_v_field_type:
        if (id_field_type && event_id == -1ULL) {
                /* Check "id" field */
                struct bt_field *id_field = NULL;
                int ret_get_value = 0;
 
                // TODO: optimalize!
-               id_field = bt_field_structure_get_field_by_name(
+               id_field = bt_field_structure_borrow_field_by_name(
                        notit->dscopes.stream_event_header, "id");
                if (!id_field) {
                        goto check_event_id;
                }
 
-               if (bt_field_is_integer(id_field)) {
-                       ret_get_value = bt_field_integer_unsigned_get_value(
-                               id_field, &event_id);
-               } else if (bt_field_is_enumeration(id_field)) {
-                       struct bt_field *container;
-
-                       container = bt_field_enumeration_get_container(
-                               id_field);
-                       BT_ASSERT(container);
-                       ret_get_value = bt_field_integer_unsigned_get_value(
-                               container, &event_id);
-                       BT_PUT(container);
-               }
-
+               ret_get_value = bt_field_integer_unsigned_get_value(
+                       id_field, &event_id);
                BT_ASSERT(ret_get_value == 0);
-               BT_PUT(id_field);
        }
 
 check_event_id:
@@ -1411,6 +1568,43 @@ end:
        return status;
 }
 
+static inline
+enum bt_notif_iter_status set_current_event_notification(
+               struct bt_notif_iter *notit)
+{
+       enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
+       struct bt_notification *notif = NULL;
+
+       BT_ASSERT(notit->meta.event_class);
+       BT_ASSERT(notit->packet);
+       BT_LOGV("Creating event notification from event class and packet: "
+               "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", packet-addr=%p",
+               notit, notit->meta.event_class,
+               bt_event_class_get_name(notit->meta.event_class),
+               notit->packet);
+       notif = bt_notification_event_create(notit->meta.event_class,
+               notit->packet, notit->meta.cc_prio_map);
+       if (!notif) {
+               BT_LOGE("Cannot create event notification: "
+                       "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", "
+                       "packet-addr=%p",
+                       notit, notit->meta.event_class,
+                       bt_event_class_get_name(notit->meta.event_class),
+                       notit->packet);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_PUT(notif);
+       status = BT_NOTIF_ITER_STATUS_ERROR;
+
+end:
+       BT_MOVE(notit->event_notif, notif);
+       return status;
+}
+
 static
 enum bt_notif_iter_status after_event_header_state(
                struct bt_notif_iter *notit)
@@ -1422,6 +1616,37 @@ enum bt_notif_iter_status after_event_header_state(
                goto end;
        }
 
+       status = set_current_event_notification(notit);
+       if (status != BT_NOTIF_ITER_STATUS_OK) {
+               goto end;
+       }
+
+       notit->event = bt_notification_event_borrow_event(notit->event_notif);
+       BT_ASSERT(notit->event);
+
+       if (notit->event_header_field) {
+               int ret;
+
+               BT_ASSERT(notit->event);
+               ret = bt_event_move_header(notit->event,
+                       notit->event_header_field);
+
+               if (ret) {
+                       status = BT_NOTIF_ITER_STATUS_ERROR;
+                       goto end;
+               }
+
+               notit->event_header_field = NULL;
+
+               /*
+                * At this point notit->dscopes.stream_event_header has
+                * the same value as the event header field within
+                * notit->event.
+                */
+               BT_ASSERT(bt_event_borrow_header(notit->event) ==
+                       notit->dscopes.stream_event_header);
+       }
+
        notit->state = STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN;
 
 end:
@@ -1443,6 +1668,10 @@ enum bt_notif_iter_status read_stream_event_context_begin_state(
                goto end;
        }
 
+       BT_ASSERT(!notit->dscopes.stream_event_context);
+       notit->dscopes.stream_event_context =
+               bt_event_borrow_stream_event_context(notit->event);
+       BT_ASSERT(notit->dscopes.stream_event_context);
        BT_LOGV("Decoding stream event context field: "
                "notit-addr=%p, stream-class-addr=%p, "
                "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", "
@@ -1454,7 +1683,7 @@ enum bt_notif_iter_status read_stream_event_context_begin_state(
        status = read_dscope_begin_state(notit, stream_event_context_type,
                STATE_DSCOPE_EVENT_CONTEXT_BEGIN,
                STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE,
-               &notit->dscopes.stream_event_context);
+               notit->dscopes.stream_event_context);
        if (status < 0) {
                BT_LOGW("Cannot decode stream event context field: "
                        "notit-addr=%p, stream-class-addr=%p, "
@@ -1492,6 +1721,9 @@ enum bt_notif_iter_status read_event_context_begin_state(
                goto end;
        }
 
+       BT_ASSERT(!notit->dscopes.event_context);
+       notit->dscopes.event_context = bt_event_borrow_context(notit->event);
+       BT_ASSERT(notit->dscopes.event_context);
        BT_LOGV("Decoding event context field: "
                "notit-addr=%p, event-class-addr=%p, "
                "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
@@ -1503,7 +1735,7 @@ enum bt_notif_iter_status read_event_context_begin_state(
        status = read_dscope_begin_state(notit, event_context_type,
                STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
                STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
-               &notit->dscopes.event_context);
+               notit->dscopes.event_context);
        if (status < 0) {
                BT_LOGW("Cannot decode event context field: "
                        "notit-addr=%p, event-class-addr=%p, "
@@ -1541,6 +1773,9 @@ enum bt_notif_iter_status read_event_payload_begin_state(
                goto end;
        }
 
+       BT_ASSERT(!notit->dscopes.event_payload);
+       notit->dscopes.event_payload = bt_event_borrow_payload(notit->event);
+       BT_ASSERT(notit->dscopes.event_payload);
        BT_LOGV("Decoding event payload field: "
                "notit-addr=%p, event-class-addr=%p, "
                "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
@@ -1552,7 +1787,7 @@ enum bt_notif_iter_status read_event_payload_begin_state(
        status = read_dscope_begin_state(notit, event_payload_type,
                STATE_EMIT_NOTIF_EVENT,
                STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
-               &notit->dscopes.event_payload);
+               notit->dscopes.event_payload);
        if (status < 0) {
                BT_LOGW("Cannot decode event payload field: "
                        "notit-addr=%p, event-class-addr=%p, "
@@ -1712,7 +1947,25 @@ void bt_notif_iter_reset(struct bt_notif_iter *notit)
        notit->meta.event_class = NULL;
        BT_PUT(notit->packet);
        BT_PUT(notit->stream);
-       put_all_dscopes(notit);
+       BT_PUT(notit->event_notif);
+       release_all_dscopes(notit);
+       notit->cur_dscope_field = NULL;
+
+       if (notit->packet_header_field) {
+               bt_packet_header_field_release(notit->packet_header_field);
+               notit->packet_header_field = NULL;
+       }
+
+       if (notit->packet_context_field) {
+               bt_packet_context_field_release(notit->packet_context_field);
+               notit->packet_context_field = NULL;
+       }
+
+       if (notit->event_header_field) {
+               bt_event_header_field_release(notit->event_header_field);
+               notit->event_header_field = NULL;
+       }
+
        notit->buf.addr = NULL;
        notit->buf.sz = 0;
        notit->buf.at = 0;
@@ -1723,6 +1976,7 @@ void bt_notif_iter_reset(struct bt_notif_iter *notit)
        notit->cur_packet_size = -1;
        notit->cur_packet_offset = -1;
        notit->stream_begin_emitted = false;
+       notit->cur_timestamp_end = NULL;
 }
 
 static
@@ -1736,17 +1990,21 @@ int bt_notif_iter_switch_packet(struct bt_notif_iter *notit)
         * iterator refer to the same stream class (the first one).
         */
        BT_ASSERT(notit);
+
        if (notit->cur_packet_size != -1) {
                notit->cur_packet_offset += notit->cur_packet_size;
        }
+
        BT_LOGV("Switching packet: notit-addr=%p, cur=%zu, "
                "packet-offset=%" PRId64, notit, notit->buf.at,
                notit->cur_packet_offset);
        stack_clear(notit->stack);
        notit->meta.event_class = NULL;
        BT_PUT(notit->packet);
-       BT_PUT(notit->cur_timestamp_end);
-       put_all_dscopes(notit);
+       BT_PUT(notit->event_notif);
+       notit->cur_timestamp_end = NULL;
+       release_all_dscopes(notit);
+       notit->cur_dscope_field = NULL;
 
        /*
         * Adjust current buffer so that addr points to the beginning of the new
@@ -1780,7 +2038,7 @@ end:
 }
 
 static
-struct bt_field *get_next_field(struct bt_notif_iter *notit)
+struct bt_field *borrow_next_field(struct bt_notif_iter *notit)
 {
        struct bt_field *next_field = NULL;
        struct bt_field *base_field;
@@ -1797,18 +2055,18 @@ struct bt_field *get_next_field(struct bt_notif_iter *notit)
        switch (bt_field_type_get_type_id(base_type)) {
        case BT_FIELD_TYPE_ID_STRUCT:
        {
-               next_field = bt_field_structure_get_field_by_index(
+               next_field = bt_field_structure_borrow_field_by_index(
                        base_field, index);
                break;
        }
        case BT_FIELD_TYPE_ID_ARRAY:
-               next_field = bt_field_array_get_field(base_field, index);
+               next_field = bt_field_array_borrow_field(base_field, index);
                break;
        case BT_FIELD_TYPE_ID_SEQUENCE:
-               next_field = bt_field_sequence_get_field(base_field, index);
+               next_field = bt_field_sequence_borrow_field(base_field, index);
                break;
        case BT_FIELD_TYPE_ID_VARIANT:
-               next_field = bt_field_variant_get_current_field(base_field);
+               next_field = bt_field_variant_borrow_current_field(base_field);
                break;
        default:
                BT_LOGF("Unknown base field type ID: "
@@ -1823,17 +2081,15 @@ struct bt_field *get_next_field(struct bt_notif_iter *notit)
 }
 
 static
-void update_clock_state(uint64_t *state,
-               struct bt_field *value_field)
+void update_clock_state(uint64_t *state, struct bt_field *value_field,
+               struct bt_field_type *value_type)
 {
-       struct bt_field_type *value_type = NULL;
        uint64_t requested_new_value;
        uint64_t requested_new_value_mask;
        uint64_t cur_value_masked;
        int requested_new_value_size;
        int ret;
 
-       value_type = bt_field_borrow_type(value_field);
        BT_ASSERT(value_type);
        BT_ASSERT(bt_field_type_is_integer(value_type));
        requested_new_value_size =
@@ -1888,6 +2144,13 @@ enum bt_btr_status update_clock(struct bt_notif_iter *notit,
 
        int_field_type = bt_field_borrow_type(int_field);
        BT_ASSERT(int_field_type);
+
+       if (bt_field_type_is_enumeration(int_field_type)) {
+               int_field_type =
+                       bt_field_type_enumeration_borrow_container_field_type(
+                               int_field_type);
+       }
+
        clock_class = bt_field_type_integer_borrow_mapped_clock_class(
                int_field_type);
        if (likely(!clock_class)) {
@@ -1914,7 +2177,7 @@ enum bt_btr_status update_clock(struct bt_notif_iter *notit,
                "clock-class-name=\"%s\", value=%" PRIu64,
                notit, clock_class,
                bt_clock_class_get_name(clock_class), *clock_state);
-       update_clock_state(clock_state, int_field);
+       update_clock_state(clock_state, int_field, int_field_type);
 
 end:
        return ret;
@@ -1923,11 +2186,10 @@ end:
 static
 enum bt_btr_status btr_unsigned_int_common(uint64_t value,
                struct bt_field_type *type, void *data,
-               struct bt_field **out_int_field)
+               struct bt_field **out_field)
 {
        enum bt_btr_status status = BT_BTR_STATUS_OK;
        struct bt_field *field = NULL;
-       struct bt_field *int_field = NULL;
        struct bt_notif_iter *notit = data;
        int ret;
 
@@ -1938,43 +2200,20 @@ enum bt_btr_status btr_unsigned_int_common(uint64_t value,
                bt_common_field_type_id_string(
                        bt_field_type_get_type_id(type)),
                value);
-
-       /* Create next field */
-       field = get_next_field(notit);
+       field = borrow_next_field(notit);
        if (!field) {
-               BT_LOGW("Cannot get next field: notit-addr=%p", notit);
+               BT_LOGW("Cannot borrow next field: notit-addr=%p", notit);
                status = BT_BTR_STATUS_ERROR;
-               goto end_no_put;
-       }
-
-       switch(bt_field_type_get_type_id(type)) {
-       case BT_FIELD_TYPE_ID_INTEGER:
-               /* Integer field is created field */
-               BT_MOVE(int_field, field);
-               break;
-       case BT_FIELD_TYPE_ID_ENUM:
-               int_field = bt_field_enumeration_get_container(field);
-               BT_ASSERT(int_field);
-               type = bt_field_borrow_type(int_field);
-               BT_ASSERT(type);
-               break;
-       default:
-               BT_LOGF("Unexpected field type ID: "
-                       "notit-addr=%p, ft-addr=%p, ft-id=%s",
-                       notit, type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(type)));
-               abort();
+               goto end;
        }
 
-       BT_ASSERT(int_field);
-       ret = bt_field_integer_unsigned_set_value(int_field, value);
+       BT_ASSERT(bt_field_is_integer(field) || bt_field_is_enumeration(field));
+       ret = bt_field_integer_unsigned_set_value(field, value);
        BT_ASSERT(ret == 0);
        stack_top(notit->stack)->index++;
-       *out_int_field = int_field;
-       BT_PUT(field);
+       *out_field = field;
 
-end_no_put:
+end:
        return status;
 }
 
@@ -1985,6 +2224,7 @@ enum bt_btr_status btr_timestamp_end_cb(void *value,
        enum bt_btr_status status;
        struct bt_field *field = NULL;
        struct bt_notif_iter *notit = data;
+       uint64_t uvalue = *((uint64_t *) value);
 
        BT_LOGV("`timestamp_end` unsigned integer function called from BTR: "
                "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
@@ -1992,11 +2232,11 @@ enum bt_btr_status btr_timestamp_end_cb(void *value,
                notit, notit->btr, type,
                bt_common_field_type_id_string(
                        bt_field_type_get_type_id(type)));
-       status = btr_unsigned_int_common(*((uint64_t *) value), type, data,
-                       &field);
 
-       /* Set as the current packet's timestamp_end field. */
-       BT_MOVE(notit->cur_timestamp_end, field);
+       status = btr_unsigned_int_common(uvalue, type, data, &field);
+
+       /* Set as the current packet's end timestamp field */
+       notit->cur_timestamp_end = field;
        return status;
 }
 
@@ -2030,7 +2270,7 @@ enum bt_btr_status btr_unsigned_int_cb(uint64_t value,
        }
 
        status = update_clock(notit, field);
-       BT_PUT(field);
+
 end:
        return status;
 }
@@ -2041,7 +2281,6 @@ enum bt_btr_status btr_signed_int_cb(int64_t value,
 {
        enum bt_btr_status status = BT_BTR_STATUS_OK;
        struct bt_field *field = NULL;
-       struct bt_field *int_field = NULL;
        struct bt_notif_iter *notit = data;
        int ret;
 
@@ -2052,44 +2291,19 @@ enum bt_btr_status btr_signed_int_cb(int64_t value,
                bt_common_field_type_id_string(
                        bt_field_type_get_type_id(type)),
                value);
-
-       /* create next field */
-       field = get_next_field(notit);
+       field = borrow_next_field(notit);
        if (!field) {
-               BT_LOGW("Cannot get next field: notit-addr=%p", notit);
+               BT_LOGW("Cannot borrow next field: notit-addr=%p", notit);
                status = BT_BTR_STATUS_ERROR;
-               goto end_no_put;
-       }
-
-       switch(bt_field_type_get_type_id(type)) {
-       case BT_FIELD_TYPE_ID_INTEGER:
-               /* Integer field is created field */
-               BT_MOVE(int_field, field);
-               break;
-       case BT_FIELD_TYPE_ID_ENUM:
-               int_field = bt_field_enumeration_get_container(field);
-               BT_ASSERT(int_field);
-               type = bt_field_borrow_type(int_field);
-               BT_ASSERT(type);
-               break;
-       default:
-               BT_LOGF("Unexpected field type ID: "
-                       "notit-addr=%p, ft-addr=%p, ft-id=%s",
-                       notit, type,
-                       bt_common_field_type_id_string(
-                               bt_field_type_get_type_id(type)));
-               abort();
+               goto end;
        }
 
-       BT_ASSERT(int_field);
-       ret = bt_field_integer_signed_set_value(int_field, value);
-       BT_ASSERT(!ret);
+       BT_ASSERT(bt_field_is_integer(field) || bt_field_is_enumeration(field));
+       ret = bt_field_integer_signed_set_value(field, value);
+       BT_ASSERT(ret == 0);
        stack_top(notit->stack)->index++;
-       status = update_clock(notit, int_field);
-       BT_PUT(field);
-       BT_PUT(int_field);
 
-end_no_put:
+end:
        return status;
 }
 
@@ -2109,11 +2323,9 @@ enum bt_btr_status btr_floating_point_cb(double value,
                bt_common_field_type_id_string(
                        bt_field_type_get_type_id(type)),
                value);
-
-       /* Create next field */
-       field = get_next_field(notit);
+       field = borrow_next_field(notit);
        if (!field) {
-               BT_LOGW("Cannot get next field: notit-addr=%p", notit);
+               BT_LOGW("Cannot borrow next field: notit-addr=%p", notit);
                status = BT_BTR_STATUS_ERROR;
                goto end;
        }
@@ -2123,7 +2335,6 @@ enum bt_btr_status btr_floating_point_cb(double value,
        stack_top(notit->stack)->index++;
 
 end:
-       BT_PUT(field);
        return status;
 }
 
@@ -2142,15 +2353,16 @@ enum bt_btr_status btr_string_begin_cb(
                notit, notit->btr, type,
                bt_common_field_type_id_string(
                        bt_field_type_get_type_id(type)));
-
-       /* Create next field */
-       field = get_next_field(notit);
+       field = borrow_next_field(notit);
        if (!field) {
                BT_LOGW("Cannot get next field: notit-addr=%p", notit);
                status = BT_BTR_STATUS_ERROR;
                goto end;
        }
 
+       ret = bt_field_string_clear(field);
+       BT_ASSERT(ret == 0);
+
        /*
         * Push on stack. Not a compound type per se, but we know that only
         * btr_string_cb() may be called between this call and a subsequent
@@ -2164,23 +2376,7 @@ enum bt_btr_status btr_string_begin_cb(
                goto end;
        }
 
-       /*
-        * Initialize string field payload to an empty string since in the
-        * case of a length 0 string the btr_string_cb won't be called and
-        * we will end up with an unset string payload.
-        */
-       ret = bt_field_string_set_value(field, "");
-       if (ret) {
-               BT_LOGE("Cannot initialize string field's value to an empty string: "
-                       "notit-addr=%p, field-addr=%p, ret=%d",
-                       notit, field, ret);
-               status = BT_BTR_STATUS_ERROR;
-               goto end;
-       }
-
 end:
-       BT_PUT(field);
-
        return status;
 }
 
@@ -2200,12 +2396,10 @@ enum bt_btr_status btr_string_cb(const char *value,
                bt_common_field_type_id_string(
                        bt_field_type_get_type_id(type)),
                len);
-
-       /* Get string field */
        field = stack_top(notit->stack)->base;
        BT_ASSERT(field);
 
-       /* Append current string */
+       /* Append current substring */
        ret = bt_field_string_append_len(field, value, len);
        if (ret) {
                BT_LOGE("Cannot append substring to string field's value: "
@@ -2255,33 +2449,14 @@ enum bt_btr_status btr_compound_begin_cb(
                bt_common_field_type_id_string(
                        bt_field_type_get_type_id(type)));
 
-       /* Create field */
+       /* Borrow field */
        if (stack_empty(notit->stack)) {
-               /* Root: create dynamic scope field */
-               *notit->cur_dscope_field = bt_field_create(type);
-               field = *notit->cur_dscope_field;
-
-               /*
-                * Field will be put at the end of this function
-                * (stack_push() will take one reference, but this
-                * reference is lost upon the equivalent stack_pop()
-                * later), so also get it for our context to own it.
-                */
-               bt_get(*notit->cur_dscope_field);
-
-               if (!field) {
-                       BT_LOGE("Cannot create compound field: "
-                               "notit-addr=%p, ft-addr=%p, ft-id=%s",
-                               notit, type,
-                               bt_common_field_type_id_string(
-                                       bt_field_type_get_type_id(type)));
-                       status = BT_BTR_STATUS_ERROR;
-                       goto end;
-               }
+               /* Root: already set by read_dscope_begin_state() */
+               field = notit->cur_dscope_field;
        } else {
-               field = get_next_field(notit);
+               field = borrow_next_field(notit);
                if (!field) {
-                       BT_LOGW("Cannot get next field: notit-addr=%p", notit);
+                       BT_LOGW("Cannot borrow next field: notit-addr=%p", notit);
                        status = BT_BTR_STATUS_ERROR;
                        goto end;
                }
@@ -2302,7 +2477,6 @@ enum bt_btr_status btr_compound_begin_cb(
        }
 
 end:
-       BT_PUT(field);
        return status;
 }
 
@@ -2383,8 +2557,6 @@ struct bt_field *resolve_field(struct bt_notif_iter *notit,
                goto end;
        }
 
-       bt_get(field);
-
        for (i = 0; i < bt_field_path_get_index_count(path); ++i) {
                struct bt_field *next_field = NULL;
                struct bt_field_type *field_type;
@@ -2393,15 +2565,15 @@ struct bt_field *resolve_field(struct bt_notif_iter *notit,
                field_type = bt_field_borrow_type(field);
                BT_ASSERT(field_type);
 
-               if (is_struct_type(field_type)) {
-                       next_field = bt_field_structure_get_field_by_index(
+               if (bt_field_type_is_structure(field_type)) {
+                       next_field = bt_field_structure_borrow_field_by_index(
                                field, index);
-               } else if (is_variant_type(field_type)) {
+               } else if (bt_field_type_is_variant(field_type)) {
                        next_field =
-                               bt_field_variant_get_current_field(field);
+                               bt_field_variant_borrow_current_field(field);
                }
 
-               BT_PUT(field);
+               field = NULL;
 
                if (!next_field) {
                        BT_LOGW("Cannot find next field: "
@@ -2414,7 +2586,7 @@ struct bt_field *resolve_field(struct bt_notif_iter *notit,
                }
 
                /* Move next field -> field */
-               BT_MOVE(field, next_field);
+               field = next_field;
        }
 
 end:
@@ -2451,19 +2623,18 @@ int64_t btr_get_sequence_length_cb(struct bt_field_type *type, void *data)
        }
 
        seq_field = stack_top(notit->stack)->base;
-       iret = bt_field_sequence_set_length(seq_field, length_field);
+       iret = bt_field_sequence_set_length(seq_field, length);
        if (iret) {
                BT_LOGE("Cannot set sequence field's length field: "
                        "notit-addr=%p, seq-field-addr=%p, "
-                       "length-field-addr=%p, ",
-                       notit, seq_field, length_field);
+                       "length=%" PRIu64,
+                       notit, seq_field, length);
                goto end;
        }
 
        ret = (int64_t) length;
 
 end:
-       BT_PUT(length_field);
        return ret;
 }
 
@@ -2471,10 +2642,13 @@ static
 struct bt_field_type *btr_borrow_variant_field_type_cb(
                struct bt_field_type *type, void *data)
 {
+       int ret;
        struct bt_field_path *path;
        struct bt_notif_iter *notit = data;
        struct bt_field *var_field;
        struct bt_field *tag_field = NULL;
+       struct bt_field_type *tag_ft = NULL;
+       struct bt_field_type *tag_int_ft = NULL;
        struct bt_field *selected_field = NULL;
        struct bt_field_type *selected_field_type = NULL;
 
@@ -2493,33 +2667,51 @@ struct bt_field_type *btr_borrow_variant_field_type_cb(
         * able to select a current field for this variant. This
         * callback function we're in is called _after_
         * compound_begin(), so the current stack top's base field is
-        * the variant field in question. We get the selected field here
-        * thanks to this tag field (thus creating the selected field),
-        * which will also provide us with its type. Then, this field
-        * will remain the current selected one until the next callback
-        * function call which is used to fill the current selected
-        * field.
+        * the variant field in question. We set the variant field's tag
+        * here and then get the current (selected) field thanks to this
+        * tag field's value. This current field will also provide us
+        * with its type. Then, this current field will remain the
+        * current selected one until the next callback function call
+        * which is used to fill it.
         */
        var_field = stack_top(notit->stack)->base;
-       selected_field = bt_field_variant_get_field(var_field, tag_field);
+       tag_ft = bt_field_borrow_type(tag_field);
+       tag_int_ft = bt_field_type_enumeration_borrow_container_field_type(
+               tag_ft);
+
+       if (bt_field_type_integer_is_signed(tag_int_ft)) {
+               int64_t tag_value;
+
+               ret = bt_field_integer_signed_get_value(tag_field, &tag_value);
+               BT_ASSERT(ret == 0);
+               ret = bt_field_variant_set_tag_signed(var_field, tag_value);
+               BT_ASSERT(ret == 0);
+       } else {
+               uint64_t tag_value;
+
+               ret = bt_field_integer_unsigned_get_value(tag_field,
+                       &tag_value);
+               BT_ASSERT(ret == 0);
+               ret = bt_field_variant_set_tag_unsigned(var_field, tag_value);
+               BT_ASSERT(ret == 0);
+       }
+
+       selected_field = bt_field_variant_borrow_current_field(var_field);
        if (!selected_field) {
-               BT_LOGW("Cannot get variant field's selection using tag field: "
-                       "notit-addr=%p, var-field-addr=%p, tag-field-addr=%p",
-                       notit, var_field, tag_field);
+               BT_LOGW("Cannot borrow variant field's current field: "
+                       "notit-addr=%p, var-field-addr=%p",
+                       notit, var_field);
                goto end;
        }
 
        selected_field_type = bt_field_borrow_type(selected_field);
 
 end:
-       BT_PUT(tag_field);
-       BT_PUT(selected_field);
        return selected_field_type;
 }
 
 static
-int set_event_clocks(struct bt_event *event,
-               struct bt_notif_iter *notit)
+int set_event_clocks(struct bt_notif_iter *notit)
 {
        int ret;
        GHashTableIter iter;
@@ -2529,13 +2721,13 @@ int set_event_clocks(struct bt_event *event,
        g_hash_table_iter_init(&iter, notit->clock_states);
 
        while (g_hash_table_iter_next(&iter, (gpointer) &clock_class,
-                       (gpointer) &clock_state)) {
+                       (gpointer) &clock_state)) {
                struct bt_clock_value *clock_value;
 
-               clock_value = bt_clock_value_create(clock_class,
-                       *clock_state);
+               clock_value = bt_event_borrow_clock_value(notit->event,
+                       clock_class);
                if (!clock_value) {
-                       BT_LOGE("Cannot create clock value from clock class: "
+                       BT_LOGE("Cannot borrow clock value from event with given clock class: "
                                "notit-addr=%p, clock-class-addr=%p, "
                                "clock-class-name=\"%s\"",
                                notit, clock_class,
@@ -2543,309 +2735,26 @@ int set_event_clocks(struct bt_event *event,
                        ret = -1;
                        goto end;
                }
-               ret = bt_event_set_clock_value(event, clock_value);
-               bt_put(clock_value);
-               if (ret) {
-                       struct bt_event_class *event_class =
-                               bt_event_borrow_class(event);
-
-                       BT_ASSERT(event_class);
-                       BT_LOGE("Cannot set event's clock value: "
-                               "notit-addr=%p, event-addr=%p, "
-                               "event-class-name=\"%s\", "
-                               "event-class-id=%" PRId64 ", "
-                               "clock-class-addr=%p, "
-                               "clock-class-name=\"%s\", "
-                               "clock-value-addr=%p",
-                               notit, event,
-                               bt_event_class_get_name(event_class),
-                               bt_event_class_get_id(event_class),
-                               clock_class,
-                               bt_clock_class_get_name(clock_class),
-                               clock_value);
-                       goto end;
-               }
-       }
-
-       ret = 0;
-end:
-       return ret;
-}
-
-static
-struct bt_event *create_event(struct bt_notif_iter *notit)
-{
-       int ret;
-       struct bt_event *event;
-
-       BT_LOGV("Creating event for event notification: "
-               "notit-addr=%p, event-class-addr=%p, "
-               "event-class-name=\"%s\", "
-               "event-class-id=%" PRId64,
-               notit, notit->meta.event_class,
-               bt_event_class_get_name(notit->meta.event_class),
-               bt_event_class_get_id(notit->meta.event_class));
-
-       /* Create event object. */
-       event = bt_event_create(notit->meta.event_class);
-       if (!event) {
-               BT_LOGE("Cannot create event: "
-                       "notit-addr=%p, event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64,
-                       notit, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
-                       bt_event_class_get_id(notit->meta.event_class));
-               goto error;
-       }
-
-       /* Set header, stream event context, context, and payload fields. */
-       ret = bt_event_set_header(event,
-               notit->dscopes.stream_event_header);
-       if (ret) {
-               BT_LOGE("Cannot set event's header field: "
-                       "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", field-addr=%p",
-                       notit, event, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
-                       bt_event_class_get_id(notit->meta.event_class),
-                       notit->dscopes.stream_event_header);
-               goto error;
-       }
-
-       ret = bt_event_set_stream_event_context(event,
-               notit->dscopes.stream_event_context);
-       if (ret) {
-               BT_LOGE("Cannot set event's context field: "
-                       "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", field-addr=%p",
-                       notit, event, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
-                       bt_event_class_get_id(notit->meta.event_class),
-                       notit->dscopes.stream_event_context);
-               goto error;
-       }
-
-       ret = bt_event_set_context(event,
-               notit->dscopes.event_context);
-       if (ret) {
-               BT_LOGE("Cannot set event's stream event context field: "
-                       "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", field-addr=%p",
-                       notit, event, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
-                       bt_event_class_get_id(notit->meta.event_class),
-                       notit->dscopes.event_context);
-               goto error;
-       }
-
-       ret = bt_event_set_payload(event,
-               notit->dscopes.event_payload);
-       if (ret) {
-               BT_LOGE("Cannot set event's payload field: "
-                       "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", field-addr=%p",
-                       notit, event, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
-                       bt_event_class_get_id(notit->meta.event_class),
-                       notit->dscopes.event_payload);
-               goto error;
-       }
-
-       ret = set_event_clocks(event, notit);
-       if (ret) {
-               BT_LOGE("Cannot set event's clock values: "
-                       "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64,
-                       notit, event, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
-                       bt_event_class_get_id(notit->meta.event_class));
-               goto error;
-       }
-
-       /* Associate with current packet. */
-       BT_ASSERT(notit->packet);
-       ret = bt_event_set_packet(event, notit->packet);
-       if (ret) {
-               BT_LOGE("Cannot set event's header field: "
-                       "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", packet-addr=%p",
-                       notit, event, notit->meta.event_class,
-                       bt_event_class_get_name(notit->meta.event_class),
-                       bt_event_class_get_id(notit->meta.event_class),
-                       notit->packet);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_PUT(event);
-
-end:
-       return event;
-}
-
-static
-uint64_t get_cur_stream_instance_id(struct bt_notif_iter *notit)
-{
-       struct bt_field *stream_instance_id_field = NULL;
-       uint64_t stream_instance_id = -1ULL;
-       int ret;
-
-       if (!notit->dscopes.trace_packet_header) {
-               goto end;
-       }
-
-       stream_instance_id_field = bt_field_structure_get_field_by_name(
-               notit->dscopes.trace_packet_header, "stream_instance_id");
-       if (!stream_instance_id_field) {
-               goto end;
-       }
-
-       ret = bt_field_integer_unsigned_get_value(stream_instance_id_field,
-               &stream_instance_id);
-       if (ret) {
-               stream_instance_id = -1ULL;
-               goto end;
-       }
-
-end:
-       bt_put(stream_instance_id_field);
-       return stream_instance_id;
-}
-
-static
-int set_stream(struct bt_notif_iter *notit)
-{
-       int ret = 0;
-       struct bt_stream *stream = NULL;
-
-       BT_LOGV("Calling user function (get stream): notit-addr=%p, "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64,
-               notit, notit->meta.stream_class,
-               bt_stream_class_get_name(notit->meta.stream_class),
-               bt_stream_class_get_id(notit->meta.stream_class));
-       stream = bt_get(notit->medium.medops.get_stream(
-               notit->meta.stream_class, get_cur_stream_instance_id(notit),
-               notit->medium.data));
-       BT_LOGV("User function returned: stream-addr=%p", stream);
-       if (!stream) {
-               BT_LOGW_STR("User function failed to return a stream object for the given stream class.");
-               ret = -1;
-               goto end;
-       }
 
-       if (notit->stream && stream != notit->stream) {
-               BT_LOGW("User function returned a different stream than the previous one for the same sequence of packets.");
-               ret = -1;
-               goto end;
+               ret = bt_clock_value_set_value(clock_value, *clock_state);
+               BT_ASSERT(ret == 0);
        }
 
-       BT_MOVE(notit->stream, stream);
-
+       ret = 0;
 end:
-       bt_put(stream);
        return ret;
 }
 
-static
-void create_packet(struct bt_notif_iter *notit)
-{
-       int ret;
-       struct bt_packet *packet = NULL;
-
-       BT_LOGV("Creating packet for packet notification: "
-               "notit-addr=%p", notit);
-       BT_LOGV("Creating packet from stream: "
-               "notit-addr=%p, stream-addr=%p, "
-               "stream-class-addr=%p, "
-               "stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64,
-               notit, notit->stream, notit->meta.stream_class,
-               bt_stream_class_get_name(notit->meta.stream_class),
-               bt_stream_class_get_id(notit->meta.stream_class));
-
-       /* Create packet */
-       BT_ASSERT(notit->stream);
-       packet = bt_packet_create(notit->stream);
-       if (!packet) {
-               BT_LOGE("Cannot create packet from stream: "
-                       "notit-addr=%p, stream-addr=%p, "
-                       "stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64,
-                       notit, notit->stream, notit->meta.stream_class,
-                       bt_stream_class_get_name(notit->meta.stream_class),
-                       bt_stream_class_get_id(notit->meta.stream_class));
-               goto error;
-       }
-
-       /* Set packet's context and header fields */
-       if (notit->dscopes.trace_packet_header) {
-               ret = bt_packet_set_header(packet,
-                       notit->dscopes.trace_packet_header);
-               if (ret) {
-                       BT_LOGE("Cannot set packet's header field: "
-                               "notit-addr=%p, packet-addr=%p, "
-                               "stream-addr=%p, "
-                               "stream-class-addr=%p, "
-                               "stream-class-name=\"%s\", "
-                               "stream-class-id=%" PRId64 ", "
-                               "field-addr=%p",
-                               notit, packet, notit->stream, notit->meta.stream_class,
-                               bt_stream_class_get_name(notit->meta.stream_class),
-                               bt_stream_class_get_id(notit->meta.stream_class),
-                               notit->dscopes.trace_packet_header);
-                       goto error;
-               }
-       }
-
-       if (notit->dscopes.stream_packet_context) {
-               ret = bt_packet_set_context(packet,
-                       notit->dscopes.stream_packet_context);
-               if (ret) {
-                       BT_LOGE("Cannot set packet's context field: "
-                               "notit-addr=%p, packet-addr=%p, "
-                               "stream-addr=%p, "
-                               "stream-class-addr=%p, "
-                               "stream-class-name=\"%s\", "
-                               "stream-class-id=%" PRId64 ", "
-                               "field-addr=%p",
-                               notit, packet, notit->stream, notit->meta.stream_class,
-                               bt_stream_class_get_name(notit->meta.stream_class),
-                               bt_stream_class_get_id(notit->meta.stream_class),
-                               notit->dscopes.trace_packet_header);
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       BT_PUT(packet);
-
-end:
-       BT_MOVE(notit->packet, packet);
-}
-
 static
 void notify_new_stream(struct bt_notif_iter *notit,
                struct bt_notification **notification)
 {
+       enum bt_notif_iter_status status;
        struct bt_notification *ret = NULL;
-       int iret;
 
-       /* Ask the user for the stream */
-       iret = set_stream(notit);
-       if (iret) {
+       status = set_current_stream(notit);
+       if (status != BT_NOTIF_ITER_STATUS_OK) {
+               BT_PUT(ret);
                goto end;
        }
 
@@ -2888,82 +2797,85 @@ static
 void notify_new_packet(struct bt_notif_iter *notit,
                struct bt_notification **notification)
 {
-       struct bt_notification *ret;
+       int ret;
+       enum bt_notif_iter_status status;
+       struct bt_notification *notif = NULL;
 
-       /* Initialize the iterator's current packet */
-       create_packet(notit);
-       if (!notit->packet) {
-               BT_LOGE("Cannot create packet for packet notification: "
-                       "notit-addr=%p", notit);
-               return;
+       status = set_current_packet(notit);
+       if (status != BT_NOTIF_ITER_STATUS_OK) {
+               goto end;
        }
 
-       ret = bt_notification_packet_begin_create(notit->packet);
-       if (!ret) {
+       BT_ASSERT(notit->packet);
+
+       if (notit->packet_header_field) {
+               ret = bt_packet_move_header(notit->packet,
+                       notit->packet_header_field);
+               if (ret) {
+                       goto end;
+               }
+
+               notit->packet_header_field = NULL;
+
+               /*
+                * At this point notit->dscopes.trace_packet_header has
+                * the same value as the packet header field within
+                * notit->packet.
+                */
+               BT_ASSERT(bt_packet_borrow_header(notit->packet) ==
+                       notit->dscopes.trace_packet_header);
+       }
+
+       if (notit->packet_context_field) {
+               ret = bt_packet_move_context(notit->packet,
+                       notit->packet_context_field);
+               if (ret) {
+                       goto end;
+               }
+
+               notit->packet_context_field = NULL;
+
+               /*
+                * At this point notit->dscopes.trace_packet_header has
+                * the same value as the packet header field within
+                * notit->packet.
+                */
+               BT_ASSERT(bt_packet_borrow_context(notit->packet) ==
+                       notit->dscopes.stream_packet_context);
+       }
+
+       notif = bt_notification_packet_begin_create(notit->packet);
+       if (!notif) {
                BT_LOGE("Cannot create packet beginning notification: "
                        "notit-addr=%p, packet-addr=%p",
                        notit, notit->packet);
                return;
        }
-       *notification = ret;
+
+end:
+       *notification = notif;
 }
 
 static
 void notify_end_of_packet(struct bt_notif_iter *notit,
                struct bt_notification **notification)
 {
-       struct bt_notification *ret;
+       struct bt_notification *notif;
 
        if (!notit->packet) {
                return;
        }
 
-       ret = bt_notification_packet_end_create(notit->packet);
-       if (!ret) {
+       notif = bt_notification_packet_end_create(notit->packet);
+       if (!notif) {
                BT_LOGE("Cannot create packet end notification: "
                        "notit-addr=%p, packet-addr=%p",
                        notit, notit->packet);
                return;
        }
-       BT_PUT(notit->packet);
-       *notification = ret;
-}
-
-static
-void notify_event(struct bt_notif_iter *notit,
-               struct bt_clock_class_priority_map *cc_prio_map,
-               struct bt_notification **notification)
-{
-       struct bt_event *event = NULL;
-       struct bt_notification *ret = NULL;
 
-       /* Make sure that the event contains at least one bit of data */
-       if (notit->buf.at == notit->buf.last_eh_at) {
-               BT_LOGE("Cannot create empty event with 0 bits of data: "
-                       "notit-addr=%p, packet-cur=%zu",
-                       notit, packet_at(notit));
-               goto end;
-       }
-
-       /* Create event */
-       event = create_event(notit);
-       if (!event) {
-               BT_LOGE("Cannot create event for event notification: "
-                       "notit-addr=%p", notit);
-               goto end;
-       }
-
-       ret = bt_notification_event_create(event, cc_prio_map);
-       if (!ret) {
-               BT_LOGE("Cannot create event notification: "
-                       "notit-addr=%p, event-addr=%p, "
-                       "cc-prio-map-addr=%p",
-                       notit, event, cc_prio_map);
-               goto end;
-       }
-       *notification = ret;
-end:
-       BT_PUT(event);
+       BT_PUT(notit->packet);
+       *notification = notif;
 }
 
 static
@@ -3038,7 +2950,7 @@ struct bt_notif_iter *bt_notif_iter_create(struct bt_trace *trace,
 
        BT_ASSERT(trace);
        BT_ASSERT(medops.request_bytes);
-       BT_ASSERT(medops.get_stream);
+       BT_ASSERT(medops.borrow_stream);
        BT_LOGD("Creating CTF plugin notification iterator: "
                "trace-addr=%p, trace-name=\"%s\", max-request-size=%zu, "
                "data=%p",
@@ -3106,8 +3018,8 @@ void bt_notif_iter_destroy(struct bt_notif_iter *notit)
 {
        BT_PUT(notit->packet);
        BT_PUT(notit->stream);
-       BT_PUT(notit->cur_timestamp_end);
-       put_all_dscopes(notit);
+       BT_PUT(notit->meta.cc_prio_map);
+       release_all_dscopes(notit);
 
        BT_LOGD("Destroying CTF plugin notification iterator: addr=%p", notit);
 
@@ -3141,11 +3053,17 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                struct bt_clock_class_priority_map *cc_prio_map,
                struct bt_notification **notification)
 {
+       int ret;
        enum bt_notif_iter_status status = BT_NOTIF_ITER_STATUS_OK;
 
        BT_ASSERT(notit);
        BT_ASSERT(notification);
 
+       if (cc_prio_map != notit->meta.cc_prio_map) {
+               bt_put(notit->meta.cc_prio_map);
+               notit->meta.cc_prio_map = bt_get(cc_prio_map);
+       }
+
        if (notit->state == STATE_DONE) {
                status = BT_NOTIF_ITER_STATUS_EOF;
                goto end;
@@ -3160,6 +3078,7 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                        BT_LOGV_STR("Medium returned BT_NOTIF_ITER_STATUS_AGAIN.");
                        goto end;
                }
+
                if (status != BT_NOTIF_ITER_STATUS_OK) {
                        if (status == BT_NOTIF_ITER_STATUS_EOF) {
                                enum state next_state = notit->state;
@@ -3167,9 +3086,11 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                                BT_LOGV_STR("Medium returned BT_NOTIF_ITER_STATUS_EOF.");
 
                                if (notit->packet) {
-                                       notify_end_of_packet(notit, notification);
+                                       notify_end_of_packet(notit,
+                                               notification);
                                } else {
-                                       notify_end_of_stream(notit, notification);
+                                       notify_end_of_stream(notit,
+                                               notification);
                                        next_state = STATE_DONE;
                                }
 
@@ -3180,12 +3101,12 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
 
                                status = BT_NOTIF_ITER_STATUS_OK;
                                notit->state = next_state;
-                               goto end;
                        } else {
                                BT_LOGW("Cannot handle state: "
                                        "notit-addr=%p, state=%s",
                                        notit, state_string(notit->state));
                        }
+
                        goto end;
                }
 
@@ -3204,23 +3125,23 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                        if (!*notification) {
                                status = BT_NOTIF_ITER_STATUS_ERROR;
                        }
+
                        goto end;
                case STATE_EMIT_NOTIF_EVENT:
-                       /* notify_event() logs errors */
-                       notify_event(notit, cc_prio_map, notification);
-                       if (!*notification) {
+                       BT_ASSERT(notit->event_notif);
+                       ret = set_event_clocks(notit);
+                       if (ret) {
                                status = BT_NOTIF_ITER_STATUS_ERROR;
+                               goto end;
                        }
+
+                       BT_MOVE(*notification, notit->event_notif);
                        goto end;
                case STATE_EMIT_NOTIF_END_OF_PACKET:
                        /* Update clock with timestamp_end field. */
                        if (notit->cur_timestamp_end) {
                                enum bt_btr_status btr_status;
-                               struct bt_field_type *field_type =
-                                               bt_field_borrow_type(
-                                                       notit->cur_timestamp_end);
 
-                               BT_ASSERT(field_type);
                                btr_status = update_clock(notit,
                                        notit->cur_timestamp_end);
                                if (btr_status != BT_BTR_STATUS_OK) {
@@ -3236,6 +3157,7 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
                        if (!*notification) {
                                status = BT_NOTIF_ITER_STATUS_ERROR;
                        }
+
                        goto end;
                default:
                        /* Non-emitting state: continue */
@@ -3248,7 +3170,7 @@ end:
 }
 
 BT_HIDDEN
-enum bt_notif_iter_status bt_notif_iter_get_packet_header_context_fields(
+enum bt_notif_iter_status bt_notif_iter_borrow_packet_header_context_fields(
                struct bt_notif_iter *notit,
                struct bt_field **packet_header_field,
                struct bt_field **packet_context_field)
@@ -3309,19 +3231,20 @@ enum bt_notif_iter_status bt_notif_iter_get_packet_header_context_fields(
        }
 
 set_fields:
+       ret = set_current_packet_content_sizes(notit);
+       if (ret) {
+               status = BT_NOTIF_ITER_STATUS_ERROR;
+               goto end;
+       }
+
        if (packet_header_field) {
-               *packet_header_field = bt_get(notit->dscopes.trace_packet_header);
+               *packet_header_field = notit->dscopes.trace_packet_header;
        }
 
        if (packet_context_field) {
-               *packet_context_field = bt_get(notit->dscopes.stream_packet_context);
+               *packet_context_field = notit->dscopes.stream_packet_context;
        }
 
-       ret = set_current_packet_content_sizes(notit);
-       if (ret) {
-               status = BT_NOTIF_ITER_STATUS_ERROR;
-               goto end;
-       }
 end:
        return status;
 }
index 640bcf94855bab67c9fccd2f1084261433c3f618..baaa9cd67e7854103f8fddd50bcf92262607633d 100644 (file)
@@ -226,7 +226,7 @@ struct bt_notif_iter_medium_ops {
         * @returns             Stream instance (weak reference) or
         *                      \c NULL on error
         */
-       struct bt_stream * (* get_stream)(
+       struct bt_stream * (* borrow_stream)(
                        struct bt_stream_class *stream_class,
                        uint64_t stream_id, void *data);
 };
@@ -318,7 +318,7 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
 
 /**
  * Returns the first packet header and context fields. This function
- * never needs to call the `get_stream()` medium operation because
+ * never needs to call the `borrow_stream()` medium operation because
  * it does not create packet or event objects.
  *
  * @param notif_iter           CTF notification iterator
@@ -329,7 +329,7 @@ enum bt_notif_iter_status bt_notif_iter_get_next_notification(
  * @returns                    One of #bt_notif_iter_status values
  */
 BT_HIDDEN
-enum bt_notif_iter_status bt_notif_iter_get_packet_header_context_fields(
+enum bt_notif_iter_status bt_notif_iter_borrow_packet_header_context_fields(
                struct bt_notif_iter *notit,
                struct bt_field **packet_header_field,
                struct bt_field **packet_context_field);
index db266af151dc75f2097f7e6f6c2f3694344d5868..2b97ca3a2c556b8c1f4e611fa997ac8f1b9a2d53 100644 (file)
@@ -173,7 +173,7 @@ end:
 }
 
 static
-struct bt_stream *medop_get_stream(
+struct bt_stream *medop_borrow_stream(
                struct bt_stream_class *stream_class, uint64_t stream_id,
                void *data)
 {
@@ -252,7 +252,7 @@ end:
 BT_HIDDEN
 struct bt_notif_iter_medium_ops ctf_fs_ds_file_medops = {
        .request_bytes = medop_request_bytes,
-       .get_stream = medop_get_stream,
+       .borrow_stream = medop_borrow_stream,
        .seek = medop_seek,
 };
 
@@ -374,11 +374,11 @@ int borrow_ds_file_packet_bounds_clock_classes(struct ctf_fs_ds_file *ds_file,
                struct bt_clock_class **timestamp_end_cc)
 {
        struct bt_field *packet_context = NULL;
-       int ret = ctf_fs_ds_file_get_packet_header_context_fields(ds_file,
-                       NULL, &packet_context);
+       int ret = ctf_fs_ds_file_borrow_packet_header_context_fields(ds_file,
+               NULL, &packet_context);
 
        if (ret || !packet_context) {
-               BT_LOGD("Cannot retrieve packet context field of stream \'%s\'",
+               BT_LOGD("Cannot retrieve packet context field: ds-file-path=\"%s\"",
                        ds_file->file->path->str);
                ret = -1;
                goto end;
@@ -389,7 +389,6 @@ int borrow_ds_file_packet_bounds_clock_classes(struct ctf_fs_ds_file *ds_file,
                        timestamp_end_cc, NULL);
 
 end:
-       bt_put(packet_context);
        return ret;
 }
 
@@ -397,23 +396,7 @@ static
 int convert_cycles_to_ns(struct bt_clock_class *clock_class,
                uint64_t cycles, int64_t *ns)
 {
-       int ret = 0;
-       struct bt_clock_value *clock_value;
-
-       BT_ASSERT(ns);
-       clock_value = bt_clock_value_create(clock_class, cycles);
-       if (!clock_value) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_clock_value_get_value_ns_from_epoch(clock_value, ns);
-       if (ret) {
-               goto end;
-       }
-end:
-       bt_put(clock_value);
-       return ret;
+       return bt_clock_class_cycles_to_ns(clock_class, cycles, ns);
 }
 
 static
@@ -661,7 +644,6 @@ struct ctf_fs_ds_index *build_index_from_stream_file(
        int ret;
        struct ctf_fs_ds_index *index = NULL;
        enum bt_notif_iter_status iter_status;
-       struct bt_field *packet_context = NULL;
 
        BT_LOGD("Indexing stream file %s", ds_file->file->path->str);
 
@@ -675,17 +657,19 @@ struct ctf_fs_ds_index *build_index_from_stream_file(
                off_t next_packet_offset;
                off_t current_packet_size, current_packet_size_bytes;
                struct ctf_fs_ds_index_entry *entry;
+               struct bt_field *packet_context = NULL;
 
-               iter_status = bt_notif_iter_get_packet_header_context_fields(
-                               ds_file->notif_iter, NULL, &packet_context);
+               iter_status = bt_notif_iter_borrow_packet_header_context_fields(
+                       ds_file->notif_iter, NULL, &packet_context);
                if (iter_status != BT_NOTIF_ITER_STATUS_OK) {
                        if (iter_status == BT_NOTIF_ITER_STATUS_EOF) {
                                break;
                        }
                        goto error;
                }
+
                current_packet_offset =
-                               bt_notif_iter_get_current_packet_offset(
+                       bt_notif_iter_get_current_packet_offset(
                                ds_file->notif_iter);
                if (current_packet_offset < 0) {
                        BT_LOGE_STR("Cannot get the current packet's offset.");
@@ -693,14 +677,14 @@ struct ctf_fs_ds_index *build_index_from_stream_file(
                }
 
                current_packet_size = bt_notif_iter_get_current_packet_size(
-                               ds_file->notif_iter);
+                       ds_file->notif_iter);
                if (current_packet_size < 0) {
                        BT_LOGE("Cannot get packet size: packet-offset=%jd",
                                        current_packet_offset);
                        goto error;
                }
                current_packet_size_bytes =
-                               ((current_packet_size + 7) & ~7) / CHAR_BIT;
+                       ((current_packet_size + 7) & ~7) / CHAR_BIT;
 
                if (current_packet_offset + current_packet_size_bytes >
                                ds_file->file->size) {
@@ -715,10 +699,10 @@ struct ctf_fs_ds_index *build_index_from_stream_file(
                }
 
                next_packet_offset = current_packet_offset +
-                               current_packet_size_bytes;
+                       current_packet_size_bytes;
                BT_LOGD("Seeking to next packet: current-packet-offset=%jd, "
-                               "next-packet-offset=%jd", current_packet_offset,
-                               next_packet_offset);
+                       "next-packet-offset=%jd", current_packet_offset,
+                       next_packet_offset);
 
                entry = ctf_fs_ds_index_add_new_entry(index);
                if (!entry) {
@@ -727,23 +711,23 @@ struct ctf_fs_ds_index *build_index_from_stream_file(
                }
 
                ret = init_index_entry(entry, packet_context,
-                               current_packet_size_bytes,
-                               current_packet_offset);
+                       current_packet_size_bytes,
+                       current_packet_offset);
                if (ret) {
                        goto error;
                }
 
                iter_status = bt_notif_iter_seek(ds_file->notif_iter,
                                next_packet_offset);
-               BT_PUT(packet_context);
        } while (iter_status == BT_NOTIF_ITER_STATUS_OK);
 
        if (iter_status != BT_NOTIF_ITER_STATUS_EOF) {
                goto error;
        }
+
 end:
-       bt_put(packet_context);
        return index;
+
 error:
        ctf_fs_ds_index_destroy(index);
        index = NULL;
@@ -870,7 +854,7 @@ struct bt_notification_iterator_next_method_return ctf_fs_ds_file_next(
 }
 
 BT_HIDDEN
-int ctf_fs_ds_file_get_packet_header_context_fields(
+int ctf_fs_ds_file_borrow_packet_header_context_fields(
                struct ctf_fs_ds_file *ds_file,
                struct bt_field **packet_header_field,
                struct bt_field **packet_context_field)
@@ -879,7 +863,7 @@ int ctf_fs_ds_file_get_packet_header_context_fields(
        int ret = 0;
 
        BT_ASSERT(ds_file);
-       notif_iter_status = bt_notif_iter_get_packet_header_context_fields(
+       notif_iter_status = bt_notif_iter_borrow_packet_header_context_fields(
                ds_file->notif_iter, packet_header_field, packet_context_field);
        switch (notif_iter_status) {
        case BT_NOTIF_ITER_STATUS_EOF:
@@ -899,14 +883,6 @@ int ctf_fs_ds_file_get_packet_header_context_fields(
 error:
        ret = -1;
 
-       if (packet_header_field) {
-               bt_put(*packet_header_field);
-       }
-
-       if (packet_context_field) {
-               bt_put(*packet_context_field);
-       }
-
 end:
        return ret;
 }
index 093f360bc8892694d1f0f51a5be305a7e7e2561f..e1620b9f601c4fddba5cc1f7184397782f1dc45a 100644 (file)
@@ -127,7 +127,7 @@ struct ctf_fs_ds_file *ctf_fs_ds_file_create(
                struct bt_stream *stream, const char *path);
 
 BT_HIDDEN
-int ctf_fs_ds_file_get_packet_header_context_fields(
+int ctf_fs_ds_file_borrow_packet_header_context_fields(
                struct ctf_fs_ds_file *ds_file,
                struct bt_field **packet_header_field,
                struct bt_field **packet_context_field);
index 523f6c34e8e73d01331973ff918c366378f429d7..07b4c049fc28bbd0ca155f6ab239a1921197f965 100644 (file)
@@ -439,7 +439,6 @@ uint64_t get_packet_header_stream_instance_id(struct ctf_fs_trace *ctf_fs_trace,
        }
 
 end:
-       bt_put(stream_instance_id_field);
        return stream_instance_id;
 }
 
@@ -454,7 +453,6 @@ uint64_t get_packet_context_timestamp_begin_ns(
        uint64_t timestamp_begin_ns = -1ULL;
        int64_t timestamp_begin_ns_signed;
        struct bt_clock_class *timestamp_begin_clock_class = NULL;
-       struct bt_clock_value *clock_value = NULL;
 
        if (!packet_context_field) {
                goto end;
@@ -480,14 +478,8 @@ uint64_t get_packet_context_timestamp_begin_ns(
                goto end;
        }
 
-       clock_value = bt_clock_value_create(timestamp_begin_clock_class,
-               timestamp_begin_raw_value);
-       if (!clock_value) {
-               goto end;
-       }
-
-       ret = bt_clock_value_get_value_ns_from_epoch(clock_value,
-               &timestamp_begin_ns_signed);
+       ret = bt_clock_class_cycles_to_ns(timestamp_begin_clock_class,
+               timestamp_begin_raw_value, &timestamp_begin_ns_signed);
        if (ret) {
                goto end;
        }
@@ -495,7 +487,6 @@ uint64_t get_packet_context_timestamp_begin_ns(
        timestamp_begin_ns = (uint64_t) timestamp_begin_ns_signed;
 
 end:
-       bt_put(clock_value);
        return timestamp_begin_ns;
 }
 
@@ -678,7 +669,7 @@ int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace,
                goto error;
        }
 
-       ret = ctf_fs_ds_file_get_packet_header_context_fields(ds_file,
+       ret = ctf_fs_ds_file_borrow_packet_header_context_fields(ds_file,
                &packet_header_field, &packet_context_field);
        if (ret) {
                BT_LOGE("Cannot get stream file's first packet's header and context fields (`%s`).",
@@ -789,8 +780,6 @@ end:
        }
 
        ctf_fs_ds_index_destroy(index);
-       bt_put(packet_header_field);
-       bt_put(packet_context_field);
        return ret;
 }
 
index 36047924c63638c72fd445c9c876c29e67775777..f7bfff8e900da02b176db1fe85d4207e97f2bf36 100644 (file)
@@ -1,7 +1,6 @@
 AM_CPPFLAGS += -I$(top_srcdir)/plugins
 
-SUBDIRS = pretty .
-# dmesg
+SUBDIRS = pretty dmesg
 
 plugindir = "$(PLUGINSDIR)"
 plugin_LTLIBRARIES = babeltrace-plugin-text.la
@@ -12,9 +11,8 @@ babeltrace_plugin_text_la_LDFLAGS = \
        -avoid-version -module
 
 babeltrace_plugin_text_la_LIBADD = \
-       pretty/libbabeltrace-plugin-text-pretty-cc.la
-
-#      dmesg/libbabeltrace-plugin-text-dmesg-cc.la
+       pretty/libbabeltrace-plugin-text-pretty-cc.la \
+       dmesg/libbabeltrace-plugin-text-dmesg-cc.la
 
 if !ENABLE_BUILT_IN_PLUGINS
 babeltrace_plugin_text_la_LIBADD += \
index 51fa20f8110bb0b7af1dccc1806160ef9a353b25..7d208ed35b50eb23616a0b440388ab3082b6c546 100644 (file)
@@ -47,6 +47,16 @@ struct dmesg_notif_iter {
        char *linebuf;
        size_t linebuf_len;
        FILE *fp;
+       struct bt_notification *tmp_event_notif;
+
+       enum {
+               STATE_EMIT_STREAM_BEGINNING,
+               STATE_EMIT_PACKET_BEGINNING,
+               STATE_EMIT_EVENT,
+               STATE_EMIT_PACKET_END,
+               STATE_EMIT_STREAM_END,
+               STATE_DONE,
+       } state;
 };
 
 struct dmesg_component {
@@ -108,58 +118,6 @@ end:
        return root_ft;
 }
 
-static
-struct bt_field_type *create_packet_context_ft(void)
-{
-       struct bt_field_type *root_ft = NULL;
-       struct bt_field_type *ft = NULL;
-       int ret;
-
-       root_ft = bt_field_type_structure_create();
-       if (!root_ft) {
-               BT_LOGE_STR("Cannot create an empty structure field type object.");
-               goto error;
-       }
-
-       ft = bt_field_type_integer_create(64);
-       if (!ft) {
-               BT_LOGE_STR("Cannot create an integer field type object.");
-               goto error;
-       }
-
-       ret = bt_field_type_structure_add_field(root_ft,
-               ft, "content_size");
-       if (ret) {
-               BT_LOGE("Cannot add `content_size` field type to structure field type: "
-                       "ret=%d", ret);
-               goto error;
-       }
-
-       BT_PUT(ft);
-       ft = bt_field_type_integer_create(64);
-       if (!ft) {
-               BT_LOGE_STR("Cannot create an integer field type object.");
-               goto error;
-       }
-
-       ret = bt_field_type_structure_add_field(root_ft,
-               ft, "packet_size");
-       if (ret) {
-               BT_LOGE("Cannot add `packet_size` field type to structure field type: "
-                       "ret=%d", ret);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_PUT(root_ft);
-
-end:
-       bt_put(ft);
-       return root_ft;
-}
-
 static
 struct bt_field_type *create_event_header_ft(
                struct bt_clock_class *clock_class)
@@ -268,7 +226,7 @@ int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
                goto error;
        }
 
-       ret = bt_trace_set_packet_header_type(dmesg_comp->trace, ft);
+       ret = bt_trace_set_packet_header_field_type(dmesg_comp->trace, ft);
        if (ret) {
                BT_LOGE_STR("Cannot set trace's packet header field type.");
                goto error;
@@ -294,26 +252,12 @@ int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
                }
        }
 
-       dmesg_comp->stream_class = bt_stream_class_create_empty(NULL);
+       dmesg_comp->stream_class = bt_stream_class_create(NULL);
        if (!dmesg_comp->stream_class) {
                BT_LOGE_STR("Cannot create an empty stream class object.");
                goto error;
        }
 
-       bt_put(ft);
-       ft = create_packet_context_ft();
-       if (!ft) {
-               BT_LOGE_STR("Cannot create packet context field type.");
-               goto error;
-       }
-
-       ret = bt_stream_class_set_packet_context_type(
-               dmesg_comp->stream_class, ft);
-       if (ret) {
-               BT_LOGE_STR("Cannot set stream class's packet context field type.");
-               goto error;
-       }
-
        dmesg_comp->cc_prio_map = bt_clock_class_priority_map_create();
        if (!dmesg_comp->cc_prio_map) {
                BT_LOGE_STR("Cannot create empty clock class priority map.");
@@ -348,7 +292,7 @@ int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
                        goto error;
                }
 
-               ret = bt_stream_class_set_event_header_type(
+               ret = bt_stream_class_set_event_header_field_type(
                        dmesg_comp->stream_class, ft);
                if (ret) {
                        BT_LOGE_STR("Cannot set stream class's event header field type.");
@@ -369,7 +313,7 @@ int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
                goto error;
        }
 
-       ret = bt_event_class_set_payload_type(dmesg_comp->event_class, ft);
+       ret = bt_event_class_set_payload_field_type(dmesg_comp->event_class, ft);
        if (ret) {
                BT_LOGE_STR("Cannot set event class's event payload field type.");
                goto error;
@@ -463,97 +407,38 @@ end:
 }
 
 static
-struct bt_field *create_packet_header_field(struct bt_field_type *ft)
+int fill_packet_header_field(struct bt_packet *packet)
 {
        struct bt_field *ph = NULL;
        struct bt_field *magic = NULL;
        int ret;
 
-       ph = bt_field_create(ft);
-       if (!ph) {
-               BT_LOGE_STR("Cannot create field object.");
-               goto error;
-       }
-
-       magic = bt_field_structure_get_field_by_name(ph, "magic");
+       ph = bt_packet_borrow_header(packet);
+       BT_ASSERT(ph);
+       magic = bt_field_structure_borrow_field_by_name(ph, "magic");
        if (!magic) {
-               BT_LOGE_STR("Cannot get `magic` field from structure field.");
-               goto error;
-       }
-
-       ret = bt_field_unsigned_integer_set_value(magic, 0xc1fc1fc1);
-       if (ret) {
-               BT_LOGE_STR("Cannot set integer field's value.");
+               BT_LOGE_STR("Cannot borrow `magic` field from structure field.");
                goto error;
        }
 
+       ret = bt_field_integer_unsigned_set_value(magic, 0xc1fc1fc1);
+       BT_ASSERT(ret == 0);
        goto end;
 
 error:
-       BT_PUT(ph);
-
-end:
-       bt_put(magic);
-       return ph;
-}
-
-static
-struct bt_field *create_packet_context_field(struct bt_field_type *ft)
-{
-       struct bt_field *pc = NULL;
-       struct bt_field *field = NULL;
-       int ret;
-
-       pc = bt_field_create(ft);
-       if (!pc) {
-               BT_LOGE_STR("Cannot create field object.");
-               goto error;
-       }
-
-       field = bt_field_structure_get_field_by_name(pc, "content_size");
-       if (!field) {
-               BT_LOGE_STR("Cannot get `content_size` field from structure field.");
-               goto error;
-       }
-
-       ret = bt_field_unsigned_integer_set_value(field, 0);
-       if (ret) {
-               BT_LOGE_STR("Cannot set integer field's value.");
-               goto error;
-       }
-
-       bt_put(field);
-       field = bt_field_structure_get_field_by_name(pc, "packet_size");
-       if (!field) {
-               BT_LOGE_STR("Cannot get `packet_size` field from structure field.");
-               goto error;
-       }
-
-       ret = bt_field_unsigned_integer_set_value(field, 0);
-       if (ret) {
-               BT_LOGE_STR("Cannot set integer field's value.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_PUT(pc);
+       ret = -1;
 
 end:
-       bt_put(field);
-       return pc;
+       return ret;
 }
 
 static
 int create_packet_and_stream(struct dmesg_component *dmesg_comp)
 {
        int ret = 0;
-       struct bt_field_type *ft = NULL;
-       struct bt_field *field = NULL;
 
        dmesg_comp->stream = bt_stream_create(dmesg_comp->stream_class,
-               NULL);
+               NULL, 0);
        if (!dmesg_comp->stream) {
                BT_LOGE_STR("Cannot create stream object.");
                goto error;
@@ -565,34 +450,9 @@ int create_packet_and_stream(struct dmesg_component *dmesg_comp)
                goto error;
        }
 
-       ft = bt_trace_get_packet_header_type(dmesg_comp->trace);
-       BT_ASSERT(ft);
-       field = create_packet_header_field(ft);
-       if (!field) {
-               BT_LOGE_STR("Cannot create packet header field.");
-               goto error;
-       }
-
-       ret = bt_packet_set_header(dmesg_comp->packet, field);
-       if (ret) {
-               BT_LOGE_STR("Cannot set packet's header field.");
-               goto error;
-       }
-
-       bt_put(ft);
-       bt_put(field);
-       ft = bt_stream_class_get_packet_context_type(
-               dmesg_comp->stream_class);
-       BT_ASSERT(ft);
-       field = create_packet_context_field(ft);
-       if (!field) {
-               BT_LOGE_STR("Cannot create packet context field.");
-               goto error;
-       }
-
-       ret = bt_packet_set_context(dmesg_comp->packet, field);
+       ret = fill_packet_header_field(dmesg_comp->packet);
        if (ret) {
-               BT_LOGE_STR("Cannot set packet's context field.");
+               BT_LOGE_STR("Cannot fill packet header field.");
                goto error;
        }
 
@@ -608,8 +468,6 @@ error:
        ret = -1;
 
 end:
-       bt_put(field);
-       bt_put(ft);
        return ret;
 }
 
@@ -738,24 +596,20 @@ void dmesg_finalize(struct bt_private_component *priv_comp)
 }
 
 static
-int create_event_header_from_line(
+struct bt_notification *create_init_event_notif_from_line(
                struct dmesg_component *dmesg_comp,
-               const char *line, const char **new_start,
-               struct bt_field **user_field,
-               struct bt_clock_value **user_clock_value)
+               const char *line, const char **new_start)
 {
+       struct bt_event *event;
+       struct bt_notification *notif = NULL;
        bool has_timestamp = false;
        unsigned long sec, usec, msec;
        unsigned int year, mon, mday, hour, min;
        uint64_t ts = 0;
-       struct bt_clock_value *clock_value = NULL;
-       struct bt_field_type *ft = NULL;
        struct bt_field *eh_field = NULL;
        struct bt_field *ts_field = NULL;
        int ret = 0;
 
-       BT_ASSERT(user_clock_value);
-       BT_ASSERT(user_field);
        *new_start = line;
 
        if (dmesg_comp->params.no_timestamp) {
@@ -818,78 +672,58 @@ skip_ts:
                goto error;
        }
 
-       if (dmesg_comp->clock_class) {
-               clock_value = bt_clock_value_create(dmesg_comp->clock_class,
-                       ts);
-               if (!clock_value) {
-                       BT_LOGE_STR("Cannot create clock value object.");
-                       goto error;
-               }
+       notif = bt_notification_event_create(dmesg_comp->event_class,
+               dmesg_comp->packet, dmesg_comp->cc_prio_map);
+       if (!notif) {
+               BT_LOGE_STR("Cannot create event notification.");
+               goto error;
+       }
 
-               ft = bt_stream_class_get_event_header_type(
-                       dmesg_comp->stream_class);
-               BT_ASSERT(ft);
-               eh_field = bt_field_create(ft);
-               if (!eh_field) {
-                       BT_LOGE_STR("Cannot create event header field object.");
-                       goto error;
-               }
+       event = bt_notification_event_borrow_event(notif);
+       BT_ASSERT(event);
 
-               ts_field = bt_field_structure_get_field_by_name(eh_field,
+       if (dmesg_comp->clock_class) {
+               struct bt_clock_value *cv = bt_event_borrow_clock_value(event,
+                       dmesg_comp->clock_class);
+
+               ret = bt_clock_value_set_value(cv, ts);
+               BT_ASSERT(ret == 0);
+               eh_field = bt_event_borrow_header(event);
+               BT_ASSERT(eh_field);
+               ts_field = bt_field_structure_borrow_field_by_name(eh_field,
                        "timestamp");
                if (!ts_field) {
-                       BT_LOGE_STR("Cannot get `timestamp` field from structure field.");
-                       goto error;
-               }
-
-               ret = bt_field_unsigned_integer_set_value(ts_field, ts);
-               if (ret) {
-                       BT_LOGE_STR("Cannot set integer field's value.");
+                       BT_LOGE_STR("Cannot borrow `timestamp` field from event header structure field.");
                        goto error;
                }
 
-               *user_clock_value = clock_value;
-               clock_value = NULL;
-               *user_field = eh_field;
-               eh_field = NULL;
+               ret = bt_field_integer_unsigned_set_value(ts_field, ts);
+               BT_ASSERT(ret == 0);
        }
 
        goto end;
 
 error:
-       ret = -1;
+       BT_PUT(notif);
 
 end:
-       bt_put(ft);
-       bt_put(ts_field);
-       bt_put(clock_value);
-       bt_put(eh_field);
-       return ret;
+       return notif;
 }
 
 static
-int create_event_payload_from_line(
-               struct dmesg_component *dmesg_comp,
-               const char *line, struct bt_field **user_field)
+int fill_event_payload_from_line(struct dmesg_component *dmesg_comp,
+               const char *line, struct bt_event *event)
 {
-       struct bt_field_type *ft = NULL;
        struct bt_field *ep_field = NULL;
        struct bt_field *str_field = NULL;
        size_t len;
        int ret;
 
-       BT_ASSERT(user_field);
-       ft = bt_event_class_get_payload_type(dmesg_comp->event_class);
-       BT_ASSERT(ft);
-       ep_field = bt_field_create(ft);
-       if (!ep_field) {
-               BT_LOGE_STR("Cannot create event payload field object.");
-               goto error;
-       }
-
-       str_field = bt_field_structure_get_field_by_name(ep_field, "str");
+       ep_field = bt_event_borrow_payload(event);
+       BT_ASSERT(ep_field);
+       str_field = bt_field_structure_borrow_field_by_name(ep_field, "str");
        if (!str_field) {
-               BT_LOGE_STR("Cannot get `timestamp` field from structure field.");
+               BT_LOGE_STR("Cannot borrow `timestamp` field from event payload structure field.");
                goto error;
        }
 
@@ -899,6 +733,12 @@ int create_event_payload_from_line(
                len--;
        }
 
+       ret = bt_field_string_clear(str_field);
+       if (ret) {
+               BT_LOGE_STR("Cannot clear string field object.");
+               goto error;
+       }
+
        ret = bt_field_string_append_len(str_field, line, len);
        if (ret) {
                BT_LOGE("Cannot append value to string field object: "
@@ -906,17 +746,12 @@ int create_event_payload_from_line(
                goto error;
        }
 
-       *user_field = ep_field;
-       ep_field = NULL;
        goto end;
 
 error:
        ret = -1;
 
 end:
-       bt_put(ft);
-       bt_put(ep_field);
-       bt_put(str_field);
        return ret;
 }
 
@@ -924,81 +759,33 @@ static
 struct bt_notification *create_notif_from_line(
                struct dmesg_component *dmesg_comp, const char *line)
 {
-       struct bt_field *eh_field = NULL;
-       struct bt_field *ep_field = NULL;
-       struct bt_clock_value *clock_value = NULL;
        struct bt_event *event = NULL;
        struct bt_notification *notif = NULL;
        const char *new_start;
        int ret;
 
-       ret = create_event_header_from_line(dmesg_comp, line, &new_start,
-               &eh_field, &clock_value);
-       if (ret) {
-               BT_LOGE("Cannot create event header field from line: "
-                       "ret=%d", ret);
+       notif = create_init_event_notif_from_line(dmesg_comp, line, &new_start);
+       if (!notif) {
+               BT_LOGE_STR("Cannot create and initialize event notification from line.");
                goto error;
        }
 
-       ret = create_event_payload_from_line(dmesg_comp, new_start,
-               &ep_field);
+       event = bt_notification_event_borrow_event(notif);
+       BT_ASSERT(event);
+       ret = fill_event_payload_from_line(dmesg_comp, new_start,
+               event);
        if (ret) {
-               BT_LOGE("Cannot create event payload field from line: "
+               BT_LOGE("Cannot fill event payload field from line: "
                        "ret=%d", ret);
                goto error;
        }
 
-       BT_ASSERT(ep_field);
-       event = bt_event_create(dmesg_comp->event_class);
-       if (!event) {
-               BT_LOGE_STR("Cannot create event object.");
-               goto error;
-       }
-
-       ret = bt_event_set_packet(event, dmesg_comp->packet);
-       if (ret) {
-               BT_LOGE_STR("Cannot set event's packet.");
-               goto error;
-       }
-
-       if (eh_field) {
-               ret = bt_event_set_header(event, eh_field);
-               if (ret) {
-                       BT_LOGE_STR("Cannot set event's header field.");
-                       goto error;
-               }
-       }
-
-       ret = bt_event_set_event_payload(event, ep_field);
-       if (ret) {
-               BT_LOGE_STR("Cannot set event's payload field.");
-               goto error;
-       }
-
-       if (clock_value) {
-               ret = bt_event_set_clock_value(event, clock_value);
-               if (ret) {
-                       BT_LOGE_STR("Cannot set event's clock value.");
-                       goto error;
-               }
-       }
-
-       notif = bt_notification_event_create(event, dmesg_comp->cc_prio_map);
-       if (!notif) {
-               BT_LOGE_STR("Cannot create event notification.");
-               goto error;
-       }
-
        goto end;
 
 error:
        BT_PUT(notif);
 
 end:
-       bt_put(eh_field);
-       bt_put(ep_field);
-       bt_put(clock_value);
-       bt_put(event);
        return notif;
 }
 
@@ -1015,6 +802,7 @@ void destroy_dmesg_notif_iter(struct dmesg_notif_iter *dmesg_notif_iter)
                }
        }
 
+       bt_put(dmesg_notif_iter->tmp_event_notif);
        free(dmesg_notif_iter->linebuf);
        g_free(dmesg_notif_iter);
 }
@@ -1097,6 +885,17 @@ struct bt_notification_iterator_next_method_return dmesg_notif_iter_next(
        dmesg_comp = dmesg_notif_iter->dmesg_comp;
        BT_ASSERT(dmesg_comp);
 
+       if (dmesg_notif_iter->state == STATE_DONE) {
+               next_ret.status = BT_NOTIFICATION_ITERATOR_STATUS_END;
+               goto end;
+       }
+
+       if (dmesg_notif_iter->tmp_event_notif ||
+                       dmesg_notif_iter->state == STATE_EMIT_PACKET_END ||
+                       dmesg_notif_iter->state == STATE_EMIT_STREAM_END) {
+               goto handle_state;
+       }
+
        while (true) {
                const char *ch;
                bool only_spaces = true;
@@ -1111,8 +910,17 @@ struct bt_notification_iterator_next_method_return dmesg_notif_iter_next(
                                next_ret.status =
                                        BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
                        } else {
-                               next_ret.status =
-                                       BT_NOTIFICATION_ITERATOR_STATUS_END;
+                               if (dmesg_notif_iter->state == STATE_EMIT_STREAM_BEGINNING) {
+                                       /* Stream did not even begin */
+                                       next_ret.status =
+                                               BT_NOTIFICATION_ITERATOR_STATUS_END;
+                                       goto end;
+                               } else {
+                                       /* End current packet now */
+                                       dmesg_notif_iter->state =
+                                               STATE_EMIT_PACKET_END;
+                                       goto handle_state;
+                               }
                        }
 
                        goto end;
@@ -1133,12 +941,54 @@ struct bt_notification_iterator_next_method_return dmesg_notif_iter_next(
                }
        }
 
-       next_ret.notification = create_notif_from_line(dmesg_comp,
+       dmesg_notif_iter->tmp_event_notif = create_notif_from_line(dmesg_comp,
                dmesg_notif_iter->linebuf);
-       if (!next_ret.notification) {
+       if (!dmesg_notif_iter->tmp_event_notif) {
                BT_LOGE("Cannot create event notification from line: "
                        "dmesg-comp-addr=%p, line=\"%s\"", dmesg_comp,
                        dmesg_notif_iter->linebuf);
+               goto end;
+       }
+
+handle_state:
+       BT_ASSERT(dmesg_comp->trace);
+
+       switch (dmesg_notif_iter->state) {
+       case STATE_EMIT_STREAM_BEGINNING:
+               BT_ASSERT(dmesg_notif_iter->tmp_event_notif);
+               next_ret.notification = bt_notification_stream_begin_create(
+                       dmesg_comp->stream);
+               dmesg_notif_iter->state = STATE_EMIT_PACKET_BEGINNING;
+               break;
+       case STATE_EMIT_PACKET_BEGINNING:
+               BT_ASSERT(dmesg_notif_iter->tmp_event_notif);
+               next_ret.notification = bt_notification_packet_begin_create(
+                       dmesg_comp->packet);
+               dmesg_notif_iter->state = STATE_EMIT_EVENT;
+               break;
+       case STATE_EMIT_EVENT:
+               BT_ASSERT(dmesg_notif_iter->tmp_event_notif);
+               BT_MOVE(next_ret.notification,
+                       dmesg_notif_iter->tmp_event_notif);
+               break;
+       case STATE_EMIT_PACKET_END:
+               next_ret.notification = bt_notification_packet_end_create(
+                       dmesg_comp->packet);
+               dmesg_notif_iter->state = STATE_EMIT_STREAM_END;
+               break;
+       case STATE_EMIT_STREAM_END:
+               next_ret.notification = bt_notification_stream_end_create(
+                       dmesg_comp->stream);
+               dmesg_notif_iter->state = STATE_DONE;
+               break;
+       default:
+               break;
+       }
+
+       if (!next_ret.notification) {
+               BT_LOGE("Cannot create notification: dmesg-comp-addr=%p",
+                       dmesg_comp);
+               next_ret.status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
        }
 
 end:
index 2188f95644d891d2145445311a53e088387dbc25..58a7f8f75f46172a154fbd77fd45dad478e122ae 100644 (file)
@@ -42,7 +42,6 @@ BT_PLUGIN_SINK_COMPONENT_CLASS_PORT_CONNECTED_METHOD(pretty,
 BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(pretty,
        "Pretty-print notifications (`text` format of Babeltrace 1).");
 
-#if 0
 /* dmesg source */
 BT_PLUGIN_SOURCE_COMPONENT_CLASS(dmesg, dmesg_notif_iter_next);
 BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION(dmesg,
@@ -53,4 +52,3 @@ BT_PLUGIN_SOURCE_COMPONENT_CLASS_NOTIFICATION_ITERATOR_INIT_METHOD(dmesg,
        dmesg_notif_iter_init);
 BT_PLUGIN_SOURCE_COMPONENT_CLASS_NOTIFICATION_ITERATOR_FINALIZE_METHOD(dmesg,
        dmesg_notif_iter_finalize);
-#endif
index c6369aa35f455ef894e761f6c31fb174b300453c..a9e6104d667ff84437fafbab9ec310da1a7b6d97 100644 (file)
@@ -570,35 +570,51 @@ enum bt_component_status print_integer(struct pretty_component *pretty,
        enum bt_integer_base base;
        enum bt_string_encoding encoding;
        int signedness;
+       struct bt_field_type *int_ft;
        union {
                uint64_t u;
                int64_t s;
        } v;
        bool rst_color = false;
+       enum bt_field_type_id ft_id;
 
        field_type = bt_field_borrow_type(field);
        if (!field_type) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       signedness = bt_field_type_integer_is_signed(field_type);
+
+       ft_id = bt_field_get_type_id(field);
+
+       switch (ft_id) {
+       case BT_FIELD_TYPE_ID_INTEGER:
+               int_ft = field_type;
+               break;
+       case BT_FIELD_TYPE_ID_ENUM:
+               int_ft = bt_field_type_enumeration_borrow_container_field_type(
+                       field_type);
+               break;
+       default:
+               abort();
+       }
+
+       signedness = bt_field_type_integer_is_signed(int_ft);
        if (signedness < 0) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
        if (!signedness) {
-               if (bt_field_integer_unsigned_get_value(field, &v.u) < 0) {
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
+               ret = bt_field_integer_unsigned_get_value(field, &v.u);
        } else {
-               if (bt_field_integer_signed_get_value(field, &v.s) < 0) {
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
+               ret = bt_field_integer_signed_get_value(field, &v.s);
+       }
+
+       if (ret < 0) {
+               ret = BT_COMPONENT_STATUS_ERROR;
+               goto end;
        }
 
-       encoding = bt_field_type_integer_get_encoding(field_type);
+       encoding = bt_field_type_integer_get_encoding(int_ft);
        switch (encoding) {
        case BT_STRING_ENCODING_UTF8:
        case BT_STRING_ENCODING_ASCII:
@@ -617,13 +633,13 @@ enum bt_component_status print_integer(struct pretty_component *pretty,
                rst_color = true;
        }
 
-       base = bt_field_type_integer_get_base(field_type);
+       base = bt_field_type_integer_get_base(int_ft);
        switch (base) {
        case BT_INTEGER_BASE_BINARY:
        {
                int bitnr, len;
 
-               len = bt_field_type_integer_get_size(field_type);
+               len = bt_field_type_integer_get_size(int_ft);
                if (len < 0) {
                        ret = BT_COMPONENT_STATUS_ERROR;
                        goto end;
@@ -641,7 +657,7 @@ enum bt_component_status print_integer(struct pretty_component *pretty,
                if (signedness) {
                        int len;
 
-                       len = bt_field_type_integer_get_size(field_type);
+                       len = bt_field_type_integer_get_size(int_ft);
                        if (len < 0) {
                                ret = BT_COMPONENT_STATUS_ERROR;
                                goto end;
@@ -671,7 +687,7 @@ enum bt_component_status print_integer(struct pretty_component *pretty,
        {
                int len;
 
-               len = bt_field_type_integer_get_size(field_type);
+               len = bt_field_type_integer_get_size(int_ft);
                if (len < 0) {
                        ret = BT_COMPONENT_STATUS_ERROR;
                        goto end;
@@ -770,54 +786,28 @@ enum bt_component_status print_enum(struct pretty_component *pretty,
                struct bt_field *field)
 {
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
-       struct bt_field *container_field = NULL;
        struct bt_field_type *enumeration_field_type = NULL;
        struct bt_field_type *container_field_type = NULL;
        struct bt_field_type_enumeration_mapping_iterator *iter = NULL;
        int nr_mappings = 0;
-       int is_signed;
 
        enumeration_field_type = bt_field_borrow_type(field);
        if (!enumeration_field_type) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       container_field = bt_field_enumeration_borrow_container(field);
-       if (!container_field) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-       container_field_type = bt_field_borrow_type(container_field);
+       container_field_type =
+               bt_field_type_enumeration_borrow_container_field_type(
+                       enumeration_field_type);
        if (!container_field_type) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       is_signed = bt_field_type_integer_is_signed(container_field_type);
-       if (is_signed < 0) {
+       iter = bt_field_enumeration_get_mappings(field);
+       if (!iter) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       if (is_signed) {
-               int64_t value;
-
-               if (bt_field_integer_signed_get_value(container_field,
-                               &value)) {
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-               iter = bt_field_type_enumeration_signed_find_mappings_by_value(
-                               enumeration_field_type, value);
-       } else {
-               uint64_t value;
-
-               if (bt_field_integer_unsigned_get_value(container_field,
-                               &value)) {
-                       ret = BT_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-               iter = bt_field_type_enumeration_unsigned_find_mappings_by_value(
-                               enumeration_field_type, value);
-       }
        g_string_append(pretty->string, "( ");
        ret = bt_field_type_enumeration_mapping_iterator_next(iter);
        if (ret) {
@@ -853,7 +843,7 @@ enum bt_component_status print_enum(struct pretty_component *pretty,
        }
 skip_loop:
        g_string_append(pretty->string, " : container = ");
-       ret = print_integer(pretty, container_field);
+       ret = print_integer(pretty, field);
        if (ret != BT_COMPONENT_STATUS_OK) {
                goto end;
        }
@@ -1108,9 +1098,8 @@ enum bt_component_status print_sequence(struct pretty_component *pretty,
 {
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
        struct bt_field_type *seq_type = NULL, *field_type = NULL;
-       struct bt_field *length_field = NULL;
        enum bt_field_type_id type_id;
-       uint64_t len;
+       int64_t len;
        uint64_t i;
        bool is_string = false;
 
@@ -1119,12 +1108,8 @@ enum bt_component_status print_sequence(struct pretty_component *pretty,
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
-       length_field = bt_field_sequence_borrow_length(seq);
-       if (!length_field) {
-               ret = BT_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-       if (bt_field_integer_unsigned_get_value(length_field, &len) < 0) {
+       len = bt_field_sequence_get_length(seq);
+       if (len < 0) {
                ret = BT_COMPONENT_STATUS_ERROR;
                goto end;
        }
@@ -1206,29 +1191,62 @@ enum bt_component_status print_variant(struct pretty_component *pretty,
        g_string_append(pretty->string, "{ ");
        pretty->depth++;
        if (print_names) {
-               int iter_ret;
-               struct bt_field *tag_field = NULL;
+               int iret;
+               struct bt_field_type *var_ft;
+               struct bt_field_type *tag_ft;
+               struct bt_field_type *container_ft;
                const char *tag_choice;
+               bt_bool is_signed;
                struct bt_field_type_enumeration_mapping_iterator *iter;
 
-               tag_field = bt_field_variant_borrow_tag(variant);
-               if (!tag_field) {
+               var_ft = bt_field_borrow_type(variant);
+               tag_ft = bt_field_type_variant_borrow_tag_field_type(
+                       var_ft);
+               container_ft =
+                       bt_field_type_enumeration_borrow_container_field_type(
+                               tag_ft);
+               is_signed = bt_field_type_integer_is_signed(container_ft);
+
+               if (is_signed) {
+                       int64_t tag;
+
+                       iret = bt_field_variant_get_tag_signed(variant, &tag);
+                       if (iret) {
+                               ret = BT_COMPONENT_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       iter = bt_field_type_enumeration_signed_find_mappings_by_value(
+                               tag_ft, tag);
+               } else {
+                       uint64_t tag;
+
+                       iret = bt_field_variant_get_tag_unsigned(variant, &tag);
+                       if (iret) {
+                               ret = BT_COMPONENT_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       iter = bt_field_type_enumeration_unsigned_find_mappings_by_value(
+                               tag_ft, tag);
+               }
+
+               if (!iter) {
                        ret = BT_COMPONENT_STATUS_ERROR;
                        goto end;
                }
 
-               iter = bt_field_enumeration_get_mappings(tag_field);
-               iter_ret = bt_field_type_enumeration_mapping_iterator_next(
+               iret = bt_field_type_enumeration_mapping_iterator_next(
                        iter);
                if (!iter || ret) {
                        ret = BT_COMPONENT_STATUS_ERROR;
                        goto end;
                }
 
-               iter_ret =
+               iret =
                        bt_field_type_enumeration_mapping_iterator_signed_get(
                                iter, &tag_choice, NULL, NULL);
-               if (iter_ret) {
+               if (iret) {
                        bt_put(iter);
                        ret = BT_COMPONENT_STATUS_ERROR;
                        goto end;
index 2398d4e3245b2bbf6867e4c93e7bbea47c8264c7..8f889fcda1dad29677dc0a66517b1e1df61d0752 100644 (file)
@@ -401,18 +401,6 @@ enum bt_notification_iterator_status src_iter_init(
        return BT_NOTIFICATION_ITERATOR_STATUS_OK;
 }
 
-static
-struct bt_event *src_create_event(struct bt_packet *packet)
-{
-       struct bt_event *event = bt_event_create(src_event_class);
-       int ret;
-
-       assert(event);
-       ret = bt_event_set_packet(event, packet);
-       assert(ret == 0);
-       return event;
-}
-
 static
 struct bt_notification_iterator_next_method_return src_iter_next_seq(
                struct src_iter_user_data *user_data)
@@ -513,12 +501,10 @@ struct bt_notification_iterator_next_method_return src_iter_next_seq(
        }
 
        if (event_packet) {
-               struct bt_event *event = src_create_event(event_packet);
-
-               assert(event);
-               next_return.notification = bt_notification_event_create(event,
+               next_return.notification =
+                       bt_notification_event_create(src_event_class,
+                       event_packet,
                        src_empty_cc_prio_map);
-               bt_put(event);
                assert(next_return.notification);
        }
 
@@ -599,12 +585,10 @@ enum bt_notification_iterator_status common_consume(
                struct bt_event *event;
 
                test_event.type = TEST_EV_TYPE_NOTIF_EVENT;
-               event = bt_notification_event_get_event(notification);
+               event = bt_notification_event_borrow_event(notification);
                assert(event);
-               test_event.packet = bt_event_get_packet(event);
-               bt_put(event);
+               test_event.packet = bt_event_borrow_packet(event);
                assert(test_event.packet);
-               bt_put(test_event.packet);
                break;
        }
        case BT_NOTIFICATION_TYPE_INACTIVITY:
@@ -613,30 +597,26 @@ enum bt_notification_iterator_status common_consume(
        case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
                test_event.type = TEST_EV_TYPE_NOTIF_STREAM_BEGIN;
                test_event.stream =
-                       bt_notification_stream_begin_get_stream(notification);
+                       bt_notification_stream_begin_borrow_stream(notification);
                assert(test_event.stream);
-               bt_put(test_event.stream);
                break;
        case BT_NOTIFICATION_TYPE_STREAM_END:
                test_event.type = TEST_EV_TYPE_NOTIF_STREAM_END;
                test_event.stream =
-                       bt_notification_stream_end_get_stream(notification);
+                       bt_notification_stream_end_borrow_stream(notification);
                assert(test_event.stream);
-               bt_put(test_event.stream);
                break;
        case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
                test_event.type = TEST_EV_TYPE_NOTIF_PACKET_BEGIN;
                test_event.packet =
-                       bt_notification_packet_begin_get_packet(notification);
+                       bt_notification_packet_begin_borrow_packet(notification);
                assert(test_event.packet);
-               bt_put(test_event.packet);
                break;
        case BT_NOTIFICATION_TYPE_PACKET_END:
                test_event.type = TEST_EV_TYPE_NOTIF_PACKET_END;
                test_event.packet =
-                       bt_notification_packet_end_get_packet(notification);
+                       bt_notification_packet_end_borrow_packet(notification);
                assert(test_event.packet);
-               bt_put(test_event.packet);
                break;
        default:
                test_event.type = TEST_EV_TYPE_NOTIF_UNEXPECTED;
@@ -644,9 +624,8 @@ enum bt_notification_iterator_status common_consume(
        }
 
        if (test_event.packet) {
-               test_event.stream = bt_packet_get_stream(test_event.packet);
+               test_event.stream = bt_packet_borrow_stream(test_event.packet);
                assert(test_event.stream);
-               bt_put(test_event.stream);
        }
 
 end:
index 5601809136548b4c0af5f9107435af9545950c8f..928ff982183f7f5b2f2716779d35c5cf2d508a60 100644 (file)
@@ -57,7 +57,7 @@
 #define DEFAULT_CLOCK_TIME 0
 #define DEFAULT_CLOCK_VALUE 0
 
-#define NR_TESTS 347
+#define NR_TESTS 346
 
 struct bt_utsname {
        char sysname[BABELTRACE_HOST_NAME_MAX];
@@ -511,7 +511,7 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class,
                *inner_structure_field, *complex_structure_field,
                *a_sequence_field, *enum_variant_field, *enum_container_field,
                *variant_field, *an_array_field, *stream_event_ctx_field,
-               *stream_event_ctx_int_field, *ret_field;
+               *stream_event_ctx_int_field;
        uint64_t ret_unsigned_int;
        int64_t ret_signed_int;
        const char *ret_string;
@@ -769,9 +769,6 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class,
 
        ok(bt_ctf_field_sequence_set_length(a_sequence_field,
                uint_35_field) == 0, "Set a sequence field's length");
-       ret_field = bt_ctf_field_sequence_get_length(a_sequence_field);
-       ok(ret_field == uint_35_field,
-               "bt_ctf_field_sequence_get_length returns the correct length field");
 
        for (i = 0; i < SEQUENCE_TEST_LENGTH; i++) {
                int_16_field = bt_ctf_field_sequence_get_field(
@@ -820,7 +817,6 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class,
        bt_put(enum_variant_field);
        bt_put(enum_container_field);
        bt_put(variant_field);
-       bt_put(ret_field);
        bt_put(packet_context_field);
        bt_put(packet_context);
        bt_put(uint_35_type);
index aa7f29809e3e2d2bc695ccf002baa7f06e041a18..27c905c588da30c65b73183689cb2b9319fdcb16 100644 (file)
@@ -302,6 +302,8 @@ void init_static_data(void)
        struct bt_trace *trace;
        struct bt_stream *stream;
        struct bt_field_type *empty_struct_ft;
+       struct bt_field_type *eh_ft;
+       struct bt_field_type *eh_ts_ft;
 
        /* Test events */
        test_events = g_array_new(FALSE, TRUE, sizeof(struct test_event));
@@ -310,6 +312,8 @@ void init_static_data(void)
        /* Metadata */
        empty_struct_ft = bt_field_type_structure_create();
        assert(empty_struct_ft);
+       src_clock_class = bt_clock_class_create("my-clock", 1000000000);
+       assert(src_clock_class);
        trace = bt_trace_create();
        assert(trace);
        ret = bt_trace_set_native_byte_order(trace,
@@ -317,8 +321,6 @@ void init_static_data(void)
        assert(ret == 0);
        ret = bt_trace_set_packet_header_field_type(trace, empty_struct_ft);
        assert(ret == 0);
-       src_clock_class = bt_clock_class_create("my-clock", 1000000000);
-       assert(src_clock_class);
        ret = bt_clock_class_set_is_absolute(src_clock_class, 1);
        assert(ret == 0);
        ret = bt_trace_add_clock_class(trace, src_clock_class);
@@ -335,8 +337,17 @@ void init_static_data(void)
        ret = bt_stream_class_set_packet_context_field_type(src_stream_class,
                empty_struct_ft);
        assert(ret == 0);
+       eh_ft = bt_field_type_structure_create();
+       assert(eh_ft);
+       eh_ts_ft = bt_field_type_integer_create(64);
+       assert(eh_ts_ft);
+       ret = bt_field_type_structure_add_field(eh_ft, eh_ts_ft, "ts");
+       assert(ret == 0);
+       ret = bt_field_type_integer_set_mapped_clock_class(eh_ts_ft,
+               src_clock_class);
+       assert(ret == 0);
        ret = bt_stream_class_set_event_header_field_type(src_stream_class,
-               empty_struct_ft);
+               eh_ft);
        assert(ret == 0);
        ret = bt_stream_class_set_event_context_field_type(src_stream_class,
                empty_struct_ft);
@@ -376,6 +387,8 @@ void init_static_data(void)
 
        bt_put(trace);
        bt_put(empty_struct_ft);
+       bt_put(eh_ft);
+       bt_put(eh_ts_ft);
 }
 
 static
@@ -493,28 +506,31 @@ enum bt_notification_iterator_status src_iter_init(
 }
 
 static
-struct bt_event *src_create_event(struct bt_packet *packet,
-               int64_t ts_ns)
+struct bt_notification *src_create_event_notif(struct bt_packet *packet,
+               struct bt_clock_class_priority_map *cc_prio_map, int64_t ts_ns)
 {
-       struct bt_event *event = bt_event_create(src_event_class);
        int ret;
-
+       struct bt_event *event;
+       struct bt_notification *notif;
+       struct bt_clock_value *clock_value;
+       struct bt_field *field;
+
+       notif = bt_notification_event_create(src_event_class,
+               packet, cc_prio_map);
+       assert(notif);
+       event = bt_notification_event_borrow_event(notif);
        assert(event);
-       ret = bt_event_set_packet(event, packet);
+       field = bt_event_borrow_header(event);
+       assert(field);
+       field = bt_field_structure_borrow_field_by_name(field, "ts");
+       assert(field);
+       ret = bt_field_integer_unsigned_set_value(field, (uint64_t) ts_ns);
        assert(ret == 0);
-
-       if (ts_ns != -1) {
-               struct bt_clock_value *clock_value;
-
-               clock_value = bt_clock_value_create(src_clock_class,
-                       (uint64_t) ts_ns);
-               assert(clock_value);
-               ret = bt_event_set_clock_value(event, clock_value);
-               assert(ret == 0);
-               bt_put(clock_value);
-       }
-
-       return event;
+       clock_value = bt_event_borrow_clock_value(event, src_clock_class);
+       assert(clock_value);
+       ret = bt_clock_value_set_value(clock_value, (uint64_t) ts_ns);
+       assert(ret == 0);
+       return notif;
 }
 
 static
@@ -565,13 +581,8 @@ struct bt_notification_iterator_next_method_return src_iter_next_seq(
                break;
        default:
        {
-               struct bt_event *event = src_create_event(
-                       user_data->packet, cur_ts_ns);
-
-               assert(event);
-               next_return.notification = bt_notification_event_create(event,
-                       src_cc_prio_map);
-               bt_put(event);
+               next_return.notification = src_create_event_notif(
+                       user_data->packet, src_cc_prio_map, cur_ts_ns);
                assert(next_return.notification);
                break;
        }
@@ -618,15 +629,11 @@ struct bt_notification_iterator_next_method_return src_iter_next(
                                                user_data->packet);
                                assert(next_return.notification);
                        } else if (user_data->at < 7) {
-                               struct bt_event *event = src_create_event(
-                                       user_data->packet, -1);
-
-                               assert(event);
                                next_return.notification =
-                                       bt_notification_event_create(event,
-                                               src_empty_cc_prio_map);
+                                       src_create_event_notif(
+                                               user_data->packet,
+                                               src_empty_cc_prio_map, 0);
                                assert(next_return.notification);
-                               bt_put(event);
                        } else if (user_data->at == 7) {
                                next_return.notification =
                                        bt_notification_packet_end_create(
@@ -792,33 +799,29 @@ enum bt_component_status sink_consume(
 
                test_event.type = TEST_EV_TYPE_NOTIF_EVENT;
                cc_prio_map =
-                       bt_notification_event_get_clock_class_priority_map(
+                       bt_notification_event_borrow_clock_class_priority_map(
                                notification);
                assert(cc_prio_map);
-               event = bt_notification_event_get_event(notification);
+               event = bt_notification_event_borrow_event(notification);
                assert(event);
 
                if (bt_clock_class_priority_map_get_clock_class_count(cc_prio_map) > 0) {
                        struct bt_clock_value *clock_value;
                        struct bt_clock_class *clock_class =
-                               bt_clock_class_priority_map_get_highest_priority_clock_class(
+                               bt_clock_class_priority_map_borrow_highest_priority_clock_class(
                                        cc_prio_map);
 
                        assert(clock_class);
-                       clock_value = bt_event_get_clock_value(event,
+                       clock_value = bt_event_borrow_clock_value(event,
                                clock_class);
                        assert(clock_value);
                        ret = bt_clock_value_get_value_ns_from_epoch(
                                        clock_value, &test_event.ts_ns);
                        assert(ret == 0);
-                       bt_put(clock_value);
-                       bt_put(clock_class);
                } else {
                        test_event.ts_ns = -1;
                }
 
-               bt_put(cc_prio_map);
-               bt_put(event);
                break;
        }
        case BT_NOTIFICATION_TYPE_INACTIVITY:
@@ -826,31 +829,28 @@ enum bt_component_status sink_consume(
                struct bt_clock_class_priority_map *cc_prio_map;
 
                test_event.type = TEST_EV_TYPE_NOTIF_INACTIVITY;
-               cc_prio_map = bt_notification_event_get_clock_class_priority_map(
+               cc_prio_map = bt_notification_inactivity_borrow_clock_class_priority_map(
                        notification);
                assert(cc_prio_map);
 
                if (bt_clock_class_priority_map_get_clock_class_count(cc_prio_map) > 0) {
                        struct bt_clock_value *clock_value;
                        struct bt_clock_class *clock_class =
-                               bt_clock_class_priority_map_get_highest_priority_clock_class(
+                               bt_clock_class_priority_map_borrow_highest_priority_clock_class(
                                        cc_prio_map);
 
                        assert(clock_class);
                        clock_value =
-                               bt_notification_inactivity_get_clock_value(
+                               bt_notification_inactivity_borrow_clock_value(
                                        notification, clock_class);
                        assert(clock_value);
                        ret = bt_clock_value_get_value_ns_from_epoch(
                                        clock_value, &test_event.ts_ns);
                        assert(ret == 0);
-                       bt_put(clock_value);
-                       bt_put(clock_class);
                } else {
                        test_event.ts_ns = -1;
                }
 
-               bt_put(cc_prio_map);
                break;
        }
        case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
This page took 0.227738 seconds and 4 git commands to generate.