From: Michael R Sweet Date: Thu, 17 Apr 2025 18:34:53 +0000 (-0400) Subject: Add rwlock to Subscriptions and subscription objects since we send X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f7d98a0c06e594ba1c2bff69c30e9e9673ae0534;p=thirdparty%2Fcups.git Add rwlock to Subscriptions and subscription objects since we send events from a background thread. --- diff --git a/scheduler/ipp.c b/scheduler/ipp.c index a00a7df19e..0708fb85db 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -4912,6 +4912,8 @@ copy_subscription_attrs( cupsdLogClient(con, CUPSD_LOG_DEBUG2, "copy_subscription_attrs: sub=%p, ra=%p, exclude=%p", (void *)sub, (void *)ra, (void *)exclude); + cupsRWLockRead(&sub->lock); + /* * Copy the subscription attributes to the response using the * requested-attributes attribute that may be provided by the client. @@ -4999,6 +5001,8 @@ copy_subscription_attrs( if (!ra || cupsArrayFind(ra, "notify-subscription-id")) ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-subscription-id", sub->id); + + cupsRWUnlock(&sub->lock); } @@ -5255,7 +5259,6 @@ create_local_bg_thread( goto finish_response; } - // TODO: Grab printer icon file... httpClose(http); /* @@ -7685,7 +7688,9 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer/job URI */ { http_status_t status; /* Policy status */ - int count; /* Number of subscriptions */ + int i, /* Looping var */ + scount; /* Total number of subscriptions */ + int count; /* Number of subscriptions returned */ int limit; /* Limit */ cupsd_subscription_t *sub; /* Subscription */ cups_array_t *ra; /* Requested attributes array */ @@ -7805,9 +7810,12 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ else username[0] = '\0'; - for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), count = 0; - sub; - sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + cupsRWLockRead(&SubscriptionsLock); + + for (i = 0, count = 0, scount = cupsArrayGetCount(Subscriptions); i < scount; i ++) + { + sub = (cupsd_subscription_t *)cupsArrayGetElement(Subscriptions, i); + if ((!printer || sub->dest == printer) && (!job || sub->job == job) && (!username[0] || !_cups_strcasecmp(username, sub->owner))) { @@ -7823,6 +7831,9 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ if (limit && count >= limit) break; } + } + + cupsRWUnlock(&SubscriptionsLock); cupsArrayDelete(ra); @@ -9158,6 +9169,8 @@ renew_subscription( * Renew the subscription... */ + cupsRWLockWrite(&sub->lock); + lease = ippFindAttribute(con->request, "notify-lease-duration", IPP_TAG_INTEGER); @@ -9171,6 +9184,8 @@ renew_subscription( sub->expire = sub->lease ? time(NULL) + sub->lease : 0; + cupsRWUnlock(&sub->lock); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); con->response->request.status.status_code = IPP_STATUS_OK; diff --git a/scheduler/subscriptions.c b/scheduler/subscriptions.c index f10b217164..565cdd65f7 100644 --- a/scheduler/subscriptions.c +++ b/scheduler/subscriptions.c @@ -27,7 +27,7 @@ static int cupsd_compare_subscriptions(cupsd_subscription_t *first, cupsd_subscription_t *second, void *unused); -static void cupsd_delete_event(cupsd_event_t *event, void *data); +static void cupsd_delete_event(cupsd_event_t *event, void *data); #ifdef HAVE_DBUS static void cupsd_send_dbus(cupsd_eventmask_t event, cupsd_printer_t *dest, cupsd_job_t *job); @@ -50,10 +50,12 @@ cupsdAddEvent( const char *text, /* I - Notification text */ ...) /* I - Additional arguments as needed */ { + int i, /* Looping var */ + scount; /* Number of subscriptions */ va_list ap; /* Pointer to additional arguments */ char ftext[1024]; /* Formatted text buffer */ ipp_attribute_t *attr; /* Printer/job attribute */ - cupsd_event_t *temp; /* New event pointer */ + cupsd_event_t *temp = NULL; /* New event pointer */ cupsd_subscription_t *sub; /* Current subscription */ @@ -92,14 +94,16 @@ cupsdAddEvent( if (job && !dest) dest = cupsdFindPrinter(job->dest); - for (temp = NULL, sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); - sub; - sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + cupsRWLockRead(&SubscriptionsLock); + + for (i = 0, scount = cupsArrayGetCount(Subscriptions); i < scount; i ++) { /* * Check if this subscription requires this event... */ + sub = (cupsd_subscription_t *)cupsArrayGetElement(Subscriptions, i); + if ((sub->mask & event) != 0 && (sub->dest == dest || !sub->dest || sub->job == job)) { /* @@ -111,6 +115,7 @@ cupsdAddEvent( cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for event - %s", strerror(errno)); + cupsRWUnlock(&SubscriptionsLock); return; } @@ -240,6 +245,8 @@ cupsdAddEvent( } } + cupsRWUnlock(&SubscriptionsLock); + if (temp) cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); else @@ -268,6 +275,8 @@ cupsdAddSubscription( mask, (void *)dest, dest ? dest->name : "", (void *)job, job ? job->id : 0, uri ? uri : "(null)"); + cupsRWLockWrite(&SubscriptionsLock); + if (!Subscriptions) Subscriptions = cupsArrayNew((cups_array_func_t)cupsd_compare_subscriptions, NULL); @@ -277,6 +286,7 @@ cupsdAddSubscription( cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for subscriptions - %s", strerror(errno)); + cupsRWUnlock(&SubscriptionsLock); return (NULL); } @@ -290,6 +300,7 @@ cupsdAddSubscription( "cupsdAddSubscription: Reached MaxSubscriptions %d " "(count=%d)", MaxSubscriptions, cupsArrayCount(Subscriptions)); + cupsRWUnlock(&SubscriptionsLock); return (NULL); } @@ -310,6 +321,7 @@ cupsdAddSubscription( "cupsdAddSubscription: Reached MaxSubscriptionsPerJob %d " "for job #%d (count=%d)", MaxSubscriptionsPerJob, job->id, count); + cupsRWUnlock(&SubscriptionsLock); return (NULL); } } @@ -331,6 +343,7 @@ cupsdAddSubscription( "cupsdAddSubscription: Reached " "MaxSubscriptionsPerPrinter %d for %s (count=%d)", MaxSubscriptionsPerPrinter, dest->name, count); + cupsRWUnlock(&SubscriptionsLock); return (NULL); } } @@ -344,9 +357,12 @@ cupsdAddSubscription( cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for subscription object - %s", strerror(errno)); + cupsRWUnlock(&SubscriptionsLock); return (NULL); } + cupsRWInit(&temp->lock); + /* * Fill in common data... */ @@ -380,6 +396,8 @@ cupsdAddSubscription( cupsArrayAdd(Subscriptions, temp); + cupsRWUnlock(&SubscriptionsLock); + /* * For RSS subscriptions, run the notifier immediately... */ @@ -404,6 +422,8 @@ cupsdDeleteAllSubscriptions(void) if (!Subscriptions) return; + cupsRWLockWrite(&SubscriptionsLock); + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); sub; sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) @@ -411,6 +431,8 @@ cupsdDeleteAllSubscriptions(void) cupsArrayDelete(Subscriptions); Subscriptions = NULL; + + cupsRWUnlock(&SubscriptionsLock); } @@ -434,12 +456,18 @@ cupsdDeleteSubscription( * Remove subscription from array... */ + cupsRWLockWrite(&SubscriptionsLock); + cupsArrayRemove(Subscriptions, sub); + cupsRWUnlock(&SubscriptionsLock); + /* * Free memory... */ + cupsRWDestroy(&sub->lock); + cupsdClearString(&(sub->owner)); cupsdClearString(&(sub->recipient)); @@ -651,12 +679,18 @@ cupsdExpireSubscriptions( cupsd_subscription_t * /* O - Subscription object */ cupsdFindSubscription(int id) /* I - Subscription ID */ { - cupsd_subscription_t sub; /* Subscription template */ + cupsd_subscription_t key, /* Subscription key */ + *sub; /* Matching subscription */ + + key.id = id; + + cupsRWLockRead(&SubscriptionsLock); + sub = (cupsd_subscription_t *)cupsArrayFind(Subscriptions, &sub); - sub.id = id; + cupsRWUnlock(&SubscriptionsLock); - return ((cupsd_subscription_t *)cupsArrayFind(Subscriptions, &sub)); + return (sub); } @@ -1020,7 +1054,8 @@ cupsdLoadAllSubscriptions(void) void cupsdSaveAllSubscriptions(void) { - int i; /* Looping var */ + int i, j, /* Looping vars */ + scount; /* Number of subscriptions */ cups_file_t *fp; /* subscriptions.conf file */ char filename[1024]; /* subscriptions.conf filename */ cupsd_subscription_t *sub; /* Current subscription */ @@ -1053,10 +1088,12 @@ cupsdSaveAllSubscriptions(void) * Write every subscription known to the system... */ - for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); - sub; - sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + cupsRWLockRead(&SubscriptionsLock); + + for (i = 0, scount = cupsArrayGetCount(Subscriptions); i < scount; i ++) { + sub = (cupsd_subscription_t *)cupsArrayGetElement(Subscriptions, i); + cupsFilePrintf(fp, "\n", sub->id); if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL) @@ -1095,29 +1132,29 @@ cupsdSaveAllSubscriptions(void) { cupsFilePuts(fp, "UserData "); - for (i = 0, hex = 0; i < sub->user_data_len; i ++) + for (j = 0, hex = 0; j < sub->user_data_len; j ++) { - if (sub->user_data[i] < ' ' || - sub->user_data[i] > 0x7f || - sub->user_data[i] == '<') + if (sub->user_data[j] < ' ' || + sub->user_data[j] > 0x7f || + sub->user_data[j] == '<') { if (!hex) { - cupsFilePrintf(fp, "<%02X", sub->user_data[i]); + cupsFilePrintf(fp, "<%02X", sub->user_data[j]); hex = 1; } else - cupsFilePrintf(fp, "%02X", sub->user_data[i]); + cupsFilePrintf(fp, "%02X", sub->user_data[j]); } else { if (hex) { - cupsFilePrintf(fp, ">%c", sub->user_data[i]); + cupsFilePrintf(fp, ">%c", sub->user_data[j]); hex = 0; } else - cupsFilePutChar(fp, sub->user_data[i]); + cupsFilePutChar(fp, sub->user_data[j]); } } @@ -1135,6 +1172,8 @@ cupsdSaveAllSubscriptions(void) cupsFilePuts(fp, "\n"); } + cupsRWUnlock(&SubscriptionsLock); + cupsdCloseCreatedConfFile(fp, filename); } @@ -1326,6 +1365,8 @@ cupsd_send_notification( * Allocate the events array as needed... */ + cupsRWLockWrite(&sub->lock); + if (!sub->events) { sub->events = cupsArrayNew3((cups_array_func_t)NULL, NULL, @@ -1425,6 +1466,8 @@ cupsd_send_notification( */ sub->next_event_id ++; + + cupsRWUnlock(&sub->lock); } diff --git a/scheduler/subscriptions.h b/scheduler/subscriptions.h index bc2a7dcb70..4dc8307b60 100644 --- a/scheduler/subscriptions.h +++ b/scheduler/subscriptions.h @@ -79,6 +79,7 @@ typedef struct cupsd_event_s /**** Event structure ****/ typedef struct cupsd_subscription_s /**** Subscription structure ****/ { + cups_rwlock_t lock; /* Reader/writer lock */ int id; /* subscription-id */ unsigned mask; /* Event mask */ char *owner; /* notify-subscriber-user-name */ @@ -104,27 +105,30 @@ typedef struct cupsd_subscription_s /**** Subscription structure ****/ * Globals... */ -VAR int MaxSubscriptions VALUE(100), +VAR int MaxSubscriptions VALUE(100), /* Overall subscription limit */ - MaxSubscriptionsPerJob VALUE(0), + MaxSubscriptionsPerJob VALUE(0), /* Per-job subscription limit */ MaxSubscriptionsPerPrinter VALUE(0), /* Per-printer subscription limit */ - MaxSubscriptionsPerUser VALUE(0), + MaxSubscriptionsPerUser VALUE(0), /* Per-user subscription limit */ - NextSubscriptionId VALUE(1), + NextSubscriptionId VALUE(1), /* Next subscription ID */ - DefaultLeaseDuration VALUE(86400), + DefaultLeaseDuration VALUE(86400), /* Default notify-lease-duration */ - MaxLeaseDuration VALUE(0); + MaxLeaseDuration VALUE(0); /* Maximum notify-lease-duration */ -VAR cups_array_t *Subscriptions VALUE(NULL); +VAR cups_array_t *Subscriptions VALUE(NULL); /* Active subscriptions */ - -VAR int MaxEvents VALUE(100); /* Maximum number of events */ - -VAR unsigned LastEvent VALUE(0); /* Last event(s) processed */ -VAR int NotifierPipes[2] VALUE2(-1, -1); +VAR cups_rwlock_t SubscriptionsLock VALUE(CUPS_RWLOCK_INITIALIZER); + /* Reader/writer lock for subscriptions */ +VAR int MaxEvents VALUE(100); + /* Maximum number of events */ + +VAR unsigned LastEvent VALUE(0); + /* Last event(s) processed */ +VAR int NotifierPipes[2] VALUE2(-1, -1); /* Pipes for notifier error/debug output */ VAR cupsd_statbuf_t *NotifierStatusBuffer VALUE(NULL); /* Status buffer for pipes */