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

