4 * System management functions for the CUPS scheduler.
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 2006 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
18 * Include necessary headers...
24 # include <IOKit/pwr_mgt/IOPMLib.h>
25 #endif /* __APPLE__ */
29 * The system management functions cover disk and power management which
30 * are primarily used for portable computers.
32 * Disk management involves delaying the write of certain configuration
33 * and state files to minimize the number of times the disk has to spin
34 * up or flash to be written to.
36 * Power management support is currently only implemented on OS X, but
37 * essentially we use four functions to let the OS know when it is OK to
38 * put the system to sleep, typically when we are not in the middle of
39 * printing a job. And on OS X we can also "sleep print" - basically the
40 * system only wakes up long enough to service network requests and process
46 * 'cupsdCleanDirty()' - Write dirty config and state files.
52 if (DirtyFiles
& CUPSD_DIRTY_PRINTERS
)
53 cupsdSaveAllPrinters();
55 if (DirtyFiles
& CUPSD_DIRTY_CLASSES
)
56 cupsdSaveAllClasses();
58 if (DirtyFiles
& CUPSD_DIRTY_PRINTCAP
)
61 if (DirtyFiles
& CUPSD_DIRTY_JOBS
)
63 cupsd_job_t
*job
; /* Current job */
67 for (job
= (cupsd_job_t
*)cupsArrayFirst(Jobs
);
69 job
= (cupsd_job_t
*)cupsArrayNext(Jobs
))
74 if (DirtyFiles
& CUPSD_DIRTY_SUBSCRIPTIONS
)
75 cupsdSaveAllSubscriptions();
77 DirtyFiles
= CUPSD_DIRTY_NONE
;
85 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
89 cupsdMarkDirty(int what
) /* I - What file(s) are dirty? */
91 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdMarkDirty(%c%c%c%c%c)",
92 (what
& CUPSD_DIRTY_PRINTERS
) ? 'P' : '-',
93 (what
& CUPSD_DIRTY_CLASSES
) ? 'C' : '-',
94 (what
& CUPSD_DIRTY_PRINTCAP
) ? 'p' : '-',
95 (what
& CUPSD_DIRTY_JOBS
) ? 'J' : '-',
96 (what
& CUPSD_DIRTY_SUBSCRIPTIONS
) ? 'S' : '-');
98 if (what
== CUPSD_DIRTY_PRINTCAP
&& !Printcap
)
104 DirtyCleanTime
= time(NULL
) + DirtyCleanInterval
;
111 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
115 cupsdSetBusyState(void)
117 int i
; /* Looping var */
118 cupsd_job_t
*job
; /* Current job */
119 cupsd_printer_t
*p
; /* Current printer */
120 int newbusy
; /* New busy state */
121 static int busy
= 0; /* Current busy state */
122 static const char * const busy_text
[] =
123 { /* Text for busy states */
127 "Printing jobs and dirty files",
129 "Active clients and dirty files",
130 "Active clients and printing jobs",
131 "Active clients, printing jobs, and dirty files"
134 static vproc_transaction_t vtran
= 0; /* Current busy transaction */
135 static IOPMAssertionID keep_awake
= 0;/* Keep the system awake while printing */
136 #endif /* __APPLE__ */
140 * Figure out how busy we are...
143 newbusy
= (DirtyCleanTime
? 1 : 0) |
144 (cupsArrayCount(ActiveClients
) ? 4 : 0);
146 for (job
= (cupsd_job_t
*)cupsArrayFirst(PrintingJobs
);
148 job
= (cupsd_job_t
*)cupsArrayNext(PrintingJobs
))
150 if ((p
= job
->printer
) != NULL
)
152 for (i
= 0; i
< p
->num_reasons
; i
++)
153 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
156 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
164 cupsdLogMessage(CUPSD_LOG_DEBUG
,
165 "cupsdSetBusyState: newbusy=\"%s\", busy=\"%s\"",
166 busy_text
[newbusy
], busy_text
[busy
]);
169 * Manage state changes...
178 vtran
= vproc_transaction_begin(NULL
);
179 else if (!busy
&& vtran
)
181 vproc_transaction_end(NULL
, vtran
);
184 #endif /* __APPLE__ */
188 if (cupsArrayCount(PrintingJobs
) > 0 && !keep_awake
)
190 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Asserting NetworkClientActive.");
192 IOPMAssertionCreateWithName(kIOPMAssertNetworkClientActive
,
193 kIOPMAssertionLevelOn
,
194 CFSTR("org.cups.cupsd"), &keep_awake
);
196 else if (cupsArrayCount(PrintingJobs
) == 0 && keep_awake
)
198 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Releasing power assertion.");
199 IOPMAssertionRelease(keep_awake
);
202 #endif /* __APPLE__ */
208 * This is the Apple-specific system event code. It works by creating
209 * a worker thread that waits for events from the OS and relays them
210 * to the main thread via a traditional pipe.
214 * Include MacOS-specific headers...
218 # include <IOKit/IOKitLib.h>
219 # include <IOKit/IOMessage.h>
220 # include <IOKit/ps/IOPowerSources.h>
221 # include <IOKit/pwr_mgt/IOPMLib.h>
222 # include <SystemConfiguration/SystemConfiguration.h>
223 # include <pthread.h>
230 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
231 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
232 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
233 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
234 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
241 typedef struct cupsd_sysevent_s
/*** System event data ****/
243 unsigned char event
; /* Event bit field */
244 io_connect_t powerKernelPort
; /* Power context data */
245 long powerNotificationID
; /* Power event data */
249 typedef struct cupsd_thread_data_s
/*** Thread context data ****/
251 cupsd_sysevent_t sysevent
; /* System event */
252 CFRunLoopTimerRef timerRef
; /* Timer to delay some change *
254 } cupsd_thread_data_t
;
261 static pthread_t SysEventThread
= NULL
;
262 /* Thread to host a runloop */
263 static pthread_mutex_t SysEventThreadMutex
= { 0 };
264 /* Coordinates access to shared gloabals */
265 static pthread_cond_t SysEventThreadCond
= { 0 };
266 /* Thread initialization complete condition */
267 static CFRunLoopRef SysEventRunloop
= NULL
;
268 /* The runloop. Access must be protected! */
269 static CFStringRef ComputerNameKey
= NULL
,
270 /* Computer name key */
271 BTMMKey
= NULL
, /* Back to My Mac key */
272 NetworkGlobalKeyIPv4
= NULL
,
273 /* Network global IPv4 key */
274 NetworkGlobalKeyIPv6
= NULL
,
275 /* Network global IPv6 key */
276 NetworkGlobalKeyDNS
= NULL
,
277 /* Network global DNS key */
280 NetworkInterfaceKeyIPv4
= NULL
,
281 /* Netowrk interface key */
282 NetworkInterfaceKeyIPv6
= NULL
;
283 /* Netowrk interface key */
284 static cupsd_sysevent_t LastSysEvent
; /* Last system event (for delayed sleep) */
285 static int NameChanged
= 0;/* Did we get a 'name changed' event during sleep? */
286 static int PSToken
= 0; /* Power source notifications */
293 static void *sysEventThreadEntry(void);
294 static void sysEventPowerNotifier(void *context
, io_service_t service
,
295 natural_t messageType
,
296 void *messageArgument
);
297 static void sysEventConfigurationNotifier(SCDynamicStoreRef store
,
298 CFArrayRef changedKeys
,
300 static void sysEventTimerNotifier(CFRunLoopTimerRef timer
, void *context
);
301 static void sysUpdate(void);
302 static void sysUpdateNames(void);
306 * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
310 cupsdAllowSleep(void)
314 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
315 IOAllowPowerChange(LastSysEvent
.powerKernelPort
,
316 LastSysEvent
.powerNotificationID
);
321 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
325 cupsdStartSystemMonitor(void)
327 int flags
; /* fcntl flags on pipe */
330 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartSystemMonitor()");
332 if (cupsdOpenPipe(SysEventPipes
))
334 cupsdLogMessage(CUPSD_LOG_ERROR
, "System event monitor pipe() failed - %s!",
339 cupsdAddSelect(SysEventPipes
[0], (cupsd_selfunc_t
)sysUpdate
, NULL
, NULL
);
342 * Set non-blocking mode on the descriptor we will be receiving notification
346 flags
= fcntl(SysEventPipes
[0], F_GETFL
, 0);
347 fcntl(SysEventPipes
[0], F_SETFL
, flags
| O_NONBLOCK
);
350 * Start the thread that runs the runloop...
353 pthread_mutex_init(&SysEventThreadMutex
, NULL
);
354 pthread_cond_init(&SysEventThreadCond
, NULL
);
355 pthread_create(&SysEventThread
, NULL
, (void *(*)())sysEventThreadEntry
, NULL
);
358 * Monitor for power source changes via dispatch queue...
361 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartSystemMonitor: IOPSGetTimeRemainingEstimate=%f", IOPSGetTimeRemainingEstimate());
362 ACPower
= IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited
;
363 notify_register_dispatch(kIOPSNotifyPowerSource
, &PSToken
, dispatch_get_main_queue(), ^(int t
) { (void)t
;
364 ACPower
= IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited
; });
369 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
373 cupsdStopSystemMonitor(void)
375 CFRunLoopRef rl
; /* The event handler runloop */
378 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStopSystemMonitor()");
383 * Make sure the thread has completed it's initialization and
384 * stored it's runloop reference in the shared global.
387 pthread_mutex_lock(&SysEventThreadMutex
);
389 if (!SysEventRunloop
)
390 pthread_cond_wait(&SysEventThreadCond
, &SysEventThreadMutex
);
392 rl
= SysEventRunloop
;
393 SysEventRunloop
= NULL
;
395 pthread_mutex_unlock(&SysEventThreadMutex
);
400 pthread_join(SysEventThread
, NULL
);
401 pthread_mutex_destroy(&SysEventThreadMutex
);
402 pthread_cond_destroy(&SysEventThreadCond
);
405 if (SysEventPipes
[0] >= 0)
407 cupsdRemoveSelect(SysEventPipes
[0]);
408 cupsdClosePipe(SysEventPipes
);
413 notify_cancel(PSToken
);
420 * 'sysEventThreadEntry()' - A thread to receive power and computer name
421 * change notifications.
424 static void * /* O - Return status/value */
425 sysEventThreadEntry(void)
427 io_object_t powerNotifierObj
;
428 /* Power notifier object */
429 IONotificationPortRef powerNotifierPort
;
430 /* Power notifier port */
431 SCDynamicStoreRef store
= NULL
;/* System Config dynamic store */
432 CFRunLoopSourceRef powerRLS
= NULL
,/* Power runloop source */
433 storeRLS
= NULL
;/* System Config runloop source */
434 CFStringRef key
[6], /* System Config keys */
435 pattern
[2]; /* System Config patterns */
436 CFArrayRef keys
= NULL
, /* System Config key array*/
437 patterns
= NULL
;/* System Config pattern array */
438 SCDynamicStoreContext storeContext
; /* Dynamic store context */
439 CFRunLoopTimerContext timerContext
; /* Timer context */
440 cupsd_thread_data_t threadData
; /* Thread context data for the *
441 * runloop notifiers */
445 * Register for power state change notifications
448 bzero(&threadData
, sizeof(threadData
));
450 threadData
.sysevent
.powerKernelPort
=
451 IORegisterForSystemPower(&threadData
, &powerNotifierPort
,
452 sysEventPowerNotifier
, &powerNotifierObj
);
454 if (threadData
.sysevent
.powerKernelPort
)
456 powerRLS
= IONotificationPortGetRunLoopSource(powerNotifierPort
);
457 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS
, kCFRunLoopDefaultMode
);
460 DEBUG_puts("sysEventThreadEntry: error registering for system power "
464 * Register for system configuration change notifications
467 bzero(&storeContext
, sizeof(storeContext
));
468 storeContext
.info
= &threadData
;
470 store
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"),
471 sysEventConfigurationNotifier
, &storeContext
);
473 if (!ComputerNameKey
)
474 ComputerNameKey
= SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault
);
477 BTMMKey
= SCDynamicStoreKeyCreate(kCFAllocatorDefault
,
478 CFSTR("Setup:/Network/BackToMyMac"));
480 if (!NetworkGlobalKeyIPv4
)
481 NetworkGlobalKeyIPv4
=
482 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
483 kSCDynamicStoreDomainState
,
486 if (!NetworkGlobalKeyIPv6
)
487 NetworkGlobalKeyIPv6
=
488 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
489 kSCDynamicStoreDomainState
,
492 if (!NetworkGlobalKeyDNS
)
493 NetworkGlobalKeyDNS
=
494 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
495 kSCDynamicStoreDomainState
,
499 HostNamesKey
= SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault
);
501 if (!NetworkInterfaceKeyIPv4
)
502 NetworkInterfaceKeyIPv4
=
503 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
504 kSCDynamicStoreDomainState
,
508 if (!NetworkInterfaceKeyIPv6
)
509 NetworkInterfaceKeyIPv6
=
510 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
511 kSCDynamicStoreDomainState
,
515 if (store
&& ComputerNameKey
&& HostNamesKey
&&
516 NetworkGlobalKeyIPv4
&& NetworkGlobalKeyIPv6
&& NetworkGlobalKeyDNS
&&
517 NetworkInterfaceKeyIPv4
&& NetworkInterfaceKeyIPv6
)
519 key
[0] = ComputerNameKey
;
521 key
[2] = NetworkGlobalKeyIPv4
;
522 key
[3] = NetworkGlobalKeyIPv6
;
523 key
[4] = NetworkGlobalKeyDNS
;
524 key
[5] = HostNamesKey
;
526 pattern
[0] = NetworkInterfaceKeyIPv4
;
527 pattern
[1] = NetworkInterfaceKeyIPv6
;
529 keys
= CFArrayCreate(kCFAllocatorDefault
, (const void **)key
,
530 sizeof(key
) / sizeof(key
[0]),
531 &kCFTypeArrayCallBacks
);
533 patterns
= CFArrayCreate(kCFAllocatorDefault
, (const void **)pattern
,
534 sizeof(pattern
) / sizeof(pattern
[0]),
535 &kCFTypeArrayCallBacks
);
537 if (keys
&& patterns
&&
538 SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
540 if ((storeRLS
= SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault
,
543 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS
,
544 kCFRunLoopDefaultMode
);
547 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
548 "failed: %s\n", SCErrorString(SCError())));
551 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
552 "failed: %s\n", SCErrorString(SCError())));
555 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
556 SCErrorString(SCError())));
565 * Set up a timer to delay the wake change notifications.
567 * The initial time is set a decade or so into the future, we'll adjust
571 bzero(&timerContext
, sizeof(timerContext
));
572 timerContext
.info
= &threadData
;
574 threadData
.timerRef
=
575 CFRunLoopTimerCreate(kCFAllocatorDefault
,
576 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
577 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier
,
579 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
580 kCFRunLoopDefaultMode
);
583 * Store our runloop in a global so the main thread can use it to stop us.
586 pthread_mutex_lock(&SysEventThreadMutex
);
588 SysEventRunloop
= CFRunLoopGetCurrent();
590 pthread_cond_signal(&SysEventThreadCond
);
591 pthread_mutex_unlock(&SysEventThreadMutex
);
594 * Disappear into the runloop until it's stopped by the main thread.
600 * Clean up before exiting.
603 if (threadData
.timerRef
)
605 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
606 kCFRunLoopDefaultMode
);
607 CFRelease(threadData
.timerRef
);
610 if (threadData
.sysevent
.powerKernelPort
)
612 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS
,
613 kCFRunLoopDefaultMode
);
614 IODeregisterForSystemPower(&powerNotifierObj
);
615 IOServiceClose(threadData
.sysevent
.powerKernelPort
);
616 IONotificationPortDestroy(powerNotifierPort
);
621 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS
,
622 kCFRunLoopDefaultMode
);
623 CFRunLoopSourceInvalidate(storeRLS
);
635 * 'sysEventPowerNotifier()' - Handle power notification events.
639 sysEventPowerNotifier(
640 void *context
, /* I - Thread context data */
641 io_service_t service
, /* I - Unused service info */
642 natural_t messageType
, /* I - Type of message */
643 void *messageArgument
) /* I - Message data */
645 int sendit
= 1; /* Send event to main thread? *
646 * (0 = no, 1 = yes, 2 = delayed */
647 cupsd_thread_data_t
*threadData
; /* Thread context data */
650 threadData
= (cupsd_thread_data_t
*)context
;
652 (void)service
; /* anti-compiler-warning-code */
656 case kIOMessageCanSystemPowerOff
:
657 case kIOMessageCanSystemSleep
:
658 threadData
->sysevent
.event
|= SYSEVENT_CANSLEEP
;
661 case kIOMessageSystemWillRestart
:
662 case kIOMessageSystemWillPowerOff
:
663 case kIOMessageSystemWillSleep
:
664 threadData
->sysevent
.event
|= SYSEVENT_WILLSLEEP
;
665 threadData
->sysevent
.event
&= ~SYSEVENT_WOKE
;
668 case kIOMessageSystemHasPoweredOn
:
670 * Because powered on is followed by a net-changed event, delay
675 threadData
->sysevent
.event
|= SYSEVENT_WOKE
;
678 case kIOMessageSystemWillNotPowerOff
:
679 case kIOMessageSystemWillNotSleep
:
680 # ifdef kIOMessageSystemWillPowerOn
681 case kIOMessageSystemWillPowerOn
:
682 # endif /* kIOMessageSystemWillPowerOn */
690 case kIOMessageCanSystemPowerOff
:
691 cupsdLogMessage(CUPSD_LOG_DEBUG
,
692 "Got kIOMessageCanSystemPowerOff message.");
694 case kIOMessageCanSystemSleep
:
695 cupsdLogMessage(CUPSD_LOG_DEBUG
,
696 "Got kIOMessageCannSystemSleep message.");
698 case kIOMessageSystemWillRestart
:
699 cupsdLogMessage(CUPSD_LOG_DEBUG
,
700 "Got kIOMessageSystemWillRestart message.");
702 case kIOMessageSystemWillPowerOff
:
703 cupsdLogMessage(CUPSD_LOG_DEBUG
,
704 "Got kIOMessageSystemWillPowerOff message.");
706 case kIOMessageSystemWillSleep
:
707 cupsdLogMessage(CUPSD_LOG_DEBUG
,
708 "Got kIOMessageSystemWillSleep message.");
710 case kIOMessageSystemHasPoweredOn
:
711 cupsdLogMessage(CUPSD_LOG_DEBUG
,
712 "Got kIOMessageSystemHasPoweredOn message.");
714 case kIOMessageSystemWillNotPowerOff
:
715 cupsdLogMessage(CUPSD_LOG_DEBUG
,
716 "Got kIOMessageSystemWillNotPowerOff message.");
718 case kIOMessageSystemWillNotSleep
:
719 cupsdLogMessage(CUPSD_LOG_DEBUG
,
720 "Got kIOMessageSystemWillNotSleep message.");
722 # ifdef kIOMessageSystemWillPowerOn
723 case kIOMessageSystemWillPowerOn
:
724 cupsdLogMessage(CUPSD_LOG_DEBUG
,
725 "Got kIOMessageSystemWillPowerOn message.");
727 # endif /* kIOMessageSystemWillPowerOn */
729 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Got unknown power message %d.",
735 IOAllowPowerChange(threadData
->sysevent
.powerKernelPort
,
736 (long)messageArgument
);
739 threadData
->sysevent
.powerNotificationID
= (long)messageArgument
;
744 * Send the event to the main thread now.
747 write(SysEventPipes
[1], &threadData
->sysevent
,
748 sizeof(threadData
->sysevent
));
749 threadData
->sysevent
.event
= 0;
754 * Send the event to the main thread after 1 to 2 seconds.
757 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
758 CFAbsoluteTimeGetCurrent() + 2);
765 * 'sysEventConfigurationNotifier()' - Network configuration change notification
770 sysEventConfigurationNotifier(
771 SCDynamicStoreRef store
, /* I - System data (unused) */
772 CFArrayRef changedKeys
, /* I - Changed data */
773 void *context
) /* I - Thread context data */
775 cupsd_thread_data_t
*threadData
; /* Thread context data */
778 threadData
= (cupsd_thread_data_t
*)context
;
780 (void)store
; /* anti-compiler-warning-code */
782 CFRange range
= CFRangeMake(0, CFArrayGetCount(changedKeys
));
784 if (CFArrayContainsValue(changedKeys
, range
, ComputerNameKey
) ||
785 CFArrayContainsValue(changedKeys
, range
, BTMMKey
))
786 threadData
->sysevent
.event
|= SYSEVENT_NAMECHANGED
;
789 threadData
->sysevent
.event
|= SYSEVENT_NETCHANGED
;
792 * Indicate the network interface list needs updating...
799 * Because we registered for several different kinds of change notifications
800 * this callback usually gets called several times in a row. We use a timer to
801 * de-bounce these so we only end up generating one event for the main thread.
804 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
805 CFAbsoluteTimeGetCurrent() + 5);
810 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
814 sysEventTimerNotifier(
815 CFRunLoopTimerRef timer
, /* I - Timer information */
816 void *context
) /* I - Thread context data */
818 cupsd_thread_data_t
*threadData
; /* Thread context data */
823 threadData
= (cupsd_thread_data_t
*)context
;
826 * If an event is still pending send it to the main thread.
829 if (threadData
->sysevent
.event
)
831 write(SysEventPipes
[1], &threadData
->sysevent
,
832 sizeof(threadData
->sysevent
));
833 threadData
->sysevent
.event
= 0;
839 * 'sysUpdate()' - Update the current system state.
845 int i
; /* Looping var */
846 cupsd_sysevent_t sysevent
; /* The system event */
847 cupsd_printer_t
*p
; /* Printer information */
851 * Drain the event pipe...
854 while (read((int)SysEventPipes
[0], &sysevent
, sizeof(sysevent
))
857 if (sysevent
.event
& SYSEVENT_CANSLEEP
)
860 * If there are active printers that don't have the connecting-to-device
861 * or cups-waiting-for-job-completed printer-state-reason then cancel the
862 * sleep request, i.e., these reasons indicate a job that is not actively
866 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
868 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
872 for (i
= 0; i
< p
->num_reasons
; i
++)
873 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
874 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
877 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
884 cupsdLogMessage(CUPSD_LOG_INFO
,
885 "System sleep canceled because printer %s is active.",
887 IOCancelPowerChange(sysevent
.powerKernelPort
,
888 sysevent
.powerNotificationID
);
892 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System wants to sleep.");
893 IOAllowPowerChange(sysevent
.powerKernelPort
,
894 sysevent
.powerNotificationID
);
898 if (sysevent
.event
& SYSEVENT_WILLSLEEP
)
900 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System going to sleep.");
907 * If we have no printing jobs, allow the power change immediately.
908 * Otherwise set the SleepJobs time to 10 seconds in the future when
909 * we'll take more drastic measures...
912 if (cupsArrayCount(PrintingJobs
) == 0)
914 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
915 IOAllowPowerChange(sysevent
.powerKernelPort
,
916 sysevent
.powerNotificationID
);
921 * If there are active printers that don't have the connecting-to-device
922 * or cups-waiting-for-job-completed printer-state-reasons then delay the
923 * sleep request, i.e., these reasons indicate a job is active...
926 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
928 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
932 for (i
= 0; i
< p
->num_reasons
; i
++)
933 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
934 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
937 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
944 cupsdLogMessage(CUPSD_LOG_INFO
,
945 "System sleep delayed because printer %s is active.",
948 LastSysEvent
= sysevent
;
949 SleepJobs
= time(NULL
) + 10;
953 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
954 IOAllowPowerChange(sysevent
.powerKernelPort
,
955 sysevent
.powerNotificationID
);
960 if (sysevent
.event
& SYSEVENT_WOKE
)
962 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System woke from sleep.");
963 IOAllowPowerChange(sysevent
.powerKernelPort
,
964 sysevent
.powerNotificationID
);
968 * Make sure jobs that were queued prior to the system going to sleep don't
969 * get canceled right away...
974 cupsd_job_t
*job
; /* Current job */
976 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
978 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
980 if (job
->cancel_time
)
982 ipp_attribute_t
*cancel_after
= ippFindAttribute(job
->attrs
,
987 job
->cancel_time
= time(NULL
) + ippGetInteger(cancel_after
, 0);
989 job
->cancel_time
= time(NULL
) + MaxJobTime
;
1000 if (sysevent
.event
& SYSEVENT_NETCHANGED
)
1003 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1004 "System network configuration changed - "
1005 "ignored while sleeping.");
1007 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1008 "System network configuration changed.");
1011 if (sysevent
.event
& SYSEVENT_NAMECHANGED
)
1017 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1018 "Computer name or BTMM domains changed - ignored while "
1023 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1024 "Computer name or BTMM domains changed.");
1034 * 'sysUpdateNames()' - Update computer and/or BTMM domains.
1038 sysUpdateNames(void)
1040 cupsd_printer_t
*p
; /* Current printer */
1046 * De-register the individual printers...
1049 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1051 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1052 cupsdDeregisterPrinter(p
, 1);
1054 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1056 * Update the computer name and BTMM domain list...
1059 cupsdUpdateDNSSDName();
1060 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1063 * Now re-register them...
1066 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1068 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1069 cupsdRegisterPrinter(p
);
1071 #endif /* __APPLE__ */