From 5aa046245391af3dcc606f21ea64e6e866f79e21 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Tue, 25 Oct 2022 23:26:12 +0100 Subject: [PATCH 1/2] Move serial cache from Canon to port library --- camlibs/canon/serial.c | 24 +++--------------------- libgphoto2_port/serial/unix.c | 24 ++++++++++++++++++++---- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/camlibs/canon/serial.c b/camlibs/canon/serial.c index 7d6b0f0fcd..24151d064c 100644 --- a/camlibs/canon/serial.c +++ b/camlibs/canon/serial.c @@ -218,28 +218,10 @@ serial_set_timeout (GPPort *gdev, int to) static int canon_serial_get_byte (GPPort *gdev) { - static unsigned char cache[512]; - static unsigned char *cachep = cache; - static unsigned char *cachee = cache; - int recv; - - /* if still data in cache, get it */ - if (cachep < cachee) { - return (int) *cachep++; - } - - recv = gp_port_read (gdev, (char *)cache, 1); - if (recv < 0) /* An error occurred */ + char byte; + if (gp_port_read (gdev, (char *)&byte, 1) < 0) return -1; - - cachep = cache; - cachee = cache + recv; - - if (recv) { - return (int) *cachep++; - } - - return -1; + return byte; } /* ------------------------- Frame-level processing ------------------------- */ diff --git a/libgphoto2_port/serial/unix.c b/libgphoto2_port/serial/unix.c index d751ed4d2a..5e033d21c0 100644 --- a/libgphoto2_port/serial/unix.c +++ b/libgphoto2_port/serial/unix.c @@ -184,6 +184,11 @@ struct _GPPortPrivateLibrary { int fd; /* Device handle */ int baudrate; /* Current speed */ + + /* Internal cache for faster reading */ + char cache[512]; + const char *cachep; + const char *cachee; }; static int gp_port_serial_check_speed (GPPort *dev); @@ -560,10 +565,21 @@ gp_port_serial_read (GPPort *dev, char *bytes, int size) /* FALLTHROUGH */ } } else { - /* Just read the bytes */ - now = read (dev->pl->fd, bytes, size - readen); - if (now < 0) - return GP_ERROR_IO_READ; + if (dev->pl->cachep == dev->pl->cachee) { + /* Cache is empty, fill it up. */ + now = read (dev->pl->fd, dev->pl->cache, sizeof(dev->pl->cache)); + if (now < 0) { + /* nothing more to read from the actual port */ + return GP_ERROR_IO_READ; + } + /* Reset cache pointers */ + dev->pl->cachep = dev->pl->cache; + dev->pl->cachee = dev->pl->cache + now; + } + /* read up to the required chunk size from cache */ + now = MIN(size - readen, dev->pl->cachee - dev->pl->cachep); + memcpy(bytes, dev->pl->cachep, now); + dev->pl->cachep += now; } bytes += now; readen += now; From f895c6f398ca0f0b67ca3cdc037c649dae1c5510 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Sun, 30 Oct 2022 17:54:33 +0000 Subject: [PATCH 2/2] Add fast branch that skips serial cache entirely --- libgphoto2_port/serial/unix.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/libgphoto2_port/serial/unix.c b/libgphoto2_port/serial/unix.c index 5e033d21c0..3fa5233012 100644 --- a/libgphoto2_port/serial/unix.c +++ b/libgphoto2_port/serial/unix.c @@ -517,7 +517,7 @@ gp_port_serial_read (GPPort *dev, char *bytes, int size) FD_ZERO (&readfs); FD_SET (dev->pl->fd, &readfs); - while (readen < size) { + while (size > 0) { /* Set timeout value within input loop */ timeout.tv_usec = (dev->timeout % 1000) * 1000; @@ -564,25 +564,30 @@ gp_port_serial_read (GPPort *dev, char *bytes, int size) /* Ok, we read 1 byte and it is 0xff */ /* FALLTHROUGH */ } + } else if (dev->pl->cachep == dev->pl->cachee && size >= sizeof(dev->pl->cache)) { + /* We're trying to read a chunk larger than the cache and the cache is empty. + In this case, skip the cache entirely and read as much as we can directly into the destination. */ + now = read (dev->pl->fd, bytes, size); + if (now < 0) + return GP_ERROR_IO_READ; } else { if (dev->pl->cachep == dev->pl->cachee) { - /* Cache is empty, fill it up. */ + /* We're reading only a few bytes and the cache is empty; fill it up. */ now = read (dev->pl->fd, dev->pl->cache, sizeof(dev->pl->cache)); - if (now < 0) { - /* nothing more to read from the actual port */ + if (now < 0) return GP_ERROR_IO_READ; - } /* Reset cache pointers */ dev->pl->cachep = dev->pl->cache; dev->pl->cachee = dev->pl->cache + now; } /* read up to the required chunk size from cache */ - now = MIN(size - readen, dev->pl->cachee - dev->pl->cachep); + now = MIN(size, dev->pl->cachee - dev->pl->cachep); memcpy(bytes, dev->pl->cachep, now); dev->pl->cachep += now; } bytes += now; readen += now; + size -= readen; } return readen;