From: Clemens Ladisch <clemens@ladisch.de>
To: Takashi Iwai <tiwai@suse.de>
Cc: alsa-devel@alsa-project.org, Martin Tarenskeen <m.tarenskeen@zonnet.nl>
Subject: [PATCH 2/2] amidi: fix timeout handling
Date: Sun, 10 Apr 2016 21:30:29 +0200 [thread overview]
Message-ID: <570AA9D5.4010708@ladisch.de> (raw)
In-Reply-To: <570AA980.3070802@ladisch.de>
The timeout is not supposed to expire when ignored messages are
received. This cannot be handled with the poll() timeout, so add
a separate timer.
Reported-by: Martin Tarenskeen <m.tarenskeen@zonnet.nl>
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
amidi/amidi.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 53 insertions(+), 16 deletions(-)
diff --git a/amidi/amidi.c b/amidi/amidi.c
index 4978249..a3515b1 100644
--- a/amidi/amidi.c
+++ b/amidi/amidi.c
@@ -25,9 +25,11 @@
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
+#include <math.h>
#include <getopt.h>
#include <errno.h>
#include <signal.h>
+#include <sys/timerfd.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <sys/stat.h>
@@ -37,6 +39,8 @@
#include "aconfig.h"
#include "version.h"
+#define NSEC_PER_SEC 1000000000L
+
static int do_device_list, do_rawmidi_list;
static char *port_name = "default";
static char *send_file_name;
@@ -46,7 +50,7 @@ static char *send_data;
static int send_data_length;
static int receive_file;
static int dump;
-static int timeout;
+static float timeout;
static int stop;
static snd_rawmidi_t *input, **inputp;
static snd_rawmidi_t *output, **outputp;
@@ -425,6 +429,7 @@ int main(int argc, char *argv[])
int c, err, ok = 0;
int ignore_system_realtime = 1;
int do_send_hex = 0;
+ struct itimerspec itimerspec = { .it_interval = { 0, 0 } };
while ((c = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
@@ -459,7 +464,7 @@ int main(int argc, char *argv[])
dump = 1;
break;
case 't':
- timeout = atoi(optarg);
+ timeout = atof(optarg);
break;
case 'a':
ignore_system_realtime = 0;
@@ -547,40 +552,64 @@ int main(int argc, char *argv[])
if (inputp) {
int read = 0;
- int npfds, time = 0;
+ int npfds;
struct pollfd *pfds;
- timeout *= 1000;
- npfds = snd_rawmidi_poll_descriptors_count(input);
+ npfds = 1 + snd_rawmidi_poll_descriptors_count(input);
pfds = alloca(npfds * sizeof(struct pollfd));
- snd_rawmidi_poll_descriptors(input, pfds, npfds);
+
+ if (timeout > 0) {
+ pfds[0].fd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (pfds[0].fd == -1) {
+ error("cannot create timer: %s", strerror(errno));
+ goto _exit;
+ }
+ pfds[0].events = POLLIN;
+ } else {
+ pfds[0].fd = -1;
+ }
+
+ snd_rawmidi_poll_descriptors(input, &pfds[1], npfds - 1);
+
signal(SIGINT, sig_handler);
+
+ if (timeout > 0) {
+ float timeout_int;
+
+ itimerspec.it_value.tv_nsec = modff(timeout, &timeout_int) * NSEC_PER_SEC;
+ itimerspec.it_value.tv_sec = timeout_int;
+ err = timerfd_settime(pfds[0].fd, 0, &itimerspec, NULL);
+ if (err < 0) {
+ error("cannot set timer: %s", strerror(errno));
+ goto _exit;
+ }
+ }
for (;;) {
unsigned char buf[256];
int i, length;
unsigned short revents;
- err = poll(pfds, npfds, 200);
+ err = poll(pfds, npfds, -1);
if (stop || (err < 0 && errno == EINTR))
break;
if (err < 0) {
error("poll failed: %s", strerror(errno));
break;
}
- if (err == 0) {
- time += 200;
- if (timeout && time >= timeout)
- break;
- continue;
- }
- if ((err = snd_rawmidi_poll_descriptors_revents(input, pfds, npfds, &revents)) < 0) {
+
+ err = snd_rawmidi_poll_descriptors_revents(input, &pfds[1], npfds - 1, &revents);
+ if (err < 0) {
error("cannot get poll events: %s", snd_strerror(errno));
break;
}
if (revents & (POLLERR | POLLHUP))
break;
- if (!(revents & POLLIN))
+ if (!(revents & POLLIN)) {
+ if (pfds[0].revents & POLLIN)
+ break;
continue;
+ }
+
err = snd_rawmidi_read(input, buf, sizeof(buf));
if (err == -EAGAIN)
continue;
@@ -595,7 +624,7 @@ int main(int argc, char *argv[])
if (length == 0)
continue;
read += length;
- time = 0;
+
if (receive_file != -1)
write(receive_file, buf, length);
if (dump) {
@@ -603,6 +632,14 @@ int main(int argc, char *argv[])
print_byte(buf[i]);
fflush(stdout);
}
+
+ if (timeout > 0) {
+ err = timerfd_settime(pfds[0].fd, 0, &itimerspec, NULL);
+ if (err < 0) {
+ error("cannot set timer: %s", strerror(errno));
+ break;
+ }
+ }
}
if (isatty(fileno(stdout)))
printf("\n%d bytes read\n", read);
next prev parent reply other threads:[~2016-04-10 19:30 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-04-10 19:29 [PATCH 1/2] amidi: ignore not only Active Sensing but all System Real-Time messages Clemens Ladisch
2016-04-10 19:30 ` Clemens Ladisch [this message]
2016-04-11 7:00 ` Ricard Wanderlof
2016-04-11 11:17 ` Martin Tarenskeen
2016-04-11 11:47 ` Martin Tarenskeen
2016-04-11 13:29 ` Clemens Ladisch
2016-04-11 13:41 ` Ricard Wanderlof
2016-04-11 14:13 ` Clemens Ladisch
2016-04-11 14:18 ` Ricard Wanderlof
2016-04-17 13:21 ` [PATCH v2 1/2] amidi: ignore not only Active Sensing but also Clock bytes Clemens Ladisch
2016-04-17 13:21 ` [PATCH v2 2/2] amidi: fix timeout handling Clemens Ladisch
-- strict thread matches above, loose matches on Subject: below --
2016-08-13 10:27 [PATCH 0/2] amidi: fix handling of ignored messages Clemens Ladisch
2016-08-13 10:29 ` [PATCH 2/2] amidi: fix timeout handling Clemens Ladisch
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=570AA9D5.4010708@ladisch.de \
--to=clemens@ladisch.de \
--cc=alsa-devel@alsa-project.org \
--cc=m.tarenskeen@zonnet.nl \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).