From add9975420368b7c89591b06b3d2081a5418fdb5 Mon Sep 17 00:00:00 2001 From: Zdenek Dohnal Date: Thu, 4 Jan 2024 13:33:04 +0100 Subject: [PATCH 1/2] dest.c: Fix infinite loop in `cups_enum_dests()` Update remaining time after `usleep()`, otherwise there is no difference in elapsed time, so `remaining` will never be less or equal to 0. Fixes CI on Linux --- cups/dest.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cups/dest.c b/cups/dest.c index c528fdf219..2dc8a937bd 100644 --- a/cups/dest.c +++ b/cups/dest.c @@ -3229,8 +3229,6 @@ cups_enum_dests( goto enum_finished; // Get DNS-SD printers... - gettimeofday(&curtime, NULL); - if ((dnssd = cupsDNSSDNew(dnssd_error_cb, NULL)) == NULL) { DEBUG_puts("1cups_enum_dests: Unable to create service browser, returning 0."); @@ -3268,15 +3266,13 @@ cups_enum_dests( else remaining = msec; + gettimeofday(&curtime, NULL); + while (remaining > 0 && (!cancel || !*cancel)) { // Check for input... DEBUG_printf("1cups_enum_dests: remaining=%d", remaining); - cups_elapsed(&curtime); - - remaining -= cups_elapsed(&curtime); - cupsRWLockRead(&data.rwlock); for (i = 0, num_devices = cupsArrayCount(data.devices), count = 0, completed = 0; i < num_devices; i ++) @@ -3369,6 +3365,8 @@ cups_enum_dests( break; usleep(100000); + + remaining -= cups_elapsed(&curtime); } // Return... From 78a051b419f05291714ff2913c19f6cf2aace32c Mon Sep 17 00:00:00 2001 From: Zdenek Dohnal Date: Thu, 4 Jan 2024 13:58:42 +0100 Subject: [PATCH 2/2] dnssd.c: Fix deadlock in `cups_enum_dests()` Deadlock happens when we are about to destroy DNSSD struct by the end of `cups_enum_dests()`. The main thread locks the mutex when the other thread is in avahi poll callback at function `poll()` and unlocked the mutex before - the other thread tries to lock the mutex once poll timeout expires, but it cannot because it was locked by the main thread and wait there. Meanwhile the main thread tries to cancel the other thread, but the function where the other thread is not a cancellation point, thus the cancel event is ignored and the main thread thread waits indefinitely for the end of the other thread. We can make the other thread asynchronous (which would cancel the thread immediately) or release the mutex earlier in `cupsDNSSDDelete()`. The commit does the latter. Fixes CI for Linux --- cups/dnssd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cups/dnssd.c b/cups/dnssd.c index 4daa4169e6..45c9f57ac9 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -434,6 +434,8 @@ cupsDNSSDDelete(cups_dnssd_t *dnssd) // I - DNS-SD context cupsArrayDelete(dnssd->resolves); cupsArrayDelete(dnssd->services); + cupsMutexUnlock(&dnssd->mutex); + #ifdef HAVE_MDNSRESPONDER cupsThreadCancel(dnssd->monitor); cupsThreadWait(dnssd->monitor); @@ -447,7 +449,6 @@ cupsDNSSDDelete(cups_dnssd_t *dnssd) // I - DNS-SD context avahi_simple_poll_free(dnssd->poll); #endif // HAVE_MDNSRESPONDER - cupsMutexUnlock(&dnssd->mutex); cupsMutexDestroy(&dnssd->mutex); free(dnssd); }