Skip to content

Commit

Permalink
serial: Use non-blocking reads in a polling loop
Browse files Browse the repository at this point in the history
Instead of doing blocking reads, which are not cancellable and therefore
cause deadlocks when the .shutdown callback is called, use a fast
polling loop with non-blocking reads.

This fixes the read thread not closing on shutdown.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
  • Loading branch information
pcercuei committed Dec 1, 2023
1 parent a288006 commit 4701693
Showing 1 changed file with 25 additions and 4 deletions.
29 changes: 25 additions & 4 deletions serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@
#include <iio/iio-lock.h>
#include <iio/iiod-client.h>

#include <ctype.h>
#include <errno.h>
#include <libserialport.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

struct iio_context_pdata {
struct sp_port *port;
struct iiod_client *iiod_client;

struct iio_context_params params;

bool shutdown;
};

struct iio_buffer_pdata {
Expand Down Expand Up @@ -149,17 +152,33 @@ static ssize_t serial_read_data(struct iiod_client_pdata *io_data,
char *buf, size_t len, unsigned int timeout_ms)
{
struct iio_context_pdata *pdata = (struct iio_context_pdata *) io_data;
long long time_left_ns = (long long)timeout_ms * 1000 * 1000;
const struct timespec ts = {
/* One millisecond */
.tv_nsec = 1 * 1000 * 1000,
};
enum sp_return sp_ret;
ssize_t ret;

sp_ret = sp_blocking_read_next(pdata->port, buf, len, timeout_ms);
ret = (ssize_t) libserialport_to_errno(sp_ret);
while (true) {
if (timeout_ms && time_left_ns <= 0)
break;

sp_ret = sp_nonblocking_read(pdata->port, buf, len);
ret = (ssize_t) libserialport_to_errno(sp_ret);
if (ret || pdata->shutdown)
break;

nanosleep(&ts, NULL);
time_left_ns -= ts.tv_nsec;
}

prm_dbg(&pdata->params, "Read returned %li: %.*s\n",
(long) ret, (int) ret, buf);

if (ret == 0) {
prm_err(&pdata->params, "sp_blocking_read_next has timed out\n");
if (!pdata->shutdown)
prm_err(&pdata->params, "serial_read_data has timed out\n");
return -ETIMEDOUT;
}

Expand All @@ -170,6 +189,8 @@ static void serial_shutdown(struct iio_context *ctx)
{
struct iio_context_pdata *ctx_pdata = iio_context_get_pdata(ctx);

ctx_pdata->shutdown = true;

iiod_client_destroy(ctx_pdata->iiod_client);
sp_close(ctx_pdata->port);
sp_free_port(ctx_pdata->port);
Expand Down

0 comments on commit 4701693

Please sign in to comment.