1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

wlcontext: use poll with wake pipe instead of read deadlines

This commit is contained in:
bbedward
2025-12-13 00:46:30 -05:00
parent ce4aca9a72
commit 830a715b6d
4 changed files with 94 additions and 36 deletions

View File

@@ -500,14 +500,13 @@ func (m *Manager) receiveData(offer *ext_data_control.ExtDataControlOfferV1, mim
receiveErr := make(chan error, 1) receiveErr := make(chan error, 1)
m.post(func() { m.post(func() {
err := offer.Receive(mimeType, int(w.Fd())) err := offer.Receive(mimeType, int(w.Fd()))
w.Close()
receiveErr <- err receiveErr <- err
}) })
if err := <-receiveErr; err != nil { if err := <-receiveErr; err != nil {
w.Close()
return nil, err return nil, err
} }
w.Close()
type result struct { type result struct {
data []byte data []byte

View File

@@ -1,11 +1,11 @@
package wlcontext package wlcontext
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"sync" "sync"
"time"
"golang.org/x/sys/unix"
"github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log" "github.com/AvengeMedia/DankMaterialShell/core/internal/log"
@@ -27,6 +27,8 @@ type SharedContext struct {
stopChan chan struct{} stopChan chan struct{}
fatalError chan error fatalError chan error
cmdQueue chan func() cmdQueue chan func()
wakeR int
wakeW int
wg sync.WaitGroup wg sync.WaitGroup
mu sync.Mutex mu sync.Mutex
started bool started bool
@@ -38,11 +40,31 @@ func New() (*SharedContext, error) {
return nil, fmt.Errorf("%w: %v", errdefs.ErrNoWaylandDisplay, err) return nil, fmt.Errorf("%w: %v", errdefs.ErrNoWaylandDisplay, err)
} }
fds := make([]int, 2)
if err := unix.Pipe(fds); err != nil {
display.Context().Close()
return nil, fmt.Errorf("failed to create wake pipe: %w", err)
}
if err := unix.SetNonblock(fds[0], true); err != nil {
unix.Close(fds[0])
unix.Close(fds[1])
display.Context().Close()
return nil, fmt.Errorf("failed to set wake pipe nonblock: %w", err)
}
if err := unix.SetNonblock(fds[1], true); err != nil {
unix.Close(fds[0])
unix.Close(fds[1])
display.Context().Close()
return nil, fmt.Errorf("failed to set wake pipe nonblock: %w", err)
}
sc := &SharedContext{ sc := &SharedContext{
display: display, display: display,
stopChan: make(chan struct{}), stopChan: make(chan struct{}),
fatalError: make(chan error, 1), fatalError: make(chan error, 1),
cmdQueue: make(chan func(), 256), cmdQueue: make(chan func(), 256),
wakeR: fds[0],
wakeW: fds[1],
started: false, started: false,
} }
@@ -69,6 +91,9 @@ func (sc *SharedContext) Display() *wlclient.Display {
func (sc *SharedContext) Post(fn func()) { func (sc *SharedContext) Post(fn func()) {
select { select {
case sc.cmdQueue <- fn: case sc.cmdQueue <- fn:
if _, err := unix.Write(sc.wakeW, []byte{1}); err != nil && err != unix.EAGAIN {
log.Errorf("wake pipe write error: %v", err)
}
default: default:
} }
} }
@@ -89,7 +114,14 @@ func (sc *SharedContext) eventDispatcher() {
} }
} }
}() }()
ctx := sc.display.Context() ctx := sc.display.Context()
wlFd := ctx.Fd()
pollFds := []unix.PollFd{
{Fd: int32(wlFd), Events: unix.POLLIN},
{Fd: int32(sc.wakeR), Events: unix.POLLIN},
}
for { for {
select { select {
@@ -100,20 +132,33 @@ func (sc *SharedContext) eventDispatcher() {
sc.drainCmdQueue() sc.drainCmdQueue()
if err := ctx.SetReadDeadline(time.Now().Add(50 * time.Millisecond)); err != nil { n, err := unix.Poll(pollFds, 50)
log.Errorf("Failed to set read deadline: %v", err) if err != nil {
} if err == unix.EINTR {
err := ctx.Dispatch() continue
if err := ctx.SetReadDeadline(time.Time{}); err != nil { }
log.Errorf("Failed to clear read deadline: %v", err) log.Errorf("Poll error: %v", err)
return
} }
switch { if n == 0 {
case err == nil: continue
case errors.Is(err, os.ErrDeadlineExceeded): }
default:
log.Errorf("Wayland connection error: %v", err) if pollFds[1].Revents&unix.POLLIN != 0 {
return var buf [64]byte
if _, err := unix.Read(sc.wakeR, buf[:]); err != nil && err != unix.EAGAIN {
log.Errorf("wake pipe read error: %v", err)
}
}
if pollFds[0].Revents&unix.POLLIN != 0 {
if err := ctx.Dispatch(); err != nil {
if !os.IsTimeout(err) {
log.Errorf("Wayland connection error: %v", err)
return
}
}
} }
} }
} }
@@ -133,6 +178,9 @@ func (sc *SharedContext) Close() {
close(sc.stopChan) close(sc.stopChan)
sc.wg.Wait() sc.wg.Wait()
unix.Close(sc.wakeR)
unix.Close(sc.wakeW)
if sc.display != nil { if sc.display != nil {
sc.display.Context().Close() sc.display.Context().Close()
} }

View File

@@ -58,6 +58,18 @@ func (ctx *Context) SetReadDeadline(t time.Time) error {
return ctx.conn.SetReadDeadline(t) return ctx.conn.SetReadDeadline(t)
} }
func (ctx *Context) Fd() int {
rawConn, err := ctx.conn.SyscallConn()
if err != nil {
return -1
}
var fd int
rawConn.Control(func(f uintptr) {
fd = int(f)
})
return fd
}
// Dispatch reads and processes incoming messages and calls [client.Dispatcher.Dispatch] on the // Dispatch reads and processes incoming messages and calls [client.Dispatcher.Dispatch] on the
// respective wayland protocol. // respective wayland protocol.
// Dispatch must be called on the same goroutine as other interactions with the Context. // Dispatch must be called on the same goroutine as other interactions with the Context.

View File

@@ -105,7 +105,7 @@ get_status_display() {
# Check each PPA # Check each PPA
for PPA_NAME in "${PPAS[@]}"; do for PPA_NAME in "${PPAS[@]}"; do
PPA_ARCHIVE="${LAUNCHPAD_API}/~${PPA_OWNER}/+archive/ubuntu/${PPA_NAME}" PPA_ARCHIVE="${LAUNCHPAD_API}/~${PPA_OWNER}/+archive/ubuntu/${PPA_NAME}"
echo "==========================================" echo "=========================================="
echo "=== PPA: ${PPA_OWNER}/${PPA_NAME} ===" echo "=== PPA: ${PPA_OWNER}/${PPA_NAME} ==="
echo "==========================================" echo "=========================================="
@@ -122,55 +122,55 @@ for PPA_NAME in "${PPAS[@]}"; do
echo "----------------------------------------" echo "----------------------------------------"
echo "--- $pkg ---" echo "--- $pkg ---"
echo "----------------------------------------" echo "----------------------------------------"
# Get published sources for this package # Get published sources for this package
SOURCES_URL="${PPA_ARCHIVE}?ws.op=getPublishedSources&source_name=${pkg}&distro_series=${LAUNCHPAD_API}/ubuntu/${DISTRO_SERIES}&status=Published" SOURCES_URL="${PPA_ARCHIVE}?ws.op=getPublishedSources&source_name=${pkg}&distro_series=${LAUNCHPAD_API}/ubuntu/${DISTRO_SERIES}&status=Published"
SOURCES=$(curl -s "$SOURCES_URL" 2>/dev/null) SOURCES=$(curl -s "$SOURCES_URL" 2>/dev/null)
if [[ -z "$SOURCES" ]] || [[ "$SOURCES" == "null" ]]; then if [[ -z "$SOURCES" ]] || [[ "$SOURCES" == "null" ]]; then
echo " ⚠️ No published sources found" echo " ⚠️ No published sources found"
echo "" echo ""
continue continue
fi fi
# Get the latest source # Get the latest source
TOTAL=$(echo "$SOURCES" | jq '.total_size // 0') TOTAL=$(echo "$SOURCES" | jq '.total_size // 0')
if [[ "$TOTAL" == "0" ]]; then if [[ "$TOTAL" == "0" ]]; then
echo " ⚠️ No published sources found for $DISTRO_SERIES" echo " ⚠️ No published sources found for $DISTRO_SERIES"
echo "" echo ""
continue continue
fi fi
# Get most recent entry # Get most recent entry
ENTRY=$(echo "$SOURCES" | jq '.entries[0]') ENTRY=$(echo "$SOURCES" | jq '.entries[0]')
if [[ "$ENTRY" == "null" ]]; then if [[ "$ENTRY" == "null" ]]; then
echo " ⚠️ No source entries found" echo " ⚠️ No source entries found"
echo "" echo ""
continue continue
fi fi
# Extract source info # Extract source info
VERSION=$(echo "$ENTRY" | jq -r '.source_package_version // "unknown"') VERSION=$(echo "$ENTRY" | jq -r '.source_package_version // "unknown"')
STATUS=$(echo "$ENTRY" | jq -r '.status // "unknown"') STATUS=$(echo "$ENTRY" | jq -r '.status // "unknown"')
DATE_PUBLISHED=$(echo "$ENTRY" | jq -r '.date_published // "unknown"') DATE_PUBLISHED=$(echo "$ENTRY" | jq -r '.date_published // "unknown"')
SELF_LINK=$(echo "$ENTRY" | jq -r '.self_link // ""') SELF_LINK=$(echo "$ENTRY" | jq -r '.self_link // ""')
echo " 📦 Version: $VERSION" echo " 📦 Version: $VERSION"
echo " 📅 Published: ${DATE_PUBLISHED%T*}" echo " 📅 Published: ${DATE_PUBLISHED%T*}"
echo " 📋 Source Status: $STATUS" echo " 📋 Source Status: $STATUS"
echo "" echo ""
# Get builds for this source # Get builds for this source
if [[ -n "$SELF_LINK" && "$SELF_LINK" != "null" ]]; then if [[ -n "$SELF_LINK" && "$SELF_LINK" != "null" ]]; then
BUILDS_URL="${SELF_LINK}?ws.op=getBuilds" BUILDS_URL="${SELF_LINK}?ws.op=getBuilds"
BUILDS=$(curl -s "$BUILDS_URL" 2>/dev/null) BUILDS=$(curl -s "$BUILDS_URL" 2>/dev/null)
if [[ -n "$BUILDS" && "$BUILDS" != "null" ]]; then if [[ -n "$BUILDS" && "$BUILDS" != "null" ]]; then
BUILD_COUNT=$(echo "$BUILDS" | jq '.total_size // 0') BUILD_COUNT=$(echo "$BUILDS" | jq '.total_size // 0')
if [[ "$BUILD_COUNT" -gt 0 ]]; then if [[ "$BUILD_COUNT" -gt 0 ]]; then
echo " Builds:" echo " Builds:"
echo "$BUILDS" | jq -r '.entries[] | "\(.arch_tag) \(.buildstate)"' 2>/dev/null | while read -r line; do echo "$BUILDS" | jq -r '.entries[] | "\(.arch_tag) \(.buildstate)"' 2>/dev/null | while read -r line; do
@@ -182,18 +182,18 @@ for PPA_NAME in "${PPAS[@]}"; do
fi fi
fi fi
fi fi
# Alternative: Get build records directly from archive # Alternative: Get build records directly from archive
BUILD_RECORDS_URL="${PPA_ARCHIVE}?ws.op=getBuildRecords&source_name=${pkg}" BUILD_RECORDS_URL="${PPA_ARCHIVE}?ws.op=getBuildRecords&source_name=${pkg}"
BUILD_RECORDS=$(curl -s "$BUILD_RECORDS_URL" 2>/dev/null) BUILD_RECORDS=$(curl -s "$BUILD_RECORDS_URL" 2>/dev/null)
if [[ -n "$BUILD_RECORDS" && "$BUILD_RECORDS" != "null" ]]; then if [[ -n "$BUILD_RECORDS" && "$BUILD_RECORDS" != "null" ]]; then
RECORD_COUNT=$(echo "$BUILD_RECORDS" | jq '.total_size // 0') RECORD_COUNT=$(echo "$BUILD_RECORDS" | jq '.total_size // 0')
if [[ "$RECORD_COUNT" -gt 0 ]]; then if [[ "$RECORD_COUNT" -gt 0 ]]; then
echo "" echo ""
echo " Recent build history:" echo " Recent build history:"
# Get unique version+arch combinations # Get unique version+arch combinations
echo "$BUILD_RECORDS" | jq -r '.entries[:6][] | "\(.source_package_version) \(.arch_tag) \(.buildstate)"' 2>/dev/null | while read -r line; do echo "$BUILD_RECORDS" | jq -r '.entries[:6][] | "\(.source_package_version) \(.arch_tag) \(.buildstate)"' 2>/dev/null | while read -r line; do
VER=$(echo "$line" | awk '{print $1}') VER=$(echo "$line" | awk '{print $1}')
@@ -204,10 +204,10 @@ for PPA_NAME in "${PPAS[@]}"; do
done done
fi fi
fi fi
echo "" echo ""
done done
echo "View full PPA at: https://launchpad.net/~${PPA_OWNER}/+archive/ubuntu/${PPA_NAME}" echo "View full PPA at: https://launchpad.net/~${PPA_OWNER}/+archive/ubuntu/${PPA_NAME}"
echo "" echo ""
done done
@@ -215,4 +215,3 @@ done
echo "==========================================" echo "=========================================="
echo "Status check complete!" echo "Status check complete!"
echo "" echo ""