1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-27 15:02:50 -05:00

core/wayland: thread-safety meta fixes + cleanups + hypr workaround

- fork go-wayland/client and modify to make it thread-safe internally
- use sync.Map and atomic values in many places to cut down on mutex
  boilerplate
- do not create extworkspace client unless explicitly requested
This commit is contained in:
bbedward
2025-11-15 14:41:00 -05:00
parent 20f7d60147
commit 91891a14ed
54 changed files with 8610 additions and 698 deletions

View File

@@ -47,10 +47,9 @@ func TestHandleRequest(t *testing.T) {
mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe()
m := &Manager{
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: true},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: true},
closeChan: make(chan struct{}),
}
conn := newMockNetConn()
@@ -77,10 +76,9 @@ func TestHandleRequest(t *testing.T) {
mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe()
m := &Manager{
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: false},
closeChan: make(chan struct{}),
}
conn := newMockNetConn()
@@ -107,10 +105,9 @@ func TestHandleGetState(t *testing.T) {
mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe()
m := &Manager{
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: false},
closeChan: make(chan struct{}),
}
conn := newMockNetConn()

View File

@@ -35,8 +35,7 @@ type Manager struct {
monitoredPaths map[string]bool
state State
stateMutex sync.RWMutex
subscribers map[string]chan State
subMutex sync.RWMutex
subscribers sync.Map
closeChan chan struct{}
closeOnce sync.Once
watcher *fsnotify.Watcher
@@ -69,9 +68,9 @@ func NewManager() (*Manager, error) {
devices: devices,
monitoredPaths: monitoredPaths,
state: State{Available: true, CapsLock: initialCapsLock},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
watcher: watcher,
closeChan: make(chan struct{}),
watcher: watcher,
}
for i, device := range devices {
@@ -332,37 +331,26 @@ func (m *Manager) GetState() State {
}
func (m *Manager) Subscribe(id string) chan State {
m.subMutex.Lock()
defer m.subMutex.Unlock()
ch := make(chan State, 16)
m.subscribers[id] = ch
m.subscribers.Store(id, ch)
return ch
}
func (m *Manager) Unsubscribe(id string) {
m.subMutex.Lock()
defer m.subMutex.Unlock()
ch, ok := m.subscribers[id]
if !ok {
return
if val, ok := m.subscribers.LoadAndDelete(id); ok {
close(val.(chan State))
}
close(ch)
delete(m.subscribers, id)
}
func (m *Manager) notifySubscribers(state State) {
m.subMutex.RLock()
defer m.subMutex.RUnlock()
for _, ch := range m.subscribers {
m.subscribers.Range(func(key, value interface{}) bool {
ch := value.(chan State)
select {
case ch <- state:
default:
}
}
return true
})
}
func (m *Manager) Close() {
@@ -384,12 +372,12 @@ func (m *Manager) Close() {
}
m.devicesMutex.Unlock()
m.subMutex.Lock()
for id, ch := range m.subscribers {
m.subscribers.Range(func(key, value interface{}) bool {
ch := value.(chan State)
close(ch)
delete(m.subscribers, id)
}
m.subMutex.Unlock()
m.subscribers.Delete(key)
return true
})
})
}

View File

@@ -16,10 +16,9 @@ func TestManager_Creation(t *testing.T) {
mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe()
m := &Manager{
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: false},
closeChan: make(chan struct{}),
}
assert.NotNil(t, m)
@@ -32,10 +31,9 @@ func TestManager_Creation(t *testing.T) {
mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe()
m := &Manager{
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: true},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: true},
closeChan: make(chan struct{}),
}
assert.NotNil(t, m)
@@ -52,7 +50,6 @@ func TestManager_GetState(t *testing.T) {
devices: []EvdevDevice{mockDevice},
monitoredPaths: make(map[string]bool),
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
}
@@ -69,13 +66,17 @@ func TestManager_Subscribe(t *testing.T) {
devices: []EvdevDevice{mockDevice},
monitoredPaths: make(map[string]bool),
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
}
ch := m.Subscribe("test-client")
assert.NotNil(t, ch)
assert.Len(t, m.subscribers, 1)
count := 0
m.subscribers.Range(func(key, value interface{}) bool {
count++
return true
})
assert.Equal(t, 1, count)
}
func TestManager_Unsubscribe(t *testing.T) {
@@ -86,15 +87,24 @@ func TestManager_Unsubscribe(t *testing.T) {
devices: []EvdevDevice{mockDevice},
monitoredPaths: make(map[string]bool),
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
}
ch := m.Subscribe("test-client")
assert.Len(t, m.subscribers, 1)
count := 0
m.subscribers.Range(func(key, value interface{}) bool {
count++
return true
})
assert.Equal(t, 1, count)
m.Unsubscribe("test-client")
assert.Len(t, m.subscribers, 0)
count = 0
m.subscribers.Range(func(key, value interface{}) bool {
count++
return true
})
assert.Equal(t, 0, count)
select {
case _, ok := <-ch:
@@ -112,7 +122,6 @@ func TestManager_UpdateCapsLock(t *testing.T) {
devices: []EvdevDevice{mockDevice},
monitoredPaths: make(map[string]bool),
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
}
@@ -148,7 +157,6 @@ func TestManager_Close(t *testing.T) {
devices: []EvdevDevice{mockDevice},
monitoredPaths: make(map[string]bool),
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
}
@@ -171,7 +179,12 @@ func TestManager_Close(t *testing.T) {
t.Error("channel 2 should be closed")
}
assert.Len(t, m.subscribers, 0)
count := 0
m.subscribers.Range(func(key, value interface{}) bool {
count++
return true
})
assert.Equal(t, 0, count)
m.Close()
}
@@ -230,10 +243,9 @@ func TestManager_MonitorDevice(t *testing.T) {
mockDevice.EXPECT().Close().Return(nil).Maybe()
m := &Manager{
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
devices: []EvdevDevice{mockDevice},
state: State{Available: true, CapsLock: false},
closeChan: make(chan struct{}),
}
ch := m.Subscribe("test")
@@ -276,7 +288,6 @@ func TestNotifySubscribers(t *testing.T) {
devices: []EvdevDevice{mockDevice},
monitoredPaths: make(map[string]bool),
state: State{Available: true, CapsLock: false},
subscribers: make(map[string]chan State),
closeChan: make(chan struct{}),
}