1/* 2 * Copyright (C) 2014 Igalia S.L. 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 INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27 28#if USE(GLIB) 29 30#include "GMainLoopSource.h" 31 32#include <gio/gio.h> 33 34namespace WTF { 35 36GMainLoopSource& GMainLoopSource::createAndDeleteOnDestroy() 37{ 38 return *new GMainLoopSource(DeleteOnDestroy); 39} 40 41GMainLoopSource::GMainLoopSource() 42 : m_deleteOnDestroy(DoNotDeleteOnDestroy) 43 , m_status(Ready) 44{ 45} 46 47GMainLoopSource::GMainLoopSource(DeleteOnDestroyType deleteOnDestroy) 48 : m_deleteOnDestroy(deleteOnDestroy) 49 , m_status(Ready) 50{ 51} 52 53GMainLoopSource::~GMainLoopSource() 54{ 55 cancel(); 56} 57 58bool GMainLoopSource::isScheduled() const 59{ 60 return m_status == Scheduled; 61} 62 63bool GMainLoopSource::isActive() const 64{ 65 return m_status != Ready; 66} 67 68void GMainLoopSource::cancel() 69{ 70 if (!m_source) 71 return; 72 73 GRefPtr<GSource> source; 74 m_source.swap(source); 75 76 if (m_cancellable) 77 g_cancellable_cancel(m_cancellable.get()); 78 g_source_destroy(source.get()); 79 destroy(); 80} 81 82void GMainLoopSource::reset() 83{ 84 m_status = Ready; 85 m_source = nullptr; 86 m_cancellable = nullptr; 87 m_voidCallback = nullptr; 88 m_boolCallback = nullptr; 89 m_destroyCallback = nullptr; 90} 91 92void GMainLoopSource::scheduleIdleSource(const char* name, GSourceFunc sourceFunction, int priority, GMainContext* context) 93{ 94 ASSERT(m_status == Ready); 95 m_status = Scheduled; 96 97 m_source = adoptGRef(g_idle_source_new()); 98 g_source_set_name(m_source.get(), name); 99 if (priority != G_PRIORITY_DEFAULT_IDLE) 100 g_source_set_priority(m_source.get(), priority); 101 g_source_set_callback(m_source.get(), sourceFunction, this, nullptr); 102 g_source_attach(m_source.get(), context); 103} 104 105void GMainLoopSource::schedule(const char* name, std::function<void ()> function, int priority, std::function<void ()> destroyFunction, GMainContext* context) 106{ 107 cancel(); 108 m_voidCallback = WTF::move(function); 109 m_destroyCallback = WTF::move(destroyFunction); 110 scheduleIdleSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context); 111} 112 113void GMainLoopSource::schedule(const char* name, std::function<bool ()> function, int priority, std::function<void ()> destroyFunction, GMainContext* context) 114{ 115 cancel(); 116 m_boolCallback = WTF::move(function); 117 m_destroyCallback = WTF::move(destroyFunction); 118 scheduleIdleSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context); 119} 120 121void GMainLoopSource::schedule(const char* name, std::function<bool (GIOCondition)> function, GSocket* socket, GIOCondition condition, std::function<void ()> destroyFunction, GMainContext* context) 122{ 123 cancel(); 124 ASSERT(m_status == Ready); 125 m_status = Scheduled; 126 127 m_socketCallback = WTF::move(function); 128 m_destroyCallback = WTF::move(destroyFunction); 129 m_cancellable = adoptGRef(g_cancellable_new()); 130 m_source = adoptGRef(g_socket_create_source(socket, condition, m_cancellable.get())); 131 g_source_set_name(m_source.get(), name); 132 g_source_set_callback(m_source.get(), reinterpret_cast<GSourceFunc>(socketSourceCallback), this, nullptr); 133 g_source_attach(m_source.get(), context); 134} 135 136void GMainLoopSource::scheduleTimeoutSource(const char* name, GSourceFunc sourceFunction, int priority, GMainContext* context) 137{ 138 ASSERT(m_status == Ready); 139 m_status = Scheduled; 140 141 ASSERT(m_source); 142 g_source_set_name(m_source.get(), name); 143 if (priority != G_PRIORITY_DEFAULT) 144 g_source_set_priority(m_source.get(), priority); 145 g_source_set_callback(m_source.get(), sourceFunction, this, nullptr); 146 g_source_attach(m_source.get(), context); 147} 148 149void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<void ()> function, std::chrono::milliseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context) 150{ 151 cancel(); 152 m_source = adoptGRef(g_timeout_source_new(delay.count())); 153 m_voidCallback = WTF::move(function); 154 m_destroyCallback = WTF::move(destroyFunction); 155 scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context); 156} 157 158void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<bool ()> function, std::chrono::milliseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context) 159{ 160 cancel(); 161 m_source = adoptGRef(g_timeout_source_new(delay.count())); 162 m_boolCallback = WTF::move(function); 163 m_destroyCallback = WTF::move(destroyFunction); 164 scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context); 165} 166 167void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<void ()> function, std::chrono::seconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context) 168{ 169 cancel(); 170 m_source = adoptGRef(g_timeout_source_new_seconds(delay.count())); 171 m_voidCallback = WTF::move(function); 172 m_destroyCallback = WTF::move(destroyFunction); 173 scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context); 174} 175 176void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<bool ()> function, std::chrono::seconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context) 177{ 178 cancel(); 179 m_source = adoptGRef(g_timeout_source_new_seconds(delay.count())); 180 m_boolCallback = WTF::move(function); 181 m_destroyCallback = WTF::move(destroyFunction); 182 scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context); 183} 184 185void GMainLoopSource::voidCallback() 186{ 187 if (!m_source) 188 return; 189 190 ASSERT(m_voidCallback); 191 ASSERT(m_status == Scheduled); 192 m_status = Dispatched; 193 194 GSource* source = m_source.get(); 195 m_voidCallback(); 196 if (source == m_source.get()) 197 destroy(); 198} 199 200bool GMainLoopSource::boolCallback() 201{ 202 if (!m_source) 203 return false; 204 205 ASSERT(m_boolCallback); 206 ASSERT(m_status == Scheduled || m_status == Dispatched); 207 m_status = Dispatched; 208 209 GSource* source = m_source.get(); 210 bool retval = m_boolCallback(); 211 if (!retval && source == m_source.get()) 212 destroy(); 213 214 return retval; 215} 216 217bool GMainLoopSource::socketCallback(GIOCondition condition) 218{ 219 if (!m_source) 220 return false; 221 222 ASSERT(m_socketCallback); 223 ASSERT(m_status == Scheduled || m_status == Dispatched); 224 m_status = Dispatched; 225 226 if (g_cancellable_is_cancelled(m_cancellable.get())) { 227 destroy(); 228 return false; 229 } 230 231 GSource* source = m_source.get(); 232 bool retval = m_socketCallback(condition); 233 if (!retval && source == m_source.get()) 234 destroy(); 235 236 return retval; 237} 238 239void GMainLoopSource::destroy() 240{ 241 auto destroyCallback = WTF::move(m_destroyCallback); 242 auto deleteOnDestroy = m_deleteOnDestroy; 243 reset(); 244 if (destroyCallback) 245 destroyCallback(); 246 247 if (deleteOnDestroy == DoNotDeleteOnDestroy) 248 return; 249 250 delete this; 251} 252 253gboolean GMainLoopSource::voidSourceCallback(GMainLoopSource* source) 254{ 255 source->voidCallback(); 256 return G_SOURCE_REMOVE; 257} 258 259gboolean GMainLoopSource::boolSourceCallback(GMainLoopSource* source) 260{ 261 return source->boolCallback() == Continue; 262} 263 264gboolean GMainLoopSource::socketSourceCallback(GSocket*, GIOCondition condition, GMainLoopSource* source) 265{ 266 return source->socketCallback(condition) == Continue; 267} 268 269} // namespace WTF 270 271#endif // USE(GLIB) 272