2 * System management functions for the CUPS scheduler.
4 * Copyright 2007-2017 by Apple Inc.
5 * Copyright 2006 by Easy Software Products.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * missing or damaged, see the license at "http://www.cups.org/".
16 * Include necessary headers...
22 # include <IOKit/pwr_mgt/IOPMLib.h>
23 #endif /* __APPLE__ */
27 * The system management functions cover disk and power management which
28 * are primarily used for portable computers.
30 * Disk management involves delaying the write of certain configuration
31 * and state files to minimize the number of times the disk has to spin
32 * up or flash to be written to.
34 * Power management support is currently only implemented on macOS, but
35 * essentially we use four functions to let the OS know when it is OK to
36 * put the system to sleep, typically when we are not in the middle of
37 * printing a job. And on macOS we can also "sleep print" - basically the
38 * system only wakes up long enough to service network requests and process
44 * 'cupsdCleanDirty()' - Write dirty config and state files.
50 if (DirtyFiles
& CUPSD_DIRTY_PRINTERS
)
51 cupsdSaveAllPrinters();
53 if (DirtyFiles
& CUPSD_DIRTY_CLASSES
)
54 cupsdSaveAllClasses();
56 if (DirtyFiles
& CUPSD_DIRTY_PRINTCAP
)
59 if (DirtyFiles
& CUPSD_DIRTY_JOBS
)
61 cupsd_job_t
*job
; /* Current job */
65 for (job
= (cupsd_job_t
*)cupsArrayFirst(Jobs
);
67 job
= (cupsd_job_t
*)cupsArrayNext(Jobs
))
72 if (DirtyFiles
& CUPSD_DIRTY_SUBSCRIPTIONS
)
73 cupsdSaveAllSubscriptions();
75 DirtyFiles
= CUPSD_DIRTY_NONE
;
83 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
87 cupsdMarkDirty(int what
) /* I - What file(s) are dirty? */
89 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdMarkDirty(%c%c%c%c%c)",
90 (what
& CUPSD_DIRTY_PRINTERS
) ? 'P' : '-',
91 (what
& CUPSD_DIRTY_CLASSES
) ? 'C' : '-',
92 (what
& CUPSD_DIRTY_PRINTCAP
) ? 'p' : '-',
93 (what
& CUPSD_DIRTY_JOBS
) ? 'J' : '-',
94 (what
& CUPSD_DIRTY_SUBSCRIPTIONS
) ? 'S' : '-');
96 if (what
== CUPSD_DIRTY_PRINTCAP
&& !Printcap
)
102 DirtyCleanTime
= time(NULL
) + DirtyCleanInterval
;
104 cupsdSetBusyState(0);
109 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
113 cupsdSetBusyState(int working
) /* I - Doing significant work? */
115 int i
; /* Looping var */
116 cupsd_job_t
*job
; /* Current job */
117 cupsd_printer_t
*p
; /* Current printer */
118 int newbusy
; /* New busy state */
119 static int busy
= 0; /* Current busy state */
120 static const char * const busy_text
[] =
121 { /* Text for busy states */
125 "Printing jobs and dirty files",
127 "Active clients and dirty files",
128 "Active clients and printing jobs",
129 "Active clients, printing jobs, and dirty files"
132 static int tran
= 0; /* Current busy transaction */
133 static IOPMAssertionID keep_awake
= 0;/* Keep the system awake while printing */
134 #endif /* __APPLE__ */
138 * Figure out how busy we are...
141 newbusy
= (DirtyCleanTime
? 1 : 0) |
142 ((working
|| cupsArrayCount(ActiveClients
) > 0) ? 4 : 0);
144 for (job
= (cupsd_job_t
*)cupsArrayFirst(PrintingJobs
);
146 job
= (cupsd_job_t
*)cupsArrayNext(PrintingJobs
))
148 if ((p
= job
->printer
) != NULL
)
150 for (i
= 0; i
< p
->num_reasons
; i
++)
151 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
154 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
162 cupsdLogMessage(CUPSD_LOG_DEBUG
,
163 "cupsdSetBusyState: newbusy=\"%s\", busy=\"%s\"",
164 busy_text
[newbusy
], busy_text
[busy
]);
167 * Manage state changes...
177 xpc_transaction_begin();
180 else if (!busy
&& tran
)
182 xpc_transaction_end();
185 #endif /* __APPLE__ */
189 if (cupsArrayCount(PrintingJobs
) > 0 && !keep_awake
)
191 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Asserting NetworkClientActive.");
193 IOPMAssertionCreateWithName(kIOPMAssertNetworkClientActive
,
194 kIOPMAssertionLevelOn
,
195 CFSTR("org.cups.cupsd"), &keep_awake
);
197 else if (cupsArrayCount(PrintingJobs
) == 0 && keep_awake
)
199 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Releasing power assertion.");
200 IOPMAssertionRelease(keep_awake
);
203 #endif /* __APPLE__ */
209 * This is the Apple-specific system event code. It works by creating
210 * a worker thread that waits for events from the OS and relays them
211 * to the main thread via a traditional pipe.
215 * Include MacOS-specific headers...
219 # include <IOKit/IOKitLib.h>
220 # include <IOKit/IOMessage.h>
221 # include <IOKit/ps/IOPowerSources.h>
222 # include <IOKit/pwr_mgt/IOPMLib.h>
223 # include <SystemConfiguration/SystemConfiguration.h>
224 # include <pthread.h>
231 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
232 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
233 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
234 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
235 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
242 typedef struct cupsd_sysevent_s
/*** System event data ****/
244 unsigned char event
; /* Event bit field */
245 io_connect_t powerKernelPort
; /* Power context data */
246 long powerNotificationID
; /* Power event data */
250 typedef struct cupsd_thread_data_s
/*** Thread context data ****/
252 cupsd_sysevent_t sysevent
; /* System event */
253 CFRunLoopTimerRef timerRef
; /* Timer to delay some change *
255 } cupsd_thread_data_t
;
262 static pthread_t SysEventThread
= NULL
;
263 /* Thread to host a runloop */
264 static pthread_mutex_t SysEventThreadMutex
= { 0 };
265 /* Coordinates access to shared gloabals */
266 static pthread_cond_t SysEventThreadCond
= { 0 };
267 /* Thread initialization complete condition */
268 static CFRunLoopRef SysEventRunloop
= NULL
;
269 /* The runloop. Access must be protected! */
270 static CFStringRef ComputerNameKey
= NULL
,
271 /* Computer name key */
272 BTMMKey
= NULL
, /* Back to My Mac key */
273 NetworkGlobalKeyIPv4
= NULL
,
274 /* Network global IPv4 key */
275 NetworkGlobalKeyIPv6
= NULL
,
276 /* Network global IPv6 key */
277 NetworkGlobalKeyDNS
= NULL
,
278 /* Network global DNS key */
281 NetworkInterfaceKeyIPv4
= NULL
,
282 /* Netowrk interface key */
283 NetworkInterfaceKeyIPv6
= NULL
;
284 /* Netowrk interface key */
285 static cupsd_sysevent_t LastSysEvent
; /* Last system event (for delayed sleep) */
286 static int NameChanged
= 0;/* Did we get a 'name changed' event during sleep? */
287 static int PSToken
= 0; /* Power source notifications */
294 static void *sysEventThreadEntry(void);
295 static void sysEventPowerNotifier(void *context
, io_service_t service
,
296 natural_t messageType
,
297 void *messageArgument
);
298 static void sysEventConfigurationNotifier(SCDynamicStoreRef store
,
299 CFArrayRef changedKeys
,
301 static void sysEventTimerNotifier(CFRunLoopTimerRef timer
, void *context
);
302 static void sysUpdate(void);
303 static void sysUpdateNames(void);
307 * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
311 cupsdAllowSleep(void)
315 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
316 IOAllowPowerChange(LastSysEvent
.powerKernelPort
,
317 LastSysEvent
.powerNotificationID
);
322 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
326 cupsdStartSystemMonitor(void)
328 int flags
; /* fcntl flags on pipe */
331 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartSystemMonitor()");
333 if (cupsdOpenPipe(SysEventPipes
))
335 cupsdLogMessage(CUPSD_LOG_ERROR
, "System event monitor pipe() failed - %s!",
340 cupsdAddSelect(SysEventPipes
[0], (cupsd_selfunc_t
)sysUpdate
, NULL
, NULL
);
343 * Set non-blocking mode on the descriptor we will be receiving notification
347 flags
= fcntl(SysEventPipes
[0], F_GETFL
, 0);
348 fcntl(SysEventPipes
[0], F_SETFL
, flags
| O_NONBLOCK
);
351 * Start the thread that runs the runloop...
354 pthread_mutex_init(&SysEventThreadMutex
, NULL
);
355 pthread_cond_init(&SysEventThreadCond
, NULL
);
356 pthread_create(&SysEventThread
, NULL
, (void *(*)(void *))sysEventThreadEntry
, NULL
);
359 * Monitor for power source changes via dispatch queue...
362 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartSystemMonitor: IOPSGetTimeRemainingEstimate=%f", IOPSGetTimeRemainingEstimate());
363 ACPower
= IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited
;
364 notify_register_dispatch(kIOPSNotifyPowerSource
, &PSToken
, dispatch_get_main_queue(), ^(int t
) { (void)t
;
365 ACPower
= IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited
; });
370 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
374 cupsdStopSystemMonitor(void)
376 CFRunLoopRef rl
; /* The event handler runloop */
379 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStopSystemMonitor()");
384 * Make sure the thread has completed it's initialization and
385 * stored it's runloop reference in the shared global.
388 pthread_mutex_lock(&SysEventThreadMutex
);
390 if (!SysEventRunloop
)
391 pthread_cond_wait(&SysEventThreadCond
, &SysEventThreadMutex
);
393 rl
= SysEventRunloop
;
394 SysEventRunloop
= NULL
;
396 pthread_mutex_unlock(&SysEventThreadMutex
);
401 pthread_join(SysEventThread
, NULL
);
402 pthread_mutex_destroy(&SysEventThreadMutex
);
403 pthread_cond_destroy(&SysEventThreadCond
);
406 if (SysEventPipes
[0] >= 0)
408 cupsdRemoveSelect(SysEventPipes
[0]);
409 cupsdClosePipe(SysEventPipes
);
414 notify_cancel(PSToken
);
421 * 'sysEventThreadEntry()' - A thread to receive power and computer name
422 * change notifications.
425 static void * /* O - Return status/value */
426 sysEventThreadEntry(void)
428 io_object_t powerNotifierObj
;
429 /* Power notifier object */
430 IONotificationPortRef powerNotifierPort
;
431 /* Power notifier port */
432 SCDynamicStoreRef store
= NULL
;/* System Config dynamic store */
433 CFRunLoopSourceRef powerRLS
= NULL
,/* Power runloop source */
434 storeRLS
= NULL
;/* System Config runloop source */
435 CFStringRef key
[6], /* System Config keys */
436 pattern
[2]; /* System Config patterns */
437 CFArrayRef keys
= NULL
, /* System Config key array*/
438 patterns
= NULL
;/* System Config pattern array */
439 SCDynamicStoreContext storeContext
; /* Dynamic store context */
440 CFRunLoopTimerContext timerContext
; /* Timer context */
441 cupsd_thread_data_t threadData
; /* Thread context data for the *
442 * runloop notifiers */
446 * Register for power state change notifications
449 bzero(&threadData
, sizeof(threadData
));
451 threadData
.sysevent
.powerKernelPort
=
452 IORegisterForSystemPower(&threadData
, &powerNotifierPort
,
453 sysEventPowerNotifier
, &powerNotifierObj
);
455 if (threadData
.sysevent
.powerKernelPort
)
457 powerRLS
= IONotificationPortGetRunLoopSource(powerNotifierPort
);
458 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS
, kCFRunLoopDefaultMode
);
461 DEBUG_puts("sysEventThreadEntry: error registering for system power "
465 * Register for system configuration change notifications
468 bzero(&storeContext
, sizeof(storeContext
));
469 storeContext
.info
= &threadData
;
471 store
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"),
472 sysEventConfigurationNotifier
, &storeContext
);
474 if (!ComputerNameKey
)
475 ComputerNameKey
= SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault
);
478 BTMMKey
= SCDynamicStoreKeyCreate(kCFAllocatorDefault
,
479 CFSTR("Setup:/Network/BackToMyMac"));
481 if (!NetworkGlobalKeyIPv4
)
482 NetworkGlobalKeyIPv4
=
483 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
484 kSCDynamicStoreDomainState
,
487 if (!NetworkGlobalKeyIPv6
)
488 NetworkGlobalKeyIPv6
=
489 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
490 kSCDynamicStoreDomainState
,
493 if (!NetworkGlobalKeyDNS
)
494 NetworkGlobalKeyDNS
=
495 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
496 kSCDynamicStoreDomainState
,
500 HostNamesKey
= SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault
);
502 if (!NetworkInterfaceKeyIPv4
)
503 NetworkInterfaceKeyIPv4
=
504 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
505 kSCDynamicStoreDomainState
,
509 if (!NetworkInterfaceKeyIPv6
)
510 NetworkInterfaceKeyIPv6
=
511 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
512 kSCDynamicStoreDomainState
,
516 if (store
&& ComputerNameKey
&& HostNamesKey
&&
517 NetworkGlobalKeyIPv4
&& NetworkGlobalKeyIPv6
&& NetworkGlobalKeyDNS
&&
518 NetworkInterfaceKeyIPv4
&& NetworkInterfaceKeyIPv6
)
520 key
[0] = ComputerNameKey
;
522 key
[2] = NetworkGlobalKeyIPv4
;
523 key
[3] = NetworkGlobalKeyIPv6
;
524 key
[4] = NetworkGlobalKeyDNS
;
525 key
[5] = HostNamesKey
;
527 pattern
[0] = NetworkInterfaceKeyIPv4
;
528 pattern
[1] = NetworkInterfaceKeyIPv6
;
530 keys
= CFArrayCreate(kCFAllocatorDefault
, (const void **)key
,
531 sizeof(key
) / sizeof(key
[0]),
532 &kCFTypeArrayCallBacks
);
534 patterns
= CFArrayCreate(kCFAllocatorDefault
, (const void **)pattern
,
535 sizeof(pattern
) / sizeof(pattern
[0]),
536 &kCFTypeArrayCallBacks
);
538 if (keys
&& patterns
&&
539 SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
541 if ((storeRLS
= SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault
,
544 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS
,
545 kCFRunLoopDefaultMode
);
548 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
549 "failed: %s\n", SCErrorString(SCError())));
552 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
553 "failed: %s\n", SCErrorString(SCError())));
556 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
557 SCErrorString(SCError())));
566 * Set up a timer to delay the wake change notifications.
568 * The initial time is set a decade or so into the future, we'll adjust
572 bzero(&timerContext
, sizeof(timerContext
));
573 timerContext
.info
= &threadData
;
575 threadData
.timerRef
=
576 CFRunLoopTimerCreate(kCFAllocatorDefault
,
577 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
578 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier
,
580 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
581 kCFRunLoopDefaultMode
);
584 * Store our runloop in a global so the main thread can use it to stop us.
587 pthread_mutex_lock(&SysEventThreadMutex
);
589 SysEventRunloop
= CFRunLoopGetCurrent();
591 pthread_cond_signal(&SysEventThreadCond
);
592 pthread_mutex_unlock(&SysEventThreadMutex
);
595 * Disappear into the runloop until it's stopped by the main thread.
601 * Clean up before exiting.
604 if (threadData
.timerRef
)
606 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
607 kCFRunLoopDefaultMode
);
608 CFRelease(threadData
.timerRef
);
611 if (threadData
.sysevent
.powerKernelPort
)
613 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS
,
614 kCFRunLoopDefaultMode
);
615 IODeregisterForSystemPower(&powerNotifierObj
);
616 IOServiceClose(threadData
.sysevent
.powerKernelPort
);
617 IONotificationPortDestroy(powerNotifierPort
);
622 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS
,
623 kCFRunLoopDefaultMode
);
624 CFRunLoopSourceInvalidate(storeRLS
);
636 * 'sysEventPowerNotifier()' - Handle power notification events.
640 sysEventPowerNotifier(
641 void *context
, /* I - Thread context data */
642 io_service_t service
, /* I - Unused service info */
643 natural_t messageType
, /* I - Type of message */
644 void *messageArgument
) /* I - Message data */
646 int sendit
= 1; /* Send event to main thread? *
647 * (0 = no, 1 = yes, 2 = delayed */
648 cupsd_thread_data_t
*threadData
; /* Thread context data */
651 threadData
= (cupsd_thread_data_t
*)context
;
653 (void)service
; /* anti-compiler-warning-code */
657 case kIOMessageCanSystemPowerOff
:
658 case kIOMessageCanSystemSleep
:
659 threadData
->sysevent
.event
|= SYSEVENT_CANSLEEP
;
662 case kIOMessageSystemWillRestart
:
663 case kIOMessageSystemWillPowerOff
:
664 case kIOMessageSystemWillSleep
:
665 threadData
->sysevent
.event
|= SYSEVENT_WILLSLEEP
;
666 threadData
->sysevent
.event
&= ~SYSEVENT_WOKE
;
669 case kIOMessageSystemHasPoweredOn
:
671 * Because powered on is followed by a net-changed event, delay
676 threadData
->sysevent
.event
|= SYSEVENT_WOKE
;
679 case kIOMessageSystemWillNotPowerOff
:
680 case kIOMessageSystemWillNotSleep
:
681 # ifdef kIOMessageSystemWillPowerOn
682 case kIOMessageSystemWillPowerOn
:
683 # endif /* kIOMessageSystemWillPowerOn */
691 case kIOMessageCanSystemPowerOff
:
692 cupsdLogMessage(CUPSD_LOG_DEBUG
,
693 "Got kIOMessageCanSystemPowerOff message.");
695 case kIOMessageCanSystemSleep
:
696 cupsdLogMessage(CUPSD_LOG_DEBUG
,
697 "Got kIOMessageCannSystemSleep message.");
699 case kIOMessageSystemWillRestart
:
700 cupsdLogMessage(CUPSD_LOG_DEBUG
,
701 "Got kIOMessageSystemWillRestart message.");
703 case kIOMessageSystemWillPowerOff
:
704 cupsdLogMessage(CUPSD_LOG_DEBUG
,
705 "Got kIOMessageSystemWillPowerOff message.");
707 case kIOMessageSystemWillSleep
:
708 cupsdLogMessage(CUPSD_LOG_DEBUG
,
709 "Got kIOMessageSystemWillSleep message.");
711 case kIOMessageSystemHasPoweredOn
:
712 cupsdLogMessage(CUPSD_LOG_DEBUG
,
713 "Got kIOMessageSystemHasPoweredOn message.");
715 case kIOMessageSystemWillNotPowerOff
:
716 cupsdLogMessage(CUPSD_LOG_DEBUG
,
717 "Got kIOMessageSystemWillNotPowerOff message.");
719 case kIOMessageSystemWillNotSleep
:
720 cupsdLogMessage(CUPSD_LOG_DEBUG
,
721 "Got kIOMessageSystemWillNotSleep message.");
723 # ifdef kIOMessageSystemWillPowerOn
724 case kIOMessageSystemWillPowerOn
:
725 cupsdLogMessage(CUPSD_LOG_DEBUG
,
726 "Got kIOMessageSystemWillPowerOn message.");
728 # endif /* kIOMessageSystemWillPowerOn */
730 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Got unknown power message %d.",
736 IOAllowPowerChange(threadData
->sysevent
.powerKernelPort
,
737 (long)messageArgument
);
740 threadData
->sysevent
.powerNotificationID
= (long)messageArgument
;
745 * Send the event to the main thread now.
748 write(SysEventPipes
[1], &threadData
->sysevent
,
749 sizeof(threadData
->sysevent
));
750 threadData
->sysevent
.event
= 0;
755 * Send the event to the main thread after 1 to 2 seconds.
758 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
759 CFAbsoluteTimeGetCurrent() + 2);
766 * 'sysEventConfigurationNotifier()' - Network configuration change notification
771 sysEventConfigurationNotifier(
772 SCDynamicStoreRef store
, /* I - System data (unused) */
773 CFArrayRef changedKeys
, /* I - Changed data */
774 void *context
) /* I - Thread context data */
776 cupsd_thread_data_t
*threadData
; /* Thread context data */
779 threadData
= (cupsd_thread_data_t
*)context
;
781 (void)store
; /* anti-compiler-warning-code */
783 CFRange range
= CFRangeMake(0, CFArrayGetCount(changedKeys
));
785 if (CFArrayContainsValue(changedKeys
, range
, ComputerNameKey
) ||
786 CFArrayContainsValue(changedKeys
, range
, BTMMKey
))
787 threadData
->sysevent
.event
|= SYSEVENT_NAMECHANGED
;
790 threadData
->sysevent
.event
|= SYSEVENT_NETCHANGED
;
793 * Indicate the network interface list needs updating...
800 * Because we registered for several different kinds of change notifications
801 * this callback usually gets called several times in a row. We use a timer to
802 * de-bounce these so we only end up generating one event for the main thread.
805 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
806 CFAbsoluteTimeGetCurrent() + 5);
811 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
815 sysEventTimerNotifier(
816 CFRunLoopTimerRef timer
, /* I - Timer information */
817 void *context
) /* I - Thread context data */
819 cupsd_thread_data_t
*threadData
; /* Thread context data */
824 threadData
= (cupsd_thread_data_t
*)context
;
827 * If an event is still pending send it to the main thread.
830 if (threadData
->sysevent
.event
)
832 write(SysEventPipes
[1], &threadData
->sysevent
,
833 sizeof(threadData
->sysevent
));
834 threadData
->sysevent
.event
= 0;
840 * 'sysUpdate()' - Update the current system state.
846 int i
; /* Looping var */
847 cupsd_sysevent_t sysevent
; /* The system event */
848 cupsd_printer_t
*p
; /* Printer information */
852 * Drain the event pipe...
855 while (read((int)SysEventPipes
[0], &sysevent
, sizeof(sysevent
))
858 if (sysevent
.event
& SYSEVENT_CANSLEEP
)
861 * If there are active printers that don't have the connecting-to-device
862 * or cups-waiting-for-job-completed printer-state-reason then cancel the
863 * sleep request, i.e., these reasons indicate a job that is not actively
867 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
869 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
873 for (i
= 0; i
< p
->num_reasons
; i
++)
874 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
875 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
878 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
885 cupsdLogMessage(CUPSD_LOG_INFO
,
886 "System sleep canceled because printer %s is active.",
888 IOCancelPowerChange(sysevent
.powerKernelPort
,
889 sysevent
.powerNotificationID
);
893 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System wants to sleep.");
894 IOAllowPowerChange(sysevent
.powerKernelPort
,
895 sysevent
.powerNotificationID
);
899 if (sysevent
.event
& SYSEVENT_WILLSLEEP
)
901 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System going to sleep.");
908 * If we have no printing jobs, allow the power change immediately.
909 * Otherwise set the SleepJobs time to 10 seconds in the future when
910 * we'll take more drastic measures...
913 if (cupsArrayCount(PrintingJobs
) == 0)
915 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
916 IOAllowPowerChange(sysevent
.powerKernelPort
,
917 sysevent
.powerNotificationID
);
922 * If there are active printers that don't have the connecting-to-device
923 * or cups-waiting-for-job-completed printer-state-reasons then delay the
924 * sleep request, i.e., these reasons indicate a job is active...
927 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
929 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
933 for (i
= 0; i
< p
->num_reasons
; i
++)
934 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
935 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
938 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
945 cupsdLogMessage(CUPSD_LOG_INFO
,
946 "System sleep delayed because printer %s is active.",
949 LastSysEvent
= sysevent
;
950 SleepJobs
= time(NULL
) + 10;
954 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
955 IOAllowPowerChange(sysevent
.powerKernelPort
,
956 sysevent
.powerNotificationID
);
961 if (sysevent
.event
& SYSEVENT_WOKE
)
963 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System woke from sleep.");
964 IOAllowPowerChange(sysevent
.powerKernelPort
,
965 sysevent
.powerNotificationID
);
969 * Make sure jobs that were queued prior to the system going to sleep don't
970 * get canceled right away...
975 cupsd_job_t
*job
; /* Current job */
977 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
979 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
981 if (job
->cancel_time
)
983 ipp_attribute_t
*cancel_after
= ippFindAttribute(job
->attrs
,
988 job
->cancel_time
= time(NULL
) + ippGetInteger(cancel_after
, 0);
990 job
->cancel_time
= time(NULL
) + MaxJobTime
;
1001 if (sysevent
.event
& SYSEVENT_NETCHANGED
)
1004 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1005 "System network configuration changed - "
1006 "ignored while sleeping.");
1008 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1009 "System network configuration changed.");
1012 if (sysevent
.event
& SYSEVENT_NAMECHANGED
)
1018 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1019 "Computer name or BTMM domains changed - ignored while "
1024 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1025 "Computer name or BTMM domains changed.");
1035 * 'sysUpdateNames()' - Update computer and/or BTMM domains.
1039 sysUpdateNames(void)
1041 cupsd_printer_t
*p
; /* Current printer */
1047 * De-register the individual printers...
1050 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1052 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1053 cupsdDeregisterPrinter(p
, 1);
1055 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1057 * Update the computer name and BTMM domain list...
1060 cupsdUpdateDNSSDName();
1061 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1064 * Now re-register them...
1067 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1069 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1070 cupsdRegisterPrinter(p
);
1072 #endif /* __APPLE__ */