Changeset 191741 in webkit
- Timestamp:
- Oct 29, 2015 11:45:11 AM (9 years ago)
- Location:
- trunk/Source/bmalloc
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/bmalloc/ChangeLog
r191196 r191741 1 2015-10-29 Geoffrey Garen <ggaren@apple.com> 2 3 bmalloc: AsyncTask should handle destruction 4 https://bugs.webkit.org/show_bug.cgi?id=150648 5 6 Reviewed by Mark Lam. 7 8 So we can use it in more places. 9 10 * bmalloc/AsyncTask.h: Use std::thread instead of pthread because it 11 should be more portable. 12 13 (bmalloc::Function>::AsyncTask): Renamed Signaled to RunRequested for 14 clarity. Added an ExitRequested state. 15 16 (bmalloc::Function>::~AsyncTask): Wait for our child thread to exit 17 before destroying ourselves because our child thread will modify our 18 data (and might modify our client's data). Note that we only need to 19 wait for the last child thread since any prior child thread, having 20 reached the Exited condition, is guaranteed not to read or write any 21 data. 22 23 (bmalloc::Function>::run): 24 (bmalloc::Function>::runSlowCase): Updated for interface changes. Also 25 changed to use our WebKit style for condition signal: Hold the lock 26 during the signal and always notify all. Technically, neither is necessary, 27 but it is easier to understand the code this way, and harder to make 28 mistakes. 29 30 (bmalloc::Function>::threadEntryPoint): 31 (bmalloc::Function>::threadRunLoop): Handle the new ExitRequested state. 32 Technically, this state has no meaningful difference from the Exited 33 state, but it is nice to be explicit. 34 35 (bmalloc::Function>::join): Deleted. 36 (bmalloc::Function>::pthreadEntryPoint): Deleted. 37 (bmalloc::Function>::entryPoint): Deleted. 38 1 39 2015-10-15 Geoffrey Garen <ggaren@apple.com> 2 40 -
trunk/Source/bmalloc/bmalloc/AsyncTask.h
r179923 r191741 1 1 /* 2 * Copyright (C) 2014 Apple Inc. All rights reserved.2 * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 32 32 #include <atomic> 33 33 #include <condition_variable> 34 #include <pthread.h>35 34 #include <thread> 36 35 … … 41 40 public: 42 41 AsyncTask(Object&, const Function&); 42 ~AsyncTask(); 43 43 44 44 void run(); 45 void join();46 45 47 46 private: 48 enum State { Exited, Sleeping, Running, Signaled };47 enum State { Exited, ExitRequested, Sleeping, Running, RunRequested }; 49 48 50 49 static const constexpr std::chrono::seconds exitDelay = std::chrono::seconds(1); … … 52 51 void runSlowCase(); 53 52 54 static void * pthreadEntryPoint(void*);55 void entryPoint();53 static void threadEntryPoint(AsyncTask*); 54 void threadRunLoop(); 56 55 57 56 std::atomic<State> m_state; … … 59 58 Mutex m_conditionMutex; 60 59 std::condition_variable_any m_condition; 61 pthread_t m_thread; 60 61 std::thread m_thread; 62 62 63 63 Object& m_object; … … 78 78 79 79 template<typename Object, typename Function> 80 void AsyncTask<Object, Function>::join()80 AsyncTask<Object, Function>::~AsyncTask() 81 81 { 82 if (m_state == Exited)83 return;82 // Prevent our thread from entering the running or sleeping state. 83 State oldState = m_state.exchange(ExitRequested); 84 84 85 { std::lock_guard<Mutex> lock(m_conditionMutex); } 86 m_condition.notify_one(); 85 // Wake our thread if it was already in the sleeping state. 86 if (oldState == Sleeping) { 87 std::lock_guard<Mutex> lock(m_conditionMutex); 88 m_condition.notify_all(); 89 } 87 90 88 while (m_state != Exited) 89 std::this_thread::yield(); 91 // Wait for our thread to exit because it uses our data members (and it may 92 // use m_object's data members). 93 if (m_thread.joinable()) 94 m_thread.join(); 90 95 } 91 96 … … 93 98 inline void AsyncTask<Object, Function>::run() 94 99 { 95 if (m_state == Signaled)100 if (m_state == RunRequested) 96 101 return; 97 102 runSlowCase(); … … 101 106 NO_INLINE void AsyncTask<Object, Function>::runSlowCase() 102 107 { 103 State oldState = m_state.exchange( Signaled);104 if (oldState == Signaled || oldState == Running)108 State oldState = m_state.exchange(RunRequested); 109 if (oldState == RunRequested || oldState == Running) 105 110 return; 106 111 107 112 if (oldState == Sleeping) { 108 { std::lock_guard<Mutex> lock(m_conditionMutex); }109 m_condition.notify_ one();113 std::lock_guard<Mutex> lock(m_conditionMutex); 114 m_condition.notify_all(); 110 115 return; 111 116 } 112 117 113 118 BASSERT(oldState == Exited); 114 pthread_create(&m_thread, nullptr, &pthreadEntryPoint, this); 115 pthread_detach(m_thread); 119 if (m_thread.joinable()) 120 m_thread.detach(); 121 m_thread = std::thread(&AsyncTask::threadEntryPoint, this); 116 122 } 117 123 118 124 template<typename Object, typename Function> 119 void * AsyncTask<Object, Function>::pthreadEntryPoint(void* asyncTask)125 void AsyncTask<Object, Function>::threadEntryPoint(AsyncTask* asyncTask) 120 126 { 121 static_cast<AsyncTask*>(asyncTask)->entryPoint(); 122 return nullptr; 127 asyncTask->threadRunLoop(); 123 128 } 124 129 125 130 template<typename Object, typename Function> 126 void AsyncTask<Object, Function>:: entryPoint()131 void AsyncTask<Object, Function>::threadRunLoop() 127 132 { 133 // This loop ratchets downward from most active to least active state, and 134 // finally exits. While we ratchet downward, any other thread may reset our 135 // state to RunRequested or ExitRequested. 136 137 // We require any state change while we are sleeping to signal to our 138 // condition variable and wake us up. 139 128 140 while (1) { 129 State expectedState = Signaled;141 State expectedState = RunRequested; 130 142 if (m_state.compare_exchange_weak(expectedState, Running)) 131 143 (m_object.*m_function)(); … … 140 152 if (m_state.compare_exchange_weak(expectedState, Exited)) 141 153 return; 154 155 expectedState = ExitRequested; 156 if (m_state.compare_exchange_weak(expectedState, Exited)) 157 return; 142 158 } 143 159 }
Note: See TracChangeset
for help on using the changeset viewer.