]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/sysman.c
b6d1751423a741d2b17972ac6f1f0db418300dd1
[thirdparty/cups.git] / scheduler / sysman.c
1 /*
2 * "$Id: sysman.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * System management definitions for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 2006 by Easy Software Products.
8 *
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/".
14 *
15 * Contents:
16 *
17 * cupsdCleanDirty() - Write dirty config and state files.
18 * cupsdMarkDirty() - Mark config or state files as needing a
19 * write.
20 * cupsdSetBusyState() - Let the system know when we are busy
21 * doing something.
22 * cupsdStartSystemMonitor() - Start monitoring for system change.
23 * cupsdStopSystemMonitor() - Stop monitoring for system change.
24 * cupsdUpdateSystemMonitor() - Update the current system state.
25 * sysEventThreadEntry() - A thread to receive power and computer
26 * name change notifications.
27 * sysEventPowerNotifier() - Handle power notification events.
28 * sysEventConfigurationNotifier() - Computer name changed notification
29 * callback.
30 * sysEventTimerNotifier() - Handle delayed event notifications.
31 */
32
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include "cupsd.h"
39
40
41 /*
42 * The system management functions cover disk and power management which
43 * are primarily used on portable computers.
44 *
45 * Disk management involves delaying the write of certain configuration
46 * and state files to minimize the number of times the disk has to spin
47 * up.
48 *
49 * Power management support is currently only implemented on MacOS X, but
50 * essentially we use four functions to let the OS know when it is OK to
51 * put the system to idle sleep, typically when we are not in the middle of
52 * printing a job.
53 *
54 * Once put to sleep, we invalidate all remote printers since it is common
55 * to wake up in a new location/on a new wireless network.
56 */
57
58
59 /*
60 * 'cupsdCleanDirty()' - Write dirty config and state files.
61 */
62
63 void
64 cupsdCleanDirty(void)
65 {
66 if (DirtyFiles & CUPSD_DIRTY_PRINTERS)
67 cupsdSaveAllPrinters();
68
69 if (DirtyFiles & CUPSD_DIRTY_CLASSES)
70 cupsdSaveAllClasses();
71
72 if (DirtyFiles & CUPSD_DIRTY_REMOTE)
73 cupsdSaveRemoteCache();
74
75 if (DirtyFiles & CUPSD_DIRTY_PRINTCAP)
76 cupsdWritePrintcap();
77
78 if (DirtyFiles & CUPSD_DIRTY_JOBS)
79 {
80 cupsd_job_t *job; /* Current job */
81
82 cupsdSaveAllJobs();
83
84 for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
85 job;
86 job = (cupsd_job_t *)cupsArrayNext(Jobs))
87 if (job->dirty)
88 cupsdSaveJob(job);
89 }
90
91 if (DirtyFiles & CUPSD_DIRTY_SUBSCRIPTIONS)
92 cupsdSaveAllSubscriptions();
93
94 DirtyFiles = CUPSD_DIRTY_NONE;
95 DirtyCleanTime = 0;
96 }
97
98
99 /*
100 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
101 */
102
103 void
104 cupsdMarkDirty(int what) /* I - What file(s) are dirty? */
105 {
106 DirtyFiles |= what;
107
108 if (!DirtyCleanTime)
109 DirtyCleanTime = time(NULL) + DirtyCleanInterval;
110
111 cupsdSetBusyState();
112 }
113
114
115 /*
116 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
117 */
118
119 void
120 cupsdSetBusyState(void)
121 {
122 int newbusy; /* New busy state */
123 static int busy = 0; /* Current busy state */
124
125
126 newbusy = DirtyCleanTime ||
127 cupsArrayCount(PrintingJobs) ||
128 cupsArrayCount(ActiveClients);
129
130 if (newbusy != busy)
131 {
132 busy = newbusy;
133
134 if (busy)
135 cupsdLogMessage(CUPSD_LOG_DEBUG2,
136 "cupsdSetBusyState: Server no longer busy...");
137 else
138 cupsdLogMessage(CUPSD_LOG_DEBUG2,
139 "cupsdSetBusyState: Server is now busy...");
140 }
141 }
142
143
144 #ifdef __APPLE__
145 /*
146 * This is the Apple-specific system event code. It works by creating
147 * a worker thread that waits for events from the OS and relays them
148 * to the main thread via a traditional pipe.
149 */
150
151 /*
152 * Include MacOS-specific headers...
153 */
154
155 # include <IOKit/IOKitLib.h>
156 # include <IOKit/IOMessage.h>
157 # include <IOKit/pwr_mgt/IOPMLib.h>
158 # include <SystemConfiguration/SystemConfiguration.h>
159 # include <pthread.h>
160
161
162 /*
163 * Constants...
164 */
165
166 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
167 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
168 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
169 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
170 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
171
172
173 /*
174 * Structures...
175 */
176
177 typedef struct cupsd_sysevent_s /*** System event data ****/
178 {
179 unsigned char event; /* Event bit field */
180 io_connect_t powerKernelPort; /* Power context data */
181 long powerNotificationID; /* Power event data */
182 } cupsd_sysevent_t;
183
184
185 typedef struct cupsd_thread_data_s /*** Thread context data ****/
186 {
187 cupsd_sysevent_t sysevent; /* System event */
188 CFRunLoopTimerRef timerRef; /* Timer to delay some change *
189 * notifications */
190 } cupsd_thread_data_t;
191
192
193 /*
194 * Local globals...
195 */
196
197 static pthread_t SysEventThread = NULL;
198 /* Thread to host a runloop */
199 static pthread_mutex_t SysEventThreadMutex = { 0 };
200 /* Coordinates access to shared gloabals */
201 static pthread_cond_t SysEventThreadCond = { 0 };
202 /* Thread initialization complete condition */
203 static CFRunLoopRef SysEventRunloop = NULL;
204 /* The runloop. Access must be protected! */
205 static CFStringRef ComputerNameKey = NULL,
206 /* Computer name key */
207 NetworkGlobalKeyIPv4 = NULL,
208 /* Network global IPv4 key */
209 NetworkGlobalKeyIPv6 = NULL,
210 /* Network global IPv6 key */
211 NetworkGlobalKeyDNS = NULL,
212 /* Network global DNS key */
213 HostNamesKey = NULL,
214 /* Host name key */
215 NetworkInterfaceKeyIPv4 = NULL,
216 /* Netowrk interface key */
217 NetworkInterfaceKeyIPv6 = NULL;
218 /* Netowrk interface key */
219
220
221 /*
222 * Local functions...
223 */
224
225 static void *sysEventThreadEntry(void);
226 static void sysEventPowerNotifier(void *context, io_service_t service,
227 natural_t messageType,
228 void *messageArgument);
229 static void sysEventConfigurationNotifier(SCDynamicStoreRef store,
230 CFArrayRef changedKeys,
231 void *context);
232 static void sysEventTimerNotifier(CFRunLoopTimerRef timer, void *context);
233
234
235 /*
236 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
237 */
238
239 void
240 cupsdStartSystemMonitor(void)
241 {
242 int flags; /* fcntl flags on pipe */
243
244
245 if (cupsdOpenPipe(SysEventPipes))
246 {
247 cupsdLogMessage(CUPSD_LOG_ERROR, "System event monitor pipe() failed - %s!",
248 strerror(errno));
249 return;
250 }
251
252 cupsdAddSelect(SysEventPipes[0], (cupsd_selfunc_t)cupsdUpdateSystemMonitor,
253 NULL, NULL);
254
255 /*
256 * Set non-blocking mode on the descriptor we will be receiving notification
257 * events on.
258 */
259
260 flags = fcntl(SysEventPipes[0], F_GETFL, 0);
261 fcntl(SysEventPipes[0], F_SETFL, flags | O_NONBLOCK);
262
263 /*
264 * Start the thread that runs the runloop...
265 */
266
267 pthread_mutex_init(&SysEventThreadMutex, NULL);
268 pthread_cond_init(&SysEventThreadCond, NULL);
269 pthread_create(&SysEventThread, NULL, (void *(*)())sysEventThreadEntry, NULL);
270 }
271
272
273 /*
274 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
275 */
276
277 void
278 cupsdStopSystemMonitor(void)
279 {
280 CFRunLoopRef rl; /* The event handler runloop */
281
282
283 if (SysEventThread)
284 {
285 /*
286 * Make sure the thread has completed it's initialization and
287 * stored it's runloop reference in the shared global.
288 */
289
290 pthread_mutex_lock(&SysEventThreadMutex);
291
292 if (!SysEventRunloop)
293 pthread_cond_wait(&SysEventThreadCond, &SysEventThreadMutex);
294
295 rl = SysEventRunloop;
296 SysEventRunloop = NULL;
297
298 pthread_mutex_unlock(&SysEventThreadMutex);
299
300 if (rl)
301 CFRunLoopStop(rl);
302
303 pthread_join(SysEventThread, NULL);
304 pthread_mutex_destroy(&SysEventThreadMutex);
305 pthread_cond_destroy(&SysEventThreadCond);
306 }
307
308 if (SysEventPipes[0] >= 0)
309 {
310 cupsdRemoveSelect(SysEventPipes[0]);
311 cupsdClosePipe(SysEventPipes);
312 }
313 }
314
315
316 /*
317 * 'cupsdUpdateSystemMonitor()' - Update the current system state.
318 */
319
320 void
321 cupsdUpdateSystemMonitor(void)
322 {
323 int i; /* Looping var */
324 cupsd_sysevent_t sysevent; /* The system event */
325 cupsd_printer_t *p; /* Printer information */
326
327
328 /*
329 * Drain the event pipe...
330 */
331
332 while (read((int)SysEventPipes[0], &sysevent, sizeof(sysevent))
333 == sizeof(sysevent))
334 {
335 if (sysevent.event & SYSEVENT_CANSLEEP)
336 {
337 /*
338 * If there are active printers that don't have the connecting-to-device
339 * printer-state-reason then cancel the sleep request (i.e. this reason
340 * indicates a job that is not yet connected to the printer)...
341 */
342
343 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
344 p;
345 p = (cupsd_printer_t *)cupsArrayNext(Printers))
346 {
347 if (p->job)
348 {
349 for (i = 0; i < p->num_reasons; i ++)
350 if (!strcmp(p->reasons[i], "connecting-to-device"))
351 break;
352
353 if (!p->num_reasons || i >= p->num_reasons)
354 break;
355 }
356 }
357
358 if (p)
359 {
360 cupsdLogMessage(CUPSD_LOG_INFO,
361 "System sleep canceled because printer %s is active",
362 p->name);
363 IOCancelPowerChange(sysevent.powerKernelPort,
364 sysevent.powerNotificationID);
365 }
366 else
367 {
368 cupsdLogMessage(CUPSD_LOG_DEBUG, "System wants to sleep");
369 IOAllowPowerChange(sysevent.powerKernelPort,
370 sysevent.powerNotificationID);
371 }
372 }
373
374 if (sysevent.event & SYSEVENT_WILLSLEEP)
375 {
376 cupsdLogMessage(CUPSD_LOG_DEBUG, "System going to sleep");
377
378 Sleeping = 1;
379
380 cupsdStopAllJobs(0);
381
382 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
383 p;
384 p = (cupsd_printer_t *)cupsArrayNext(Printers))
385 {
386 if (p->type & CUPS_PRINTER_DISCOVERED)
387 {
388 cupsdLogMessage(CUPSD_LOG_DEBUG,
389 "Deleting remote destination \"%s\"", p->name);
390 cupsArraySave(Printers);
391 cupsdDeletePrinter(p, 0);
392 cupsArrayRestore(Printers);
393 }
394 else
395 {
396 cupsdLogMessage(CUPSD_LOG_DEBUG,
397 "Deregistering local printer \"%s\"", p->name);
398 cupsdDeregisterPrinter(p, 0);
399 }
400 }
401
402 cupsdCleanDirty();
403
404 IOAllowPowerChange(sysevent.powerKernelPort,
405 sysevent.powerNotificationID);
406 }
407
408 if (sysevent.event & SYSEVENT_WOKE)
409 {
410 cupsdLogMessage(CUPSD_LOG_DEBUG, "System woke from sleep");
411 IOAllowPowerChange(sysevent.powerKernelPort,
412 sysevent.powerNotificationID);
413 Sleeping = 0;
414 cupsdCheckJobs();
415 }
416
417 if (sysevent.event & SYSEVENT_NETCHANGED)
418 {
419 if (!Sleeping)
420 {
421 cupsdLogMessage(CUPSD_LOG_DEBUG,
422 "System network configuration changed");
423
424 /*
425 * Resetting browse_time before calling cupsdSendBrowseList causes
426 * browse packets to be sent for local shared printers.
427 */
428
429 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
430 p;
431 p = (cupsd_printer_t *)cupsArrayNext(Printers))
432 p->browse_time = 0;
433
434 cupsdSendBrowseList();
435 cupsdRestartPolling();
436 }
437 else
438 cupsdLogMessage(CUPSD_LOG_DEBUG,
439 "System network configuration changed; "
440 "ignored while sleeping");
441 }
442
443 if (sysevent.event & SYSEVENT_NAMECHANGED)
444 {
445 if (!Sleeping)
446 {
447 cupsdLogMessage(CUPSD_LOG_DEBUG, "Computer name changed");
448
449 /*
450 * De-register the individual printers...
451 */
452
453 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
454 p;
455 p = (cupsd_printer_t *)cupsArrayNext(Printers))
456 cupsdDeregisterPrinter(p, 1);
457
458 /*
459 * Update the computer name...
460 */
461
462 cupsdUpdateDNSSDName();
463
464 /*
465 * Now re-register them...
466 */
467
468 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
469 p;
470 p = (cupsd_printer_t *)cupsArrayNext(Printers))
471 {
472 p->browse_time = 0;
473 cupsdRegisterPrinter(p);
474 }
475 }
476 else
477 cupsdLogMessage(CUPSD_LOG_DEBUG,
478 "Computer name changed; ignored while sleeping");
479 }
480 }
481 }
482
483
484 /*
485 * 'sysEventThreadEntry()' - A thread to receive power and computer name
486 * change notifications.
487 */
488
489 static void * /* O - Return status/value */
490 sysEventThreadEntry(void)
491 {
492 io_object_t powerNotifierObj;
493 /* Power notifier object */
494 IONotificationPortRef powerNotifierPort;
495 /* Power notifier port */
496 SCDynamicStoreRef store = NULL;/* System Config dynamic store */
497 CFRunLoopSourceRef powerRLS = NULL,/* Power runloop source */
498 storeRLS = NULL;/* System Config runloop source */
499 CFStringRef key[5], /* System Config keys */
500 pattern[2]; /* System Config patterns */
501 CFArrayRef keys = NULL, /* System Config key array*/
502 patterns = NULL;/* System Config pattern array */
503 SCDynamicStoreContext storeContext; /* Dynamic store context */
504 CFRunLoopTimerContext timerContext; /* Timer context */
505 cupsd_thread_data_t threadData; /* Thread context data for the *
506 * runloop notifiers */
507
508
509 /*
510 * Register for power state change notifications
511 */
512
513 bzero(&threadData, sizeof(threadData));
514
515 threadData.sysevent.powerKernelPort =
516 IORegisterForSystemPower(&threadData, &powerNotifierPort,
517 sysEventPowerNotifier, &powerNotifierObj);
518
519 if (threadData.sysevent.powerKernelPort)
520 {
521 powerRLS = IONotificationPortGetRunLoopSource(powerNotifierPort);
522 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS, kCFRunLoopDefaultMode);
523 }
524 else
525 DEBUG_puts("sysEventThreadEntry: error registering for system power "
526 "notifications");
527
528 /*
529 * Register for system configuration change notifications
530 */
531
532 bzero(&storeContext, sizeof(storeContext));
533 storeContext.info = &threadData;
534
535 store = SCDynamicStoreCreate(NULL, CFSTR("cupsd"),
536 sysEventConfigurationNotifier, &storeContext);
537
538 if (!ComputerNameKey)
539 ComputerNameKey = SCDynamicStoreKeyCreateComputerName(NULL);
540
541 if (!NetworkGlobalKeyIPv4)
542 NetworkGlobalKeyIPv4 =
543 SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
544 kSCDynamicStoreDomainState,
545 kSCEntNetIPv4);
546
547 if (!NetworkGlobalKeyIPv6)
548 NetworkGlobalKeyIPv6 =
549 SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
550 kSCDynamicStoreDomainState,
551 kSCEntNetIPv6);
552
553 if (!NetworkGlobalKeyDNS)
554 NetworkGlobalKeyDNS =
555 SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
556 kSCDynamicStoreDomainState,
557 kSCEntNetDNS);
558
559 if (!HostNamesKey)
560 HostNamesKey = SCDynamicStoreKeyCreateHostNames(NULL);
561
562 if (!NetworkInterfaceKeyIPv4)
563 NetworkInterfaceKeyIPv4 =
564 SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
565 kSCDynamicStoreDomainState,
566 kSCCompAnyRegex,
567 kSCEntNetIPv4);
568
569 if (!NetworkInterfaceKeyIPv6)
570 NetworkInterfaceKeyIPv6 =
571 SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
572 kSCDynamicStoreDomainState,
573 kSCCompAnyRegex,
574 kSCEntNetIPv6);
575
576 if (store && ComputerNameKey && HostNamesKey &&
577 NetworkGlobalKeyIPv4 && NetworkGlobalKeyIPv6 && NetworkGlobalKeyDNS &&
578 NetworkInterfaceKeyIPv4 && NetworkInterfaceKeyIPv6)
579 {
580 key[0] = ComputerNameKey;
581 key[1] = NetworkGlobalKeyIPv4;
582 key[2] = NetworkGlobalKeyIPv6;
583 key[3] = NetworkGlobalKeyDNS;
584 key[4] = HostNamesKey;
585
586 pattern[0] = NetworkInterfaceKeyIPv4;
587 pattern[1] = NetworkInterfaceKeyIPv6;
588
589 keys = CFArrayCreate(NULL, (const void **)key,
590 sizeof(key) / sizeof(key[0]),
591 &kCFTypeArrayCallBacks);
592
593 patterns = CFArrayCreate(NULL, (const void **)pattern,
594 sizeof(pattern) / sizeof(pattern[0]),
595 &kCFTypeArrayCallBacks);
596
597 if (keys && patterns &&
598 SCDynamicStoreSetNotificationKeys(store, keys, patterns))
599 {
600 if ((storeRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0))
601 != NULL)
602 {
603 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS,
604 kCFRunLoopDefaultMode);
605 }
606 else
607 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
608 "failed: %s\n", SCErrorString(SCError())));
609 }
610 else
611 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
612 "failed: %s\n", SCErrorString(SCError())));
613 }
614 else
615 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
616 SCErrorString(SCError())));
617
618 if (keys)
619 CFRelease(keys);
620
621 if (patterns)
622 CFRelease(patterns);
623
624 /*
625 * Set up a timer to delay the wake change notifications.
626 *
627 * The initial time is set a decade or so into the future, we'll adjust
628 * this later.
629 */
630
631 bzero(&timerContext, sizeof(timerContext));
632 timerContext.info = &threadData;
633
634 threadData.timerRef =
635 CFRunLoopTimerCreate(NULL,
636 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
637 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier,
638 &timerContext);
639 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData.timerRef,
640 kCFRunLoopDefaultMode);
641
642 /*
643 * Store our runloop in a global so the main thread can use it to stop us.
644 */
645
646 pthread_mutex_lock(&SysEventThreadMutex);
647
648 SysEventRunloop = CFRunLoopGetCurrent();
649
650 pthread_cond_signal(&SysEventThreadCond);
651 pthread_mutex_unlock(&SysEventThreadMutex);
652
653 /*
654 * Disappear into the runloop until it's stopped by the main thread.
655 */
656
657 CFRunLoopRun();
658
659 /*
660 * Clean up before exiting.
661 */
662
663 if (threadData.timerRef)
664 {
665 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData.timerRef,
666 kCFRunLoopDefaultMode);
667 CFRelease(threadData.timerRef);
668 }
669
670 if (threadData.sysevent.powerKernelPort)
671 {
672 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS,
673 kCFRunLoopDefaultMode);
674 IODeregisterForSystemPower(&powerNotifierObj);
675 IOServiceClose(threadData.sysevent.powerKernelPort);
676 IONotificationPortDestroy(powerNotifierPort);
677 }
678
679 if (storeRLS)
680 {
681 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS,
682 kCFRunLoopDefaultMode);
683 CFRunLoopSourceInvalidate(storeRLS);
684 CFRelease(storeRLS);
685 }
686
687 if (store)
688 CFRelease(store);
689
690 pthread_exit(NULL);
691 }
692
693
694 /*
695 * 'sysEventPowerNotifier()' - Handle power notification events.
696 */
697
698 static void
699 sysEventPowerNotifier(
700 void *context, /* I - Thread context data */
701 io_service_t service, /* I - Unused service info */
702 natural_t messageType, /* I - Type of message */
703 void *messageArgument) /* I - Message data */
704 {
705 int sendit = 1; /* Send event to main thread? *
706 * (0 = no, 1 = yes, 2 = delayed */
707 cupsd_thread_data_t *threadData; /* Thread context data */
708
709
710 threadData = (cupsd_thread_data_t *)context;
711
712 (void)service; /* anti-compiler-warning-code */
713
714 switch (messageType)
715 {
716 case kIOMessageCanSystemPowerOff:
717 case kIOMessageCanSystemSleep:
718 threadData->sysevent.event |= SYSEVENT_CANSLEEP;
719 break;
720
721 case kIOMessageSystemWillRestart:
722 case kIOMessageSystemWillPowerOff:
723 case kIOMessageSystemWillSleep:
724 threadData->sysevent.event |= SYSEVENT_WILLSLEEP;
725 break;
726
727 case kIOMessageSystemHasPoweredOn:
728 /*
729 * Because powered on is followed by a net-changed event, delay
730 * before sending it.
731 */
732
733 sendit = 2;
734 threadData->sysevent.event |= SYSEVENT_WOKE;
735 break;
736
737 case kIOMessageSystemWillNotPowerOff:
738 case kIOMessageSystemWillNotSleep:
739 #ifdef kIOMessageSystemWillPowerOn
740 case kIOMessageSystemWillPowerOn:
741 #endif /* kIOMessageSystemWillPowerOn */
742 default:
743 sendit = 0;
744 break;
745 }
746
747 if (sendit == 0)
748 IOAllowPowerChange(threadData->sysevent.powerKernelPort,
749 (long)messageArgument);
750 else
751 {
752 threadData->sysevent.powerNotificationID = (long)messageArgument;
753
754 if (sendit == 1)
755 {
756 /*
757 * Send the event to the main thread now.
758 */
759
760 write(SysEventPipes[1], &threadData->sysevent,
761 sizeof(threadData->sysevent));
762 threadData->sysevent.event = 0;
763 }
764 else
765 {
766 /*
767 * Send the event to the main thread after 1 to 2 seconds.
768 */
769
770 CFRunLoopTimerSetNextFireDate(threadData->timerRef,
771 CFAbsoluteTimeGetCurrent() + 2);
772 }
773 }
774 }
775
776
777 /*
778 * 'sysEventConfigurationNotifier()' - Computer name changed notification
779 * callback.
780 */
781
782 static void
783 sysEventConfigurationNotifier(
784 SCDynamicStoreRef store, /* I - System data (unused) */
785 CFArrayRef changedKeys, /* I - Changed data */
786 void *context) /* I - Thread context data */
787 {
788 cupsd_thread_data_t *threadData; /* Thread context data */
789
790
791 threadData = (cupsd_thread_data_t *)context;
792
793 (void)store; /* anti-compiler-warning-code */
794
795 CFRange range = CFRangeMake(0, CFArrayGetCount(changedKeys));
796
797 if (CFArrayContainsValue(changedKeys, range, ComputerNameKey))
798 threadData->sysevent.event |= SYSEVENT_NAMECHANGED;
799 else
800 {
801 threadData->sysevent.event |= SYSEVENT_NETCHANGED;
802
803 /*
804 * Indicate the network interface list needs updating...
805 */
806
807 NetIFUpdate = 1;
808 }
809
810 /*
811 * Because we registered for several different kinds of change notifications
812 * this callback usually gets called several times in a row. We use a timer to
813 * de-bounce these so we only end up generating one event for the main thread.
814 */
815
816 CFRunLoopTimerSetNextFireDate(threadData->timerRef,
817 CFAbsoluteTimeGetCurrent() + 5);
818 }
819
820
821 /*
822 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
823 */
824
825 static void
826 sysEventTimerNotifier(
827 CFRunLoopTimerRef timer, /* I - Timer information */
828 void *context) /* I - Thread context data */
829 {
830 cupsd_thread_data_t *threadData; /* Thread context data */
831
832
833 threadData = (cupsd_thread_data_t *)context;
834
835 /*
836 * If an event is still pending send it to the main thread.
837 */
838
839 if (threadData->sysevent.event)
840 {
841 write(SysEventPipes[1], &threadData->sysevent,
842 sizeof(threadData->sysevent));
843 threadData->sysevent.event = 0;
844 }
845 }
846 #endif /* __APPLE__ */
847
848
849 /*
850 * End of "$Id: sysman.c 6649 2007-07-11 21:46:42Z mike $".
851 */