aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShinichiro Hamaji <shinichiro.hamaji@gmail.com>2016-01-27 17:21:39 +0900
committerShinichiro Hamaji <shinichiro.hamaji@gmail.com>2016-01-27 17:34:10 +0900
commit702befcaafe658291f1f6ca2ec6293dbcdac5bbb (patch)
treecc77e2edcc518524dc62312c56cbd53ee32117c2
parent6ca9cfe313bafd3f2ef8278140d2a8fe3ee67de3 (diff)
downloadkati-702befcaafe658291f1f6ca2ec6293dbcdac5bbb.tar.gz
[C++] Re-invent C++11-ish thread library
Android's build system uses -static to build ckati, and you cannot use C++11's threading library with -static. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52590
-rw-r--r--Makefile.ckati3
-rw-r--r--condvar.cc42
-rw-r--r--condvar.h35
-rw-r--r--mutex.cc37
-rw-r--r--mutex.h50
-rw-r--r--regen.cc4
-rw-r--r--stats.cc2
-rw-r--r--stats.h3
-rw-r--r--thread.cc78
-rw-r--r--thread.h18
-rw-r--r--thread_pool.cc86
-rw-r--r--thread_pool.h35
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");
+}
diff --git a/mutex.h b/mutex.h
new file mode 100644
index 0000000..d6f1f5a
--- /dev/null
+++ b/mutex.h
@@ -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_
diff --git a/regen.cc b/regen.cc
index 81fd189..a40ebf3 100644
--- a/regen.cc
+++ b/regen.cc
@@ -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 {
diff --git a/stats.cc b/stats.cc
index e1e7992..9d4a160 100644
--- a/stats.cc
+++ b/stats.cc
@@ -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"
diff --git a/stats.h b/stats.h
index 63acc55..6244b54 100644
--- a/stats.h
+++ b/stats.h
@@ -15,9 +15,10 @@
#ifndef STATS_H_
#define STATS_H_
-#include <mutex>
#include <string>
+#include "mutex.h"
+
using namespace std;
class Stats {
diff --git a/thread.cc b/thread.cc
index 1450466..9733208 100644
--- a/thread.cc
+++ b/thread.cc
@@ -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;
}
diff --git a/thread.h b/thread.h
index 8fd3842..440fc5b 100644
--- a/thread.h
+++ b/thread.h
@@ -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_