From b7011015f4c011c75ac69c5bde87219263ff6dec Mon Sep 17 00:00:00 2001 From: Ivan Chikish Date: Thu, 26 Dec 2024 12:46:02 +0300 Subject: [PATCH] [C++] Further reduce memory usage (device vector) --- src/daemon.cpp | 11 +++---- src/device.cpp | 36 ++++++++++++---------- src/device.h | 4 +-- src/evloop.cpp | 82 ++++++++++++++++++++++++-------------------------- src/keyd.h | 7 ++--- 5 files changed, 67 insertions(+), 73 deletions(-) diff --git a/src/daemon.cpp b/src/daemon.cpp index 9e1dfcf..44bf67b 100644 --- a/src/daemon.cpp +++ b/src/daemon.cpp @@ -24,6 +24,7 @@ struct config_ent { static int ipcfd = -1; static std::shared_ptr vkbd; static std::unique_ptr configs; +extern std::vector device_table; static uint8_t keystate[256]; @@ -144,7 +145,7 @@ static void activate_leds(const struct keyboard *kbd) break; } - for (size_t i = 0; i < device_table_sz; i++) + for (size_t i = 0; i < device_table.size(); i++) if (device_table[i].data == kbd && (device_table[i].capabilities & CAP_LEDS)) { if (std::exchange(device_table[i].led_state[ind], active_layers) == active_layers) continue; @@ -154,7 +155,7 @@ static void activate_leds(const struct keyboard *kbd) static void restore_leds() { - for (size_t i = 0; i < device_table_sz; i++) { + for (size_t i = 0; i < device_table.size(); i++) { struct device* dev = &device_table[i]; if (dev->grabbed && dev->data && (dev->capabilities & CAP_LEDS)) { for (int j = 0; j < LED_CNT; j++) { @@ -283,7 +284,7 @@ static void reload(std::shared_ptr env) restore_leds(); load_configs(); - for (size_t i = 0; i < device_table_sz; i++) + for (size_t i = 0; i < device_table.size(); i++) manage_device(&device_table[i]); clear_vkbd(); @@ -632,13 +633,11 @@ static int event_handler(struct event *ev) break; } } else if (ev->dev->is_virtual && ev->devev->type == DEV_LED) { - size_t i; - /* * Propagate LED events received by the virtual device from userspace * to all grabbed devices. */ - for (i = 0; i < device_table_sz; i++) { + for (size_t i = 0; i < device_table.size(); i++) { ::device& dev = device_table[i]; if (dev.data && (dev.capabilities & CAP_LEDS)) { struct keyboard* kbd = (struct keyboard*)dev.data; diff --git a/src/device.cpp b/src/device.cpp index 680db76..3cef2d8 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -216,41 +216,45 @@ static void *device_scan_worker(void *arg) return &w->dev; } -int device_scan(struct device devices[MAX_DEVICES]) +void device_scan(std::vector& devices) { - int i; - struct device_worker workers[MAX_DEVICES]; - struct dirent *ent; + devices.clear(); + struct device_worker workers[16]; // Ring buffer DIR *dh = opendir("/dev/input/"); - int n = 0, ndevs; + size_t n = 0; if (!dh) { perror("opendir /dev/input"); exit(-1); } - while((ent = readdir(dh))) { + auto join = [&] (size_t n) { + struct device *d; + struct device_worker *w = &workers[n % std::size(workers)]; + pthread_join(w->tid, (void**)&d); + if (d) + devices.emplace_back(std::move(w->dev)); + }; + + while (struct dirent* ent = readdir(dh)) { if (ent->d_type != DT_DIR && !strncmp(ent->d_name, "event", 5)) { - assert(n < MAX_DEVICES); - struct device_worker *w = &workers[n++]; + struct device_worker *w = &workers[n % std::size(workers)]; + if (n >= std::size(workers)) { + join(n); + } w->dev = {}; w->dev.num = atoi(ent->d_name + 5); pthread_create(&w->tid, NULL, device_scan_worker, w); + n++; } } - ndevs = 0; - for(i = 0; i < n; i++) { - struct device *d; - pthread_join(workers[i].tid, (void**)&d); - - if (d) - devices[ndevs++] = workers[i].dev; + for (size_t i = n % std::size(workers); i < n; i++) { + join(i); } closedir(dh); - return ndevs; } /* diff --git a/src/device.h b/src/device.h index ae22976..e9627cc 100644 --- a/src/device.h +++ b/src/device.h @@ -13,8 +13,6 @@ #define CAP_KEYBOARD 0x4 #define CAP_LEDS 0x8 -#define MAX_DEVICES 64 - struct device { /* * A file descriptor that can be used to monitor events subsequently read with @@ -68,7 +66,7 @@ struct device_event { struct device_event *device_read_event(struct device *dev); -int device_scan(struct device devices[MAX_DEVICES]); +void device_scan(std::vector& devices); int device_grab(struct device *dev); int device_ungrab(struct device *dev); diff --git a/src/evloop.cpp b/src/evloop.cpp index 9de4342..e316d9d 100644 --- a/src/evloop.cpp +++ b/src/evloop.cpp @@ -2,11 +2,8 @@ #define MAX_AUX_FDS 32 -static int aux_fds[MAX_AUX_FDS]; -static size_t nr_aux_fds = 0; - -struct device device_table[MAX_DEVICES]; -size_t device_table_sz; +static int aux_fd = -1; +std::vector device_table; static void panic_check(uint8_t code, uint8_t pressed) { @@ -40,14 +37,14 @@ int evloop(int (*event_handler) (struct event *ev)) int timeout = 0; int monfd; - struct pollfd pfds[MAX_DEVICES+MAX_AUX_FDS+1]; + struct pollfd pfds[130]{}; // TODO: fix hard limit but calling poll with too many descriptors is inefficient anyway - struct event ev; + struct event ev{}; monfd = devmon_create(); - device_table_sz = device_scan(device_table); + device_scan(device_table); - for (i = 0; i < device_table_sz; i++) { + for (i = 0; i < device_table.size(); i++) { ev.type = EV_DEV_ADD; ev.dev = &device_table[i]; @@ -55,38 +52,39 @@ int evloop(int (*event_handler) (struct event *ev)) } bool monitor = true; - for (i = 0; i < device_table_sz; i++) { + for (i = 0; i < device_table.size(); i++) { if (device_table[i].grabbed) { monitor = false; break; } } + pfds[0].fd = monfd; + pfds[0].events = POLLIN; + pfds[1].fd = aux_fd; + pfds[1].events = POLLIN; + auto pfdsd = pfds + 2; + while (1) { int removed = 0; int start_time; int elapsed; - pfds[0].fd = monfd; - pfds[0].events = POLLIN; - - for (i = 0; i < device_table_sz; i++) { - pfds[i+1].fd = device_table[i].fd; - pfds[i+1].events = 0; + for (i = 0; i < device_table.size(); i++) { + if (i == std::size(pfds) - (pfdsd - pfds)) { + break; + } + pfdsd[i].fd = device_table[i].fd; + pfdsd[i].events = 0; if (monitor || device_table[i].grabbed) - pfds[i+1].events = POLLIN; + pfdsd[i].events = POLLIN; else if (device_table[i].capabilities & CAP_KEYBOARD && device_table[i].is_virtual) - pfds[i+1].events = POLLIN; - } - - for (i = 0; i < nr_aux_fds; i++) { - pfds[i+device_table_sz+1].fd = aux_fds[i]; - pfds[i+device_table_sz+1].events = POLLIN | POLLERR; + pfdsd[i].events = POLLIN; } start_time = get_time_ms(); - poll(pfds, device_table_sz+nr_aux_fds+1, timeout > 0 ? timeout : -1); + poll(pfds, i + (pfdsd - pfds), timeout > 0 ? timeout : -1); ev.timestamp = get_time_ms(); elapsed = ev.timestamp - start_time; @@ -99,11 +97,12 @@ int evloop(int (*event_handler) (struct event *ev)) timeout -= elapsed; } - for (i = 0; i < device_table_sz; i++) { - if (pfds[i+1].revents) { + // Count backwards + for (; i + 1; i--) { + if (pfdsd[i].revents) { struct device_event *devev = nullptr; - while ((pfds[i+1].revents & (POLLERR | POLLHUP)) || (devev = device_read_event(&device_table[i]))) { + while ((pfdsd[i].revents & (POLLERR | POLLHUP)) || (devev = device_read_event(&device_table[i]))) { if (!devev || devev->type == DEV_REMOVED) { ev.type = EV_DEV_REMOVE; ev.dev = &device_table[i]; @@ -128,12 +127,10 @@ int evloop(int (*event_handler) (struct event *ev)) } } - for (i = 0; i < nr_aux_fds; i++) { - short events = pfds[i+device_table_sz+1].revents; - - if (events) { + { + if (auto events = pfds[1].revents) { ev.type = events & POLLERR ? EV_FD_ERR : EV_FD_ACTIVITY; - ev.fd = aux_fds[i]; + ev.fd = aux_fd; timeout = event_handler(&ev); } @@ -143,23 +140,22 @@ int evloop(int (*event_handler) (struct event *ev)) if (pfds[0].revents) { struct device dev; while (devmon_read_device(monfd, &dev) == 0) { - assert(device_table_sz < MAX_DEVICES); - device_table[device_table_sz++] = dev; + if (device_table.size() >= std::size(pfds) - 2) { + err("Too many devices, some of them will be ignored."); + } + device_table.emplace_back(std::move(dev)); ev.type = EV_DEV_ADD; - ev.dev = &device_table[device_table_sz-1]; + ev.dev = &device_table.back(); timeout = event_handler(&ev); } } if (removed) { - size_t n = 0; - for (i = 0; i < device_table_sz; i++) { - if (device_table[i].fd != -1) - device_table[n++] = device_table[i]; - } - device_table_sz = n; + std::erase_if(device_table, [](device& dev) { + return dev.fd < 0; + }); } } @@ -169,6 +165,6 @@ int evloop(int (*event_handler) (struct event *ev)) void evloop_add_fd(int fd) { - assert(nr_aux_fds < MAX_AUX_FDS); - aux_fds[nr_aux_fds++] = fd; + assert(aux_fd < 0); + aux_fd = fd; } diff --git a/src/keyd.h b/src/keyd.h index 38c5cfd..8dbece1 100644 --- a/src/keyd.h +++ b/src/keyd.h @@ -103,9 +103,6 @@ bool xread(int fd, void *buf, size_t sz); int ipc_create_server(); int ipc_connect(); -extern struct device device_table[MAX_DEVICES]; -extern size_t device_table_sz; - // One-time file reader struct file_reader { @@ -128,7 +125,7 @@ struct file_reader T result; size_t rd = 0; V buf[4096]; - while ((rd = read(this->fd, buf, sizeof(buf))) <= sizeof(buf)) { + while (fd >= 0 && (rd = read(this->fd, buf, sizeof(buf))) <= sizeof(buf)) { if (rd == 0) break; // Unimplemented, but won't happen for single-byte types @@ -141,7 +138,7 @@ struct file_reader void reset() { - if (lseek(fd, 0, SEEK_SET) < 0) + if (fd >= 0 && lseek(fd, 0, SEEK_SET) < 0) perror("file_reader::lseek"); }