2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "BlockAllocator.h"
29 #include "MarkedBlock.h"
30 #include <wtf/CurrentTime.h>
34 BlockAllocator::BlockAllocator()
35 : m_numberOfFreeBlocks(0)
36 , m_isCurrentlyAllocating(false)
37 , m_blockFreeingThreadShouldQuit(false)
38 , m_blockFreeingThread(GCActivityCallback::s_shouldCreateGCTimer
?
39 createThread(blockFreeingThreadStartFunc
, this, "JavaScriptCore::BlockFree") : 0)
41 ASSERT(m_blockFreeingThread
|| !GCActivityCallback::s_shouldCreateGCTimer
);
44 BlockAllocator::~BlockAllocator()
48 MutexLocker
locker(m_freeBlockLock
);
49 m_blockFreeingThreadShouldQuit
= true;
50 m_freeBlockCondition
.broadcast();
52 if (GCActivityCallback::s_shouldCreateGCTimer
)
53 waitForThreadCompletion(m_blockFreeingThread
);
56 void BlockAllocator::releaseFreeBlocks()
61 MutexLocker
locker(m_freeBlockLock
);
62 if (!m_numberOfFreeBlocks
)
65 // FIXME: How do we know this is a MarkedBlock? It could be a CopiedBlock.
66 block
= static_cast<MarkedBlock
*>(m_freeBlocks
.removeHead());
68 m_numberOfFreeBlocks
--;
75 MarkedBlock::destroy(block
);
79 void BlockAllocator::waitForRelativeTimeWhileHoldingLock(double relative
)
81 if (m_blockFreeingThreadShouldQuit
)
83 m_freeBlockCondition
.timedWait(m_freeBlockLock
, currentTime() + relative
);
86 void BlockAllocator::waitForRelativeTime(double relative
)
88 // If this returns early, that's fine, so long as it doesn't do it too
89 // frequently. It would only be a bug if this function failed to return
90 // when it was asked to do so.
92 MutexLocker
locker(m_freeBlockLock
);
93 waitForRelativeTimeWhileHoldingLock(relative
);
96 void BlockAllocator::blockFreeingThreadStartFunc(void* blockAllocator
)
98 static_cast<BlockAllocator
*>(blockAllocator
)->blockFreeingThreadMain();
101 void BlockAllocator::blockFreeingThreadMain()
103 while (!m_blockFreeingThreadShouldQuit
) {
104 // Generally wait for one second before scavenging free blocks. This
105 // may return early, particularly when we're being asked to quit.
106 waitForRelativeTime(1.0);
107 if (m_blockFreeingThreadShouldQuit
)
110 if (m_isCurrentlyAllocating
) {
111 m_isCurrentlyAllocating
= false;
115 // Now process the list of free blocks. Keep freeing until half of the
116 // blocks that are currently on the list are gone. Assume that a size_t
117 // field can be accessed atomically.
118 size_t currentNumberOfFreeBlocks
= m_numberOfFreeBlocks
;
119 if (!currentNumberOfFreeBlocks
)
122 size_t desiredNumberOfFreeBlocks
= currentNumberOfFreeBlocks
/ 2;
124 while (!m_blockFreeingThreadShouldQuit
) {
127 MutexLocker
locker(m_freeBlockLock
);
128 if (m_numberOfFreeBlocks
<= desiredNumberOfFreeBlocks
)
131 // FIXME: How do we know this is a MarkedBlock? It could be a CopiedBlock.
132 block
= static_cast<MarkedBlock
*>(m_freeBlocks
.removeHead());
134 m_numberOfFreeBlocks
--;
141 MarkedBlock::destroy(block
);