Files
my_device_handler/registries_items.c
2026-03-13 16:38:39 +01:00

202 lines
5.5 KiB
C

#include "registries_items.h"
#include <libevdev.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "events.h"
pthread_barrier_t all_devices_wrote_barrier;
pthread_barrier_t devices_write_new_round_barrier;
/* the spawning thread must reach the barrier and only after that, take the mutex
the spawned instead first takes the mutex and sets the flag, then releases the mutex and reach the barrier, thus allowing the spawning to get a consistent read
!!!
beware that if a signal reaches a waiting thread, that thread will handle the signal and then resume its wait unless such wait didn't complete in the meanwhile
!!! it is unspecified whether the other threads wait for the signaled thread
*/
pthread_barrier_t device_added_flag_barrier;
pthread_mutex_t device_added_flag_mutex = PTHREAD_MUTEX_INITIALIZER;
int device_added_flag;
pthread_mutex_t enqueue_events_mutex = PTHREAD_MUTEX_INITIALIZER;
/* nice struct from the phtread_create manpage example */
typedef struct { /* Used as argument to thread_start() */
pthread_t thread_id; /* ID returned by pthread_create() */
int thread_num; /* Application-defined thread # */
char *argv_string; /* From command-line argument */
} thread_info;
void initialize_device_added_flag_barrier(){
int anyerror = pthread_barrier_init( &device_added_flag_barrier, NULL, 2);
if(anyerror){
fprintf( stderr, "setup failed\n");
}
}
void* collecting_routine( void *args){
const char *path = (char*) args;
struct libevdev *dev = NULL;
int fd;
int rc = 1;
int open_error = 0;
struct input_event ev;
device_event *evt;
events_queue *queue;
fd = open( path, O_RDONLY|O_NONBLOCK);
rc = libevdev_new_from_fd( fd, &dev);
if (rc < 0) {
fprintf(stderr, "Failed to init libevdev for device (%s)\n", strerror(-rc));
fprintf(stderr, "[NEWBIE TIP] : try with sudo (maybe you don't have the rights for the EVDEVs)\n");
open_error = 1;
}
pthread_mutex_lock( &device_added_flag_mutex);
device_added_flag = ( !open_error);
pthread_mutex_unlock( &device_added_flag_mutex);
pthread_barrier_wait( &device_added_flag_barrier);
if( !open_error){
queue = events_queue_new();
printf( "Input device name: \"%s\"\n", libevdev_get_name( dev));
printf( "Input device ID: bus %#x vendor %#x product %#x\n",
libevdev_get_id_bustype( dev),
libevdev_get_id_vendor( dev),
libevdev_get_id_product( dev));
/*
if (!libevdev_has_event_type(dev, EV_REL) ||
!libevdev_has_event_code(dev, EV_KEY, BTN_LEFT)) {
printf("This device does not look like a mouse\n");
exit(1);
}
*/
do {
rc = libevdev_next_event( dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
/* RC = 1 should be SYN_DROPPED event */
if (rc == 0){
evt = malloc( sizeof( device_event));
evt->type = ev.type;
evt->code = ev.code;
evt->value = ev.value;
add_to_events_queue( queue, evt);
/*
printf("LIBEVDEV Event: %s %s %d\n",
libevdev_event_type_get_name( ev.type),
libevdev_event_code_get_name( ev.type, ev.code),
ev.value);
*/
}
if( rc == -EAGAIN){
/*
printf("lock %s\n", libevdev_get_name( dev));
*/
pthread_mutex_lock( &enqueue_events_mutex);
add_all_to_global_queue( queue);
pthread_mutex_unlock( &enqueue_events_mutex);
pthread_barrier_wait( &all_devices_wrote_barrier);
pthread_barrier_wait( &devices_write_new_round_barrier);
}
}
while ( rc == 1 || rc == 0 || rc == -EAGAIN);
}
return NULL;
}
/* !!! type defaults to INSERT */
pending_registry_request* pending_registry_request_new( const char *path){
pending_registry_request *req = malloc( sizeof( pending_registry_request));
req->path = malloc( ( 1 + strlen( path)) * sizeof( char));
strcpy( req->path, path);
return req;
}
void pending_registry_request_destroy( pending_registry_request *req){
free( req->path);
free( req);
}
active_registry_item* active_registry_item_dummy_new( const char *path){
active_registry_item* item = malloc( sizeof( active_registry_item));
item->path = malloc(( 1 + strlen( path)) * sizeof(char));
strcpy( item->path, path);
return item;
}
active_registry_item* active_registry_item_new( const char *path){
active_registry_item* item = active_registry_item_dummy_new( path);
/*HERE CREATE THE THREAD*/
thread_info th_info;
/*
all the thread attribute stuff has been postponed
SCHED(7)
Response time
A blocked high priority thread waiting for I/O has a certain response time before it is scheduled again. The device driver writer can greatly reduce this response time by using
a "slow interrupt" interrupt handler.
https://en.wikipedia.org/wiki/Interrupt_handler
*/
/* null implies default values */
const pthread_attr_t *attr = NULL;
int thread_create_failed = 1;
int device_add_error = 0;
thread_create_failed = pthread_create(
&th_info.thread_id,
attr,
collecting_routine,
(void *) path
);
if( thread_create_failed){
fprintf( stderr, "unable to create device polling thread\n");
exit(1);
}
pthread_barrier_wait( &device_added_flag_barrier);
pthread_mutex_lock( &device_added_flag_mutex);
device_add_error = ( !device_added_flag);
pthread_mutex_unlock( &device_added_flag_mutex);
if( device_add_error){
fprintf( stderr, "device polling thread failed to initialize its resources\n");
exit(1);
}
return item;
}
void active_registry_item_dummy_destroy(active_registry_item *item){
free( item->path);
free( item);
}
void active_registry_item_destroy( active_registry_item *item){
pthread_cancel( item->thread);
active_registry_item_dummy_destroy( item);
}