Scanner C++ API
util.h
1 /* Copyright 2016 Carnegie Mellon University, NVIDIA Corporation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #pragma once
17 
18 #include <glog/logging.h>
19 #include <libgen.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <atomic>
24 #include <chrono>
25 #include <condition_variable>
26 #include <cstring>
27 #include <mutex>
28 #include <sstream>
29 #include <string>
30 #include <vector>
31 
32 #ifdef __linux__
33 #include <sys/prctl.h>
34 #include <sys/stat.h>
35 #include <sys/wait.h>
36 #endif
37 
38 namespace scanner {
39 
40 class SpinLock {
41  std::atomic_flag locked = ATOMIC_FLAG_INIT;
42 
43  public:
44  void lock() {
45  while (locked.test_and_set(std::memory_order_acquire)) {
46  ;
47  }
48  }
49  void unlock() { locked.clear(std::memory_order_release); }
50 };
51 
52 using timepoint_t = std::chrono::time_point<std::chrono::high_resolution_clock>;
53 
54 inline timepoint_t now() { return std::chrono::high_resolution_clock::now(); }
55 
56 inline double seconds_since(timepoint_t then) {
57  return std::chrono::duration_cast<std::chrono::seconds>(now() - then)
58  .count();
59 }
60 
61 inline double ms_since(timepoint_t then) {
62  return std::chrono::duration_cast<std::chrono::milliseconds>(now() - then)
63  .count();
64 }
65 
66 inline double nano_since(timepoint_t then) {
67  return std::chrono::duration_cast<std::chrono::nanoseconds>(now() - then)
68  .count();
69 }
70 
73 inline void split(const std::string& s, char delim,
74  std::vector<std::string>& elems) {
75  std::stringstream ss;
76  ss.str(s);
77  std::string item;
78  while (std::getline(ss, item, delim)) {
79  elems.push_back(item);
80  }
81 }
82 
83 inline std::vector<std::string> split(const std::string& s, char delim) {
84  std::vector<std::string> elems;
85  split(s, delim, elems);
86  return elems;
87 }
88 
91 #define THREAD_RETURN_SUCCESS() \
92  do { \
93  void* val = malloc(sizeof(int)); \
94  *((int*)val) = EXIT_SUCCESS; \
95  pthread_exit(val); \
96  } while (0);
97 
98 template <typename T>
99 T sum(const std::vector<T>& vec) {
100  T result{};
101  for (const T& v : vec) {
102  result += v;
103  }
104  return result;
105 }
106 
107 template <typename T>
108 T nano_to_ms(T ns) {
109  return ns / 1000000;
110 }
111 
112 template <typename T>
113 class Condition {
114  public:
115  Condition(const T& v) : value_(v) {}
116 
117  T get() {
118  return value_.load();
119  }
120 
121  void set(const T& v) {
122  std::unique_lock<std::mutex> lock(m_);
123  value_ = v;
124  lock.unlock();
125  cv_.notify_all();
126  }
127 
128  bool test_and_set(const T& test, const T& set) {
129  std::unique_lock<std::mutex> lock(m_);
130  if (value_ == test) {
131  value_ = set;
132  lock.unlock();
133  cv_.notify_all();
134  return true;
135  }
136  return false;
137  }
138 
139  bool wait_and_set(const T& wait_for, const T& set_to) {
140  std::unique_lock<std::mutex> lock(m_);
141  if (value_ == wait_for) {
142  value_ = set_to;
143  lock.unlock();
144  cv_.notify_all();
145  return true;
146  }
147  T temp = value_.load();
148  cv_.wait(lock, [&] { return value_ == wait_for; });
149  value_ = set_to;
150  lock.unlock();
151  cv_.notify_all();
152  return true;
153  }
154 
155  T wait_for_change(const T& v) {
156  std::unique_lock<std::mutex> lock(m_);
157  if (value_ != v) return value_;
158  cv_.wait(lock, [&] { return value_ != v; });
159  return value_;
160  }
161 
162  void wait_until_changed_to(const T& v) {
163  std::unique_lock<std::mutex> lock(m_);
164  if (value_ == v) return;
165  cv_.wait(lock, [&] { return value_ == v; });
166  }
167 
168  void wait_until_changed_to_for(const T& v, int ms) {
169  std::unique_lock<std::mutex> lock(m_);
170  if (value_ == v) return;
171  cv_.wait_for(lock, std::chrono::milliseconds(ms),
172  [&] { return value_ = v; });
173  }
174 
175  private:
176  std::mutex m_;
177  std::condition_variable cv_;
178  std::atomic<T> value_;
179 };
180 
181 class Flag {
182  public:
183  void set() {
184  std::unique_lock<std::mutex> lock(m_);
185  bit_ = true;
186  lock.unlock();
187  cv_.notify_all();
188  }
189 
190  bool raised() { return bit_.load(); }
191 
192  void wait() {
193  std::unique_lock<std::mutex> lock(m_);
194  cv_.wait(lock, [&] { return bit_.load(); });
195  }
196 
197  void wait_for(int ms) {
198  std::unique_lock<std::mutex> lock(m_);
199  cv_.wait_for(lock, std::chrono::milliseconds(ms),
200  [&] { return bit_.load(); });
201  }
202 
203  private:
204  std::mutex m_;
205  std::condition_variable cv_;
206  std::atomic<bool> bit_{false};
207 };
210 
211 #ifdef __linux
212 
213 // Hacky way to print a stack trace while running. Useful right before
214 // a LOG(FATAL) or other type of fatal event.
215 inline void print_trace() {
216  char pid_buf[30];
217  sprintf(pid_buf, "%d", getpid());
218  char name_buf[512];
219  name_buf[readlink("/proc/self/exe", name_buf, 511)] = 0;
220  prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
221  int child_pid = fork();
222  if (!child_pid) {
223  dup2(2, 1); // redirect output to stderr
224  fprintf(stdout, "stack trace for %s pid=%s\n", name_buf, pid_buf);
225  execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread apply all bt",
226  name_buf, pid_buf, NULL);
227  abort(); /* If gdb failed to start */
228  } else {
229  waitpid(child_pid, NULL, 0);
230  }
231 }
232 
233 #endif
234 
235 }
Definition: util.h:181
Definition: database.cpp:36
Definition: util.h:113
Definition: util.h:40