1 // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 // Copyright 2018 Pawel Bylica. 3 // Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 5 #include "ethash-internal.hpp" 6 7 #include <memory> 8 #include <mutex> 9 10 #if !defined(__has_cpp_attribute) 11 #define __has_cpp_attribute(x) 0 12 #endif 13 14 #if __has_cpp_attribute(gnu::noinline) 15 #define ATTRIBUTE_NOINLINE [[gnu::noinline]] 16 #elif _MSC_VER 17 #define ATTRIBUTE_NOINLINE __declspec(noinline) 18 #else 19 #define ATTRIBUTE_NOINLINE 20 #endif 21 22 namespace ethash 23 { 24 namespace 25 { 26 std::mutex shared_context_mutex; 27 std::shared_ptr<epoch_context> shared_context; 28 thread_local std::shared_ptr<epoch_context> thread_local_context; 29 30 std::mutex shared_context_full_mutex; 31 std::shared_ptr<epoch_context_full> shared_context_full; 32 thread_local std::shared_ptr<epoch_context_full> thread_local_context_full; 33 34 /// Update thread local epoch context. 35 /// 36 /// This function is on the slow path. It's separated to allow inlining the fast 37 /// path. 38 /// 39 /// @todo: Redesign to guarantee deallocation before new allocation. 40 ATTRIBUTE_NOINLINE update_local_context(int epoch_number)41void update_local_context(int epoch_number) 42 { 43 // Release the shared pointer of the obsoleted context. 44 thread_local_context.reset(); 45 46 // Local context invalid, check the shared context. 47 std::lock_guard<std::mutex> lock{shared_context_mutex}; 48 49 if (!shared_context || shared_context->epoch_number != epoch_number) 50 { 51 // Release the shared pointer of the obsoleted context. 52 shared_context.reset(); 53 54 // Build new context. 55 shared_context = create_epoch_context(epoch_number); 56 } 57 58 thread_local_context = shared_context; 59 } 60 61 ATTRIBUTE_NOINLINE update_local_context_full(int epoch_number)62void update_local_context_full(int epoch_number) 63 { 64 // Release the shared pointer of the obsoleted context. 65 thread_local_context_full.reset(); 66 67 // Local context invalid, check the shared context. 68 std::lock_guard<std::mutex> lock{shared_context_full_mutex}; 69 70 if (!shared_context_full || shared_context_full->epoch_number != epoch_number) 71 { 72 // Release the shared pointer of the obsoleted context. 73 shared_context_full.reset(); 74 75 // Build new context. 76 shared_context_full = create_epoch_context_full(epoch_number); 77 } 78 79 thread_local_context_full = shared_context_full; 80 } 81 } // namespace 82 get_global_epoch_context(int epoch_number)83const epoch_context& get_global_epoch_context(int epoch_number) 84 { 85 // Check if local context matches epoch number. 86 if (!thread_local_context || thread_local_context->epoch_number != epoch_number) 87 update_local_context(epoch_number); 88 89 return *thread_local_context; 90 } 91 get_global_epoch_context_full(int epoch_number)92const epoch_context_full& get_global_epoch_context_full(int epoch_number) 93 { 94 // Check if local context matches epoch number. 95 if (!thread_local_context_full || thread_local_context_full->epoch_number != epoch_number) 96 update_local_context_full(epoch_number); 97 98 return *thread_local_context_full; 99 } 100 } // namespace ethash 101