@@ -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
5857static 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
6972static 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
103106static 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
117120void * 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