From f01764a67e64bd48a6c21002bede62e995a76344 Mon Sep 17 00:00:00 2001 From: Antoine Rousseau <_antoine_@metalu.net> Date: Wed, 9 Oct 2024 12:07:37 +0200 Subject: [PATCH] on Linux and Mac, allow to lock the device with flock(), if it's already locked elsewhere then close it --- comport.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/comport.c b/comport.c index 426f301..520769d 100644 --- a/comport.c +++ b/comport.c @@ -43,6 +43,7 @@ JZ 20210321 allow the user to specify a device pattern as creation argument #include #include /* for ioctl DTR */ #include /* for TERMIO ioctl calls */ +#include /* for flock() */ #include #include #define HANDLE int @@ -74,6 +75,8 @@ typedef struct comport int comhandle; /* holds the comport handle */ struct termios oldcom_termio; /* save the old com config */ struct termios com_termio; /* for the new com config */ + t_bool x_lock; /* the file descriptor has to be locked when opened */ + t_bool x_locked; /* the file descriptor has been locked */ #endif /* device specifications */ @@ -933,6 +936,58 @@ static int set_break(t_comport *x, int on) return ((status < 0)? status: (on != 0)); } +static t_bool lock_fd(t_comport *x, int fd, int lock) +{ + int operation = (lock ? LOCK_EX : LOCK_UN) | LOCK_NB; + int ret; + + if((lock == x->x_locked) || (fd == INVALID_HANDLE_VALUE)) return 1; + ret = flock(fd, operation); + if(ret == 0) { + x->x_locked = lock; + } + return (ret == 0); +} + +static void check_lock(t_comport *x) +{ + if(x->x_lock) { + if(!lock_fd(x, x->comhandle, 1)) { + comport_verbose("[comport] file descriptor of %s is already locked, closing!\n", + x->serial_device->s_name); + comport_close(x); + } + } +} + +#if 0 +t_bool check_file_availability(const char *device_name) +{ + FILE *fp; + int status; + char buffer[256]; + + snprintf(buffer, sizeof(buffer), "fuser %s", device_name); + fp = popen(buffer, "r"); + if (fp == NULL) return 0; + + /*while (fgets(buffer, sizeof(buffer), fp) != NULL) + { + //printf("%s", buffer); + }*/ + + + status = pclose(fp); + if (status == -1) { + /* Error reported by pclose() */ + } else { + /* Use macros described under wait() to inspect `status' in order + to determine success/failure of command executed by popen() */ + } + return 1; +} +#endif + static int open_serial(unsigned int com_num, t_comport *x) { int fd; @@ -989,6 +1044,8 @@ static int open_serial(unsigned int com_num, t_comport *x) } globfree( &(glob_buffer) ); + //check_file_availability(x->serial_device->s_name); + if((fd = open(x->serial_device->s_name, OPENPARAMS)) == INVALID_HANDLE_VALUE) { pd_error(x, "[comport] ** ERROR ** could not open device %s:\n failure(%d): %s\n", @@ -1073,6 +1130,7 @@ static int close_serial(t_comport *x) if(fd != INVALID_HANDLE_VALUE) { + lock_fd(x, fd, 0); tcsetattr(fd, TCSANOW, tios); close(fd); comport_verbose("[comport] closed port %i (%s)", x->comport, x->serial_device->s_name); @@ -1480,6 +1538,9 @@ static void *comport_new(t_symbol *s, int argc, t_atom *argv) x->x_verbose = 0; x->x_inprocess = 0; +#ifndef _WIN32 + x->x_lock = x->x_locked = 0; +#endif return x; } @@ -1654,6 +1715,13 @@ static void comport_close(t_comport *x) if (x->x_status_outlet != NULL) outlet_float(x->x_status_outlet, (float)x->comport); } +static void comport_lock(t_comport *x, t_floatarg f) +{ +#ifndef _WIN32 + x->x_lock = (f != 0); +#endif +} + static void comport_open(t_comport *x, t_floatarg f) { if(x->comhandle != INVALID_HANDLE_VALUE) @@ -1662,6 +1730,9 @@ static void comport_open(t_comport *x, t_floatarg f) x->comhandle = open_serial(f,x); clock_delay(x->x_clock, x->x_deltime); +#ifndef _WIN32 + check_lock(x); +#endif } /* @@ -1677,6 +1748,9 @@ static void comport_devicename(t_comport *x, t_symbol *s) x->comhandle = open_serial(USE_DEVICENAME,x); clock_delay(x->x_clock, x->x_deltime); +#ifndef _WIN32 + check_lock(x); +#endif } static void comport_print(t_comport *x, t_symbol *s, int argc, t_atom *argv) @@ -1986,6 +2060,7 @@ void comport_setup(void) class_addmethod(comport_class, (t_method)comport_parity, gensym("parity"), A_FLOAT, 0); class_addmethod(comport_class, (t_method)comport_xonxoff, gensym("xonxoff"), A_FLOAT, 0); class_addmethod(comport_class, (t_method)comport_hupcl, gensym("hupcl"), A_FLOAT, 0); + class_addmethod(comport_class, (t_method)comport_lock, gensym("lock"), A_FLOAT, 0); class_addmethod(comport_class, (t_method)comport_close, gensym("close"), 0); class_addmethod(comport_class, (t_method)comport_open, gensym("open"), A_FLOAT, 0); class_addmethod(comport_class, (t_method)comport_devicename, gensym("devicename"), A_SYMBOL, 0);