1/*
2 * Copyright (C) 2012 Company 100 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. ``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 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#include "config.h"
27#include "ImageDecodeWorker.h"
28
29#include <limits>
30
31#include <wtf/NumberOfCores.h>
32#include <wtf/WorkQueue.h>
33#include <wtf/text/CString.h>
34#include <wtf/text/WTFString.h>
35
36namespace WebCore {
37
38Vector<WorkQueue*>* ImageDecodeWorker::s_workQueuePool = 0;
39Vector<int>* ImageDecodeWorker::s_workQueueAcquireCount = 0;
40
41PassRefPtr<ImageDecodeWorker> ImageDecodeWorker::acquireSharedWorker()
42{
43 if (!s_workQueuePool)
44 initializeWorkQueuePool();
45
46 return adoptRef(new ImageDecodeWorker());
47}
48
49void ImageDecodeWorker::initializeWorkQueuePool()
50{
51 const int numCores = WTF::numberOfProcessorCores();
52
53 s_workQueueAcquireCount = new Vector<int>(numCores, 0);
54 s_workQueuePool = new Vector<WorkQueue*>();
55 s_workQueuePool->reserveInitialCapacity(numCores);
56 for (int i = 0; i < numCores; i++) {
57 s_workQueueAcquireCount->at(i) = 0;
58 String queueName = "ImageDecodeWorker." + String::number(i);
59 s_workQueuePool->append(new WorkQueue(queueName.ascii().data()));
60 }
61}
62
63int ImageDecodeWorker::queueIdWithMinimumAcquireCount()
64{
65 int minimumAcquireCount = std::numeric_limits<int>::max();
66 int index = s_workQueuePool->size();
67
68 for (size_t i = 0; i < s_workQueuePool->size(); i++)
69 if (s_workQueueAcquireCount->at(i) < minimumAcquireCount) {
70 minimumAcquireCount = s_workQueueAcquireCount->at(i);
71 index = i;
72 }
73
74 ASSERT(index < s_workQueuePool->size());
75 return index;
76}
77
78ImageDecodeWorker::ImageDecodeWorker()
79 : m_workerStatus(Running)
80{
81 m_workQueueId = queueIdWithMinimumAcquireCount();
82 m_workQueue = (*s_workQueuePool)[m_workQueueId];
83 s_workQueueAcquireCount->at(m_workQueueId)++;
84}
85
86ImageDecodeWorker::~ImageDecodeWorker()
87{
88 ASSERT(m_workerStatus == InvaidationReady);
89}
90
91bool ImageDecodeWorker::hasInvalidationBegun()
92{
93 MutexLocker locker(m_workerStatusMutex);
94 if (m_workerStatus == InvalidationBegun) {
95 m_workerStatus = InvaidationReady;
96 m_invalidationReady.signal();
97 }
98 return m_workerStatus != Running;
99}
100
101void ImageDecodeWorker::cancelableFunction(PassRefPtr<ImageDecodeWorker> worker, const Function<void()>& function)
102{
103 if (UNLIKELY(worker->hasInvalidationBegun()))
104 return;
105
106 function();
107}
108
109void ImageDecodeWorker::postTask(const Function<void()>& function)
110{
111 ASSERT(m_workerStatus == Running);
112 m_workQueue->dispatch(bind(ImageDecodeWorker::cancelableFunction, this, function));
113}
114
115void ImageDecodeWorker::invalidate()
116{
117 MutexLocker locker(m_workerStatusMutex);
118
119 if (m_workerStatus != Running)
120 return;
121
122 m_workerStatus = InvalidationBegun;
123
124 m_workQueue->dispatch(bind(&ImageDecodeWorker::ensureTerminate, this));
125 while (m_workerStatus != InvaidationReady)
126 m_invalidationReady.wait(m_workerStatusMutex);
127 s_workQueueAcquireCount->at(m_workQueueId)--;
128}
129
130void ImageDecodeWorker::ensureTerminate(PassRefPtr<ImageDecodeWorker> worker)
131{
132 MutexLocker locker(worker->m_workerStatusMutex);
133 ASSERT(worker->m_workerStatus != Running);
134 worker->m_workerStatus = InvaidationReady;
135 worker->m_invalidationReady.signal();
136}
137
138} // namespace WebCore