Add "Identified" base class to replace a whole bunch of custom identifier generators.
[WebKit-https.git] / Source / WebCore / workers / service / server / SWServer.cpp
1 /*
2  * Copyright (C) 2017 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 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 #include "SWServer.h"
28
29 #if ENABLE(SERVICE_WORKER)
30
31 #include "ExceptionCode.h"
32 #include "ExceptionData.h"
33 #include "Logging.h"
34 #include "SWServerRegistration.h"
35 #include "ServiceWorkerJobData.h"
36 #include <wtf/text/WTFString.h>
37
38 namespace WebCore {
39
40 SWServer::Connection::Connection(SWServer& server, uint64_t identifier)
41     : Identified(identifier)
42     , m_server(server)
43 {
44     m_server.registerConnection(*this);
45 }
46
47 SWServer::Connection::~Connection()
48 {
49     m_server.unregisterConnection(*this);
50 }
51
52 SWServer::~SWServer()
53 {
54     RELEASE_ASSERT(m_connections.isEmpty());
55     RELEASE_ASSERT(m_registrations.isEmpty());
56
57     ASSERT(m_taskQueue.isEmpty());
58     ASSERT(m_taskReplyQueue.isEmpty());
59
60     // For a SWServer to be cleanly shut down its thread must have finished and gone away.
61     // At this stage in development of the feature that actually never happens.
62     // But once it does start happening, this ASSERT will catch us doing it wrong.
63     Locker<Lock> locker(m_taskThreadLock);
64     ASSERT(!m_taskThread);
65 }
66
67 void SWServer::Connection::scheduleJobInServer(const ServiceWorkerJobData& jobData)
68 {
69     LOG(ServiceWorker, "Scheduling ServiceWorker job %" PRIu64 "-%" PRIu64 " in server", jobData.connectionIdentifier(), jobData.identifier());
70     ASSERT(identifier() == jobData.connectionIdentifier());
71
72     m_server.scheduleJob(jobData);
73 }
74
75 SWServer::SWServer()
76 {
77     m_taskThread = Thread::create(ASCIILiteral("ServiceWorker Task Thread"), [this] {
78         taskThreadEntryPoint();
79     });
80 }
81
82 void SWServer::scheduleJob(const ServiceWorkerJobData& jobData)
83 {
84     ASSERT(m_connections.contains(jobData.connectionIdentifier()));
85
86     auto result = m_registrations.add(jobData.registrationKey(), nullptr);
87     if (result.isNewEntry)
88         result.iterator->value = std::make_unique<SWServerRegistration>(*this, jobData.registrationKey());
89
90     ASSERT(result.iterator->value);
91
92     result.iterator->value->enqueueJob(jobData);
93 }
94
95 void SWServer::rejectJob(const ServiceWorkerJobData& jobData, const ExceptionData& exceptionData)
96 {
97     LOG(ServiceWorker, "Rejected ServiceWorker job %" PRIu64 "-%" PRIu64 " in server", jobData.connectionIdentifier(), jobData.identifier());
98     auto* connection = m_connections.get(jobData.connectionIdentifier());
99     if (!connection)
100         return;
101
102     connection->rejectJobInClient(jobData.identifier(), exceptionData);
103 }
104
105 void SWServer::resolveJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationData& registrationData)
106 {
107     LOG(ServiceWorker, "Resolved ServiceWorker job %" PRIu64 "-%" PRIu64 " in server with registration %" PRIu64, jobData.connectionIdentifier(), jobData.identifier(), registrationData.identifier);
108     auto* connection = m_connections.get(jobData.connectionIdentifier());
109     if (!connection)
110         return;
111
112     connection->resolveJobInClient(jobData.identifier(), registrationData);
113 }
114
115 void SWServer::taskThreadEntryPoint()
116 {
117     ASSERT(!isMainThread());
118
119     while (!m_taskQueue.isKilled())
120         m_taskQueue.waitForMessage().performTask();
121
122     Locker<Lock> locker(m_taskThreadLock);
123     m_taskThread = nullptr;
124 }
125
126 void SWServer::postTask(CrossThreadTask&& task)
127 {
128     m_taskQueue.append(WTFMove(task));
129 }
130
131 void SWServer::postTaskReply(CrossThreadTask&& task)
132 {
133     m_taskReplyQueue.append(WTFMove(task));
134
135     Locker<Lock> locker(m_mainThreadReplyLock);
136     if (m_mainThreadReplyScheduled)
137         return;
138
139     m_mainThreadReplyScheduled = true;
140     callOnMainThread([this] {
141         handleTaskRepliesOnMainThread();
142     });
143 }
144
145 void SWServer::handleTaskRepliesOnMainThread()
146 {
147     {
148         Locker<Lock> locker(m_mainThreadReplyLock);
149         m_mainThreadReplyScheduled = false;
150     }
151
152     while (auto task = m_taskReplyQueue.tryGetMessage())
153         task->performTask();
154 }
155
156 void SWServer::registerConnection(Connection& connection)
157 {
158     auto result = m_connections.add(connection.identifier(), nullptr);
159     ASSERT(result.isNewEntry);
160     result.iterator->value = &connection;
161 }
162
163 void SWServer::unregisterConnection(Connection& connection)
164 {
165     ASSERT(m_connections.get(connection.identifier()) == &connection);
166     m_connections.remove(connection.identifier());
167 }
168
169 } // namespace WebCore
170
171 #endif // ENABLE(SERVICE_WORKER)