Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | // ok is an experimental test harness, maybe to replace DM. Key features: |
| 9 | // * work is balanced across separate processes for stability and isolation; |
| 10 | // * ok is entirely opt-in. No more maintaining huge --blacklists. |
| 11 | |
| 12 | #include "SkGraphics.h" |
Florin Malita | ab244f0 | 2017-05-03 19:16:58 +0000 | [diff] [blame] | 13 | #include "SkImage.h" |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 14 | #include "ok.h" |
Mike Klein | 9827256 | 2017-03-23 15:29:26 -0400 | [diff] [blame] | 15 | #include <chrono> |
Mike Klein | 9827256 | 2017-03-23 15:29:26 -0400 | [diff] [blame] | 16 | #include <list> |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 17 | #include <stdio.h> |
| 18 | #include <stdlib.h> |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 19 | #include <vector> |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 20 | |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 21 | #if !defined(__has_include) |
| 22 | #define __has_include(x) 0 |
| 23 | #endif |
| 24 | |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 25 | static thread_local const char* tls_currently_running = ""; |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 26 | |
Mike Klein | 1b4602b | 2017-08-30 10:23:01 -0400 | [diff] [blame] | 27 | #if __has_include(<execinfo.h>) |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 28 | #include <execinfo.h> |
Mike Klein | 1b4602b | 2017-08-30 10:23:01 -0400 | [diff] [blame] | 29 | |
| 30 | #define CAN_BACKTRACE |
| 31 | static void backtrace(int fd) { |
| 32 | void* stack[128]; |
| 33 | int frames = backtrace(stack, sizeof(stack)/sizeof(*stack)); |
| 34 | backtrace_symbols_fd(stack, frames, fd); |
| 35 | } |
| 36 | |
| 37 | #elif __has_include(<dlfcn.h>) && __has_include(<unwind.h>) |
| 38 | #include <cxxabi.h> |
| 39 | #include <dlfcn.h> |
| 40 | #include <unwind.h> |
| 41 | |
| 42 | #define CAN_BACKTRACE |
| 43 | static void backtrace(int fd) { |
| 44 | FILE* file = fdopen(fd, "a"); |
| 45 | _Unwind_Backtrace([](_Unwind_Context* ctx, void* arg) { |
| 46 | auto file = (FILE*)arg; |
| 47 | if (auto ip = (void*)_Unwind_GetIP(ctx)) { |
| 48 | const char* name = "[unknown]"; |
| 49 | void* addr = nullptr; |
| 50 | Dl_info info; |
| 51 | if (dladdr(ip, &info) && info.dli_sname && info.dli_saddr) { |
| 52 | name = info.dli_sname; |
| 53 | addr = info.dli_saddr; |
| 54 | } |
| 55 | |
| 56 | int ok; |
| 57 | char* demangled = abi::__cxa_demangle(name, nullptr,0, &ok); |
| 58 | if (ok == 0 && demangled) { |
| 59 | name = demangled; |
| 60 | } |
| 61 | |
| 62 | fprintf(file, "\t%p %s+%zu\n", ip, name, (size_t)ip - (size_t)addr); |
| 63 | free(demangled); |
| 64 | } |
| 65 | return _URC_NO_REASON; |
| 66 | }, file); |
| 67 | fflush(file); |
| 68 | } |
| 69 | #endif |
| 70 | |
| 71 | #if defined(CAN_BACKTRACE) && __has_include(<fcntl.h>) && __has_include(<signal.h>) |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 72 | #include <fcntl.h> |
| 73 | #include <signal.h> |
| 74 | |
Mike Klein | 94fef59 | 2017-08-30 14:02:47 -0400 | [diff] [blame] | 75 | // We'd ordinarily just use lockf(), but fcntl() is more portable to older Android NDK APIs. |
| 76 | static void lock_or_unlock_fd(int fd, short type) { |
| 77 | struct flock fl{}; |
| 78 | fl.l_type = type; |
| 79 | fl.l_whence = SEEK_CUR; |
| 80 | fl.l_start = 0; |
| 81 | fl.l_len = 0; // 0 == the entire file |
| 82 | fcntl(fd, F_SETLKW, &fl); |
| 83 | } |
| 84 | static void lock_fd(int fd) { lock_or_unlock_fd(fd, F_WRLCK); } |
| 85 | static void unlock_fd(int fd) { lock_or_unlock_fd(fd, F_UNLCK); } |
Mike Klein | 1b4602b | 2017-08-30 10:23:01 -0400 | [diff] [blame] | 86 | |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 87 | static int log_fd = 2/*stderr*/; |
| 88 | |
| 89 | static void log(const char* msg) { |
| 90 | write(log_fd, msg, strlen(msg)); |
| 91 | } |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 92 | |
| 93 | static void setup_crash_handler() { |
| 94 | static void (*original_handlers[32])(int); |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 95 | for (int sig : std::vector<int>{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV }) { |
| 96 | original_handlers[sig] = signal(sig, [](int sig) { |
Mike Klein | 1b4602b | 2017-08-30 10:23:01 -0400 | [diff] [blame] | 97 | lock_fd(log_fd); |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 98 | log("\ncaught signal "); |
| 99 | switch (sig) { |
| 100 | #define CASE(s) case s: log(#s); break |
| 101 | CASE(SIGABRT); |
| 102 | CASE(SIGBUS); |
| 103 | CASE(SIGFPE); |
| 104 | CASE(SIGILL); |
| 105 | CASE(SIGSEGV); |
| 106 | #undef CASE |
| 107 | } |
| 108 | log(" while running '"); |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 109 | log(tls_currently_running); |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 110 | log("'\n"); |
Mike Klein | 1b4602b | 2017-08-30 10:23:01 -0400 | [diff] [blame] | 111 | backtrace(log_fd); |
| 112 | unlock_fd(log_fd); |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 113 | |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 114 | signal(sig, original_handlers[sig]); |
| 115 | raise(sig); |
| 116 | }); |
| 117 | } |
| 118 | } |
| 119 | |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 120 | static void defer_logging() { |
| 121 | log_fd = fileno(tmpfile()); |
Mike Klein | 7371491 | 2017-07-26 18:30:57 +0000 | [diff] [blame] | 122 | atexit([] { |
| 123 | lseek(log_fd, 0, SEEK_SET); |
| 124 | char buf[1024]; |
| 125 | while (size_t bytes = read(log_fd, buf, sizeof(buf))) { |
| 126 | write(2, buf, bytes); |
| 127 | } |
| 128 | }); |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 129 | } |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 130 | |
| 131 | void ok_log(const char* msg) { |
Mike Klein | 1b4602b | 2017-08-30 10:23:01 -0400 | [diff] [blame] | 132 | lock_fd(log_fd); |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 133 | log("["); |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 134 | log(tls_currently_running); |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 135 | log("]\t"); |
| 136 | log(msg); |
| 137 | log("\n"); |
Mike Klein | 1b4602b | 2017-08-30 10:23:01 -0400 | [diff] [blame] | 138 | unlock_fd(log_fd); |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 139 | } |
| 140 | |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 141 | #else |
| 142 | static void setup_crash_handler() {} |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 143 | static void defer_logging() {} |
| 144 | |
| 145 | void ok_log(const char* msg) { |
Mike Klein | 84c5435 | 2017-08-29 19:59:57 -0400 | [diff] [blame] | 146 | fprintf(stderr, "[%s]\t%s\n", tls_currently_running, msg); |
Mike Klein | 200f6da | 2017-03-28 09:30:11 -0400 | [diff] [blame] | 147 | } |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 148 | #endif |
| 149 | |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 150 | struct EngineType { |
| 151 | const char *name, *help; |
| 152 | std::unique_ptr<Engine> (*factory)(Options); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 153 | }; |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 154 | static std::vector<EngineType> engine_types; |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 155 | |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 156 | struct StreamType { |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 157 | const char *name, *help; |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 158 | std::unique_ptr<Stream> (*factory)(Options); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 159 | }; |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 160 | static std::vector<StreamType> stream_types; |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 161 | |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 162 | struct DstType { |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 163 | const char *name, *help; |
Mike Klein | 0222e70 | 2017-03-25 15:53:14 -0400 | [diff] [blame] | 164 | std::unique_ptr<Dst> (*factory)(Options); |
Mike Klein | 51fe971 | 2017-03-24 14:06:47 -0400 | [diff] [blame] | 165 | }; |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 166 | static std::vector<DstType> dst_types; |
Mike Klein | 51fe971 | 2017-03-24 14:06:47 -0400 | [diff] [blame] | 167 | |
Mike Klein | f5d1a55 | 2017-03-25 12:32:22 -0400 | [diff] [blame] | 168 | struct ViaType { |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 169 | const char *name, *help; |
Mike Klein | 0222e70 | 2017-03-25 15:53:14 -0400 | [diff] [blame] | 170 | std::unique_ptr<Dst> (*factory)(Options, std::unique_ptr<Dst>); |
Mike Klein | f5d1a55 | 2017-03-25 12:32:22 -0400 | [diff] [blame] | 171 | }; |
| 172 | static std::vector<ViaType> via_types; |
| 173 | |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 174 | template <typename T> |
| 175 | static std::string help_for(std::vector<T> registered) { |
| 176 | std::string help; |
| 177 | for (auto r : registered) { |
| 178 | help += "\n "; |
| 179 | help += r.name; |
| 180 | help += ": "; |
| 181 | help += r.help; |
| 182 | } |
| 183 | return help; |
| 184 | } |
| 185 | |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 186 | int main(int argc, char** argv) { |
| 187 | SkGraphics::Init(); |
Mike Klein | 61e9902 | 2017-03-23 18:36:39 -0400 | [diff] [blame] | 188 | setup_crash_handler(); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 189 | |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 190 | std::unique_ptr<Engine> engine; |
Mike Klein | 0222e70 | 2017-03-25 15:53:14 -0400 | [diff] [blame] | 191 | std::unique_ptr<Stream> stream; |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 192 | std::function<std::unique_ptr<Dst>(void)> dst_factory = []{ |
| 193 | // A default Dst that's enough for unit tests and not much else. |
| 194 | struct : Dst { |
| 195 | Status draw(Src* src) override { return src->draw(nullptr); } |
| 196 | sk_sp<SkImage> image() override { return nullptr; } |
| 197 | } dst; |
| 198 | return move_unique(dst); |
| 199 | }; |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 200 | |
| 201 | auto help = [&] { |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 202 | std::string engine_help = help_for(engine_types), |
| 203 | stream_help = help_for(stream_types), |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 204 | dst_help = help_for( dst_types), |
| 205 | via_help = help_for( via_types); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 206 | |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 207 | printf("%s [engine] src[:k=v,...] dst[:k=v,...] [via[:k=v,...] ...] \n" |
| 208 | " engine: how to execute tasks%s \n" |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 209 | " src: content to draw%s \n" |
| 210 | " dst: how to draw that content%s \n" |
| 211 | " via: wrappers around dst%s \n" |
| 212 | " Most srcs, dsts and vias have options, e.g. skp:dir=skps sw:ct=565 \n", |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 213 | argv[0], |
| 214 | engine_help.c_str(), stream_help.c_str(), dst_help.c_str(), via_help.c_str()); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 215 | return 1; |
| 216 | }; |
| 217 | |
| 218 | for (int i = 1; i < argc; i++) { |
Mike Klein | 5a8da16 | 2017-04-12 11:02:44 -0400 | [diff] [blame] | 219 | if (0 == strcmp("-h", argv[i])) { return help(); } |
| 220 | if (0 == strcmp("--help", argv[i])) { return help(); } |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 221 | |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 222 | for (auto e : engine_types) { |
| 223 | size_t len = strlen(e.name); |
| 224 | if (0 == strncmp(e.name, argv[i], len)) { |
| 225 | switch (argv[i][len]) { |
| 226 | case ':': len++; |
| 227 | case '\0': engine = e.factory(Options{argv[i]+len}); |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 232 | for (auto s : stream_types) { |
Mike Klein | 51fe971 | 2017-03-24 14:06:47 -0400 | [diff] [blame] | 233 | size_t len = strlen(s.name); |
| 234 | if (0 == strncmp(s.name, argv[i], len)) { |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 235 | switch (argv[i][len]) { |
| 236 | case ':': len++; |
Mike Klein | 51fe971 | 2017-03-24 14:06:47 -0400 | [diff] [blame] | 237 | case '\0': stream = s.factory(Options{argv[i]+len}); |
| 238 | } |
| 239 | } |
| 240 | } |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 241 | for (auto d : dst_types) { |
Mike Klein | 51fe971 | 2017-03-24 14:06:47 -0400 | [diff] [blame] | 242 | size_t len = strlen(d.name); |
| 243 | if (0 == strncmp(d.name, argv[i], len)) { |
| 244 | switch (argv[i][len]) { |
| 245 | case ':': len++; |
Mike Klein | 0222e70 | 2017-03-25 15:53:14 -0400 | [diff] [blame] | 246 | case '\0': dst_factory = [=]{ |
| 247 | return d.factory(Options{argv[i]+len}); |
Mike Klein | f5d1a55 | 2017-03-25 12:32:22 -0400 | [diff] [blame] | 248 | }; |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | for (auto v : via_types) { |
| 253 | size_t len = strlen(v.name); |
| 254 | if (0 == strncmp(v.name, argv[i], len)) { |
Mike Klein | 0222e70 | 2017-03-25 15:53:14 -0400 | [diff] [blame] | 255 | if (!dst_factory) { return help(); } |
Mike Klein | f5d1a55 | 2017-03-25 12:32:22 -0400 | [diff] [blame] | 256 | switch (argv[i][len]) { |
| 257 | case ':': len++; |
Mike Klein | 0222e70 | 2017-03-25 15:53:14 -0400 | [diff] [blame] | 258 | case '\0': dst_factory = [=]{ |
| 259 | return v.factory(Options{argv[i]+len}, dst_factory()); |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 260 | }; |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 261 | } |
| 262 | } |
| 263 | } |
| 264 | } |
Mike Klein | d63442d | 2017-03-27 14:16:04 -0400 | [diff] [blame] | 265 | if (!stream) { return help(); } |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 266 | |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 267 | if (!engine) { engine = engine_types.back().factory(Options{}); } |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 268 | |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 269 | // If we know engine->spawn() will never crash, we can defer logging until we exit. |
| 270 | if (engine->crashproof()) { |
| 271 | defer_logging(); |
| 272 | } |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 273 | |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 274 | int ok = 0, failed = 0, crashed = 0, skipped = 0; |
| 275 | |
| 276 | auto update_stats = [&](Status s) { |
| 277 | switch (s) { |
| 278 | case Status::OK: ok++; break; |
| 279 | case Status::Failed: failed++; break; |
| 280 | case Status::Crashed: crashed++; break; |
| 281 | case Status::Skipped: skipped++; break; |
| 282 | case Status::None: return; |
| 283 | } |
| 284 | const char* leader = "\r"; |
| 285 | auto print = [&](int count, const char* label) { |
| 286 | if (count) { |
| 287 | printf("%s%d %s", leader, count, label); |
| 288 | leader = ", "; |
| 289 | } |
| 290 | }; |
| 291 | print(ok, "ok"); |
| 292 | print(failed, "failed"); |
| 293 | print(crashed, "crashed"); |
| 294 | print(skipped, "skipped"); |
| 295 | fflush(stdout); |
| 296 | }; |
| 297 | |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 298 | std::list<std::future<Status>> live; |
| 299 | const auto the_past = std::chrono::steady_clock::now(); |
| 300 | |
| 301 | auto wait_one = [&] { |
| 302 | if (live.empty()) { |
| 303 | return Status::None; |
| 304 | } |
| 305 | |
| 306 | for (;;) { |
| 307 | for (auto it = live.begin(); it != live.end(); it++) { |
| 308 | if (it->wait_until(the_past) != std::future_status::timeout) { |
| 309 | Status s = it->get(); |
| 310 | live.erase(it); |
| 311 | return s; |
| 312 | } |
| 313 | } |
| 314 | } |
| 315 | }; |
| 316 | |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 317 | auto spawn = [&](std::function<Status(void)> fn) { |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 318 | std::future<Status> status; |
| 319 | for (;;) { |
| 320 | status = engine->spawn(fn); |
| 321 | if (status.valid()) { |
| 322 | break; |
| 323 | } |
| 324 | update_stats(wait_one()); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 325 | } |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 326 | live.push_back(std::move(status)); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 327 | }; |
| 328 | |
| 329 | for (std::unique_ptr<Src> owned = stream->next(); owned; owned = stream->next()) { |
| 330 | Src* raw = owned.release(); // Can't move std::unique_ptr into a lambda in C++11. :( |
| 331 | spawn([=] { |
| 332 | std::unique_ptr<Src> src{raw}; |
| 333 | |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 334 | std::string name = src->name(); |
| 335 | tls_currently_running = name.c_str(); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 336 | |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 337 | return dst_factory()->draw(src.get()); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 338 | }); |
| 339 | } |
| 340 | |
| 341 | for (Status s = Status::OK; s != Status::None; ) { |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 342 | s = wait_one(); |
Mike Klein | 06432b2 | 2017-03-21 13:14:33 -0400 | [diff] [blame] | 343 | update_stats(s); |
| 344 | } |
| 345 | printf("\n"); |
| 346 | return (failed || crashed) ? 1 : 0; |
| 347 | } |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 348 | |
| 349 | |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 350 | Register::Register(const char* name, const char* help, |
Mike Klein | 154e6da | 2017-07-26 15:13:47 -0400 | [diff] [blame] | 351 | std::unique_ptr<Engine> (*factory)(Options)) { |
| 352 | engine_types.push_back(EngineType{name, help, factory}); |
| 353 | } |
| 354 | Register::Register(const char* name, const char* help, |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 355 | std::unique_ptr<Stream> (*factory)(Options)) { |
| 356 | stream_types.push_back(StreamType{name, help, factory}); |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 357 | } |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 358 | Register::Register(const char* name, const char* help, |
| 359 | std::unique_ptr<Dst> (*factory)(Options)) { |
| 360 | dst_types.push_back(DstType{name, help, factory}); |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 361 | } |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 362 | Register::Register(const char* name, const char* help, |
Mike Klein | 0222e70 | 2017-03-25 15:53:14 -0400 | [diff] [blame] | 363 | std::unique_ptr<Dst> (*factory)(Options, std::unique_ptr<Dst>)) { |
Mike Klein | e15a7b5 | 2017-03-29 12:41:13 -0400 | [diff] [blame] | 364 | via_types.push_back(ViaType{name, help, factory}); |
Mike Klein | f5d1a55 | 2017-03-25 12:32:22 -0400 | [diff] [blame] | 365 | } |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 366 | |
| 367 | Options::Options(std::string str) { |
| 368 | std::string k,v, *curr = &k; |
| 369 | for (auto c : str) { |
| 370 | switch(c) { |
Mike Klein | 88f9c1e | 2017-03-27 12:43:44 -0400 | [diff] [blame] | 371 | case ',': (*this)[k] = v; |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 372 | curr = &(k = ""); |
| 373 | break; |
| 374 | case '=': curr = &(v = ""); |
| 375 | break; |
| 376 | default: *curr += c; |
| 377 | } |
| 378 | } |
Mike Klein | 88f9c1e | 2017-03-27 12:43:44 -0400 | [diff] [blame] | 379 | (*this)[k] = v; |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 380 | } |
| 381 | |
Mike Klein | 88f9c1e | 2017-03-27 12:43:44 -0400 | [diff] [blame] | 382 | std::string& Options::operator[](std::string k) { return this->kv[k]; } |
| 383 | |
Mike Klein | 7ac0483 | 2017-03-25 11:29:41 -0400 | [diff] [blame] | 384 | std::string Options::operator()(std::string k, std::string fallback) const { |
| 385 | for (auto it = kv.find(k); it != kv.end(); ) { |
| 386 | return it->second; |
| 387 | } |
| 388 | return fallback; |
| 389 | } |