Currently we keep a file descriptor for each source and construct a pollfd array
from these during each loop iteration in sr_session_run(). This patch modifies
the code to keep a global pollfd array which is only modified when a source is
added or removed. On one hand this gets rid of the constant constructing and
subsequent freeing of the pollfd array in sr_session_run(), on the other hand it
will allow us to implement support for non-fd based pollfds.

Signed-off-by: Lars-Peter Clausen <[email protected]>
---
 libsigrok/session.c |   76 +++++++++++++++++++++++++++------------------------
 1 file changed, 40 insertions(+), 36 deletions(-)

diff --git a/libsigrok/session.c b/libsigrok/session.c
index 3590e49..419a8e7 100644
--- a/libsigrok/session.c
+++ b/libsigrok/session.c
@@ -29,8 +29,6 @@
 extern SR_PRIV GIOChannel channels[2];
 
 struct source {
-       int fd;
-       int events;
        int timeout;
        sr_receive_data_callback_t cb;
        void *cb_data;
@@ -41,7 +39,13 @@ struct source {
 struct sr_session *session;
 static int num_sources = 0;
 
+/* Both "sources" and "pollfds" are of the same size and contain pairs of
+ * descriptor and callback function. We can not embed the GPollFD into the
+ * source struct since we want to be able to pass the array of all poll
+ * descriptors to g_poll.
+ */
 static struct source *sources = NULL;
+static GPollFD *pollfds;
 static int source_timeout = -1;
 
 /**
@@ -207,49 +211,25 @@ SR_API int 
sr_session_datafeed_callback_add(sr_datafeed_callback_t cb)
  */
 static int sr_session_run_poll(void)
 {
-       GPollFD *fds, my_gpollfd;
        int ret, i;
 
-       fds = NULL;
        while (session->running) {
-               /* TODO: Add comment. */
-               g_free(fds);
-
-               /* Construct g_poll()'s array. */
-               if (!(fds = g_try_malloc(sizeof(GPollFD) * num_sources))) {
-                       /* Not enough memory, or num_sources was 0. */
-                       sr_err("session: %s: fds malloc failed "
-                              "(num_sources was %d).", __func__, num_sources);
-                       return SR_ERR_MALLOC;
-               }
-               for (i = 0; i < num_sources; i++) {
-#ifdef _WIN32
-                       g_io_channel_win32_make_pollfd(&channels[0],
-                                       sources[i].events, &my_gpollfd);
-#else
-                       my_gpollfd.fd = sources[i].fd;
-                       my_gpollfd.events = sources[i].events;
-                       fds[i] = my_gpollfd;
-#endif
-               }
-
-               ret = g_poll(fds, num_sources, source_timeout);
+               ret = g_poll(pollfds, num_sources, source_timeout);
 
                for (i = 0; i < num_sources; i++) {
-                       if (fds[i].revents > 0 || (ret == 0
+                       if (pollfds[i].revents > 0 || (ret == 0
                                && source_timeout == sources[i].timeout)) {
                                /*
                                 * Invoke the source's callback on an event,
                                 * or if the poll timeout out and this source
                                 * asked for that timeout.
                                 */
-                               if (!sources[i].cb(fds[i].fd, fds[i].revents,
+                               if (!sources[i].cb(pollfds[i].fd, 
pollfds[i].revents,
                                                  sources[i].cb_data))
-                                       sr_session_source_remove(sources[i].fd);
+                                       sr_session_source_remove(pollfds[i].fd);
                        }
                }
        }
-       g_free(fds);
 
        return SR_OK;
 }
@@ -326,7 +306,7 @@ SR_API int sr_session_run(void)
        session->running = TRUE;
 
        /* Do we have real sources? */
-       if (num_sources == 1 && sources[0].fd == -1) {
+       if (num_sources == 1 && pollfds[0].fd == -1) {
                /* Dummy source, freewheel over it. */
                while (session->running)
                        sources[0].cb(-1, 0, sources[0].cb_data);
@@ -497,6 +477,7 @@ SR_API int sr_session_source_add(int fd, int events, int 
timeout,
                sr_receive_data_callback_t cb, void *cb_data)
 {
        struct source *new_sources, *s;
+       GPollFD *new_pollfds, *p;
 
        if (!cb) {
                sr_err("session: %s: cb was NULL", __func__);
@@ -505,18 +486,31 @@ SR_API int sr_session_source_add(int fd, int events, int 
timeout,
 
        /* Note: cb_data can be NULL, that's not a bug. */
 
+       new_pollfds = g_try_realloc(pollfds, sizeof(GPollFD) * (num_sources + 
1));
+       if (!new_pollfds) {
+               sr_err("session: %s: new_sources malloc failed", __func__);
+               return SR_ERR_MALLOC;
+       }
+
        new_sources = g_try_realloc(sources, sizeof(struct source) * 
(num_sources + 1));
        if (!new_sources) {
                sr_err("session: %s: new_sources malloc failed", __func__);
                return SR_ERR_MALLOC;
        }
 
+       p = &new_pollfds[num_sources];
        s = &new_sources[num_sources++];
-       s->fd = fd;
-       s->events = events;
+#ifdef _WIN32
+       g_io_channel_win32_make_pollfd(&channels[0],
+                       events, p);
+#else
+       p->fd = fd;
+       p->events = events;
+#endif
        s->timeout = timeout;
        s->cb = cb;
        s->cb_data = cb_data;
+       pollfds = new_pollfds;
        sources = new_sources;
 
        if (timeout != source_timeout && timeout > 0
@@ -540,7 +534,8 @@ SR_API int sr_session_source_add(int fd, int events, int 
timeout,
 SR_API int sr_session_source_remove(int fd)
 {
        struct source *new_sources;
-       int old, new;
+       GPollFD *new_pollfds;
+       int old;
 
        if (!sources) {
                sr_err("session: %s: sources was NULL", __func__);
@@ -548,7 +543,7 @@ SR_API int sr_session_source_remove(int fd)
        }
 
        for (old = 0; old < num_sources; old++) {
-               if (sources[old].fd == fd)
+               if (pollfds[old].fd == fd)
                        break;
        }
 
@@ -559,16 +554,25 @@ SR_API int sr_session_source_remove(int fd)
        num_sources -= 1;
 
        if (old != num_sources) {
+               memmove(&pollfds[old], &pollfds[old+1],
+                       (num_sources - old) * sizeof(GPollFD));
                memmove(&sources[old], &sources[old+1],
                        (num_sources - old) * sizeof(struct source));
        }
 
-       new_sources = g_try_realloc(sources, sizeof(struct source) * 
(num_sources - 1));
+       new_pollfds = g_try_realloc(sources, sizeof(GPollFD) * num_sources);
+       if (!new_pollfds && num_sources > 0) {
+               sr_err("session: %s: new_sources malloc failed", __func__);
+               return SR_ERR_MALLOC;
+       }
+
+       new_sources = g_try_realloc(sources, sizeof(struct source) * 
num_sources);
        if (!new_sources && num_sources > 0) {
                sr_err("session: %s: new_sources malloc failed", __func__);
                return SR_ERR_MALLOC;
        }
 
+       pollfds = new_pollfds;
        sources = new_sources;
 
        return SR_OK;
-- 
1.7.10


------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
sigrok-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to