Skip to content

Commit 971f11f

Browse files
committed
cdev: fix interrupt pid list maintenance
1 parent 8ecc2aa commit 971f11f

File tree

1 file changed

+44
-42
lines changed

1 file changed

+44
-42
lines changed

c_src/hal_cdev_gpio_interrupts.c

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,20 @@ static void init_listeners(struct gpio_monitor_info *infos)
3838
memset(infos, 0, MAX_GPIO_LISTENERS * sizeof(struct gpio_monitor_info));
3939
}
4040

41-
static void compact_listeners(struct gpio_monitor_info *infos, int count)
41+
static void compact_listeners(struct gpio_monitor_info *infos)
4242
{
43-
int j = -1;
44-
for (int i = 0; i < count - 1; i++) {
45-
if (infos[i].trigger == TRIGGER_NONE) {
46-
if (j >= 0) {
47-
memcpy(&infos[j], &infos[i], sizeof(struct gpio_monitor_info));
48-
memset(&infos[i], 0, sizeof(struct gpio_monitor_info));
49-
j++;
43+
int write_pos = 0;
44+
int read_pos;
45+
for (read_pos = 0; read_pos < MAX_GPIO_LISTENERS; read_pos++) {
46+
if (infos[read_pos].trigger != TRIGGER_NONE) {
47+
if (write_pos != read_pos) {
48+
memcpy(&infos[write_pos], &infos[read_pos], sizeof(struct gpio_monitor_info));
5049
}
51-
} else {
52-
if (j < 0)
53-
j = i;
50+
write_pos++;
5451
}
5552
}
53+
int remaining = MAX_GPIO_LISTENERS - write_pos;
54+
memset(&infos[write_pos], 0, remaining * sizeof(struct gpio_monitor_info));
5655
}
5756

5857
static int handle_gpio_update(ErlNifEnv *env,
@@ -63,7 +62,11 @@ static int handle_gpio_update(ErlNifEnv *env,
6362
debug("handle_gpio_update %d", info->offset);
6463
int value = event_id == GPIO_V2_LINE_EVENT_RISING_EDGE ? 1 : 0;
6564

66-
return send_gpio_message(env, info->gpio_spec, &info->pid, timestamp, value);
65+
// Convert true/false return to the typical 0/negative returns of this file
66+
if (send_gpio_message(env, info->gpio_spec, &info->pid, timestamp, value))
67+
return 0;
68+
else
69+
return -1;
6770
}
6871

6972
static int process_gpio_events(ErlNifEnv *env,
@@ -78,10 +81,10 @@ static int process_gpio_events(ErlNifEnv *env,
7881

7982
int num_events = amount_read / sizeof(struct gpio_v2_line_event);
8083
for (int i = 0; i < num_events; i++) {
81-
if (!handle_gpio_update(env,
82-
info,
83-
events[i].timestamp_ns,
84-
events[i].id)) {
84+
if (handle_gpio_update(env,
85+
info,
86+
events[i].timestamp_ns,
87+
events[i].id) < 0) {
8588
error("send for gpio %d failed, so not listening to it any more", info->offset);
8689
return -1;
8790
}
@@ -102,16 +105,16 @@ static void add_listener(ErlNifEnv *env, struct gpio_monitor_info *infos, const
102105

103106
static void remove_listener(struct gpio_monitor_info *infos, int fd)
104107
{
108+
debug("remove_listener fd=%d", fd);
109+
bool cleanup = false;
105110
for (int i = 0; i < MAX_GPIO_LISTENERS; i++) {
106-
if (infos[i].trigger == TRIGGER_NONE)
107-
return;
108-
109111
if (infos[i].fd == fd) {
110112
infos[i].trigger = TRIGGER_NONE;
111-
compact_listeners(infos, MAX_GPIO_LISTENERS);
112-
return;
113+
cleanup = true;
113114
}
114115
}
116+
if (cleanup)
117+
compact_listeners(infos);
115118
}
116119

117120
void *gpio_poller_thread(void *arg)
@@ -161,6 +164,23 @@ void *gpio_poller_thread(void *arg)
161164
// Socket closed so quit thread. This happens on NIF unload.
162165
break;
163166
}
167+
168+
bool cleanup = false;
169+
for (nfds_t i = 0; i < count - 1; i++) {
170+
short gpio_revents = fdset[i].revents;
171+
if (gpio_revents & POLLIN) {
172+
if (process_gpio_events(env, &monitor_info[i]) < 0) {
173+
error("error processing gpio events for %d", monitor_info[i].offset);
174+
monitor_info[i].trigger = TRIGGER_NONE;
175+
cleanup = true;
176+
}
177+
} else if (gpio_revents & (POLLERR | POLLHUP | POLLNVAL)) {
178+
error("error listening on gpio %d", monitor_info[i].offset);
179+
monitor_info[i].trigger = TRIGGER_NONE;
180+
cleanup = true;
181+
}
182+
}
183+
164184
if (revents & (POLLIN | POLLHUP)) {
165185
struct gpio_monitor_info message;
166186
ssize_t amount_read = read(*pipefd, &message, sizeof(message));
@@ -175,27 +195,9 @@ void *gpio_poller_thread(void *arg)
175195
remove_listener(monitor_info, message.fd);
176196
}
177197

178-
bool cleanup = false;
179-
for (nfds_t i = 0; i < count - 1; i++) {
180-
if (fdset[i].revents) {
181-
if (fdset[i].revents) {
182-
debug("interrupt on %d", monitor_info[i].offset);
183-
if (process_gpio_events(env, &monitor_info[i]) < 0) {
184-
monitor_info[i].trigger = TRIGGER_NONE;
185-
cleanup = true;
186-
}
187-
} else {
188-
error("error listening on gpio %d", monitor_info[i].offset);
189-
monitor_info[i].trigger = TRIGGER_NONE;
190-
cleanup = true;
191-
}
192-
}
193-
}
194-
195-
if (cleanup) {
196-
// Compact the listener list
197-
compact_listeners(monitor_info, count);
198-
}
198+
// Compact the listener list if any failed
199+
if (cleanup)
200+
compact_listeners(monitor_info);
199201
}
200202

201203
enif_free_env(env);

0 commit comments

Comments
 (0)