Merge branch 'async-ptmx'

This commit is contained in:
Daniel Eklöf 2019-11-03 01:26:42 +01:00
commit e1b6aa87fb
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
12 changed files with 210 additions and 88 deletions

8
csi.c
View file

@ -325,7 +325,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
case 0: {
switch (final) {
case 'c':
vt_to_slave(term, "\033[?6c", 5);
term_to_slave(term, "\033[?6c", 5);
break;
case 'd': {
@ -690,7 +690,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
snprintf(reply, sizeof(reply), "\x1b[%d;%dR",
term->cursor.row + 1,
term->cursor.col + 1);
vt_to_slave(term, reply, strlen(reply));
term_to_slave(term, reply, strlen(reply));
break;
}
@ -910,7 +910,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
*/
char reply[32];
snprintf(reply, sizeof(reply), "\033[?%u;2$y", param);
vt_to_slave(term, reply, strlen(reply));
term_to_slave(term, reply, strlen(reply));
break;
}
@ -965,7 +965,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
break;
}
vt_to_slave(term, "\033[>41;347;0c", 12);
term_to_slave(term, "\033[>41;347;0c", 12);
break;
}

80
fdm.c
View file

@ -14,6 +14,7 @@
struct handler {
int fd;
int events;
fdm_handler_t callback;
void *callback_data;
bool deleted;
@ -78,6 +79,7 @@ fdm_add(struct fdm *fdm, int fd, int events, fdm_handler_t handler, void *data)
struct handler *fd_data = malloc(sizeof(*fd_data));
*fd_data = (struct handler) {
.fd = fd,
.events = events,
.callback = handler,
.callback_data = data,
.deleted = false,
@ -91,7 +93,7 @@ fdm_add(struct fdm *fdm, int fd, int events, fdm_handler_t handler, void *data)
};
if (epoll_ctl(fdm->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
LOG_ERRNO("failed to register FD with epoll");
LOG_ERRNO("failed to register FD=%d with epoll", fd);
free(fd_data);
tll_pop_back(fdm->fds);
return false;
@ -107,22 +109,23 @@ fdm_del_internal(struct fdm *fdm, int fd, bool close_fd)
return true;
tll_foreach(fdm->fds, it) {
if (it->item->fd == fd) {
if (epoll_ctl(fdm->epoll_fd, EPOLL_CTL_DEL, fd, NULL) < 0)
LOG_ERRNO("failed to unregister FD=%d from epoll", fd);
if (it->item->fd != fd)
continue;
if (close_fd)
close(it->item->fd);
if (epoll_ctl(fdm->epoll_fd, EPOLL_CTL_DEL, fd, NULL) < 0)
LOG_ERRNO("failed to unregister FD=%d from epoll", fd);
it->item->deleted = true;
if (fdm->is_polling)
tll_push_back(fdm->deferred_delete, it->item);
else
free(it->item);
if (close_fd)
close(it->item->fd);
tll_remove(fdm->fds, it);
return true;
}
it->item->deleted = true;
if (fdm->is_polling)
tll_push_back(fdm->deferred_delete, it->item);
else
free(it->item);
tll_remove(fdm->fds, it);
return true;
}
LOG_ERR("no such FD: %d", fd);
@ -141,6 +144,55 @@ fdm_del_no_close(struct fdm *fdm, int fd)
return fdm_del_internal(fdm, fd, false);
}
static bool
event_modify(struct fdm *fdm, struct handler *fd, int new_events)
{
if (new_events == fd->events)
return true;
struct epoll_event ev = {
.events = new_events,
.data = {.ptr = fd},
};
if (epoll_ctl(fdm->epoll_fd, EPOLL_CTL_MOD, fd->fd, &ev) < 0) {
LOG_ERRNO("failed to modify FD=%d with epoll (events 0x%08x -> 0x%08x)",
fd->fd, fd->events, new_events);
return false;
}
fd->events = new_events;
return true;
}
bool
fdm_event_add(struct fdm *fdm, int fd, int events)
{
tll_foreach(fdm->fds, it) {
if (it->item->fd != fd)
continue;
return event_modify(fdm, it->item, it->item->events | events);
}
LOG_ERR("FD=%d not registered with the FDM", fd);
return false;
}
bool
fdm_event_del(struct fdm *fdm, int fd, int events)
{
tll_foreach(fdm->fds, it) {
if (it->item->fd != fd)
continue;
return event_modify(fdm, it->item, it->item->events & ~events);
}
LOG_ERR("FD=%d not registered with the FDM", fd);
return false;
}
bool
fdm_poll(struct fdm *fdm)
{

3
fdm.h
View file

@ -13,4 +13,7 @@ bool fdm_add(struct fdm *fdm, int fd, int events, fdm_handler_t handler, void *d
bool fdm_del(struct fdm *fdm, int fd);
bool fdm_del_no_close(struct fdm *fdm, int fd);
bool fdm_event_add(struct fdm *fdm, int fd, int events);
bool fdm_event_del(struct fdm *fdm, int fd, int events);
bool fdm_poll(struct fdm *fdm);

View file

@ -258,7 +258,7 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
info->keypad_keys_mode != term->keypad_keys_mode)
continue;
vt_to_slave(term, info->seq, strlen(info->seq));
term_to_slave(term, info->seq, strlen(info->seq));
found_map = true;
term_reset_view(term);
@ -314,14 +314,14 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
char reply[1024];
snprintf(reply, sizeof(reply), "\x1b[27;%d;%d~", modify_param, sym);
vt_to_slave(term, reply, strlen(reply));
term_to_slave(term, reply, strlen(reply));
}
else {
if (effective_mods & alt)
vt_to_slave(term, "\x1b", 1);
term_to_slave(term, "\x1b", 1);
vt_to_slave(term, buf, count);
term_to_slave(term, buf, count);
}
term_reset_view(term);

18
osc.c
View file

@ -78,7 +78,7 @@ from_clipboard_cb(const char *text, size_t size, void *user)
assert(chunk != NULL);
assert(strlen(chunk) == 4);
vt_to_slave(term, chunk, 4);
term_to_slave(term, chunk, 4);
free(chunk);
ctx->idx = 0;
@ -98,7 +98,7 @@ from_clipboard_cb(const char *text, size_t size, void *user)
char *chunk = base64_encode((const uint8_t *)t, left / 3 * 3);
assert(chunk != NULL);
assert(strlen(chunk) % 4 == 0);
vt_to_slave(term, chunk, strlen(chunk));
term_to_slave(term, chunk, strlen(chunk));
free(chunk);
}
@ -120,9 +120,9 @@ osc_from_clipboard(struct terminal *term, const char *source)
if (src == 0)
return;
vt_to_slave(term, "\033]52;", 5);
vt_to_slave(term, &src, 1);
vt_to_slave(term, ";", 1);
term_to_slave(term, "\033]52;", 5);
term_to_slave(term, &src, 1);
term_to_slave(term, ";", 1);
struct clip_context ctx = {
.term = term,
@ -141,10 +141,10 @@ osc_from_clipboard(struct terminal *term, const char *source)
if (ctx.idx > 0) {
char res[4];
base64_encode_final(ctx.buf, ctx.idx, res);
vt_to_slave(term, res, 4);
term_to_slave(term, res, 4);
}
vt_to_slave(term, "\033\\", 2);
term_to_slave(term, "\033\\", 2);
}
static void
@ -343,7 +343,7 @@ osc_dispatch(struct terminal *term)
char reply[32];
snprintf(reply, sizeof(reply), "\033]4;%u;rgb:%02x/%02x/%02x\033\\",
idx, r, g, b);
vt_to_slave(term, reply, strlen(reply));
term_to_slave(term, reply, strlen(reply));
break;
}
@ -377,7 +377,7 @@ osc_dispatch(struct terminal *term)
reply, sizeof(reply), "\033]%u;rgb:%02x/%02x/%02x\033\\",
param, r, g, b);
vt_to_slave(term, reply, strlen(reply));
term_to_slave(term, reply, strlen(reply));
break;
}

