/** 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); }
/** * Start a session. * * When this function returns with a status code indicating success, the * session is running. Use sr_session_stopped_callback_set() to receive * notification upon completion, or call sr_session_run() to block until * the session stops. * * Session events will be processed in the context of the current thread. * If a thread-default GLib main context has been set, and is not owned by * any other thread, it will be used. Otherwise, libsigrok will create its * own main context for the current thread. * * @param session The session to use. Must not be NULL. * * @retval SR_OK Success. * @retval SR_ERR_ARG Invalid session passed. * @retval SR_ERR Other error. * * @since 0.4.0 */ SR_API int sr_session_start(struct sr_session *session) { struct sr_dev_inst *sdi; struct sr_channel *ch; GSList *l, *c, *lend; int ret; if (!session) { sr_err("%s: session was NULL", __func__); return SR_ERR_ARG; } if (!session->devs) { sr_err("%s: session->devs was NULL; a session " "cannot be started without devices.", __func__); return SR_ERR_ARG; } if (session->running) { sr_err("Cannot (re-)start session while it is still running."); return SR_ERR; } if (session->trigger) { ret = verify_trigger(session->trigger); if (ret != SR_OK) return ret; } /* Check enabled channels and commit settings of all devices. */ for (l = session->devs; l; l = l->next) { sdi = l->data; for (c = sdi->channels; c; c = c->next) { ch = c->data; if (ch->enabled) break; } if (!c) { sr_err("%s device %s has no enabled channels.", sdi->driver->name, sdi->connection_id); return SR_ERR; } ret = sr_config_commit(sdi); if (ret != SR_OK) { sr_err("Failed to commit %s device %s settings " "before starting acquisition.", sdi->driver->name, sdi->connection_id); return ret; } } ret = set_main_context(session); if (ret != SR_OK) return ret; sr_info("Starting."); session->running = TRUE; /* Have all devices start acquisition. */ for (l = session->devs; l; l = l->next) { sdi = l->data; ret = sdi->driver->dev_acquisition_start(sdi, sdi); if (ret != SR_OK) { sr_err("Could not start %s device %s acquisition.", sdi->driver->name, sdi->connection_id); break; } } if (ret != SR_OK) { /* If there are multiple devices, some of them may already have * started successfully. Stop them now before returning. */ lend = l->next; for (l = session->devs; l != lend; l = l->next) { sdi = l->data; if (sdi->driver->dev_acquisition_stop) sdi->driver->dev_acquisition_stop(sdi, sdi); } /* TODO: Handle delayed stops. Need to iterate the event * sources... */ session->running = FALSE; unset_main_context(session); return ret; } if (g_hash_table_size(session->event_sources) == 0) stop_check_later(session); return SR_OK; }