]> sigrok.org Git - libsigrok.git/blobdiff - session.c
drivers: return SR_ERR_NA on unsupported config key
[libsigrok.git] / session.c
index 7bff474b0aeb982afe448e5e3a73e12dfd5f4ade..acf1158b4e3ad0e75061c4aa9ab831f5c5aadbd1 100644 (file)
--- a/session.c
+++ b/session.c
@@ -79,6 +79,8 @@ SR_API struct sr_session *sr_session_new(void)
        }
 
        session->source_timeout = -1;
+       session->abort_session = FALSE;
+       g_mutex_init(&session->stop_mutex);
 
        return session;
 }
@@ -101,16 +103,54 @@ SR_API int sr_session_destroy(void)
 
        /* TODO: Error checks needed? */
 
+       g_mutex_clear(&session->stop_mutex);
+
        g_free(session);
        session = NULL;
 
        return SR_OK;
 }
 
+/**
+ * Close a device instance.
+ *
+ * @param sdi The device instance to close. Must not be NULL. Also,
+ *            sdi->driver, sdi->driver->priv, and sdi->priv must not be NULL.
+ */
 static void sr_dev_close(struct sr_dev_inst *sdi)
 {
-       if (sdi->driver && sdi->driver->dev_close)
-               sdi->driver->dev_close(sdi);
+       int ret;
+
+       if (!sdi) {
+               sr_err("Invalid device instance, can't close device.");
+               return;
+       }
+
+       /* In the drivers sdi->priv is a 'struct dev_context *devc'. */
+       if (!sdi->priv) {
+               /*
+                * Should be sr_err() in theory, but the 'demo' driver has
+                * NULL for sdi->priv, so we use sr_dbg() until that's fixed.
+                */
+               sr_dbg("Invalid device context, can't close device.");
+               return;
+       }
+
+       if (!sdi->driver) {
+               sr_err("Invalid driver, can't close device.");
+               return;
+       }
+
+       if (!sdi->driver->priv) {
+               sr_err("Driver not initialized, can't close device.");
+               return;
+       }
+
+       sr_spew("Closing '%s' device instance %d.", sdi->driver->name,
+               sdi->index);
+
+       if ((ret = sdi->driver->dev_close(sdi)) < 0)
+               sr_err("Failed to close device instance: %d.", ret);
 }
 
 /**
@@ -247,6 +287,16 @@ static int sr_session_run_poll(void)
                                                session->sources[i].cb_data))
                                        sr_session_source_remove(session->sources[i].poll_object);
                        }
+                       /*
+                        * We want to take as little time as possible to stop
+                        * the session if we have been told to do so. Therefore,
+                        * we check the flag after processing every source, not
+                        * just once per main event loop.
+                        */
+                       g_mutex_lock(&session->stop_mutex);
+                       if (session->abort_session)
+                               sr_session_stop_sync();
+                       g_mutex_unlock(&session->stop_mutex);
                }
        }
 
@@ -278,7 +328,7 @@ SR_API int sr_session_start(void)
                return SR_ERR_BUG;
        }
 
-       sr_info("session: starting");
+       sr_info("Starting.");
 
        ret = SR_OK;
        for (l = session->devs; l; l = l->next) {
@@ -330,29 +380,18 @@ SR_API int sr_session_run(void)
        return SR_OK;
 }
 
-/**
- * Halt the current session.
- *
- * This function is deprecated and should not be used in new code, use
- * sr_session_stop() instead. The behaviour of this function is identical to
- * sr_session_stop().
- *
- * @return SR_OK upon success, SR_ERR_BUG if no session exists.
- */
-SR_API int sr_session_halt(void)
-{
-       return sr_session_stop();
-}
-
 /**
  * Stop the current session.
  *
  * The current session is stopped immediately, with all acquisition sessions
  * being stopped and hardware drivers cleaned up.
  *
+ * This must be called from within the session thread, to prevent freeing
+ * resources that the session thread will try to use.
+ *
  * @return SR_OK upon success, SR_ERR_BUG if no session exists.
  */
-SR_API int sr_session_stop(void)
+SR_PRIV int sr_session_stop_sync(void)
 {
        struct sr_dev_inst *sdi;
        GSList *l;
@@ -384,6 +423,33 @@ SR_API int sr_session_stop(void)
        return SR_OK;
 }
 
+/**
+ * Stop the current session.
+ *
+ * The current session is stopped immediately, with all acquisition sessions
+ * being stopped and hardware drivers cleaned up.
+ *
+ * If the session is run in a separate thread, this function will not block
+ * until the session is finished executing. It is the caller's responsibility
+ * to wait for the session thread to return before assuming that the session is
+ * completely decommissioned.
+ *
+ * @return SR_OK upon success, SR_ERR_BUG if no session exists.
+ */
+SR_API int sr_session_stop(void)
+{
+       if (!session) {
+               sr_err("%s: session was NULL", __func__);
+               return SR_ERR_BUG;
+       }
+
+       g_mutex_lock(&session->stop_mutex);
+       session->abort_session = TRUE;
+       g_mutex_unlock(&session->stop_mutex);
+
+       return SR_OK;
+}
+
 /**
  * Debug helper.
  *