View file

@ -533,7 +533,7 @@ static void
from_clipboard_cb(const char *data, size_t size, void *user)
{
struct terminal *term = user;
vt_to_slave(term, data, size);
term_to_slave(term, data, size);
}
void
@ -544,12 +544,12 @@ selection_from_clipboard(struct terminal *term, uint32_t serial)
return;
if (term->bracketed_paste)
vt_to_slave(term, "\033[200~", 6);
term_to_slave(term, "\033[200~", 6);
text_from_clipboard(term, serial, &from_clipboard_cb, term);
if (term->bracketed_paste)
vt_to_slave(term, "\033[201~", 6);
term_to_slave(term, "\033[201~", 6);
}
bool
@ -675,12 +675,12 @@ selection_from_primary(struct terminal *term)
return;
if (term->bracketed_paste)
vt_to_slave(term, "\033[200~", 6);
term_to_slave(term, "\033[200~", 6);
text_from_primary(term, &from_clipboard_cb, term);
if (term->bracketed_paste)
vt_to_slave(term, "\033[201~", 6);
term_to_slave(term, "\033[201~", 6);
}
#if 0

View file

@ -196,7 +196,6 @@ fdm_server(struct fdm *fdm, int fd, int events, void *data)
};
if (!fdm_add(server->fdm, client_fd, EPOLLIN, &fdm_client, client)) {
LOG_ERR("client FD=%d: failed to add client to FDM", client_fd);
close(client_fd);
free(client);
return false;
@ -321,10 +320,8 @@ server_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl)
.clients = tll_init(),
};
if (!fdm_add(fdm, fd, EPOLLIN, &fdm_server, server)) {
LOG_ERR("failed to add server FD to the FDM");
if (!fdm_add(fdm, fd, EPOLLIN, &fdm_server, server))
goto err;
}
return server;

