/* * Copyright 2016 WebAssembly Community Group participants * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // Threads helpers. // #ifndef wasm_support_threads_h #define wasm_support_threads_h #include #include #include #include #include #include #include #include "compiler-support.h" namespace wasm { // The work state of a helper thread - is there more to do, // or are we finished for now. enum class ThreadWorkState { More, Finished }; class ThreadPool; // // A helper thread. // // You can only create and destroy these on the main thread. // class Thread { ThreadPool* parent; std::unique_ptr thread; std::mutex mutex; std::condition_variable condition; bool done = false; std::function doWork = nullptr; public: Thread(ThreadPool* parent); ~Thread(); // Start to do work, calling doWork() until // it returns false. void work(std::function doWork); private: static void mainLoop(void* self); }; // // A pool of helper threads. // // There is only one, to avoid recursive pools using too many cores. // class ThreadPool { std::vector> threads; bool running = false; std::condition_variable condition; std::atomic ready; // A mutex for creating the pool safely static std::mutex creationMutex; // A mutex for work() so that the pool can only work on one // thing at a time static std::mutex workMutex; // A mutex for communication with the worker threads static std::mutex threadMutex; private: void initialize(size_t num); public: // Get the number of cores we can use. static size_t getNumCores(); // Get the singleton threadpool. static ThreadPool* get(); // Execute a bunch of tasks by the pool. This calls // getTask() (in a thread-safe manner) to get tasks, and // sends them to workers to be executed. This method // blocks until all tasks are complete. void work(std::vector>& doWorkers); size_t size(); bool isRunning(); // Called by helper threads when they are free and ready. void notifyThreadIsReady(); private: void resetThreadsAreReady(); bool areThreadsReady(); }; // Verify a code segment is only entered once. Usage: // static OnlyOnce onlyOnce; // onlyOnce.verify(); class OnlyOnce { std::atomic created; public: OnlyOnce() { created.store(0); } void verify() { auto before = created.fetch_add(1); WASM_UNUSED(before); assert(before == 0); } }; } // namespace wasm #endif // wasm_support_threads_h