aboutsummaryrefslogtreecommitdiff
path: root/norns_shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'norns_shell.c')
-rw-r--r--norns_shell.c78
1 files changed, 60 insertions, 18 deletions
diff --git a/norns_shell.c b/norns_shell.c
index 386596e..425e605 100644
--- a/norns_shell.c
+++ b/norns_shell.c
@@ -16,8 +16,10 @@
#define SENTINEL_TIMEOUT (MS(1500))
#define SENTINEL_DELAY (MS(200))
+#define WAIT (MS(200))
+#define TOTAL_WAIT (S(2))
-int timespec_diff_gt(struct timespec *before, struct timespec *after, long ns)
+int time_diff_gt(struct timespec *before, struct timespec *after, long ns)
{
/* be careful not to overflow the long... */
long ss = ns / S(1) + 1;
@@ -102,7 +104,28 @@ int main (int argc, char **argv)
-- as a sentinel -- repeatedly until we get the corresponding
<ok>.
*/
+ /* Meanwhile, there are several different timeouts being checked
+ here:
+
+ 1) If nn_poll times out, it means the fd was neither writable
+ nor readable during the specified amount of time. This means
+ something's seriously wrong.
+ 2) If we don't receive a response to the sentinel within TIMEOUT,
+ this means the endpoint probably isn't responding, and there
+ may not be a server at the endpoint at all. We'll exit in this
+ case instead of leaving the user hanging forever.
+ 3) If we send the final message (i.e., if we got EOF), we'll exit
+ if we don't receive anything within WAIT of the last time we
+ received anything. This way we exit quickly if there's no more
+ responses, but if there's a flurry of quick responses we get them all.
+ 4) However, if the lua engine just keeps printing, then we don't
+ want to leave the user hanging forever. So if we sent the final
+ message (i.e., if we got EOF) more than TOTAL_WAIT ago, we exit.
+ */
int received = 0;
+ int sent_last = 0;
+ struct timespec input_ended = {0};
+ struct timespec last_received = {0};
struct timespec began = {0};
if (clock_gettime(CLOCK_MONOTONIC, &began)) {
fprintf(stderr, "Can't use the clock? %m\n");
@@ -111,18 +134,30 @@ int main (int argc, char **argv)
struct timespec sent_sentinel = {0};
/* we'll also wait for one message after EOF... */
- int sent_last = 0;
struct nn_pollfd poll_s = { .fd = s, .events = NN_POLLIN | NN_POLLOUT };
while (!killed) {
+ struct timespec now = {0};
switch (nn_poll(&poll_s, 1, 1000)) {
case -1:
- fprintf(stderr, "error polling: %m\n");
+ fprintf(stderr, "Error polling: %m\n");
goto error;
case 0:
- fprintf(stderr, "# timeout...\n");
- break;
+ fprintf(stderr, "# poll timeout. something is probably wrong.\n");
+ goto error;
case 1:
+ if (clock_gettime(CLOCK_MONOTONIC, &now)) {
+ fprintf(stderr, "Can't use the clock? %m\n");
+ goto error;
+ }
+ /* If we've sent the last message and we're over the wait
+ since the last received message, exit. */
+ if (sent_last && time_diff_gt(&last_received, &now, WAIT))
+ goto finish;
+ /* If we've sent the last message and we're over the wait
+ since we ended, exit. */
+ if (sent_last && time_diff_gt(&input_ended, &now, TOTAL_WAIT))
+ goto finish;
/* If we can read, echo out the message (unless it's the
response to the sentinel, which we handle differently). */
if (poll_s.revents & NN_POLLIN) {
@@ -137,29 +172,30 @@ int main (int argc, char **argv)
fprintf(stderr, "# it lives!\n");
} else {
/* strip final newline, if there are two... */
- if (n >= 2 && buf[n - 1] == '\n' && buf[n - 2] == '\n')
+ if (n >= 2
+ && buf[n - 1] == '\n'
+ && buf[n - 2] == '\n')
n -= 1;
if (write(STDOUT_FILENO, buf, n) < n) {
fprintf(stderr, "Couldn't write: %m\n");
goto error;
}
- if (sent_last)
- goto finish;
}
+ /* TODO: maybe if we get a stacktrace we should set the
+ exit code? */
nn_freemsg(buf);
+ if (clock_gettime(CLOCK_MONOTONIC, &last_received)) {
+ fprintf(stderr, "Can't use the clock? %m\n");
+ goto error;
+ }
received = 1;
}
/* If we can write, see if there's a full line. */
if (poll_s.revents & NN_POLLOUT) {
if (!received) {
- struct timespec now = {0};
- if (clock_gettime(CLOCK_MONOTONIC, &now)) {
- fprintf(stderr, "Can't use the clock? %m\n");
- goto error;
- }
/* if we've been waiting on sentinel response and
haven't gotten anything, time out. */
- if (timespec_diff_gt(&began, &now, SENTINEL_TIMEOUT)) {
+ if (time_diff_gt(&began, &now, SENTINEL_TIMEOUT)) {
fprintf(stderr,
"# timed out.\n"
"# are you sure there's something "
@@ -168,9 +204,9 @@ int main (int argc, char **argv)
goto error;
}
/* only do this once every SENTINEL_DELAY... */
- if (!timespec_diff_gt(&sent_sentinel,
- &now,
- SENTINEL_DELAY))
+ if (!time_diff_gt(&sent_sentinel,
+ &now,
+ SENTINEL_DELAY))
break;
memcpy(&sent_sentinel, &now, sizeof(struct timespec));
@@ -189,7 +225,13 @@ int main (int argc, char **argv)
goto error;
}
}
- if (n == 0) sent_last = 1;
+ if (n == 0) {
+ sent_last = 1;
+ if (clock_gettime(CLOCK_MONOTONIC, &input_ended)) {
+ fprintf(stderr, "Can't use the clock? %m\n");
+ goto error;
+ }
+ }
/* treat EAGAIN as "read 0" */
if (n < 1) n = 0;
line_n += n;