Skip to content

Commit

Permalink
[C++] Further reduce memory usage (device vector)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nekotekina committed Dec 26, 2024
1 parent eb3c3c9 commit b701101
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 73 deletions.
11 changes: 5 additions & 6 deletions src/daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct config_ent {
static int ipcfd = -1;
static std::shared_ptr<struct vkbd> vkbd;
static std::unique_ptr<config_ent> configs;
extern std::vector<device> device_table;

static uint8_t keystate[256];

Expand Down Expand Up @@ -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;
Expand All @@ -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++) {
Expand Down Expand Up @@ -283,7 +284,7 @@ static void reload(std::shared_ptr<env_pack> 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();
Expand Down Expand Up @@ -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;
Expand Down
36 changes: 20 additions & 16 deletions src/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<device>& 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;
}

/*
Expand Down
4 changes: 1 addition & 3 deletions src/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<device>& devices);
int device_grab(struct device *dev);
int device_ungrab(struct device *dev);

Expand Down
82 changes: 39 additions & 43 deletions src/evloop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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> device_table;

static void panic_check(uint8_t code, uint8_t pressed)
{
Expand Down Expand Up @@ -40,53 +37,54 @@ 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];

event_handler(&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;

Expand All @@ -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];
Expand All @@ -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);
}
Expand All @@ -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;
});
}

}
Expand All @@ -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;
}
7 changes: 2 additions & 5 deletions src/keyd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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
Expand All @@ -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");
}

Expand Down

0 comments on commit b701101

Please sign in to comment.