• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27#import "SharedTimer.h"
28
29#import <IOKit/IOMessage.h>
30#import <IOKit/pwr_mgt/IOPMLib.h>
31#import <wtf/Assertions.h>
32#import <wtf/Noncopyable.h>
33#import <wtf/PassOwnPtr.h>
34#import <wtf/UnusedParam.h>
35
36#include <stdio.h>
37
38// On Snow Leopard and newer we'll ask IOKit to deliver notifications on a queue.
39#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
40#define IOKIT_WITHOUT_LIBDISPATCH 1
41#endif
42
43namespace WebCore {
44
45static CFRunLoopTimerRef sharedTimer;
46static void (*sharedTimerFiredFunction)();
47static void timerFired(CFRunLoopTimerRef, void*);
48
49#if !defined(IOKIT_WITHOUT_LIBDISPATCH) && defined(BUILDING_ON_SNOW_LEOPARD)
50extern "C" void IONotificationPortSetDispatchQueue(IONotificationPortRef notify, dispatch_queue_t queue);
51#endif
52
53class PowerObserver {
54    WTF_MAKE_NONCOPYABLE(PowerObserver);
55
56public:
57    static PassOwnPtr<PowerObserver> create()
58    {
59        return adoptPtr(new PowerObserver);
60    }
61    ~PowerObserver();
62
63private:
64    PowerObserver();
65
66    static void didReceiveSystemPowerNotification(void* context, io_service_t, uint32_t messageType, void* messageArgument);
67    void didReceiveSystemPowerNotification(io_service_t, uint32_t messageType, void* messageArgument);
68
69    void restartSharedTimer();
70
71    io_connect_t m_powerConnection;
72    IONotificationPortRef m_notificationPort;
73    io_object_t m_notifierReference;
74#ifdef IOKIT_WITHOUT_LIBDISPATCH
75    CFRunLoopSourceRef m_runLoopSource;
76#else
77    dispatch_queue_t m_dispatchQueue;
78#endif
79};
80
81PowerObserver::PowerObserver()
82    : m_powerConnection(0)
83    , m_notificationPort(0)
84    , m_notifierReference(0)
85#ifdef IOKIT_WITHOUT_LIBDISPATCH
86    , m_runLoopSource(0)
87#else
88    , m_dispatchQueue(dispatch_queue_create("com.apple.WebKit.PowerObserver", 0))
89#endif
90{
91    m_powerConnection = IORegisterForSystemPower(this, &m_notificationPort, didReceiveSystemPowerNotification, &m_notifierReference);
92    if (!m_powerConnection)
93        return;
94
95#ifdef IOKIT_WITHOUT_LIBDISPATCH
96    m_runLoopSource = IONotificationPortGetRunLoopSource(m_notificationPort);
97    CFRunLoopAddSource(CFRunLoopGetMain(), m_runLoopSource, kCFRunLoopCommonModes);
98#else
99    IONotificationPortSetDispatchQueue(m_notificationPort, m_dispatchQueue);
100#endif
101}
102
103PowerObserver::~PowerObserver()
104{
105    if (!m_powerConnection)
106        return;
107
108#ifdef IOKIT_WITHOUT_LIBDISPATCH
109    CFRunLoopRemoveSource(CFRunLoopGetMain(), m_runLoopSource, kCFRunLoopCommonModes);
110#else
111    dispatch_release(m_dispatchQueue);
112#endif
113
114    IODeregisterForSystemPower(&m_notifierReference);
115    IOServiceClose(m_powerConnection);
116    IONotificationPortDestroy(m_notificationPort);
117}
118
119void PowerObserver::didReceiveSystemPowerNotification(void* context, io_service_t service, uint32_t messageType, void* messageArgument)
120{
121    static_cast<PowerObserver*>(context)->didReceiveSystemPowerNotification(service, messageType, messageArgument);
122}
123
124void PowerObserver::didReceiveSystemPowerNotification(io_service_t, uint32_t messageType, void* messageArgument)
125{
126    IOAllowPowerChange(m_powerConnection, reinterpret_cast<long>(messageArgument));
127
128    // We only care about the "wake from sleep" message.
129    if (messageType != kIOMessageSystemWillPowerOn)
130        return;
131
132#ifdef IOKIT_WITHOUT_LIBDISPATCH
133    restartSharedTimer();
134#else
135    // We need to restart the timer on the main thread.
136    CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^() {
137        restartSharedTimer();
138    });
139#endif
140}
141
142void PowerObserver::restartSharedTimer()
143{
144    ASSERT(CFRunLoopGetCurrent() == CFRunLoopGetMain());
145
146    if (!sharedTimer)
147        return;
148
149    stopSharedTimer();
150    timerFired(0, 0);
151}
152
153static PowerObserver* PowerObserver;
154
155void setSharedTimerFiredFunction(void (*f)())
156{
157    ASSERT(!sharedTimerFiredFunction || sharedTimerFiredFunction == f);
158
159    sharedTimerFiredFunction = f;
160}
161
162static void timerFired(CFRunLoopTimerRef, void*)
163{
164    // FIXME: We can remove this global catch-all if we fix <rdar://problem/5299018>.
165    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
166    sharedTimerFiredFunction();
167    [pool drain];
168}
169
170void setSharedTimerFireTime(double fireTime)
171{
172    ASSERT(sharedTimerFiredFunction);
173
174    if (sharedTimer) {
175        CFRunLoopTimerInvalidate(sharedTimer);
176        CFRelease(sharedTimer);
177    }
178
179    CFAbsoluteTime fireDate = fireTime - kCFAbsoluteTimeIntervalSince1970;
180    sharedTimer = CFRunLoopTimerCreate(0, fireDate, 0, 0, 0, timerFired, 0);
181    CFRunLoopAddTimer(CFRunLoopGetCurrent(), sharedTimer, kCFRunLoopCommonModes);
182
183    if (!PowerObserver)
184        PowerObserver = PowerObserver::create().leakPtr();
185}
186
187void stopSharedTimer()
188{
189    if (sharedTimer) {
190        CFRunLoopTimerInvalidate(sharedTimer);
191        CFRelease(sharedTimer);
192        sharedTimer = 0;
193    }
194}
195
196} // namespace WebCore
197