View file

@ -26,15 +26,103 @@
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
enum ptmx_write_status {PTMX_WRITE_DONE, PTMX_WRITE_REMAIN, PTMX_WRITE_ERR};
static enum ptmx_write_status
to_slave(struct terminal *term, const void *_data, size_t len, size_t *idx)
{
const uint8_t *const data = _data;
size_t left = len - *idx;
while (left > 0) {
ssize_t ret = write(term->ptmx, &data[*idx], left);
if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
return PTMX_WRITE_REMAIN;
LOG_ERRNO("failed to write to client");
return PTMX_WRITE_ERR;
}
*idx += ret;
left -= left;
}
return PTMX_WRITE_DONE;
}
bool
term_to_slave(struct terminal *term, const void *_data, size_t len)
{
if (tll_length(term->ptmx_buffer) > 0) {
/* With a non-empty queue, EPOLLOUT has already been enabled */
goto enqueue_data;
}
switch (to_slave(term, _data, len, &(size_t){0})) {
case PTMX_WRITE_REMAIN:
if (!fdm_event_add(term->fdm, term->ptmx, EPOLLOUT))
return false;
goto enqueue_data;
case PTMX_WRITE_DONE: return true;
case PTMX_WRITE_ERR: return false;
}
enqueue_data:
{
void *copy = malloc(len);
memcpy(copy, _data, len);
struct ptmx_buffer queued = {
.data = copy,
.len = len,
.idx = 0,
};
tll_push_back(term->ptmx_buffer, queued);
}
return true;
}
static bool
fdm_ptmx_out(struct fdm *fdm, int fd, int events, void *data)
{
struct terminal *term = data;
assert(tll_length(term->ptmx_buffer) > 0);
tll_foreach(term->ptmx_buffer, it) {
switch (to_slave(term, it->item.data, it->item.len, &it->item.idx)) {
case PTMX_WRITE_DONE:
free(it->item.data);
tll_remove(term->ptmx_buffer, it);
break;
case PTMX_WRITE_REMAIN: return true; /* to_slave() updated it->item.idx */
case PTMX_WRITE_ERR: return false;
}
}
fdm_event_del(term->fdm, term->ptmx, EPOLLOUT);
return true;
}
static bool
fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
{
struct terminal *term = data;
if (events & EPOLLOUT) {
if (!fdm_ptmx_out(fdm, fd, events, data))
return false;
}
if ((events & EPOLLHUP) && !(events & EPOLLIN))
return term_shutdown(term);
assert(events & EPOLLIN);
if (!(events & EPOLLIN))
return true;
uint8_t buf[24 * 1024];
ssize_t count = read(term->ptmx, buf, sizeof(buf));
@ -328,25 +416,20 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
goto close_fds;
}
if (!fdm_add(fdm, ptmx, EPOLLIN, &fdm_ptmx, term)) {
LOG_ERR("failed to add ptmx to FDM");
int ptmx_flags;
if ((ptmx_flags = fcntl(ptmx, F_GETFL)) < 0 ||
fcntl(ptmx, F_SETFL, ptmx_flags | O_NONBLOCK) < 0)
{
LOG_ERRNO("failed to configure ptmx as non-blocking");
goto err;
}
if (!fdm_add(fdm, flash_fd, EPOLLIN, &fdm_flash, term)) {
LOG_ERR("failed to add flash timer FD to FDM");
goto err;
}
if (!fdm_add(fdm, blink_fd, EPOLLIN, &fdm_blink, term)) {
LOG_ERR("failed to add blink tiemr FD to FDM");
goto err;
}
if (!fdm_add(fdm, delay_lower_fd, EPOLLIN, &fdm_delayed_render, term) ||
if (!fdm_add(fdm, ptmx, EPOLLIN, &fdm_ptmx, term) ||
!fdm_add(fdm, flash_fd, EPOLLIN, &fdm_flash, term) ||
!fdm_add(fdm, blink_fd, EPOLLIN, &fdm_blink, term) ||
!fdm_add(fdm, delay_lower_fd, EPOLLIN, &fdm_delayed_render, term) ||
!fdm_add(fdm, delay_upper_fd, EPOLLIN, &fdm_delayed_render, term))
{
LOG_ERR("failed to add delayed rendering timer FDs to FDM");
goto err;
}
@ -355,6 +438,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
.fdm = fdm,
.quit = false,
.ptmx = ptmx,
.ptmx_buffer = tll_init(),
.cursor_keys_mode = CURSOR_KEYS_NORMAL,
.keypad_keys_mode = KEYPAD_NUMERICAL,
.auto_margin = true,
@ -538,7 +622,6 @@ term_shutdown(struct terminal *term)
}
if (!fdm_add(term->fdm, event_fd, EPOLLIN, &fdm_shutdown, term)) {
LOG_ERR("failed to add terminal shutdown event FD to the FDM");
close(event_fd);
return false;
}
@ -629,6 +712,10 @@ term_destroy(struct terminal *term)
assert(tll_length(term->render.workers.queue) == 0);
tll_free(term->render.workers.queue);
tll_foreach(term->ptmx_buffer, it)
free(it->item.data);
tll_free(term->ptmx_buffer);
int ret = EXIT_SUCCESS;
if (term->slave > 0) {
@ -1070,7 +1157,7 @@ term_focus_in(struct terminal *term)
{
if (!term->focus_events)
return;
vt_to_slave(term, "\033[I", 3);
term_to_slave(term, "\033[I", 3);
}
void
@ -1078,7 +1165,7 @@ term_focus_out(struct terminal *term)
{
if (!term->focus_events)
return;
vt_to_slave(term, "\033[O", 3);
term_to_slave(term, "\033[O", 3);
}
static int
@ -1152,7 +1239,7 @@ report_mouse_click(struct terminal *term, int encoded_button, int row, int col,
return;
}
vt_to_slave(term, response, strlen(response));
term_to_slave(term, response, strlen(response));
}
static void

View file

@ -145,6 +145,12 @@ enum mouse_reporting {
enum cursor_style { CURSOR_BLOCK, CURSOR_UNDERLINE, CURSOR_BAR };
struct ptmx_buffer {
void *data;
size_t len;
size_t idx;
};
struct terminal {
struct fdm *fdm;
@ -152,6 +158,8 @@ struct terminal {
int ptmx;
bool quit;
tll(struct ptmx_buffer) ptmx_buffer;
enum cursor_keys cursor_keys_mode;
enum keypad_keys keypad_keys_mode;
bool reverse;
@ -303,6 +311,7 @@ bool term_shutdown(struct terminal *term);
int term_destroy(struct terminal *term);
void term_reset(struct terminal *term, bool hard);
bool term_to_slave(struct terminal *term, const void *data, size_t len);
void term_damage_rows(struct terminal *term, int start, int end);
void term_damage_rows_in_view(struct terminal *term, int start, int end);

20
vt.c
View file

@ -1015,23 +1015,3 @@ vt_from_slave(struct terminal *term, const uint8_t *data, size_t len)
}
}
}
bool
vt_to_slave(struct terminal *term, const void *_data, size_t len)
{
const uint8_t *data = _data;
size_t left = len;
while (left > 0) {
ssize_t ret = write(term->ptmx, data, left);
if (ret < 0) {
LOG_ERRNO("failed to write to client");
return false;
}
data += ret;
left -= ret;
}
return true;
}

1
vt.h
View file

@ -6,7 +6,6 @@
#include "terminal.h"
void vt_from_slave(struct terminal *term, const uint8_t *data, size_t len);
bool vt_to_slave(struct terminal *term, const void *data, size_t len);
static inline int
vt_param_get(const struct terminal *term, size_t idx, int default_value)

View file

@ -522,14 +522,9 @@ wayl_init(struct fdm *fdm)
goto out;
}
int wl_fd = wl_display_get_fd(wayl->display);
if (!fdm_add(fdm, wl_fd, EPOLLIN, &fdm_wayl, wayl)) {
LOG_ERR("failed to register Wayland connection with the FDM");
goto out;
}
if (!fdm_add(fdm, wayl->kbd.repeat.fd, EPOLLIN, &fdm_repeat, wayl)) {
LOG_ERR("failed to register keyboard repeat timer with the FDM");
if (!fdm_add(fdm, wl_display_get_fd(wayl->display), EPOLLIN, &fdm_wayl, wayl) ||
!fdm_add(fdm, wayl->kbd.repeat.fd, EPOLLIN, &fdm_repeat, wayl))
{
goto out;
}