202 lines
5.5 KiB
C
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);
|
|
}
|