Add write_poll to improve tty_write and tty_sync

Implement blockable write with poll + nonblock write.
This commit is contained in:
yabu76 2025-12-30 20:19:26 +09:00
parent b5656112d7
commit eab0f6245b
4 changed files with 62 additions and 10 deletions

View file

@ -111,6 +111,40 @@ int read_poll(int fd, void *data, size_t len, int timeout)
return 0; return 0;
} }
ssize_t write_poll(int fd, void *data, size_t len, int timeout)
{
struct pollfd fds;
ssize_t ret = 0;
fds.events = POLLOUT;
fds.fd = fd;
/* Wait data available */
ret = poll(&fds, 1, timeout);
if (ret < 0)
{
tio_error_print("%s", strerror(errno));
return ret;
}
else if (ret > 0)
{
if (fds.revents & POLLOUT)
{
// Ready to write
// return value should not be 0
return write(fd, data, len);
}
else /* if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) */
{
return -1;
}
}
/* Timeout */
return 0;
}
// Function to calculate djb2 hash of string // Function to calculate djb2 hash of string
unsigned long djb2_hash(const unsigned char *str) unsigned long djb2_hash(const unsigned char *str)
{ {

View file

@ -24,6 +24,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#define WRITE_POLL_FOREVER (-1)
#define UNUSED(expr) do { (void)(expr); } while (0) #define UNUSED(expr) do { (void)(expr); } while (0)
void delay(long ms); void delay(long ms);
@ -32,6 +33,7 @@ bool regex_match(const char *string, const char *pattern);
unsigned long djb2_hash(const unsigned char *str); unsigned long djb2_hash(const unsigned char *str);
void *base62_encode(unsigned long num, char *output); void *base62_encode(unsigned long num, char *output);
int read_poll(int fd, void *data, size_t len, int timeout); int read_poll(int fd, void *data, size_t len, int timeout);
ssize_t write_poll(int fd, const void *data, size_t len, int timeout);
double get_current_time(void); double get_current_time(void);
bool match_patterns(const char *string, const char *patterns); bool match_patterns(const char *string, const char *patterns);
int execute_shell_command(int fd, const char *command); int execute_shell_command(int fd, const char *command);

View file

@ -312,7 +312,7 @@ static int api_write(lua_State *L)
do do
{ {
ret = write(device_fd, string, len); ret = write_poll(device_fd, string, len, WRITE_POLL_FOREVER);
if (ret < 0) if (ret < 0)
return luaL_error(L, "%s", strerror(errno)); return luaL_error(L, "%s", strerror(errno));

View file

@ -238,28 +238,43 @@ inline static unsigned char char_to_nibble(char c)
void tty_sync(int fd) void tty_sync(int fd)
{ {
/* If output_delay is valid, tty_buffer should be already empty.
* So this function doesn't consider output_delay options. */
ssize_t count; ssize_t count;
size_t remain = tty_buffer_count;
char *cp = tty_buffer;
while (tty_buffer_count > 0) while (remain > 0)
{ {
count = write(fd, tty_buffer, tty_buffer_count); count = write_poll(fd, cp, remain, WRITE_POLL_FOREVER);
if (count < 0) if (count < 0)
{ {
// Error // Error
tio_debug_printf("Write error while flushing tty buffer (%s)", strerror(errno)); tio_debug_printf("Write error while flushing tty buffer (%s)", strerror(errno));
break; break;
} }
tty_buffer_count -= count; cp += count;
remain -= count;
/* Reduce the number of additional sends */
if (remain > 0)
{
int estimated_sendtime_us = (int)((int64_t)count * 10 * 1000 * 1000 / option.baudrate);
if (estimated_sendtime_us > 300 * 1000)
usleep(300 * 1000);
else
usleep(estimated_sendtime_us);
}
}
fsync(fd); fsync(fd);
tcdrain(fd); tcdrain(fd);
}
// Reset // Reset
tty_buffer_write_ptr = tty_buffer; tty_buffer_write_ptr = tty_buffer;
tty_buffer_count = 0; tty_buffer_count = 0;
} }
ssize_t tty_write(int fd, const void *buffer, size_t count) ssize_t tty_write(int fd, void *buffer, size_t count)
{ {
ssize_t retval = 0, bytes_written = 0; ssize_t retval = 0, bytes_written = 0;
size_t i; size_t i;
@ -279,7 +294,7 @@ ssize_t tty_write(int fd, const void *buffer, size_t count)
// Write byte by byte with output delay // Write byte by byte with output delay
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
retval = write(fd, &cbuf[i], 1); retval = write_poll(fd, &cbuf[i], 1, WRITE_POLL_FOREVER);
if (retval < 0) if (retval < 0)
{ {
// Error // Error
@ -2526,7 +2541,7 @@ void forward_to_tty(int fd, char output_char)
/* Map newline character */ /* Map newline character */
if ((output_char == '\n' || output_char == '\r') && (option.map_o_nl_crnl)) if ((output_char == '\n' || output_char == '\r') && (option.map_o_nl_crnl))
{ {
const char *crlf = "\r\n"; char crlf[] = "\r\n";
optional_local_echo(crlf[0]); optional_local_echo(crlf[0]);
optional_local_echo(crlf[1]); optional_local_echo(crlf[1]);
@ -2730,7 +2745,7 @@ int tty_connect(void)
else if (ret > 0) else if (ret > 0)
{ {
// Forward to tty device // Forward to tty device
ret = write(device_fd, &input_char, 1); ret = write_poll(device_fd, &input_char, 1, WRITE_POLL_FOREVER);
if (ret < 0) if (ret < 0)
{ {
tio_error_printf("Could not write to serial device (%s)", strerror(errno)); tio_error_printf("Could not write to serial device (%s)", strerror(errno));
@ -2743,6 +2758,7 @@ int tty_connect(void)
break; break;
} }
} }
tty_sync(device_fd);
} }
/* Manage script activation */ /* Manage script activation */