bmalloc: Refactored SegregatedFreeList and BoundaryTag::init
[WebKit-https.git] / Source / bmalloc / bmalloc / AsyncTask.h
1 /*
2  * Copyright (C) 2014 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. ``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 #ifndef AsyncTask_h
27 #define AsyncTask_h
28
29 #include "BAssert.h"
30 #include "Inline.h"
31 #include "Mutex.h"
32 #include <atomic>
33 #include <condition_variable>
34 #include <pthread.h>
35 #include <thread>
36
37 namespace bmalloc {
38
39 template<typename Object, typename Function>
40 class AsyncTask {
41 public:
42     AsyncTask(Object&, const Function&);
43
44     void run();
45     void join();
46
47 private:
48     enum State { Exited, Sleeping, Running, Signaled };
49
50     static const constexpr std::chrono::seconds exitDelay = std::chrono::seconds(1);
51
52     void runSlowCase();
53
54     static void* pthreadEntryPoint(void*);
55     void entryPoint();
56
57     std::atomic<State> m_state;
58
59     Mutex m_conditionMutex;
60     std::condition_variable_any m_condition;
61     pthread_t m_thread;
62
63     Object& m_object;
64     Function m_function;
65 };
66
67 template<typename Object, typename Function> const constexpr std::chrono::seconds AsyncTask<Object, Function>::exitDelay;
68
69 template<typename Object, typename Function>
70 AsyncTask<Object, Function>::AsyncTask(Object& object, const Function& function)
71     : m_state(Exited)
72     , m_condition()
73     , m_thread()
74     , m_object(object)
75     , m_function(function)
76 {
77 }
78
79 template<typename Object, typename Function>
80 void AsyncTask<Object, Function>::join()
81 {
82     if (m_state == Exited)
83         return;
84
85     { std::lock_guard<Mutex> lock(m_conditionMutex); }
86     m_condition.notify_one();
87
88     while (m_state != Exited)
89         std::this_thread::yield();
90 }
91
92 template<typename Object, typename Function>
93 inline void AsyncTask<Object, Function>::run()
94 {
95     if (m_state == Signaled)
96         return;
97     runSlowCase();
98 }
99
100 template<typename Object, typename Function>
101 NO_INLINE void AsyncTask<Object, Function>::runSlowCase()
102 {
103     State oldState = m_state.exchange(Signaled);
104     if (oldState == Signaled || oldState == Running)
105         return;
106
107     if (oldState == Sleeping) {
108         { std::lock_guard<Mutex> lock(m_conditionMutex); }
109         m_condition.notify_one();
110         return;
111     }
112
113     BASSERT(oldState == Exited);
114     pthread_create(&m_thread, nullptr, &pthreadEntryPoint, this);
115     pthread_detach(m_thread);
116 }
117
118 template<typename Object, typename Function>
119 void* AsyncTask<Object, Function>::pthreadEntryPoint(void* asyncTask)
120 {
121     static_cast<AsyncTask*>(asyncTask)->entryPoint();
122     return nullptr;
123 }
124
125 template<typename Object, typename Function>
126 void AsyncTask<Object, Function>::entryPoint()
127 {
128     while (1) {
129         State expectedState = Signaled;
130         if (m_state.compare_exchange_weak(expectedState, Running))
131             (m_object.*m_function)();
132
133         expectedState = Running;
134         if (m_state.compare_exchange_weak(expectedState, Sleeping)) {
135             std::unique_lock<Mutex> lock(m_conditionMutex);
136             m_condition.wait_for(lock, exitDelay, [=]() { return this->m_state != Sleeping; });
137         }
138
139         expectedState = Sleeping;
140         if (m_state.compare_exchange_weak(expectedState, Exited))
141             return;
142     }
143 }
144
145 } // namespace bmalloc
146
147 #endif // AsyncTask_h