2 * This file is part of the libsigrok project.
4 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
5 * Copyright (C) 2015 Daniel Elstner <daniel.kitta@gmail.com>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <libsigrok/libsigrok.h>
28 #include "libsigrok-internal.h"
31 #define LOG_PREFIX "session"
37 * Creating, using, or destroying libsigrok sessions.
41 * @defgroup grp_session Session handling
43 * Creating, using, or destroying libsigrok sessions.
48 struct datafeed_callback {
49 sr_datafeed_callback cb;
53 /** Custom GLib event source for generic descriptor I/O.
62 /* Meta-data needed to keep track of installed sources */
63 struct sr_session *session;
69 /** FD event source prepare() method.
71 static gboolean fd_source_prepare(GSource *source, int *timeout)
74 struct fd_source *fsource;
77 fsource = (struct fd_source *)source;
79 if (fsource->timeout_us >= 0) {
80 now_us = g_source_get_time(source);
82 if (fsource->due_us == 0) {
83 /* First-time initialization of the expiration time */
84 fsource->due_us = now_us + fsource->timeout_us;
86 remaining_ms = (MAX(0, fsource->due_us - now_us) + 999) / 1000;
90 *timeout = remaining_ms;
92 return (remaining_ms == 0);
95 /** FD event source check() method.
97 static gboolean fd_source_check(GSource *source)
99 struct fd_source *fsource;
100 unsigned int revents;
102 fsource = (struct fd_source *)source;
103 revents = fsource->pollfd.revents;
105 return (revents != 0 || (fsource->timeout_us >= 0
106 && fsource->due_us <= g_source_get_time(source)));
109 /** FD event source dispatch() method.
111 static gboolean fd_source_dispatch(GSource *source,
112 GSourceFunc callback, void *user_data)
114 struct fd_source *fsource;
116 unsigned int revents;
119 fsource = (struct fd_source *)source;
120 name = g_source_get_name(source);
121 revents = fsource->pollfd.revents;
124 sr_spew("%s: %s " G_POLLFD_FORMAT ", revents 0x%.2X",
125 __func__, name, fsource->pollfd.fd, revents);
127 sr_spew("%s: %s " G_POLLFD_FORMAT ", timed out",
128 __func__, name, fsource->pollfd.fd);
131 sr_err("Callback not set, cannot dispatch event.");
132 return G_SOURCE_REMOVE;
134 keep = (*(sr_receive_data_callback)callback)
135 (fsource->pollfd.fd, revents, user_data);
137 if (fsource->timeout_us >= 0 && G_LIKELY(keep)
138 && G_LIKELY(!g_source_is_destroyed(source)))
139 fsource->due_us = g_source_get_time(source)
140 + fsource->timeout_us;
144 /** FD event source finalize() method.
146 static void fd_source_finalize(GSource *source)
148 struct fd_source *fsource;
150 fsource = (struct fd_source *)source;
152 sr_dbg("%s: key %p", __func__, fsource->key);
154 sr_session_source_destroyed(fsource->session, fsource->key, source);
157 /** Create an event source for I/O on a file descriptor.
159 * In order to maintain API compatibility, this event source also doubles
160 * as a timer event source.
162 * @param session The session the event source belongs to.
163 * @param key The key used to identify this source.
164 * @param fd The file descriptor or HANDLE.
165 * @param timeout_ms The timeout interval in ms, or -1 to wait indefinitely.
166 * @return A new event source object, or NULL on failure.
168 static GSource *fd_source_new(struct sr_session *session, void *key,
169 gintptr fd, int events, int timeout_ms)
171 static GSourceFuncs fd_source_funcs = {
172 .prepare = &fd_source_prepare,
173 .check = &fd_source_check,
174 .dispatch = &fd_source_dispatch,
175 .finalize = &fd_source_finalize
178 struct fd_source *fsource;
180 source = g_source_new(&fd_source_funcs, sizeof(struct fd_source));
181 fsource = (struct fd_source *)source;
183 g_source_set_name(source, (fd < 0) ? "timer" : "fd");
185 if (timeout_ms >= 0) {
186 fsource->timeout_us = 1000 * (int64_t)timeout_ms;
189 fsource->timeout_us = -1;
190 fsource->due_us = INT64_MAX;
192 fsource->session = session;
195 fsource->pollfd.fd = fd;
196 fsource->pollfd.events = events;
197 fsource->pollfd.revents = 0;
200 g_source_add_poll(source, &fsource->pollfd);
206 * Create a new session.
208 * @param ctx The context in which to create the new session.
209 * @param new_session This will contain a pointer to the newly created
210 * session if the return value is SR_OK, otherwise the value
211 * is undefined and should not be used. Must not be NULL.
213 * @retval SR_OK Success.
214 * @retval SR_ERR_ARG Invalid argument.
218 SR_API int sr_session_new(struct sr_context *ctx,
219 struct sr_session **new_session)
221 struct sr_session *session;
226 session = g_malloc0(sizeof(struct sr_session));
230 g_mutex_init(&session->main_mutex);
232 /* To maintain API compatibility, we need a lookup table
233 * which maps poll_object IDs to GSource* pointers.
235 session->event_sources = g_hash_table_new(NULL, NULL);
237 *new_session = session;
244 * This frees up all memory used by the session.
246 * @param session The session to destroy. Must not be NULL.
248 * @retval SR_OK Success.
249 * @retval SR_ERR_ARG Invalid session passed.
253 SR_API int sr_session_destroy(struct sr_session *session)
256 sr_err("%s: session was NULL", __func__);
260 sr_session_dev_remove_all(session);
261 g_slist_free_full(session->owned_devs, (GDestroyNotify)sr_dev_inst_free);
263 g_hash_table_unref(session->event_sources);
265 g_mutex_clear(&session->main_mutex);
273 * Remove all the devices from a session.
275 * The session itself (i.e., the struct sr_session) is not free'd and still
276 * exists after this function returns.
278 * @param session The session to use. Must not be NULL.
280 * @retval SR_OK Success.
281 * @retval SR_ERR_BUG Invalid session passed.
285 SR_API int sr_session_dev_remove_all(struct sr_session *session)
287 struct sr_dev_inst *sdi;
291 sr_err("%s: session was NULL", __func__);
295 for (l = session->devs; l; l = l->next) {
296 sdi = (struct sr_dev_inst *) l->data;
300 g_slist_free(session->devs);
301 session->devs = NULL;
307 * Add a device instance to a session.
309 * @param session The session to add to. Must not be NULL.
310 * @param sdi The device instance to add to a session. Must not
311 * be NULL. Also, sdi->driver and sdi->driver->dev_open must
314 * @retval SR_OK Success.
315 * @retval SR_ERR_ARG Invalid argument.
319 SR_API int sr_session_dev_add(struct sr_session *session,
320 struct sr_dev_inst *sdi)
325 sr_err("%s: sdi was NULL", __func__);
330 sr_err("%s: session was NULL", __func__);
334 /* If sdi->session is not NULL, the device is already in this or
335 * another session. */
337 sr_err("%s: already assigned to session", __func__);
341 /* If sdi->driver is NULL, this is a virtual device. */
343 /* Just add the device, don't run dev_open(). */
344 session->devs = g_slist_append(session->devs, (gpointer)sdi);
345 sdi->session = session;
349 /* sdi->driver is non-NULL (i.e. we have a real device). */
350 if (!sdi->driver->dev_open) {
351 sr_err("%s: sdi->driver->dev_open was NULL", __func__);
355 session->devs = g_slist_append(session->devs, (gpointer)sdi);
356 sdi->session = session;
358 if (session->running) {
359 /* Adding a device to a running session. Commit settings
360 * and start acquisition on that device now. */
361 if ((ret = sr_config_commit(sdi)) != SR_OK) {
362 sr_err("Failed to commit device settings before "
363 "starting acquisition in running session (%s)",
367 if ((ret = sdi->driver->dev_acquisition_start(sdi,
368 (void *)sdi)) != SR_OK) {
369 sr_err("Failed to start acquisition of device in "
370 "running session (%s)", sr_strerror(ret));
379 * List all device instances attached to a session.
381 * @param session The session to use. Must not be NULL.
382 * @param devlist A pointer where the device instance list will be
383 * stored on return. If no devices are in the session,
384 * this will be NULL. Each element in the list points
385 * to a struct sr_dev_inst *.
386 * The list must be freed by the caller, but not the
387 * elements pointed to.
389 * @retval SR_OK Success.
390 * @retval SR_ERR_ARG Invalid argument.
394 SR_API int sr_session_dev_list(struct sr_session *session, GSList **devlist)
402 *devlist = g_slist_copy(session->devs);
408 * Remove all datafeed callbacks in a session.
410 * @param session The session to use. Must not be NULL.
412 * @retval SR_OK Success.
413 * @retval SR_ERR_ARG Invalid session passed.
417 SR_API int sr_session_datafeed_callback_remove_all(struct sr_session *session)
420 sr_err("%s: session was NULL", __func__);
424 g_slist_free_full(session->datafeed_callbacks, g_free);
425 session->datafeed_callbacks = NULL;
431 * Add a datafeed callback to a session.
433 * @param session The session to use. Must not be NULL.
434 * @param cb Function to call when a chunk of data is received.
436 * @param cb_data Opaque pointer passed in by the caller.
438 * @retval SR_OK Success.
439 * @retval SR_ERR_BUG No session exists.
443 SR_API int sr_session_datafeed_callback_add(struct sr_session *session,
444 sr_datafeed_callback cb, void *cb_data)
446 struct datafeed_callback *cb_struct;
449 sr_err("%s: session was NULL", __func__);
454 sr_err("%s: cb was NULL", __func__);
458 cb_struct = g_malloc0(sizeof(struct datafeed_callback));
460 cb_struct->cb_data = cb_data;
462 session->datafeed_callbacks =
463 g_slist_append(session->datafeed_callbacks, cb_struct);
469 * Get the trigger assigned to this session.
471 * @param session The session to use.
473 * @retval NULL Invalid (NULL) session was passed to the function.
474 * @retval other The trigger assigned to this session (can be NULL).
478 SR_API struct sr_trigger *sr_session_trigger_get(struct sr_session *session)
483 return session->trigger;
487 * Set the trigger of this session.
489 * @param session The session to use. Must not be NULL.
490 * @param trig The trigger to assign to this session. Can be NULL.
492 * @retval SR_OK Success.
493 * @retval SR_ERR_ARG Invalid argument.
497 SR_API int sr_session_trigger_set(struct sr_session *session, struct sr_trigger *trig)
502 session->trigger = trig;
507 static int verify_trigger(struct sr_trigger *trigger)
509 struct sr_trigger_stage *stage;
510 struct sr_trigger_match *match;
513 if (!trigger->stages) {
514 sr_err("No trigger stages defined.");
518 sr_spew("Checking trigger:");
519 for (l = trigger->stages; l; l = l->next) {
521 if (!stage->matches) {
522 sr_err("Stage %d has no matches defined.", stage->stage);
525 for (m = stage->matches; m; m = m->next) {
527 if (!match->channel) {
528 sr_err("Stage %d match has no channel.", stage->stage);
532 sr_err("Stage %d match is not defined.", stage->stage);
535 sr_spew("Stage %d match on channel %s, match %d", stage->stage,
536 match->channel->name, match->match);
543 /** Set up the main context the session will be executing in.
545 * Must be called just before the session starts, by the thread which
546 * will execute the session main loop. Once acquired, the main context
547 * pointer is immutable for the duration of the session run.
549 static int set_main_context(struct sr_session *session)
551 GMainContext *def_context;
553 /* May happen if sr_session_start() is called again after
554 * sr_session_run(), but the session hasn't been stopped yet.
556 if (session->main_loop) {
557 sr_err("Cannot set main context; main loop already created.");
561 g_mutex_lock(&session->main_mutex);
563 def_context = g_main_context_get_thread_default();
566 def_context = g_main_context_default();
568 * Try to use an existing main context if possible, but only if we
569 * can make it owned by the current thread. Otherwise, create our
570 * own main context so that event source callbacks can execute in
571 * the session thread.
573 if (g_main_context_acquire(def_context)) {
574 g_main_context_release(def_context);
576 sr_dbg("Using thread-default main context.");
578 session->main_context = def_context;
579 session->main_context_is_default = TRUE;
581 sr_dbg("Creating our own main context.");
583 session->main_context = g_main_context_new();
584 session->main_context_is_default = FALSE;
586 g_mutex_unlock(&session->main_mutex);
591 /** Unset the main context used for the current session run.
593 * Must be called right after stopping the session. Note that if the
594 * session is stopped asynchronously, the main loop may still be running
595 * after the main context has been unset. This is OK as long as no new
596 * event sources are created -- the main loop holds its own reference
597 * to the main context.
599 static int unset_main_context(struct sr_session *session)
603 g_mutex_lock(&session->main_mutex);
605 if (session->main_context) {
606 if (!session->main_context_is_default)
607 g_main_context_unref(session->main_context);
609 session->main_context = NULL;
612 /* May happen if the set/unset calls are not matched.
614 sr_err("No main context to unset.");
617 g_mutex_unlock(&session->main_mutex);
625 * @param session The session to use. Must not be NULL.
627 * @retval SR_OK Success.
628 * @retval SR_ERR_ARG Invalid session passed.
632 SR_API int sr_session_start(struct sr_session *session)
634 struct sr_dev_inst *sdi;
635 struct sr_channel *ch;
637 int enabled_channels, ret;
640 sr_err("%s: session was NULL", __func__);
644 if (!session->devs) {
645 sr_err("%s: session->devs was NULL; a session "
646 "cannot be started without devices.", __func__);
650 if (session->trigger && verify_trigger(session->trigger) != SR_OK)
653 ret = set_main_context(session);
657 session->running = TRUE;
659 sr_info("Starting.");
661 for (l = session->devs; l; l = l->next) {
663 enabled_channels = 0;
664 for (c = sdi->channels; c; c = c->next) {
671 if (enabled_channels == 0) {
673 sr_err("%s using connection %s has no enabled channels!",
674 sdi->driver->name, sdi->connection_id);
678 if ((ret = sr_config_commit(sdi)) != SR_OK) {
679 sr_err("Failed to commit device settings before "
680 "starting acquisition (%s)", sr_strerror(ret));
683 if ((ret = sdi->driver->dev_acquisition_start(sdi, sdi)) != SR_OK) {
684 sr_err("%s: could not start an acquisition "
685 "(%s)", __func__, sr_strerror(ret));
691 unset_main_context(session);
692 session->running = FALSE;
694 /* TODO: What if there are multiple devices? Which return code? */
702 * @param session The session to use. Must not be NULL.
704 * @retval SR_OK Success.
705 * @retval SR_ERR_ARG Invalid session passed.
706 * @retval SR_ERR Error during event processing.
710 SR_API int sr_session_run(struct sr_session *session)
713 sr_err("%s: session was NULL", __func__);
716 if (!session->devs) {
717 /* TODO: Actually the case? */
718 sr_err("%s: session->devs was NULL; a session "
719 "cannot be run without devices.", __func__);
722 if (session->main_loop) {
723 sr_err("Main loop already created.");
726 if (g_hash_table_size(session->event_sources) == 0) {
727 sr_warn("No event sources, returning immediately.");
731 g_mutex_lock(&session->main_mutex);
732 if (!session->main_context) {
733 sr_err("Cannot run without main context.");
734 g_mutex_unlock(&session->main_mutex);
739 session->main_loop = g_main_loop_new(session->main_context, FALSE);
740 g_mutex_unlock(&session->main_mutex);
742 g_main_loop_run(session->main_loop);
744 g_main_loop_unref(session->main_loop);
745 session->main_loop = NULL;
750 static gboolean session_stop_sync(void *user_data)
752 struct sr_session *session;
753 struct sr_dev_inst *sdi;
758 if (!session->running)
759 return G_SOURCE_REMOVE;
761 sr_info("Stopping.");
763 for (node = session->devs; node; node = node->next) {
765 if (sdi->driver && sdi->driver->dev_acquisition_stop)
766 sdi->driver->dev_acquisition_stop(sdi, sdi);
768 session->running = FALSE;
770 return G_SOURCE_REMOVE;
776 * The session is stopped immediately, with all acquisition sessions being
777 * stopped and hardware drivers cleaned up.
779 * If the session is run in a separate thread, this function will not block
780 * until the session is finished executing. It is the caller's responsibility
781 * to wait for the session thread to return before assuming that the session is
782 * completely decommissioned.
784 * @param session The session to use. Must not be NULL.
786 * @retval SR_OK Success.
787 * @retval SR_ERR_ARG Invalid session passed.
788 * @retval SR_ERR Other error.
792 SR_API int sr_session_stop(struct sr_session *session)
795 sr_err("%s: session was NULL", __func__);
798 g_mutex_lock(&session->main_mutex);
800 if (session->main_context) {
801 g_main_context_invoke(session->main_context,
802 &session_stop_sync, session);
804 sr_err("No main context set; already stopped?");
806 g_mutex_unlock(&session->main_mutex);
808 return unset_main_context(session);
814 * @param packet The packet to show debugging information for.
816 static void datafeed_dump(const struct sr_datafeed_packet *packet)
818 const struct sr_datafeed_logic *logic;
819 const struct sr_datafeed_analog *analog;
820 const struct sr_datafeed_analog2 *analog2;
822 /* Please use the same order as in libsigrok.h. */
823 switch (packet->type) {
825 sr_dbg("bus: Received SR_DF_HEADER packet.");
828 sr_dbg("bus: Received SR_DF_END packet.");
831 sr_dbg("bus: Received SR_DF_META packet.");
834 sr_dbg("bus: Received SR_DF_TRIGGER packet.");
837 logic = packet->payload;
838 sr_dbg("bus: Received SR_DF_LOGIC packet (%" PRIu64 " bytes, "
839 "unitsize = %d).", logic->length, logic->unitsize);
842 analog = packet->payload;
843 sr_dbg("bus: Received SR_DF_ANALOG packet (%d samples).",
844 analog->num_samples);
846 case SR_DF_FRAME_BEGIN:
847 sr_dbg("bus: Received SR_DF_FRAME_BEGIN packet.");
849 case SR_DF_FRAME_END:
850 sr_dbg("bus: Received SR_DF_FRAME_END packet.");
853 analog2 = packet->payload;
854 sr_dbg("bus: Received SR_DF_ANALOG2 packet (%d samples).",
855 analog2->num_samples);
858 sr_dbg("bus: Received unknown packet type: %d.", packet->type);
864 * Send a packet to whatever is listening on the datafeed bus.
866 * Hardware drivers use this to send a data packet to the frontend.
869 * @param packet The datafeed packet to send to the session bus.
871 * @retval SR_OK Success.
872 * @retval SR_ERR_ARG Invalid argument.
876 SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi,
877 const struct sr_datafeed_packet *packet)
880 struct datafeed_callback *cb_struct;
881 struct sr_datafeed_packet *packet_in, *packet_out;
882 struct sr_transform *t;
886 sr_err("%s: sdi was NULL", __func__);
891 sr_err("%s: packet was NULL", __func__);
896 sr_err("%s: session was NULL", __func__);
901 * Pass the packet to the first transform module. If that returns
902 * another packet (instead of NULL), pass that packet to the next
903 * transform module in the list, and so on.
905 packet_in = (struct sr_datafeed_packet *)packet;
906 for (l = sdi->session->transforms; l; l = l->next) {
908 sr_spew("Running transform module '%s'.", t->module->id);
909 ret = t->module->receive(t, packet_in, &packet_out);
911 sr_err("Error while running transform module: %d.", ret);
916 * If any of the transforms don't return an output
919 sr_spew("Transform module didn't return a packet, aborting.");
923 * Use this transform module's output packet as input
924 * for the next transform module.
926 packet_in = packet_out;
932 * If the last transform did output a packet, pass it to all datafeed
935 for (l = sdi->session->datafeed_callbacks; l; l = l->next) {
936 if (sr_log_loglevel_get() >= SR_LOG_DBG)
937 datafeed_dump(packet);
939 cb_struct->cb(sdi, packet, cb_struct->cb_data);
946 * Add an event source for a file descriptor.
948 * @param session The session to use. Must not be NULL.
949 * @param key The key which identifies the event source.
950 * @param source An event source object. Must not be NULL.
951 * @retval SR_OK Success.
952 * @retval SR_ERR_ARG Invalid argument.
953 * @retval SR_ERR_BUG Event source with @a key already installed.
954 * @retval SR_ERR Other error.
956 SR_PRIV int sr_session_source_add_internal(struct sr_session *session,
957 void *key, GSource *source)
961 * This must not ever happen, since the source has already been
962 * created and its finalize() method will remove the key for the
963 * already installed source. (Well it would, if we did not have
964 * another sanity check there.)
966 if (g_hash_table_contains(session->event_sources, key)) {
967 sr_err("Event source with key %p already exists.", key);
970 g_hash_table_insert(session->event_sources, key, source);
972 g_mutex_lock(&session->main_mutex);
974 if (session->main_context) {
975 if (g_source_attach(source, session->main_context) > 0)
980 sr_err("Cannot add event source without main context.");
983 g_mutex_unlock(&session->main_mutex);
988 SR_PRIV int sr_session_fd_source_add(struct sr_session *session,
989 void *key, gintptr fd, int events, int timeout,
990 sr_receive_data_callback cb, void *cb_data)
995 source = fd_source_new(session, key, fd, events, timeout);
999 g_source_set_callback(source, (GSourceFunc)cb, cb_data, NULL);
1001 ret = sr_session_source_add_internal(session, key, source);
1002 g_source_unref(source);
1008 * Add an event source for a file descriptor.
1010 * @param session The session to use. Must not be NULL.
1011 * @param fd The file descriptor, or a negative value to create a timer source.
1012 * @param events Events to check for.
1013 * @param timeout Max time in ms to wait before the callback is called,
1014 * or -1 to wait indefinitely.
1015 * @param cb Callback function to add. Must not be NULL.
1016 * @param cb_data Data for the callback function. Can be NULL.
1018 * @retval SR_OK Success.
1019 * @retval SR_ERR_ARG Invalid argument.
1023 SR_API int sr_session_source_add(struct sr_session *session, int fd,
1024 int events, int timeout, sr_receive_data_callback cb, void *cb_data)
1026 if (fd < 0 && timeout < 0) {
1027 sr_err("Cannot create timer source without timeout.");
1030 return sr_session_fd_source_add(session, GINT_TO_POINTER(fd),
1031 fd, events, timeout, cb, cb_data);
1035 * Add an event source for a GPollFD.
1037 * @param session The session to use. Must not be NULL.
1038 * @param pollfd The GPollFD. Must not be NULL.
1039 * @param timeout Max time in ms to wait before the callback is called,
1040 * or -1 to wait indefinitely.
1041 * @param cb Callback function to add. Must not be NULL.
1042 * @param cb_data Data for the callback function. Can be NULL.
1044 * @retval SR_OK Success.
1045 * @retval SR_ERR_ARG Invalid argument.
1049 SR_API int sr_session_source_add_pollfd(struct sr_session *session,
1050 GPollFD *pollfd, int timeout, sr_receive_data_callback cb,
1054 sr_err("%s: pollfd was NULL", __func__);
1057 return sr_session_fd_source_add(session, pollfd, pollfd->fd,
1058 pollfd->events, timeout, cb, cb_data);
1062 * Add an event source for a GIOChannel.
1064 * @param session The session to use. Must not be NULL.
1065 * @param channel The GIOChannel.
1066 * @param events Events to poll on.
1067 * @param timeout Max time in ms to wait before the callback is called,
1068 * or -1 to wait indefinitely.
1069 * @param cb Callback function to add. Must not be NULL.
1070 * @param cb_data Data for the callback function. Can be NULL.
1072 * @retval SR_OK Success.
1073 * @retval SR_ERR_ARG Invalid argument.
1077 SR_API int sr_session_source_add_channel(struct sr_session *session,
1078 GIOChannel *channel, int events, int timeout,
1079 sr_receive_data_callback cb, void *cb_data)
1084 sr_err("%s: channel was NULL", __func__);
1087 /* We should be using g_io_create_watch(), but can't without
1088 * changing the driver API, as the callback signature is different.
1091 g_io_channel_win32_make_pollfd(channel, events, &pollfd);
1093 pollfd.fd = g_io_channel_unix_get_fd(channel);
1094 pollfd.events = events;
1096 return sr_session_fd_source_add(session, channel, pollfd.fd,
1097 pollfd.events, timeout, cb, cb_data);
1101 * Remove the source identified by the specified poll object.
1103 * @param session The session to use. Must not be NULL.
1104 * @param key The key by which the source is identified.
1106 * @retval SR_OK Success
1107 * @retval SR_ERR_BUG No event source for poll_object found.
1109 SR_PRIV int sr_session_source_remove_internal(struct sr_session *session,
1114 source = g_hash_table_lookup(session->event_sources, key);
1116 * Trying to remove an already removed event source is problematic
1117 * since the poll_object handle may have been reused in the meantime.
1120 sr_warn("Cannot remove non-existing event source %p.", key);
1123 g_source_destroy(source);
1129 * Remove the source belonging to the specified file descriptor.
1131 * @param session The session to use. Must not be NULL.
1132 * @param fd The file descriptor for which the source should be removed.
1134 * @retval SR_OK Success
1135 * @retval SR_ERR_ARG Invalid argument
1136 * @retval SR_ERR_BUG Internal error.
1140 SR_API int sr_session_source_remove(struct sr_session *session, int fd)
1142 return sr_session_source_remove_internal(session, GINT_TO_POINTER(fd));
1146 * Remove the source belonging to the specified poll descriptor.
1148 * @param session The session to use. Must not be NULL.
1149 * @param pollfd The poll descriptor for which the source should be removed.
1151 * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
1152 * SR_ERR_MALLOC upon memory allocation errors, SR_ERR_BUG upon
1157 SR_API int sr_session_source_remove_pollfd(struct sr_session *session,
1161 sr_err("%s: pollfd was NULL", __func__);
1164 return sr_session_source_remove_internal(session, pollfd);
1168 * Remove the source belonging to the specified channel.
1170 * @param session The session to use. Must not be NULL.
1171 * @param channel The channel for which the source should be removed.
1173 * @retval SR_OK Success.
1174 * @retval SR_ERR_ARG Invalid argument.
1175 * @return SR_ERR_BUG Internal error.
1179 SR_API int sr_session_source_remove_channel(struct sr_session *session,
1180 GIOChannel *channel)
1183 sr_err("%s: channel was NULL", __func__);
1186 return sr_session_source_remove_internal(session, channel);
1189 /** Unregister an event source that has been destroyed.
1191 * This is intended to be called from a source's finalize() method.
1193 * @param session The session to use. Must not be NULL.
1194 * @param key The key used to identify @a source.
1195 * @param source The source object that was destroyed.
1197 * @retval SR_OK Success.
1198 * @retval SR_ERR_BUG Event source for @a key does not match @a source.
1200 SR_PRIV int sr_session_source_destroyed(struct sr_session *session,
1201 void *key, GSource *source)
1203 GSource *registered_source;
1205 registered_source = g_hash_table_lookup(session->event_sources, key);
1207 * Trying to remove an already removed event source is problematic
1208 * since the poll_object handle may have been reused in the meantime.
1210 if (!registered_source) {
1211 sr_err("No event source for key %p found.", key);
1214 if (registered_source != source) {
1215 sr_err("Event source for key %p does not match"
1216 " destroyed source.", key);
1219 g_hash_table_remove(session->event_sources, key);
1221 * Quit the main loop if we just removed the last event source.
1222 * TODO: This may need an idle callback depending on when event
1223 * sources are finalized. (The issue is remove followed by add
1224 * within the same main loop iteration.)
1226 if (session->main_loop
1227 && g_hash_table_size(session->event_sources) == 0) {
1228 sr_dbg("Stopping main loop...");
1229 g_main_loop_quit(session->main_loop);
1234 static void copy_src(struct sr_config *src, struct sr_datafeed_meta *meta_copy)
1236 g_variant_ref(src->data);
1237 meta_copy->config = g_slist_append(meta_copy->config,
1238 g_memdup(src, sizeof(struct sr_config)));
1241 SR_PRIV int sr_packet_copy(const struct sr_datafeed_packet *packet,
1242 struct sr_datafeed_packet **copy)
1244 const struct sr_datafeed_meta *meta;
1245 struct sr_datafeed_meta *meta_copy;
1246 const struct sr_datafeed_logic *logic;
1247 struct sr_datafeed_logic *logic_copy;
1248 const struct sr_datafeed_analog *analog;
1249 struct sr_datafeed_analog *analog_copy;
1252 *copy = g_malloc0(sizeof(struct sr_datafeed_packet));
1253 (*copy)->type = packet->type;
1255 switch (packet->type) {
1261 payload = g_malloc(sizeof(struct sr_datafeed_header));
1262 memcpy(payload, packet->payload, sizeof(struct sr_datafeed_header));
1263 (*copy)->payload = payload;
1266 meta = packet->payload;
1267 meta_copy = g_malloc0(sizeof(struct sr_datafeed_meta));
1268 g_slist_foreach(meta->config, (GFunc)copy_src, meta_copy->config);
1269 (*copy)->payload = meta_copy;
1272 logic = packet->payload;
1273 logic_copy = g_malloc(sizeof(logic));
1274 logic_copy->length = logic->length;
1275 logic_copy->unitsize = logic->unitsize;
1276 memcpy(logic_copy->data, logic->data, logic->length * logic->unitsize);
1277 (*copy)->payload = logic_copy;
1280 analog = packet->payload;
1281 analog_copy = g_malloc(sizeof(analog));
1282 analog_copy->channels = g_slist_copy(analog->channels);
1283 analog_copy->num_samples = analog->num_samples;
1284 analog_copy->mq = analog->mq;
1285 analog_copy->unit = analog->unit;
1286 analog_copy->mqflags = analog->mqflags;
1287 memcpy(analog_copy->data, analog->data,
1288 analog->num_samples * sizeof(float));
1289 (*copy)->payload = analog_copy;
1292 sr_err("Unknown packet type %d", packet->type);
1299 void sr_packet_free(struct sr_datafeed_packet *packet)
1301 const struct sr_datafeed_meta *meta;
1302 const struct sr_datafeed_logic *logic;
1303 const struct sr_datafeed_analog *analog;
1304 struct sr_config *src;
1307 switch (packet->type) {
1313 /* Payload is a simple struct. */
1314 g_free((void *)packet->payload);
1317 meta = packet->payload;
1318 for (l = meta->config; l; l = l->next) {
1320 g_variant_unref(src->data);
1323 g_slist_free(meta->config);
1324 g_free((void *)packet->payload);
1327 logic = packet->payload;
1328 g_free(logic->data);
1329 g_free((void *)packet->payload);
1332 analog = packet->payload;
1333 g_slist_free(analog->channels);
1334 g_free(analog->data);
1335 g_free((void *)packet->payload);
1338 sr_err("Unknown packet type %d", packet->type);