+/** Unregister an event source that has been destroyed.
+ *
+ * This is intended to be called from a source's finalize() method.
+ *
+ * @param session The session to use. Must not be NULL.
+ * @param key The key used to identify @a source.
+ * @param source The source object that was destroyed.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG Event source for @a key does not match @a source.
+ * @retval SR_ERR Other error.
+ *
+ * @private
+ */
+SR_PRIV int sr_session_source_destroyed(struct sr_session *session,
+ void *key, GSource *source)
+{
+ GSource *registered_source;
+
+ registered_source = g_hash_table_lookup(session->event_sources, key);
+ /*
+ * Trying to remove an already removed event source is problematic
+ * since the poll_object handle may have been reused in the meantime.
+ */
+ if (!registered_source) {
+ sr_err("No event source for key %p found.", key);
+ return SR_ERR_BUG;
+ }
+ if (registered_source != source) {
+ sr_err("Event source for key %p does not match"
+ " destroyed source.", key);
+ return SR_ERR_BUG;
+ }
+ g_hash_table_remove(session->event_sources, key);
+
+ if (g_hash_table_size(session->event_sources) > 0)
+ return SR_OK;
+
+ /* If no event sources are left, consider the acquisition finished.
+ * This is pretty crude, as it requires all event sources to be
+ * registered via the libsigrok API.
+ */
+ return stop_check_later(session);
+}
+
+static void copy_src(struct sr_config *src, struct sr_datafeed_meta *meta_copy)
+{
+ struct sr_config *item;
+
+#if GLIB_CHECK_VERSION(2, 67, 3)
+ item = g_memdup2(src, sizeof(*src));
+#else
+ item = g_memdup(src, sizeof(*src));
+#endif
+
+ g_variant_ref(src->data);
+ meta_copy->config = g_slist_append(meta_copy->config, item);
+}
+
+SR_API int sr_packet_copy(const struct sr_datafeed_packet *packet,
+ struct sr_datafeed_packet **copy)
+{
+ const struct sr_datafeed_meta *meta;
+ struct sr_datafeed_meta *meta_copy;
+ const struct sr_datafeed_logic *logic;
+ struct sr_datafeed_logic *logic_copy;
+ const struct sr_datafeed_analog *analog;
+ struct sr_datafeed_analog *analog_copy;
+ struct sr_analog_encoding *encoding_copy;
+ struct sr_analog_meaning *meaning_copy;
+ struct sr_analog_spec *spec_copy;
+ uint8_t *payload;
+
+ *copy = g_malloc0(sizeof(struct sr_datafeed_packet));
+ (*copy)->type = packet->type;
+
+ switch (packet->type) {
+ case SR_DF_TRIGGER:
+ case SR_DF_END:
+ /* No payload. */
+ break;
+ case SR_DF_HEADER:
+ payload = g_malloc(sizeof(struct sr_datafeed_header));
+ memcpy(payload, packet->payload, sizeof(struct sr_datafeed_header));
+ (*copy)->payload = payload;
+ break;
+ case SR_DF_META:
+ meta = packet->payload;
+ meta_copy = g_malloc0(sizeof(struct sr_datafeed_meta));
+ g_slist_foreach(meta->config, (GFunc)copy_src, meta_copy->config);
+ (*copy)->payload = meta_copy;
+ break;
+ case SR_DF_LOGIC:
+ logic = packet->payload;
+ logic_copy = g_malloc(sizeof(*logic_copy));
+ if (!logic_copy)
+ return SR_ERR;
+ logic_copy->length = logic->length;
+ logic_copy->unitsize = logic->unitsize;
+ logic_copy->data = g_malloc(logic->length * logic->unitsize);
+ if (!logic_copy->data) {
+ g_free(logic_copy);
+ return SR_ERR;
+ }
+ memcpy(logic_copy->data, logic->data, logic->length * logic->unitsize);
+ (*copy)->payload = logic_copy;
+ break;
+ case SR_DF_ANALOG:
+ analog = packet->payload;
+ analog_copy = g_malloc(sizeof(*analog_copy));
+ analog_copy->data = g_malloc(
+ analog->encoding->unitsize * analog->num_samples);
+ memcpy(analog_copy->data, analog->data,
+ analog->encoding->unitsize * analog->num_samples);
+ analog_copy->num_samples = analog->num_samples;
+#if GLIB_CHECK_VERSION(2, 67, 3)
+ encoding_copy = g_memdup2(analog->encoding, sizeof(*analog->encoding));
+ meaning_copy = g_memdup2(analog->meaning, sizeof(*analog->meaning));
+ spec_copy = g_memdup2(analog->spec, sizeof(*analog->spec));
+#else
+ encoding_copy = g_memdup(analog->encoding, sizeof(*analog->encoding));
+ meaning_copy = g_memdup(analog->meaning, sizeof(*analog->meaning));
+ spec_copy = g_memdup(analog->spec, sizeof(*analog->spec));
+#endif
+ analog_copy->encoding = encoding_copy;
+ analog_copy->meaning = meaning_copy;
+ analog_copy->meaning->channels = g_slist_copy(
+ analog->meaning->channels);
+ analog_copy->spec = spec_copy;
+ (*copy)->payload = analog_copy;
+ break;
+ default:
+ sr_err("Unknown packet type %d", packet->type);
+ return SR_ERR;
+ }
+
+ return SR_OK;
+}
+
+SR_API void sr_packet_free(struct sr_datafeed_packet *packet)
+{
+ const struct sr_datafeed_meta *meta;
+ const struct sr_datafeed_logic *logic;
+ const struct sr_datafeed_analog *analog;
+ struct sr_config *src;
+ GSList *l;
+
+ switch (packet->type) {
+ case SR_DF_TRIGGER:
+ case SR_DF_END:
+ /* No payload. */
+ break;
+ case SR_DF_HEADER:
+ /* Payload is a simple struct. */
+ g_free((void *)packet->payload);
+ break;
+ case SR_DF_META:
+ meta = packet->payload;
+ for (l = meta->config; l; l = l->next) {
+ src = l->data;
+ g_variant_unref(src->data);
+ g_free(src);
+ }
+ g_slist_free(meta->config);
+ g_free((void *)packet->payload);
+ break;
+ case SR_DF_LOGIC:
+ logic = packet->payload;
+ g_free(logic->data);
+ g_free((void *)packet->payload);
+ break;
+ case SR_DF_ANALOG:
+ analog = packet->payload;
+ g_free(analog->data);
+ g_free(analog->encoding);
+ g_slist_free(analog->meaning->channels);
+ g_free(analog->meaning);
+ g_free(analog->spec);
+ g_free((void *)packet->payload);
+ break;
+ default:
+ sr_err("Unknown packet type %d", packet->type);
+ }
+ g_free(packet);