fixed segfault when starting and stoping the event hook too quickly, it was a data race

This commit is contained in:
caue 2020-03-30 02:24:38 -03:00
parent e047a93060
commit 6c9e89be03
3 changed files with 45 additions and 90 deletions

View File

@ -16,6 +16,9 @@
#include <stdlib.h> #include <stdlib.h>
#include "pub.h" #include "pub.h"
#include "../chan/eb_chan.h" #include "../chan/eb_chan.h"
void dispatch_proc(iohook_event * const event);
eb_chan events; eb_chan events;
void go_send(char*); void go_send(char*);
@ -24,10 +27,15 @@ void go_sleep(void);
bool sending = false; bool sending = false;
void startev(){ void startev(){
// puts("start_ev");
events = eb_chan_create(1024); events = eb_chan_create(1024);
eb_chan_retain(events); eb_chan_retain(events);
sending = true; sending = true;
add_event("q"); // add_event("q");
hook_set_logger(&loggerProc);
hook_set_dispatch_proc(&dispatch_proc);
hook_run();
// puts("done_ev");
} }
void pollEv(){ void pollEv(){
@ -116,89 +124,6 @@ void dispatch_proc(iohook_event * const event) {
// fprintf(stdout, "----%s\n", buffer); // fprintf(stdout, "----%s\n", buffer);
} }
int add_event(char *key_event) {
cevent = key_event;
// Set the logger callback for library output.
hook_set_logger(&loggerProc);
// Set the event callback for IOhook events.
hook_set_dispatch_proc(&dispatch_proc);
// Start the hook and block.
// NOTE If EVENT_HOOK_ENABLED was delivered, the status will always succeed.
int status = hook_run();
switch (status) {
case IOHOOK_SUCCESS:
// Everything is ok.
break;
// System level errors.
case IOHOOK_ERROR_OUT_OF_MEMORY:
loggerProc(LOG_LEVEL_ERROR, "Failed to allocate memory. (%#X)", status);
break;
// X11 specific errors.
case IOHOOK_ERROR_X_OPEN_DISPLAY:
loggerProc(LOG_LEVEL_ERROR, "Failed to open X11 display. (%#X)", status);
break;
case IOHOOK_ERROR_X_RECORD_NOT_FOUND:
loggerProc(LOG_LEVEL_ERROR, "Unable to locate XRecord extension. (%#X)", status);
break;
case IOHOOK_ERROR_X_RECORD_ALLOC_RANGE:
loggerProc(LOG_LEVEL_ERROR, "Unable to allocate XRecord range. (%#X)", status);
break;
case IOHOOK_ERROR_X_RECORD_CREATE_CONTEXT:
loggerProc(LOG_LEVEL_ERROR, "Unable to allocate XRecord context. (%#X)", status);
break;
case IOHOOK_ERROR_X_RECORD_ENABLE_CONTEXT:
loggerProc(LOG_LEVEL_ERROR, "Failed to enable XRecord context. (%#X)", status);
break;
// Windows specific errors.
case IOHOOK_ERROR_SET_WINDOWS_HOOK_EX:
loggerProc(LOG_LEVEL_ERROR, "Failed to register low level windows hook. (%#X)", status);
break;
// Darwin specific errors.
case IOHOOK_ERROR_AXAPI_DISABLED:
loggerProc(LOG_LEVEL_ERROR, "Failed to enable access for assistive devices. (%#X)", status);
break;
case IOHOOK_ERROR_CREATE_EVENT_PORT:
loggerProc(LOG_LEVEL_ERROR, "Failed to create apple event port. (%#X)", status);
break;
case IOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE:
loggerProc(LOG_LEVEL_ERROR, "Failed to create apple run loop source. (%#X)", status);
break;
case IOHOOK_ERROR_GET_RUNLOOP:
loggerProc(LOG_LEVEL_ERROR, "Failed to acquire apple run loop. (%#X)", status);
break;
case IOHOOK_ERROR_CREATE_OBSERVER:
loggerProc(LOG_LEVEL_ERROR, "Failed to create apple run loop observer. (%#X)", status);
break;
// Default error.
case IOHOOK_FAILURE:
default:
loggerProc(LOG_LEVEL_ERROR, "An unknown hook error occurred. (%#X)", status);
break;
}
// return status;
// printf("%d\n", status);
return cstatus;
}
int stop_event(){ int stop_event(){
int status = hook_stop(); int status = hook_stop();
switch (status) { switch (status) {

View File

@ -28,6 +28,7 @@ func go_send(s *C.char) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// log.Print("sending stuff")
//todo: maybe make non-bloking //todo: maybe make non-bloking
ev <- out ev <- out
} }

41
hook.go
View File

@ -77,6 +77,7 @@ var (
keys = map[int][]uint16{} keys = map[int][]uint16{}
cbs = map[int]func(Event){} cbs = map[int]func(Event){}
events = map[uint8][]int{} events = map[uint8][]int{}
grOn = 0
) )
//from robotgo //from robotgo
@ -213,11 +214,15 @@ func Process(EvChan <-chan Event) (out chan bool) {
pressed[ev.Keycode] = false pressed[ev.Keycode] = false
} }
for _, v := range events[ev.Kind] { for _, v := range events[ev.Kind] {
if !asyncon {
break
}
if allPressed(pressed, keys[v]...) { if allPressed(pressed, keys[v]...) {
cbs[v](ev) cbs[v](ev)
} }
} }
} }
// fmt.Println("exiting after end (process)")
out <- true out <- true
}() }()
return out return out
@ -264,16 +269,32 @@ func KeychartoRawcode(kc string) uint16 {
// Adds global event hook to OS // Adds global event hook to OS
// returns event channel // returns event channel
func Start() chan Event { func Start() chan Event {
asyncon = true for grOn != 0 {
// fmt.Println("wating for goroutines to end")
time.After(50 * time.Millisecond)
}
ev = make(chan Event, 1024) ev = make(chan Event, 1024)
go C.startev()
go func() { go func() {
grOn += 1
C.startev()
grOn -= 1
// fmt.Println("exiting after end (C.startev)")
}()
// fmt.Println("started ev")
asyncon = true
go func() {
grOn += 1
for { for {
C.pollEv()
time.Sleep(time.Millisecond * 50)
//todo: find smallest time that does not destroy the cpu utilization
if !asyncon { if !asyncon {
// fmt.Println("exiting after end (start)")
grOn -= 1
return return
} else {
// fmt.Println("polling events")
C.pollEv()
time.Sleep(time.Millisecond * 50)
//todo: find smallest time that does not destroy the cpu utilization
} }
} }
}() }()
@ -282,13 +303,21 @@ func Start() chan Event {
// End removes global event hook // End removes global event hook
func End() { func End() {
asyncon = false
C.endPoll() C.endPoll()
C.stop_event() C.stop_event()
for len(ev) != 0 { for len(ev) != 0 {
<-ev <-ev
} }
close(ev) close(ev)
asyncon = false pressed = make(map[uint16]bool, 256)
used = []int{}
keys = map[int][]uint16{}
cbs = map[int]func(Event){}
events = map[uint8][]int{}
// for grOn != 0 {
// time.After(time.Millisecond * 50)
// }
} }
// AddEvent add event listener // AddEvent add event listener