diff --git a/dxinput/utils/button_map.c b/dxinput/utils/button_map.c index 65f9212..c9bcd34 100644 --- a/dxinput/utils/button_map.c +++ b/dxinput/utils/button_map.c @@ -12,6 +12,7 @@ #include "button_map.h" #include "type.h" +#include "x11_mutex.h" static int get_button_number(Display* disp, const char* name); static const XDeviceInfo* find_device_by_name(const XDeviceInfo* devs, @@ -20,8 +21,6 @@ static int get_device_button_number(const XDeviceInfo* dev); static unsigned char* do_get_button_map(Display* disp, unsigned long xid, int nbuttons); -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - unsigned char* get_button_map(unsigned long xid, const char* name, int* nbuttons) { @@ -37,14 +36,14 @@ get_button_map(unsigned long xid, const char* name, int* nbuttons) return NULL; } - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&x11_global_mutex); setErrorHandler(); Display* disp = XOpenDisplay(NULL); if (!disp) { fprintf(stderr, "[get_button_map] open display failed for %lu %s\n", xid, name); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return NULL; } @@ -53,7 +52,7 @@ get_button_map(unsigned long xid, const char* name, int* nbuttons) XCloseDisplay(disp); fprintf(stderr, "[get_button_map] get button number failed for %lu %s\n", xid, name); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return NULL; } @@ -61,7 +60,7 @@ get_button_map(unsigned long xid, const char* name, int* nbuttons) unsigned char* map = do_get_button_map(disp, xid, num_btn); XCloseDisplay(disp); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return map; } @@ -75,14 +74,14 @@ set_button_map(unsigned long xid, const char* name, return -1; } - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&x11_global_mutex); setErrorHandler(); Display* disp = XOpenDisplay(0); if (!disp) { fprintf(stderr, "[set_button_map] open display failed: %lu %s\n", xid, name); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return -1; } @@ -91,7 +90,7 @@ set_button_map(unsigned long xid, const char* name, XCloseDisplay(disp); fprintf(stderr, "[set_button_map] open device failed for %lu %s\n", xid, name); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return -1; } @@ -101,7 +100,7 @@ set_button_map(unsigned long xid, const char* name, XCloseDevice(disp, dev); XCloseDisplay(disp); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); // TODO: if ret == MappingBusy, try again if (ret != MappingSuccess) { diff --git a/dxinput/utils/keyboard.c b/dxinput/utils/keyboard.c index 07a77ed..78245a1 100644 --- a/dxinput/utils/keyboard.c +++ b/dxinput/utils/keyboard.c @@ -12,19 +12,18 @@ #include #include #include "type.h" - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +#include "x11_mutex.h" int set_keyboard_repeat(int repeated, unsigned int delay, unsigned int interval) { - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&x11_global_mutex); setErrorHandler(); Display *disp = XOpenDisplay(0); if (!disp) { fprintf(stderr, "Open display failed\n"); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return -1; } @@ -49,7 +48,7 @@ set_keyboard_repeat(int repeated, unsigned int delay, unsigned int interval) XSync(disp, False); XCloseDisplay(disp); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return ret; } diff --git a/dxinput/utils/list.c b/dxinput/utils/list.c index 0803a65..697abc5 100644 --- a/dxinput/utils/list.c +++ b/dxinput/utils/list.c @@ -13,27 +13,27 @@ #include "list.h" #include "type.h" +#include "x11_mutex.h" static int append_device(DeviceInfo** devs, XIDeviceInfo* xinfo, int idx); static void free_device_info(DeviceInfo* dev); -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; DeviceInfo* list_device(int* num) { - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&x11_global_mutex); setErrorHandler(); if (!num) { fprintf(stderr, "list_device failed, !num\n"); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return NULL; } Display* disp = XOpenDisplay(0); if (!disp) { fprintf(stderr, "Open display failed\n"); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return NULL; } @@ -42,7 +42,7 @@ list_device(int* num) XCloseDisplay(disp); if (!xinfos) { fprintf(stderr, "List xinput device failed\n"); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return NULL; } @@ -66,7 +66,7 @@ list_device(int* num) XIFreeDeviceInfo(xinfos); *num = j; - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return devs; } @@ -115,7 +115,7 @@ append_device(DeviceInfo** devs, XIDeviceInfo* xinfo, int idx) tmp[idx].name = name; tmp[idx].id = xinfo->deviceid; tmp[idx].enabled = xinfo->enabled; - tmp[idx].ty = query_device_type(xinfo->deviceid); + tmp[idx].ty = query_device_type_unlocked(xinfo->deviceid); return 0; } diff --git a/dxinput/utils/property.c b/dxinput/utils/property.c index d1b8820..50668f4 100644 --- a/dxinput/utils/property.c +++ b/dxinput/utils/property.c @@ -10,11 +10,10 @@ #include "property.h" #include "type.h" +#include "x11_mutex.h" #define MAX_BUF_LEN 1000 -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - /** * The return data type if 'char' must be convert to 'int8_t*' * if 'int' must be convert to 'int32_t*' @@ -33,13 +32,13 @@ get_prop(int id, const char* prop, int* nitems) return NULL; } - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&x11_global_mutex); setErrorHandler(); Display* disp = XOpenDisplay(0); if (!disp) { fprintf(stderr, "[get_prop] Open display failed for %d\n", id); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return NULL; } @@ -47,7 +46,7 @@ get_prop(int id, const char* prop, int* nitems) if (prop_id == None) { XCloseDisplay(disp); fprintf(stderr, "[get_prop] Intern atom %s failed\n", prop); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return NULL; } @@ -61,14 +60,14 @@ get_prop(int id, const char* prop, int* nitems) if (ret != Success) { XCloseDisplay(disp); fprintf(stderr, "[get_prop] Get %s data failed for %d\n", prop, id); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return NULL; } *nitems = (int)num_items; XCloseDisplay(disp); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return data; } @@ -83,13 +82,13 @@ set_prop_int(int id, const char* prop, unsigned char* data, int nitems, int bit) int set_prop_float(int id, const char* prop, unsigned char* data, int nitems) { - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&x11_global_mutex); setErrorHandler(); Display* disp = XOpenDisplay(NULL); if (!disp) { fprintf(stderr, "[set_prop_float] open display failed\n"); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return -1; } @@ -97,11 +96,11 @@ set_prop_float(int id, const char* prop, unsigned char* data, int nitems) XCloseDisplay(disp); if (type == None) { fprintf(stderr, "[set_prop_float] Intern 'FLOAT' atom failed\n"); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return -1; } - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); // Format must be 32 int ret = set_prop(id, prop, data, nitems, type, 32); @@ -123,13 +122,13 @@ set_prop(int id, const char* prop, unsigned char* data, int nitems, return -1; } - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&x11_global_mutex); setErrorHandler(); Display* disp = XOpenDisplay(0); if (!disp) { fprintf(stderr, "[set_prop] Open display failed for %d\n", id); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return -1; } @@ -137,7 +136,7 @@ set_prop(int id, const char* prop, unsigned char* data, int nitems, if (prop_id == None) { XCloseDisplay(disp); fprintf(stderr, "[set_prop] Intern atom %s failed\n", prop); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return -1; } @@ -146,7 +145,7 @@ set_prop(int id, const char* prop, unsigned char* data, int nitems, /* XFree(&prop_id); */ XCloseDisplay(disp); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&x11_global_mutex); return 0; } diff --git a/dxinput/utils/type.c b/dxinput/utils/type.c index 3fd1cd7..79bcc7d 100644 --- a/dxinput/utils/type.c +++ b/dxinput/utils/type.c @@ -11,6 +11,7 @@ #include #include "type.h" +#include "x11_mutex.h" static int is_mouse_device(int deviceid); static int is_touchpad_device(int deviceid); @@ -18,8 +19,7 @@ static int is_touchscreen_device(int deviceid); static int is_wacom_device(int deviceid); static int is_keyboard_device(int deviceid); static XIDeviceInfo* get_xdevice_by_id(int deviceid); - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static int is_property_exist_unlocked(int deviceid, const char* prop); int listener_error_handler(Display * display, XErrorEvent * event) @@ -46,8 +46,9 @@ setErrorHandler(){ XSetIOErrorHandler(listener_ioerror_handler); } +// Internal version without locking - assumes caller holds x11_global_mutex int -query_device_type(int deviceid) +query_device_type_unlocked(int deviceid) { if (is_wacom_device(deviceid)) { return TYPE_WACOM; @@ -69,24 +70,34 @@ query_device_type(int deviceid) return TYPE_KEYBOARD; } - return TYPE_UNKNOWN; } +// External API - with locking int -is_property_exist(int deviceid, const char* prop) +query_device_type(int deviceid) +{ + pthread_mutex_lock(&x11_global_mutex); + + int result = query_device_type_unlocked(deviceid); + + pthread_mutex_unlock(&x11_global_mutex); + return result; +} + +// Internal version without locking - assumes caller holds x11_global_mutex +static int +is_property_exist_unlocked(int deviceid, const char* prop) { if (!prop) { return 0; } - pthread_mutex_lock(&mutex); setErrorHandler(); Display* disp = XOpenDisplay(0); if (!disp) { fprintf(stderr, "Open display failed at check prop exist\n"); - pthread_mutex_unlock(&mutex); return 0; } @@ -95,17 +106,18 @@ is_property_exist(int deviceid, const char* prop) if (!props) { XCloseDisplay(disp); fprintf(stderr, "List '%d' properties failed\n", deviceid); - pthread_mutex_unlock(&mutex); return 0; } int exist = 0; while (nprops--) { char* name = XGetAtomName(disp, props[nprops]); - if (strcmp(name, prop) == 0) { + if (name && strcmp(name, prop) == 0) { exist = 1; } - XFree(name); + if (name) { + XFree(name); + } if (exist == 1) { break; @@ -114,23 +126,31 @@ is_property_exist(int deviceid, const char* prop) XCloseDisplay(disp); XFree(props); - pthread_mutex_unlock(&mutex); - return exist; } +// External API - with locking +int +is_property_exist(int deviceid, const char* prop) +{ + pthread_mutex_lock(&x11_global_mutex); + int result = is_property_exist_unlocked(deviceid, prop); + pthread_mutex_unlock(&x11_global_mutex); + return result; +} + static int is_mouse_device(int deviceid) { - return (is_property_exist(deviceid, "Button Labels") || - is_property_exist(deviceid, "libinput Button Scrolling Button")); + return (is_property_exist_unlocked(deviceid, "Button Labels") || + is_property_exist_unlocked(deviceid, "libinput Button Scrolling Button")); } static int is_touchpad_device(int deviceid) { - return (is_property_exist(deviceid, "Synaptics Off") || - is_property_exist(deviceid, "libinput Tapping Enabled")); + return (is_property_exist_unlocked(deviceid, "Synaptics Off") || + is_property_exist_unlocked(deviceid, "libinput Tapping Enabled")); } static int @@ -139,12 +159,11 @@ is_keyboard_device(int deviceid) Display *display; int num_devices, i; - pthread_mutex_lock(&mutex); + // NOTE: No mutex lock here - called from query_device_type which already holds the lock // 打开 X11 显示 display = XOpenDisplay(NULL); if (display == NULL) { fprintf(stderr, "Open display failed at check prop exist\n"); - pthread_mutex_unlock(&mutex); return 0; } @@ -152,7 +171,6 @@ is_keyboard_device(int deviceid) XIDeviceInfo *devices = XIQueryDevice(display, deviceid, &num_devices); if (devices == NULL || num_devices != 1) { fprintf(stderr, "Error getting device information.\n"); - pthread_mutex_unlock(&mutex); XCloseDisplay(display); return 0; } @@ -160,7 +178,6 @@ is_keyboard_device(int deviceid) if(devices[0].use != XISlaveKeyboard) { fprintf(stderr, "Device is not keyboard.\n"); - pthread_mutex_unlock(&mutex); XIFreeDeviceInfo(devices); XCloseDisplay(display); return 0; @@ -171,7 +188,6 @@ is_keyboard_device(int deviceid) // 关闭 X11 显示 XCloseDisplay(display); - pthread_mutex_unlock(&mutex); return 1; } @@ -180,14 +196,14 @@ is_keyboard_device(int deviceid) static int is_wacom_device(int deviceid) { - return is_property_exist(deviceid, "Wacom Tool Type"); + return is_property_exist_unlocked(deviceid, "Wacom Tool Type"); } static int is_touchscreen_device(int deviceid) { // for libinput - if (is_property_exist(deviceid, "libinput Calibration Matrix")) { + if (is_property_exist_unlocked(deviceid, "libinput Calibration Matrix")) { return 1; } // Now XInput2 library detect touchscreen as mouse diff --git a/dxinput/utils/type.h b/dxinput/utils/type.h index b23bcbe..5a47c42 100644 --- a/dxinput/utils/type.h +++ b/dxinput/utils/type.h @@ -19,6 +19,7 @@ int listener_error_handler(Display * display, XErrorEvent * event); int listener_ioerror_handler(Display * display); int query_device_type(int deviceid); +int query_device_type_unlocked(int deviceid); // Internal version, caller must hold x11_global_mutex int is_property_exist(int deviceid, const char* prop); #endif diff --git a/dxinput/utils/wrapper.go b/dxinput/utils/wrapper.go index 7d7c917..389efab 100644 --- a/dxinput/utils/wrapper.go +++ b/dxinput/utils/wrapper.go @@ -7,6 +7,7 @@ package utils // #cgo pkg-config: x11 xi // #cgo CFLAGS: -W -Wall -fPIC -fstack-protector-all // #include +// #include "x11_mutex.h" // #include "property.h" // #include "list.h" // #include "type.h" @@ -86,9 +87,9 @@ func IsPropertyExist(id int32, prop string) bool { cprop := C.CString(prop) - defer func() { - if cprop != nil { - C.free(unsafe.Pointer(cprop)) + defer func() { + if cprop != nil { + C.free(unsafe.Pointer(cprop)) } }() @@ -103,15 +104,15 @@ func GetProperty(id int32, prop string) ([]byte, int32) { cprop := C.CString(prop) - defer func() { - if cprop != nil { - C.free(unsafe.Pointer(cprop)) + defer func() { + if cprop != nil { + C.free(unsafe.Pointer(cprop)) } }() nitems := C.int(0) cdatas := C.get_prop(C.int(id), cprop, &nitems) - if cdatas == nil { + if cdatas == nil || nitems == 0 { return nil, 0 } @@ -123,9 +124,9 @@ func SetInt8Prop(id int32, prop string, values []int8) error { cdatas := byteArrayToUChar(WriteInt8(values)) cprop := C.CString(prop) - defer func() { - if cprop != nil { - C.free(unsafe.Pointer(cprop)) + defer func() { + if cprop != nil { + C.free(unsafe.Pointer(cprop)) } }() @@ -142,9 +143,9 @@ func SetInt16Prop(id int32, prop string, values []int16) error { cdatas := byteArrayToUChar(WriteInt16(values)) cprop := C.CString(prop) - defer func() { - if cprop != nil { - C.free(unsafe.Pointer(cprop)) + defer func() { + if cprop != nil { + C.free(unsafe.Pointer(cprop)) } }() @@ -161,9 +162,9 @@ func SetInt32Prop(id int32, prop string, values []int32) error { cdatas := byteArrayToUChar(WriteInt32(values)) cprop := C.CString(prop) - defer func() { - if cprop != nil { - C.free(unsafe.Pointer(cprop)) + defer func() { + if cprop != nil { + C.free(unsafe.Pointer(cprop)) } }() @@ -180,9 +181,9 @@ func SetFloat32Prop(id int32, prop string, values []float32) error { cdatas := byteArrayToUChar(WriteFloat32(values)) cprop := C.CString(prop) - defer func() { - if cprop != nil { - C.free(unsafe.Pointer(cprop)) + defer func() { + if cprop != nil { + C.free(unsafe.Pointer(cprop)) } }() @@ -203,7 +204,9 @@ func ucharArrayToByte(cData *C.uchar, length int) []byte { var data []byte for i := 0; i < length; i++ { - cdata := (*C.uchar)(unsafe.Pointer(uintptr(unsafe.Pointer(cData)) + uintptr(i)*cItemSize)) + offset := uintptr(i) * cItemSize + addr := uintptr(unsafe.Pointer(cData)) + offset + cdata := (*C.uchar)(unsafe.Pointer(addr)) if cdata == nil { break } diff --git a/dxinput/utils/x11_mutex.c b/dxinput/utils/x11_mutex.c new file mode 100644 index 0000000..1c3a33e --- /dev/null +++ b/dxinput/utils/x11_mutex.c @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "x11_mutex.h" + +// Global mutex for all X11 operations +pthread_mutex_t x11_global_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/dxinput/utils/x11_mutex.h b/dxinput/utils/x11_mutex.h new file mode 100644 index 0000000..59c2364 --- /dev/null +++ b/dxinput/utils/x11_mutex.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef X11_MUTEX_H +#define X11_MUTEX_H + +#include + +// Global mutex for all X11 operations to prevent race conditions +// across different source files (list.c, type.c, property.c) +extern pthread_mutex_t x11_global_mutex; + +#endif