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