diff options
-rw-r--r-- | Makefile.ckati | 3 | ||||
-rw-r--r-- | condvar.cc | 42 | ||||
-rw-r--r-- | condvar.h | 35 | ||||
-rw-r--r-- | mutex.cc | 37 | ||||
-rw-r--r-- | mutex.h | 50 | ||||
-rw-r--r-- | regen.cc | 4 | ||||
-rw-r--r-- | stats.cc | 2 | ||||
-rw-r--r-- | stats.h | 3 | ||||
-rw-r--r-- | thread.cc | 78 | ||||
-rw-r--r-- | thread.h | 18 | ||||
-rw-r--r-- | thread_pool.cc | 86 | ||||
-rw-r--r-- | thread_pool.h | 35 |
12 files changed, 317 insertions, 76 deletions
diff --git a/Makefile.ckati b/Makefile.ckati index f35824b..18ed906 100644 --- a/Makefile.ckati +++ b/Makefile.ckati @@ -23,6 +23,7 @@ KATI_BIN_PATH ?= . KATI_CXX_SRCS := \ command.cc \ + condvar.cc \ dep.cc \ eval.cc \ exec.cc \ @@ -36,6 +37,7 @@ KATI_CXX_SRCS := \ io.cc \ log.cc \ main.cc \ + mutex.cc \ ninja.cc \ parser.cc \ regen.cc \ @@ -47,6 +49,7 @@ KATI_CXX_SRCS := \ strutil.cc \ symtab.cc \ thread.cc \ + thread_pool.cc \ timeutil.cc \ var.cc diff --git a/condvar.cc b/condvar.cc new file mode 100644 index 0000000..d7d4e39 --- /dev/null +++ b/condvar.cc @@ -0,0 +1,42 @@ +// Copyright 2016 Google Inc. All rights reserved +// +// 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. + +#include "condvar.h" + +#include "log.h" + +condition_variable::condition_variable() { + if (pthread_cond_init(&cond_, NULL) != 0) + PERROR("pthread_cond_init"); +} + +condition_variable::~condition_variable() { + if (pthread_cond_destroy(&cond_) != 0) + PERROR("pthread_cond_destroy"); +} + +void condition_variable::wait(const unique_lock<mutex>& mu) { + if (pthread_cond_wait(&cond_, &mu.mutex()->mu_) != 0) + PERROR("pthread_cond_wait"); +} + +void condition_variable::notify_one() { + if (pthread_cond_signal(&cond_) != 0) + PERROR("pthread_cond_signal"); +} + +void condition_variable::notify_all() { + if (pthread_cond_broadcast(&cond_) != 0) + PERROR("pthread_cond_broadcast"); +} diff --git a/condvar.h b/condvar.h new file mode 100644 index 0000000..2f9ab3a --- /dev/null +++ b/condvar.h @@ -0,0 +1,35 @@ +// Copyright 2016 Google Inc. All rights reserved +// +// 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. + +#ifndef CONDVAR_H_ +#define CONDVAR_H_ + +#include <pthread.h> + +#include "mutex.h" + +class condition_variable { + public: + condition_variable(); + ~condition_variable(); + + void wait(const unique_lock<mutex>& mu); + void notify_one(); + void notify_all(); + + private: + pthread_cond_t cond_; +}; + +#endif // CONDVAR_H_ diff --git a/mutex.cc b/mutex.cc new file mode 100644 index 0000000..ae4bd3b --- /dev/null +++ b/mutex.cc @@ -0,0 +1,37 @@ +// Copyright 2016 Google Inc. All rights reserved +// +// 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. + +#include "mutex.h" + +#include "log.h" + +mutex::mutex() { + if (pthread_mutex_init(&mu_, NULL) != 0) + PERROR("pthread_mutex_init"); +} + +mutex::~mutex() { + if (pthread_mutex_destroy(&mu_) != 0) + PERROR("pthread_mutex_destroy"); +} + +void mutex::lock() { + if (pthread_mutex_lock(&mu_) != 0) + PERROR("pthread_mutex_lock"); +} + +void mutex::unlock() { + if (pthread_mutex_unlock(&mu_) != 0) + PERROR("pthread_mutex_unlock"); +} @@ -0,0 +1,50 @@ +// Copyright 2016 Google Inc. All rights reserved +// +// 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. + +#ifndef MUTEX_H_ +#define MUTEX_H_ + +#include <pthread.h> + +class mutex { + public: + explicit mutex(); + ~mutex(); + + void lock(); + void unlock(); + + private: + pthread_mutex_t mu_; + + friend class condition_variable; +}; + +template<class T> class unique_lock { + public: + explicit unique_lock(T& mu) + : mu_(mu) { + mu_.lock(); + } + ~unique_lock() { + mu_.unlock(); + } + + T* mutex() const { return &mu_; } + + private: + T& mu_; +}; + +#endif // MUTEX_H_ @@ -18,17 +18,17 @@ #include <algorithm> #include <memory> -#include <mutex> #include <vector> #include "fileutil.h" #include "find.h" #include "io.h" #include "log.h" +#include "mutex.h" #include "ninja.h" #include "stats.h" #include "strutil.h" -#include "thread.h" +#include "thread_pool.h" namespace { @@ -16,11 +16,11 @@ #include "stats.h" -#include <mutex> #include <vector> #include "flags.h" #include "log.h" +#include "mutex.h" #include "stringprintf.h" #include "thread_local.h" #include "timeutil.h" @@ -15,9 +15,10 @@ #ifndef STATS_H_ #define STATS_H_ -#include <mutex> #include <string> +#include "mutex.h" + using namespace std; class Stats { @@ -14,71 +14,21 @@ #include "thread.h" -#include <condition_variable> -#include <mutex> -#include <stack> -#include <thread> -#include <vector> +#include "log.h" -class ThreadPoolImpl : public ThreadPool { - public: - explicit ThreadPoolImpl(int num_threads) - : is_waiting_(false) { - for (int i = 0; i < num_threads; i++) { - threads_.push_back(thread([this]() { Loop(); })); - } - } - - virtual ~ThreadPoolImpl() override { - } - - virtual void Submit(function<void(void)> task) override { - unique_lock<mutex> lock(mu_); - tasks_.push(task); - cond_.notify_one(); - } - - virtual void Wait() override { - { - unique_lock<mutex> lock(mu_); - is_waiting_ = true; - cond_.notify_all(); - } - - for (thread& th : threads_) { - th.join(); - } - } - - private: - void Loop() { - while (true) { - function<void(void)> task; - { - unique_lock<mutex> lock(mu_); - if (tasks_.empty()) { - if (is_waiting_) - return; - cond_.wait(lock); - } - - if (tasks_.empty()) - continue; - - task = tasks_.top(); - tasks_.pop(); - } - task(); - } - } +thread::thread(const fn_t& fn) { + if (pthread_create(&th_, NULL, &thread::Run, new fn_t(fn)) != 0) + PERROR("pthread_create"); +} - vector<thread> threads_; - mutex mu_; - condition_variable cond_; - stack<function<void(void)>> tasks_; - bool is_waiting_; -}; +void thread::join() { + if (pthread_join(th_, NULL) != 0) + PERROR("pthread_join"); +} -ThreadPool* NewThreadPool(int num_threads) { - return new ThreadPoolImpl(num_threads); +void* thread::Run(void* p) { + fn_t* fn = static_cast<fn_t*>(p); + (*fn)(); + delete fn; + return NULL; } @@ -15,21 +15,23 @@ #ifndef THREAD_H_ #define THREAD_H_ +#include <pthread.h> + #include <functional> using namespace std; -class ThreadPool { +class thread { + typedef function<void(void)> fn_t; + public: - virtual ~ThreadPool() = default; + explicit thread(const fn_t& fn); + void join(); - virtual void Submit(function<void(void)> task) = 0; - virtual void Wait() = 0; + private: + static void* Run(void* p); - protected: - ThreadPool() = default; + pthread_t th_; }; -ThreadPool* NewThreadPool(int num_threads); - #endif // THREAD_H_ diff --git a/thread_pool.cc b/thread_pool.cc new file mode 100644 index 0000000..ba7ee00 --- /dev/null +++ b/thread_pool.cc @@ -0,0 +1,86 @@ +// Copyright 2016 Google Inc. All rights reserved +// +// 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. + +#include "thread_pool.h" + +#include <stack> +#include <vector> + +#include "condvar.h" +#include "mutex.h" +#include "thread.h" + +class ThreadPoolImpl : public ThreadPool { + public: + explicit ThreadPoolImpl(int num_threads) + : is_waiting_(false) { + threads_.reserve(num_threads); + for (int i = 0; i < num_threads; i++) { + threads_.push_back(thread([this]() { Loop(); })); + } + } + + virtual ~ThreadPoolImpl() override { + } + + virtual void Submit(function<void(void)> task) override { + unique_lock<mutex> lock(mu_); + tasks_.push(task); + cond_.notify_one(); + } + + virtual void Wait() override { + { + unique_lock<mutex> lock(mu_); + is_waiting_ = true; + cond_.notify_all(); + } + + for (thread& th : threads_) { + th.join(); + } + } + + private: + void Loop() { + while (true) { + function<void(void)> task; + { + unique_lock<mutex> lock(mu_); + if (tasks_.empty()) { + if (is_waiting_) + return; + cond_.wait(lock); + } + + if (tasks_.empty()) + continue; + + task = tasks_.top(); + tasks_.pop(); + } + task(); + } + } + + vector<thread> threads_; + mutex mu_; + condition_variable cond_; + stack<function<void(void)>> tasks_; + bool is_waiting_; +}; + +ThreadPool* NewThreadPool(int num_threads) { + return new ThreadPoolImpl(num_threads); +} diff --git a/thread_pool.h b/thread_pool.h new file mode 100644 index 0000000..0384ce8 --- /dev/null +++ b/thread_pool.h @@ -0,0 +1,35 @@ +// Copyright 2016 Google Inc. All rights reserved +// +// 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. + +#ifndef THREAD_POOL_H_ +#define THREAD_POOL_H_ + +#include <functional> + +using namespace std; + +class ThreadPool { + public: + virtual ~ThreadPool() = default; + + virtual void Submit(function<void(void)> task) = 0; + virtual void Wait() = 0; + + protected: + ThreadPool() = default; +}; + +ThreadPool* NewThreadPool(int num_threads); + +#endif // THREAD_POOL_H_ |