├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── benchmarks ├── CMakeLists.txt ├── iconcur.cc ├── iopool.cc ├── iowait.cc ├── ring.cc ├── server_client.cc ├── spawn_task.cc └── timer_event_loop.cc ├── cmake ├── ExternalProject.cmake ├── ParseArguments.cmake ├── configure.cmake ├── prog.cmake ├── ragel.cmake ├── scm-version ├── ten.cmake └── version.cmake ├── doc ├── Makefile ├── build.rst ├── conf.py ├── http.rst ├── index.rst ├── internals.rst ├── ioproc.rst ├── kernel.rst ├── net.rst └── task.rst ├── examples ├── CMakeLists.txt ├── chat-server.cc ├── echo-server.cc ├── http-get.cc ├── http-proxy.cc ├── http-server.cc ├── https-get.cc ├── json-path.cc ├── memg.cc ├── msgpack.cc ├── prime-sieve.cc ├── rpc-server.cc ├── stack-guard.cc ├── stack-trace.cc └── synch.cc ├── googletest ├── CHANGES ├── CMakeLists.txt ├── CONTRIBUTORS ├── LICENSE ├── Makefile.am ├── README ├── build-aux │ └── .keep ├── cmake │ └── internal_utils.cmake ├── codegear │ ├── gtest.cbproj │ ├── gtest.groupproj │ ├── gtest_all.cc │ ├── gtest_link.cc │ ├── gtest_main.cbproj │ └── gtest_unittest.cbproj ├── configure.ac ├── include │ └── gtest │ │ ├── gtest-death-test.h │ │ ├── gtest-message.h │ │ ├── gtest-param-test.h │ │ ├── gtest-param-test.h.pump │ │ ├── gtest-printers.h │ │ ├── gtest-spi.h │ │ ├── gtest-test-part.h │ │ ├── gtest-typed-test.h │ │ ├── gtest.h │ │ ├── gtest_pred_impl.h │ │ ├── gtest_prod.h │ │ └── internal │ │ ├── gtest-death-test-internal.h │ │ ├── gtest-filepath.h │ │ ├── gtest-internal.h │ │ ├── gtest-linked_ptr.h │ │ ├── gtest-param-util-generated.h │ │ ├── gtest-param-util-generated.h.pump │ │ ├── gtest-param-util.h │ │ ├── gtest-port.h │ │ ├── gtest-string.h │ │ ├── gtest-tuple.h │ │ ├── gtest-tuple.h.pump │ │ ├── gtest-type-util.h │ │ └── gtest-type-util.h.pump ├── m4 │ ├── acx_pthread.m4 │ └── gtest.m4 ├── make │ └── Makefile ├── msvc │ ├── gtest-md.sln │ ├── gtest-md.vcproj │ ├── gtest.sln │ ├── gtest.vcproj │ ├── gtest_main-md.vcproj │ ├── gtest_main.vcproj │ ├── gtest_prod_test-md.vcproj │ ├── gtest_prod_test.vcproj │ ├── gtest_unittest-md.vcproj │ └── gtest_unittest.vcproj ├── samples │ ├── prime_tables.h │ ├── sample1.cc │ ├── sample1.h │ ├── sample10_unittest.cc │ ├── sample1_unittest.cc │ ├── sample2.cc │ ├── sample2.h │ ├── sample2_unittest.cc │ ├── sample3-inl.h │ ├── sample3_unittest.cc │ ├── sample4.cc │ ├── sample4.h │ ├── sample4_unittest.cc │ ├── sample5_unittest.cc │ ├── sample6_unittest.cc │ ├── sample7_unittest.cc │ ├── sample8_unittest.cc │ └── sample9_unittest.cc ├── scripts │ ├── common.py │ ├── fuse_gtest_files.py │ ├── gen_gtest_pred_impl.py │ ├── gtest-config.in │ ├── pump.py │ ├── release_docs.py │ ├── test │ │ └── Makefile │ ├── upload.py │ └── upload_gtest.py ├── src │ ├── gtest-all.cc │ ├── gtest-death-test.cc │ ├── gtest-filepath.cc │ ├── gtest-internal-inl.h │ ├── gtest-port.cc │ ├── gtest-printers.cc │ ├── gtest-test-part.cc │ ├── gtest-typed-test.cc │ ├── gtest.cc │ └── gtest_main.cc ├── test │ ├── gtest-death-test_ex_test.cc │ ├── gtest-death-test_test.cc │ ├── gtest-filepath_test.cc │ ├── gtest-linked_ptr_test.cc │ ├── gtest-listener_test.cc │ ├── gtest-message_test.cc │ ├── gtest-options_test.cc │ ├── gtest-param-test2_test.cc │ ├── gtest-param-test_test.cc │ ├── gtest-param-test_test.h │ ├── gtest-port_test.cc │ ├── gtest-printers_test.cc │ ├── gtest-test-part_test.cc │ ├── gtest-tuple_test.cc │ ├── gtest-typed-test2_test.cc │ ├── gtest-typed-test_test.cc │ ├── gtest-typed-test_test.h │ ├── gtest-unittest-api_test.cc │ ├── gtest_all_test.cc │ ├── gtest_break_on_failure_unittest.py │ ├── gtest_break_on_failure_unittest_.cc │ ├── gtest_catch_exceptions_test.py │ ├── gtest_catch_exceptions_test_.cc │ ├── gtest_color_test.py │ ├── gtest_color_test_.cc │ ├── gtest_env_var_test.py │ ├── gtest_env_var_test_.cc │ ├── gtest_environment_test.cc │ ├── gtest_filter_unittest.py │ ├── gtest_filter_unittest_.cc │ ├── gtest_help_test.py │ ├── gtest_help_test_.cc │ ├── gtest_list_tests_unittest.py │ ├── gtest_list_tests_unittest_.cc │ ├── gtest_main_unittest.cc │ ├── gtest_no_test_unittest.cc │ ├── gtest_output_test.py │ ├── gtest_output_test_.cc │ ├── gtest_output_test_golden_lin.txt │ ├── gtest_pred_impl_unittest.cc │ ├── gtest_premature_exit_test.cc │ ├── gtest_prod_test.cc │ ├── gtest_repeat_test.cc │ ├── gtest_shuffle_test.py │ ├── gtest_shuffle_test_.cc │ ├── gtest_sole_header_test.cc │ ├── gtest_stress_test.cc │ ├── gtest_test_utils.py │ ├── gtest_throw_on_failure_ex_test.cc │ ├── gtest_throw_on_failure_test.py │ ├── gtest_throw_on_failure_test_.cc │ ├── gtest_uninitialized_test.py │ ├── gtest_uninitialized_test_.cc │ ├── gtest_unittest.cc │ ├── gtest_xml_outfile1_test_.cc │ ├── gtest_xml_outfile2_test_.cc │ ├── gtest_xml_outfiles_test.py │ ├── gtest_xml_output_unittest.py │ ├── gtest_xml_output_unittest_.cc │ ├── gtest_xml_test_utils.py │ ├── production.cc │ └── production.h └── xcode │ ├── Config │ ├── DebugProject.xcconfig │ ├── FrameworkTarget.xcconfig │ ├── General.xcconfig │ ├── ReleaseProject.xcconfig │ ├── StaticLibraryTarget.xcconfig │ └── TestTarget.xcconfig │ ├── Resources │ └── Info.plist │ ├── Samples │ └── FrameworkSample │ │ ├── Info.plist │ │ ├── WidgetFramework.xcodeproj │ │ └── project.pbxproj │ │ ├── runtests.sh │ │ ├── widget.cc │ │ ├── widget.h │ │ └── widget_test.cc │ ├── Scripts │ ├── runtests.sh │ └── versiongenerate.py │ └── gtest.xcodeproj │ └── project.pbxproj ├── include ├── chrono_io ├── ratio_io └── ten │ ├── app.hh │ ├── apply.hh │ ├── backoff.hh │ ├── bits │ ├── miniz.c │ └── optional.hpp │ ├── buffer.hh │ ├── channel.hh │ ├── consistent_hash.hh │ ├── descriptors.hh │ ├── encoders.hh │ ├── error.hh │ ├── ewma.hh │ ├── http │ ├── client.hh │ ├── http_error.hh │ ├── http_message.hh │ ├── http_parser.h │ └── server.hh │ ├── ioproc.hh │ ├── iter.hh │ ├── json.hh │ ├── jsonpack.hh │ ├── jsonstream.hh │ ├── llqueue.hh │ ├── logging.hh │ ├── lru.hh │ ├── metrics.hh │ ├── mpmc_bounded_queue.hh │ ├── mpsc_queue.hh │ ├── msgpack.hh │ ├── net.hh │ ├── net │ ├── address.hh │ ├── cmd_server.hh │ └── ssl.hh │ ├── optional.hh │ ├── ptr.hh │ ├── rpc │ ├── client.hh │ ├── protocol.hh │ ├── server.hh │ └── thunk.hh │ ├── semaphore.hh │ ├── shared_pool.hh │ ├── striped.hh │ ├── synchronized.hh │ ├── task.hh │ ├── task │ ├── compat.hh │ ├── deadline.hh │ ├── kernel.hh │ ├── qutex.hh │ ├── rendez.hh │ └── task.hh │ ├── term.hh │ ├── thread_guard.hh │ ├── thread_local.hh │ ├── uri.hh │ ├── work_deque.hh │ ├── zip.hh │ └── zookeeper.hh ├── src ├── CMakeLists.txt ├── alarm.hh ├── app.cc ├── cares.cc ├── chrono_io.cpp ├── compat.cc ├── context.cc ├── context.hh ├── deadline.cc ├── error.cc ├── http_message.cc ├── http_parser.c ├── io.cc ├── io.hh ├── ioproc.cc ├── json.cc ├── jsonstream.cc ├── kernel.cc ├── metrics.cc ├── net.cc ├── qutex.cc ├── rendez.cc ├── scheduler.cc ├── scheduler.hh ├── ssl.cc ├── stack_alloc.cc ├── stack_alloc.hh ├── task.cc ├── task_impl.hh ├── term.cc ├── thread_context.cc ├── thread_context.hh ├── uri_grammar.rl ├── uri_parser.rl └── zip.cc └── tests ├── CMakeLists.txt ├── test_backoff.cc ├── test_buffer.cc ├── test_channel.cc ├── test_descriptors.cc ├── test_hash_ring.cc ├── test_http.cc ├── test_ioproc.cc ├── test_json.cc ├── test_llqueue.cc ├── test_metrics.cc ├── test_mpmc_queue.cc ├── test_mpsc_queue.cc ├── test_net.cc ├── test_qutex.cc ├── test_striped.cc ├── test_task.cc ├── test_thread_local.cc ├── test_uri.cc ├── test_work_deque.cc └── test_zip.cc /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | @* 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | before_install: 4 | - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y 5 | - sudo add-apt-repository ppa:boost-latest/ppa -y 6 | - sudo apt-get update -qq 7 | - export CC=${REAL_CC} CXX=${REAL_CXX} 8 | 9 | install: 10 | - sudo apt-get install cmake 11 | - sudo apt-get install -qq g++-4.8 12 | - sudo apt-get install libssl-dev 13 | - sudo apt-get install ragel 14 | - sudo apt-get install libjansson-dev 15 | - sudo apt-get install libc-ares-dev 16 | - sudo apt-get install libboost1.54-all-dev 17 | 18 | env: REAL_CC=gcc-4.8 REAL_CXX=g++-4.8 19 | 20 | script: 21 | - mkdir b 22 | - cd b 23 | - cmake .. 24 | - make 25 | - make world 26 | - ctest --output-on-failure 27 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(TEN) 2 | cmake_minimum_required(VERSION 2.8) 3 | enable_testing() 4 | 5 | if (NOT TEN_SUBPROJECT) 6 | include(cmake/prog.cmake) 7 | endif () 8 | include(cmake/ten.cmake) 9 | include(cmake/ragel.cmake) 10 | include(cmake/configure.cmake) 11 | 12 | #set (CMAKE_EXE_LINKER_FLAGS -lc++abi) 13 | #set (CMAKE_SHARED_LINKER_FLAGS -lc++abi) 14 | #set (CMAKE_MODULE_LINKER_FLAGS -lc++abi) 15 | 16 | add_subdirectory(double-conversion) 17 | add_subdirectory(glog) 18 | 19 | if (OPENSSL_FOUND) 20 | set(SSL_SRC src/ssl.cc) 21 | else (OPENSSL_FOUND) 22 | message(FATAL_ERROR "openssl not found") 23 | endif (OPENSSL_FOUND) 24 | 25 | add_definitions(-DHTTP_PARSER_STRICT=0) 26 | if (TASK_TRACE) 27 | message(STATUS "Task tracing: on") 28 | add_definitions(-DTEN_TASK_TRACE) 29 | else (TASK_TRACE) 30 | message(STATUS "Task tracing: off") 31 | endif (TASK_TRACE) 32 | 33 | add_subdirectory(msgpack) 34 | add_subdirectory(src) 35 | set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/src/uri_parser.cc PROPERTIES GENERATED 1) 36 | 37 | # for double-conversion.h 38 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/double-conversion/src/) 39 | 40 | add_library(ten 41 | src/deadline.cc 42 | src/http_message.cc 43 | src/ioproc.cc 44 | src/json.cc 45 | src/jsonstream.cc 46 | src/metrics.cc 47 | src/ssl.cc 48 | src/term.cc 49 | ${CMAKE_CURRENT_BINARY_DIR}/src/uri_parser.cc 50 | src/zip.cc 51 | src/http_parser.c 52 | src/rendez.cc 53 | src/qutex.cc 54 | src/cares.cc 55 | src/net.cc 56 | src/compat.cc 57 | src/kernel.cc 58 | src/thread_context.cc 59 | src/stack_alloc.cc 60 | src/task.cc 61 | src/scheduler.cc 62 | src/io.cc 63 | src/error.cc 64 | src/context.cc 65 | src/app.cc 66 | src/chrono_io.cpp 67 | ) 68 | add_dependencies(ten libglog ragel_uri_parser double-conversion) 69 | 70 | # TODO: compile miniz separately, so warnings remain high for ten-specific code in zip.cc 71 | set_source_files_properties(src/zip.cc PROPERTIES 72 | COMPILE_FLAGS "-fno-strict-aliasing -Wno-strict-aliasing -Wno-attributes -Wno-extra") 73 | 74 | target_link_libraries(ten glog double-conversion boost_context ${CARES_LIB} rt ${OPENSSL_LIBRARIES}) 75 | 76 | if (NOT TEN_SUBPROJECT) 77 | add_subdirectory(examples) 78 | add_subdirectory(tests) 79 | add_subdirectory(benchmarks) 80 | 81 | add_custom_target(world DEPENDS 82 | examples 83 | benchmarks 84 | ) 85 | endif () 86 | 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | libten [![Build Status](https://travis-ci.org/toffaletti/libten.png)](https://travis-ci.org/toffaletti/libten) 2 | ====== 3 | 4 | C++11 library for network services on modern x86-64 Linux. 5 | 6 | Features 7 | -------- 8 | 9 | * lightweight cooperative tasks (using boost.context) 10 | * typed channels for communicating between threads and tasks 11 | * http client and server 12 | * fast uri parser 13 | * JSON parser (wrapper around jansson) 14 | * logging (glog) 15 | * rpc (using msgpack) 16 | * epoll event loop 17 | 18 | Why 19 | --- 20 | Or rather why not libevent, libev, or boost.asio? libten is designed 21 | around the concept of task-based concurrency, while the other 22 | libraries are designed for event driven concurrency with callbacks. 23 | They are not entirely at odds, libten's event loop could be built on 24 | any of these libraries. However, another major difference is that 25 | other libraries strive to provide a cross platform solution to event 26 | driven network programming. They are great if you need portable 27 | code that works across many versions and platforms. libten's approach 28 | is to focus only on modern Linux, modern compilers, and performance. 29 | This makes libten's code base smaller and easier to maintain, with 30 | very minimal abstraction. libten uses epoll, timerfd, and signalfd. 31 | In addition to networking and concurrency it provides logging, JSON, 32 | URI, http client and server, rpc, zookeeper and more. 33 | 34 | API Stability 35 | ------------- 36 | libten is not a stable API yet. Don't let this scare you away though. 37 | Most changes at this point are minor and incremental. 38 | 39 | Dependencies 40 | ------------ 41 | 42 | * cmake >= 2.8 43 | * g++ >= 4.7.0 44 | * libssl-dev >= 0.9.8 45 | * libboost-dev >= 1.51 46 | * libboost-date-time-dev >= 1.51 47 | * libboost-program-options-dev >= 1.51 48 | * libboost-context-dev >= 1.51 49 | * ragel >= 6.5 50 | * libjansson-dev >= 2.3 51 | * libc-ares-dev 52 | 53 | Bundled 3rd-party components 54 | ____________________________ 55 | 56 | * http_parser v2 from https://github.com/joyent/http-parser 57 | * glog-0.3.2 from http://code.google.com/p/google-glog/ 58 | * stlencoders 1.1.1 from http://code.google.com/p/stlencoders/ 59 | * msgpack-0.5.7 from http://msgpack.org/ 60 | * miniz v1.14 from http://code.google.com/p/miniz/ 61 | 62 | -------------------------------------------------------------------------------- /benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | add_executable(timer_event_loop EXCLUDE_FROM_ALL timer_event_loop.cc) 4 | target_link_libraries(timer_event_loop ten) 5 | 6 | add_executable(server_client EXCLUDE_FROM_ALL server_client.cc) 7 | target_link_libraries(server_client ten) 8 | 9 | add_executable(iconcur EXCLUDE_FROM_ALL iconcur.cc) 10 | target_link_libraries(iconcur ten) 11 | 12 | add_executable(ring EXCLUDE_FROM_ALL ring.cc) 13 | target_link_libraries(ring ten) 14 | 15 | add_executable(iopool EXCLUDE_FROM_ALL iopool.cc) 16 | target_link_libraries(iopool ten boost_program_options) 17 | 18 | add_executable(iowait EXCLUDE_FROM_ALL iowait.cc) 19 | target_link_libraries(iowait ten) 20 | 21 | add_executable(spawn_task EXCLUDE_FROM_ALL spawn_task.cc) 22 | target_link_libraries(spawn_task ten) 23 | 24 | add_custom_target(benchmarks DEPENDS 25 | timer_event_loop 26 | server_client 27 | iconcur 28 | ring 29 | iopool 30 | iowait 31 | spawn_task 32 | ) 33 | -------------------------------------------------------------------------------- /benchmarks/iconcur.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ten/thread_guard.hh" 3 | #include "ten/task/rendez.hh" 4 | #include "ten/logging.hh" 5 | 6 | using namespace ten; 7 | 8 | struct state { 9 | qutex q; 10 | rendez r; 11 | int x; 12 | 13 | state() : x(0) {} 14 | }; 15 | 16 | void qlocker(std::shared_ptr st) { 17 | taskname("qlocker"); 18 | taskstate("looping"); 19 | for (int i=0; i<1000; ++i) { 20 | std::lock_guard lk(st->q); 21 | ++(st->x); 22 | } 23 | taskstate("done"); 24 | std::lock_guard lk(st->q); 25 | taskname("qlocker %d", st->x); 26 | st->r.wakeup(); 27 | } 28 | 29 | bool is_done(int &x) { 30 | taskstate("sleeping on rendez: %d %x", x, &x); 31 | return x == 20*1000; 32 | } 33 | 34 | void qutex_task_spawn() { 35 | taskname("qutex_task_spawn"); 36 | std::shared_ptr st = std::make_shared(); 37 | std::vector threads; 38 | for (int i=0; i<20; ++i) { 39 | taskstate("spawning %d", i); 40 | threads.emplace_back(task::spawn_thread([=] { 41 | qlocker(st); 42 | })); 43 | } 44 | std::unique_lock lk(st->q); 45 | st->r.sleep(lk, std::bind(is_done, std::ref(st->x))); 46 | CHECK(st->x == 20*1000); 47 | } 48 | 49 | int main() { 50 | return task::main([] { 51 | for (int i=0; i<10; ++i) { 52 | task::spawn(qutex_task_spawn); 53 | } 54 | }); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /benchmarks/iowait.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | #include "ten/descriptors.hh" 3 | 4 | int main() { 5 | using namespace ten; 6 | using namespace std::chrono; 7 | return task::main([] { 8 | pipe_fd p{O_NONBLOCK}; 9 | for (unsigned i=0; i<10; ++i) { 10 | fdwait(p.r.fd, 'r', milliseconds{100}); 11 | } 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /benchmarks/ring.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | #include "ten/channel.hh" 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace ten; 8 | using namespace std::chrono; 9 | 10 | void one_ring(channel chin, channel chout, int m, int n) { 11 | auto start = high_resolution_clock::now(); 12 | std::cout << "sending " << m << " messages in ring of " << n << " tasks\n"; 13 | chout.send(0); 14 | for (;;) { 15 | int i = chin.recv(); 16 | if (i < m) { 17 | ++i; 18 | chout.send(std::move(i)); 19 | } else { 20 | chout.close(); 21 | break; 22 | } 23 | } 24 | auto stop = high_resolution_clock::now(); 25 | std::cout << (n*m) << " messages in " << duration_cast(stop - start).count() << "ms\n"; 26 | } 27 | 28 | void ring(channel chin, channel chout) { 29 | try { 30 | for (;;) { 31 | int n = chin.recv(); 32 | chout.send(std::move(n)); 33 | } 34 | } catch (channel_closed_error &e) { 35 | chout.close(); 36 | } 37 | } 38 | 39 | int main(int argc, char *argv[]) { 40 | return task::main([&] { 41 | channel chin; 42 | channel chfirst = chin; 43 | int n = 10; 44 | int m = 1000; 45 | if (argc >= 2) { 46 | n = boost::lexical_cast(argv[1]); 47 | } 48 | if (argc >= 3) { 49 | m = boost::lexical_cast(argv[2]); 50 | } 51 | for (int i=0; i chout; 53 | task::spawn([=] { 54 | ring(chin, chout); 55 | }); 56 | chin = chout; 57 | } 58 | task::spawn([=] { 59 | one_ring(chin, chfirst, m, n); 60 | }); 61 | }); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /benchmarks/server_client.cc: -------------------------------------------------------------------------------- 1 | #include "ten/net.hh" 2 | #include "ten/channel.hh" 3 | #include 4 | #include 5 | 6 | using namespace ten; 7 | 8 | static void connecter(const address &addr, channel ch) { 9 | try { 10 | netsock s(AF_INET, SOCK_STREAM); 11 | if (s.connect(addr, std::chrono::milliseconds{100}) == 0) { 12 | ch.send(0); 13 | } else { 14 | ch.send(std::move(errno)); 15 | } 16 | } catch (errorx &e) { 17 | ch.send(std::move(errno)); 18 | } 19 | } 20 | 21 | static void handler(int fd) { 22 | netsock s(fd); 23 | char buf[32]; 24 | for (;;) { 25 | ssize_t nr = s.recv(buf, sizeof(buf)); 26 | if (nr <= 0) break; 27 | } 28 | } 29 | 30 | static void listener(netsock &sock) { 31 | address addr; 32 | for (;;) { 33 | int fd = sock.accept(addr); 34 | if (fd != -1) { 35 | task::spawn([=] { 36 | handler(fd); 37 | }); 38 | } 39 | } 40 | } 41 | 42 | static void connecter_spawner(const address &addr, const channel &ch) { 43 | for (int i=0; i<1000; ++i) { 44 | task::spawn([=] { 45 | connecter(addr, ch); 46 | }); 47 | } 48 | } 49 | 50 | int main(int argc, char *argv[]) { 51 | return task::main([] { 52 | channel ch(1000); 53 | address addr{AF_INET}; 54 | netsock s(AF_INET, SOCK_STREAM | SOCK_NONBLOCK); 55 | s.bind(addr); 56 | s.listen(); 57 | s.getsockname(addr); 58 | task listen_task = task::spawn([&] { 59 | listener(s); 60 | }); 61 | this_task::yield(); // let listener get setup 62 | std::thread connecter_thread = task::spawn_thread([=] { 63 | connecter_spawner(addr, ch); 64 | }); 65 | 66 | std::unordered_map results; 67 | for (unsigned i=0; i<1000; ++i) { 68 | int result = ch.recv(); 69 | results[result] += 1; 70 | } 71 | for (auto i=results.begin(); i!=results.end(); ++i) { 72 | if (i->first == 0) { 73 | std::cout << "Success: " << i->second << "\n"; 74 | } else { 75 | std::cout << strerror(i->first) << ": " << i->second << "\n"; 76 | } 77 | } 78 | std::cout << std::endl; 79 | listen_task.cancel(); 80 | connecter_thread.join(); 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /benchmarks/spawn_task.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | #include 3 | 4 | using namespace ten; 5 | 6 | int main() { 7 | return task::main([] { 8 | intmax_t count=0; 9 | try { 10 | for (;;) { 11 | task::spawn([] {}); 12 | ++count; 13 | } 14 | } catch (std::bad_alloc &) {} 15 | std::cout << count << "\n"; 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /benchmarks/timer_event_loop.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | #include "ten/descriptors.hh" 3 | #include 4 | 5 | using namespace ten; 6 | using namespace std::chrono; 7 | 8 | static void yield_task() { 9 | uint64_t counter = 0; 10 | task::spawn([&] { 11 | for (;;) { 12 | this_task::yield(); 13 | ++counter; 14 | } 15 | }); 16 | 17 | for (;;) { 18 | this_task::sleep_for(seconds{1}); 19 | std::cout << "counter: " << counter << "\n"; 20 | counter = 0; 21 | } 22 | } 23 | 24 | int main() { 25 | return task::main([] { 26 | task::spawn(yield_task); 27 | for (int i=0; i<1000; ++i) { 28 | task::spawn([] { 29 | this_task::sleep_for(milliseconds{random() % 1000}); 30 | }); 31 | } 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /cmake/ParseArguments.cmake: -------------------------------------------------------------------------------- 1 | # TODO: remove this when we get a new cmake 2 | # cmake 2.8.3 includes a better version, but we're on 2.8.0 :( 3 | 4 | MACRO(PARSE_ARGUMENTS prefix arg_names option_names) 5 | SET(DEFAULT_ARGS) 6 | FOREACH(arg_name ${arg_names}) 7 | SET(${prefix}_${arg_name}) 8 | ENDFOREACH(arg_name) 9 | FOREACH(option ${option_names}) 10 | SET(${prefix}_${option} FALSE) 11 | ENDFOREACH(option) 12 | 13 | SET(current_arg_name DEFAULT_ARGS) 14 | SET(current_arg_list) 15 | FOREACH(arg ${ARGN}) 16 | SET(larg_names ${arg_names}) 17 | LIST(FIND larg_names "${arg}" is_arg_name) 18 | IF (is_arg_name GREATER -1) 19 | SET(${prefix}_${current_arg_name} ${current_arg_list}) 20 | SET(current_arg_name ${arg}) 21 | SET(current_arg_list) 22 | ELSE (is_arg_name GREATER -1) 23 | SET(loption_names ${option_names}) 24 | LIST(FIND loption_names "${arg}" is_option) 25 | IF (is_option GREATER -1) 26 | SET(${prefix}_${arg} TRUE) 27 | ELSE (is_option GREATER -1) 28 | SET(current_arg_list ${current_arg_list} ${arg}) 29 | ENDIF (is_option GREATER -1) 30 | ENDIF (is_arg_name GREATER -1) 31 | ENDFOREACH(arg) 32 | SET(${prefix}_${current_arg_name} ${current_arg_list}) 33 | ENDMACRO(PARSE_ARGUMENTS) 34 | -------------------------------------------------------------------------------- /cmake/configure.cmake: -------------------------------------------------------------------------------- 1 | # functions require cmake 2.6 2 | # function to run ./configure; make; make install 3 | # and properly handled cmake dependencies 4 | # configure_flags are passed at the end 5 | function(configure_make_install cmi_target cmi_subdir cmi_generated) 6 | exec_program(${CMAKE_COMMAND} ARGS -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/${cmi_subdir} ${CMAKE_CURRENT_BINARY_DIR}/${cmi_subdir} OUTPUT_VARIABLE SILENT) 7 | add_custom_command(OUTPUT ${cmi_generated} 8 | COMMAND ./configure ${ARGN} 9 | COMMAND make 10 | COMMAND make install 11 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${cmi_subdir} 12 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${cmi_subdir} 13 | ) 14 | set_source_files_properties(${cmi_generated} PROPERTIES GENERATED TRUE) 15 | add_custom_target(${cmi_target} DEPENDS ${cmi_generated}) 16 | endfunction(configure_make_install) 17 | 18 | -------------------------------------------------------------------------------- /cmake/prog.cmake: -------------------------------------------------------------------------------- 1 | # For building programs inside libten; 2 | # these will only ever be tests, most likely 3 | 4 | if(NOT CMAKE_BUILD_TYPE) 5 | set(CMAKE_BUILD_TYPE "Debug") 6 | endif(NOT CMAKE_BUILD_TYPE) 7 | 8 | option(USE_GPROF 9 | "Profile the project using gprof" 10 | OFF) 11 | if(USE_GPROF) 12 | message("Adding profiling info for gprof...") 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") 14 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") 15 | endif(USE_GPROF) 16 | 17 | option(USE_PPROF 18 | "Profile the project using gprof" 19 | OFF) 20 | if(USE_PPROF) 21 | message("Linking with -lprofiler") 22 | set(EXTRA_LIBS profiler) 23 | endif(USE_PPROF) 24 | 25 | # general flags for any compilation with gcc/g++ 26 | set(GNU_FLAGS "-pthread") 27 | set(GNU_FLAGS "${GNU_FLAGS} -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter") 28 | set(GNU_FLAGS "${GNU_FLAGS} -Wpointer-arith -Wcast-align -Wuninitialized -Wwrite-strings") 29 | 30 | # profile guided optimization 31 | if (WITH_PGO STREQUAL "generate") 32 | set(GNU_FLAGS "${GNU_FLAGS} -fprofile-generate") 33 | endif (WITH_PGO STREQUAL "generate") 34 | 35 | if (WITH_PGO STREQUAL "use") 36 | set(GNU_FLAGS "${GNU_FLAGS} -fprofile-use") 37 | endif (WITH_PGO STREQUAL "use") 38 | 39 | set(GXX_FLAGS "-std=c++11 ${GNU_FLAGS}") 40 | set(GCC_FLAGS "-std=c11 ${GNU_FLAGS} -Wstrict-prototypes -Wmissing-prototypes") 41 | 42 | # release- and debug-specific flags for gcc 43 | set(DEBUG_FLAGS "-O0 -ggdb -D_DEBUG -rdynamic") 44 | set(RELEASE_FLAGS "-O2") 45 | 46 | # now that we know what the UB flags are, paste them into the cmake macros 47 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_FLAGS}") 48 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GXX_FLAGS}") 49 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") 50 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEBUG_FLAGS}") 51 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}") 52 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEBUG_FLAGS}") 53 | -------------------------------------------------------------------------------- /cmake/ragel.cmake: -------------------------------------------------------------------------------- 1 | find_program(RAGEL "ragel") 2 | 3 | function(ragel_gen in_rl) 4 | add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${in_rl}.cc 5 | COMMAND ${RAGEL} -G2 -o ${CMAKE_CURRENT_BINARY_DIR}/${in_rl}.cc ${CMAKE_CURRENT_SOURCE_DIR}/${in_rl}.rl -I ${CMAKE_CURRENT_SOURCE_DIR} ${ARGN} 6 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${in_rl}.rl 7 | ) 8 | add_custom_target(ragel_${in_rl} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${in_rl}.cc) 9 | endfunction(ragel_gen) 10 | 11 | if(RAGEL) 12 | message(STATUS "ragel found at: ${RAGEL}") 13 | else(RAGEL) 14 | message(FATAL_ERROR "ragel not found") 15 | endif(RAGEL) 16 | -------------------------------------------------------------------------------- /cmake/scm-version: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | use Getopt::Long; 5 | 6 | my $strict; 7 | 8 | my $result = GetOptions( 9 | "strict" => \$strict 10 | ); 11 | 12 | if ($_ = `git symbolic-ref -q HEAD 2>/dev/null`) { 13 | my ($branch) = m{^refs\/heads\/(\w\S+)$}xm; 14 | if ($strict) { 15 | my $tag = $branch; # tag and branch should have the same name 16 | my ($branch_rev, $branch_msg) = split(/\s+/, 17 | `git log -1 --no-walk --oneline refs/heads/$branch 2>/dev/null`, 2); 18 | my ($tag_rev, $tag_msg) = split(/\s+/, 19 | `git log -1 --no-walk --oneline refs/tags/$tag 2>/dev/null`, 2); 20 | die "No tag named $tag\n" 21 | unless ${^CHILD_ERROR_NATIVE} == 0; 22 | die "branch $branch ref $branch_rev does not match tag ref of same name $tag_rev\n" 23 | unless $tag_rev eq $branch_rev; 24 | my $clean_checkout = `git status --porcelain -uno`; 25 | die "checkout has been modified. see git status\n" 26 | unless $clean_checkout eq ''; 27 | } 28 | my ($hash, $date, $time, $tz) = 29 | split /\s+/, `git log -n1 --pretty=format:'%H %ci'`; 30 | my $rev = substr($hash, 0, 8); 31 | $rev .= ".$date"; 32 | $branch //= 'unknown'; 33 | print "$branch.$rev\n"; 34 | } else { 35 | die "No source control or not in a branch\n"; 36 | } 37 | -------------------------------------------------------------------------------- /cmake/ten.cmake: -------------------------------------------------------------------------------- 1 | set(TEN_CMAKE_INCLUDED 1) 2 | 3 | include(FindOpenSSL) 4 | include(CheckSymbolExists) 5 | include(CheckIncludeFiles) 6 | 7 | ## boost 8 | 9 | set(Boost_FIND_REQUIRED ON) 10 | set(Boost_USE_MULTITHREADED OFF) # Linux doesn't need this 11 | if (BOOST_ROOT) 12 | # Prevent falling back to system paths when using a custom Boost prefix. 13 | set(Boost_NO_SYSTEM_PATHS ON) 14 | endif () 15 | find_package(Boost 1.51.0 COMPONENTS 16 | context program_options) 17 | if (NOT Boost_FOUND) 18 | message(FATAL_ERROR, "Boost >= 1.51 not found") 19 | else() 20 | message(STATUS "boost includes: ${Boost_INCLUDE_DIRS}") 21 | message(STATUS "boost libs: ${Boost_LIBRARY_DIRS}") 22 | include_directories(${Boost_INCLUDE_DIRS}) 23 | link_directories(${Boost_LIBRARY_DIRS}) 24 | endif() 25 | 26 | #add_definitions(-DUSE_UCONTEXT) 27 | add_definitions(-DUSE_BOOST_FCONTEXT) 28 | 29 | ## jansson 30 | 31 | find_library(JANSSON_LIB jansson) 32 | find_file(JANSSON_INCLUDE jansson.h) 33 | if (JANSSON_LIB AND JANSSON_INCLUDE) 34 | message(STATUS "Using jansson: ${JANSSON_LIB} ${JANSSON_INCLUDE}") 35 | add_definitions(-DHAVE_JANSSON) 36 | else (JANSSON_LIB AND JANSSON_INCLUDE) 37 | message(FATAL_ERROR "jansson not found") 38 | endif (JANSSON_LIB AND JANSSON_INCLUDE) 39 | 40 | set(CMAKE_REQUIRED_LIBRARIES "jansson") 41 | CHECK_SYMBOL_EXISTS(json_string_length "jansson.h" HAVE_JANSSON_STRLEN) 42 | if (HAVE_JANSSON_STRLEN) 43 | add_definitions(-DHAVE_JANSSON_STRLEN) 44 | endif (HAVE_JANSSON_STRLEN) 45 | 46 | ## c-ares 47 | 48 | find_library(CARES_LIB cares) 49 | find_file(CARES_INCLUDE ares.h) 50 | if (CARES_LIB AND CARES_INCLUDE) 51 | message(STATUS "Using c-ares: ${CARES_LIB} ${CARES_INCLUDE}") 52 | add_definitions(-DHAVE_CARES) 53 | else (CARES_LIB AND CARES_INCLUDE) 54 | message(FATAL_ERROR "c-ares not found") 55 | endif (CARES_LIB AND CARES_INCLUDE) 56 | 57 | ## valgrind 58 | 59 | check_include_files("valgrind/valgrind.h" HAVE_VALGRIND_H) 60 | if (HAVE_VALGRIND_H) 61 | message(STATUS "Valgrind found") 62 | else() 63 | message(STATUS "Valgrind not found") 64 | add_definitions(-DNVALGRIND) 65 | endif () 66 | 67 | ## finally, libten 68 | 69 | add_definitions(-D_REENTRANT -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE) 70 | # needed for std::thread features 71 | add_definitions(-D_GLIBCXX_USE_NANOSLEEP -D_GLIBCXX_USE_SCHED_YIELD) 72 | 73 | if (NOT TEN_SOURCE_DIR) 74 | get_filename_component(TEN_SOURCE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH) 75 | get_filename_component(TEN_SOURCE_DIR ${TEN_SOURCE_DIR}/.. ABSOLUTE) 76 | endif () 77 | include_directories(${TEN_SOURCE_DIR}) # for stlencoders and stringencoders 78 | include_directories(${TEN_SOURCE_DIR}/include) 79 | include_directories(${TEN_SOURCE_DIR}/msgpack) 80 | include_directories(${TEN_SOURCE_DIR}/glog) 81 | -------------------------------------------------------------------------------- /cmake/version.cmake: -------------------------------------------------------------------------------- 1 | get_filename_component(CWD ${CMAKE_CURRENT_LIST_FILE} PATH) 2 | execute_process(COMMAND "${CWD}/scm-version" 3 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 4 | RESULT_VARIABLE SCM_STATUS 5 | OUTPUT_STRIP_TRAILING_WHITESPACE 6 | OUTPUT_VARIABLE SCM_VERSION) 7 | if (NOT "${SCM_STATUS}" STREQUAL 0) 8 | message(FATAL_ERROR "Failed to get version from scm-version") 9 | else() 10 | message("Current revision of ${PROJECT_SOURCE_DIR} is \"${SCM_VERSION}\"") 11 | endif() 12 | 13 | add_definitions(-DSCM_VERSION="${SCM_VERSION}") 14 | -------------------------------------------------------------------------------- /doc/build.rst: -------------------------------------------------------------------------------- 1 | .. _build: 2 | 3 | ######## 4 | Building 5 | ######## 6 | 7 | Dependencies 8 | ============ 9 | 10 | * cmake >= 2.8 11 | * g++ >= 4.7.0 12 | * libssl-dev >= 0.9.8 13 | * libboost-dev = 1.51 14 | * libboost-date-time-dev = 1.51 15 | * libboost-program-options-dev = 1.51 16 | * libboost-context-dev = 1.51 17 | * ragel >= 6.5 18 | * libjansson >= 2.3 19 | * libc-ares >= 1.9 20 | 21 | CMake 22 | ===== 23 | 24 | libten uses CMake__ build system. A typical build might look like this:: 25 | 26 | $ git clone git@github.com:toffaletti/libten.git 27 | $ mkdir libten-debug 28 | $ cd libten-debug 29 | $ cmake ../libten 30 | $ make 31 | 32 | .. __: http://www.cmake.org/ 33 | 34 | This is what CMake calls an out-of-tree build, which means the source directory is untouched and all build related configuration and by-products are created inside the build directory. This allows creating several build directories for different configurations (debug, release, maybe different compilers):: 35 | 36 | $ mkdir libten-release 37 | $ cd libten-release 38 | $ cmake -DCMAKE_BUILD_TYPE=Release ../libten 39 | $ make 40 | 41 | The recommended way for building libten based applications is using git submodule (or git subtree) to include libten in the applications git repository and link statically. An example CMakeLists.txt:: 42 | 43 | project(my-app) 44 | cmake_minimum_required(VERSION 2.8) 45 | 46 | add_subdirectory(libten) 47 | include(${CMAKE_CURRENT_SOURCE_DIR}/libten/cmake/ten.cmake) 48 | 49 | add_executable(my-app my-app.cc) 50 | target_link_libraries(my-app ten boost_program_options) 51 | 52 | Using git submodule or subtree links the application to a specific revision of libten. This allows great control and prevents changes to libten from breaking the application build. 53 | 54 | ``libten/cmake/defaults.cmake`` is where libten configures compiler flags 55 | 56 | ``libten/cmake/ten.cmake`` is used for including libten in a CMake-based application. 57 | 58 | 59 | Tests 60 | ===== 61 | 62 | libten has a unit test suite that can be run with ``make test``. 63 | 64 | Extras 65 | ====== 66 | 67 | libten includes examples and benchmarks that can be built with ``make examples`` and ``make benchmarks``. ``make world`` will build both. 68 | 69 | To build this documentation install python-sphinx and run ``make html`` from ``libten/doc/``. 70 | -------------------------------------------------------------------------------- /doc/http.rst: -------------------------------------------------------------------------------- 1 | .. _http: 2 | 3 | #### 4 | HTTP 5 | #### 6 | 7 | Overview 8 | ======== 9 | 10 | Client, server, and protocol related class for HTTP. 11 | 12 | Reference 13 | ========= 14 | 15 | ```` 16 | 17 | .. class:: http_headers 18 | 19 | A list of HTTP headers. 20 | 21 | .. class:: http_request 22 | 23 | Encapsulates an HTTP request. 24 | 25 | .. class:: http_response 26 | 27 | Encapsulates an HTTP response. 28 | 29 | 30 | ```` 31 | 32 | .. class:: http_client 33 | 34 | HTTP client connection. 35 | 36 | .. class:: http_pool 37 | 38 | Pool of HTTP client connections to a single host. 39 | 40 | ```` 41 | 42 | .. class:: http_exchange 43 | 44 | Encapsulation of HTTP request, response pair. A transaction in the HTTP sense. 45 | 46 | .. class:: http_server 47 | 48 | HTTP 1.1 server that spawns a new task for every connection. 49 | 50 | Examples 51 | ======== 52 | 53 | .. code-block:: c++ 54 | 55 | #include 56 | 57 | int main() { 58 | http_client c{"www.example.com", 80}; 59 | http_response resp = c.get("/"); 60 | } 61 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. libten documentation master file, created by 2 | sphinx-quickstart on Fri Mar 8 17:26:10 2013. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | libten Manual 7 | ============= 8 | 9 | A C++11 library for network services on modern x86-64 Linux. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | build 15 | kernel 16 | task 17 | net 18 | ioproc 19 | http 20 | internals 21 | -------------------------------------------------------------------------------- /doc/internals.rst: -------------------------------------------------------------------------------- 1 | .. _internals: 2 | 3 | ############## 4 | Task Internals 5 | ############## 6 | 7 | Overview 8 | ======== 9 | 10 | This section describes libten's implementation. 11 | 12 | Task Implementation 13 | =================== 14 | ``src/task_impl.hh`` declares the private implementation part of task. 15 | ``src/task.cc`` defines task internals. 16 | 17 | .. class:: task::pimpl 18 | 19 | Thread Context 20 | ============== 21 | 22 | ``src/thread_context.hh`` 23 | 24 | .. class:: thread_context 25 | 26 | Thread-local storage for task system internals. It contains the per-thread task scheduler and c-ares context used for dns lookups. 27 | 28 | .. member:: scheduler scheduler 29 | 30 | .. member:: shared_ptr dns_channel 31 | 32 | .. member:: thread_context this_ctx 33 | 34 | Used to reference the thread local context. Whenever it is used, it potentially causes the task system to be initialized in the thread. 35 | 36 | Context 37 | ======= 38 | ``src/context.hh`` is the context switching component used for swapping stacks. It is a thin wrapper around the boost::context api. 39 | 40 | .. class:: context 41 | 42 | Stack Allocation 43 | ================ 44 | ``src/stack_alloc.hh`` is used by ``context.hh`` to allocate the alternate stack for spawned tasks. Stacks have a guard page write-protected using ``mprotect``. Stacks are recycled using a thread local cache to reduce calls to ``posix_memalign`` and ``mprotect``. 45 | 46 | .. class:: stack_allocator 47 | 48 | Scheduler 49 | ========= 50 | ``src/scheduler.hh`` is where the magic happens. It keeps a list of spawned tasks and schedules them in FIFO order. The exception to this is when a task is spawned it goes to the front of the ready queue and will be run next. When no tasks are ready to run the scheduler either waits on a ``std::condition_variable`` or the io manager calls ``epoll_wait`` if tasks are waiting for io events. 51 | 52 | .. class:: scheduler 53 | 54 | Epoll IO 55 | ======== 56 | ``src/io.hh`` defines the epoll io manager. There is zero or one of these per thread. The scheduler creates it on-demand the first time a task waits for io. ``timerfd`` is used for timeouts and ``eventfd`` is used to break out of ``epoll_wait`` when a task is woken up from other threads. 57 | 58 | .. class:: io 59 | 60 | C-ARES 61 | ====== 62 | 63 | ``src/cares.cc`` contains the code for non-blocking dns lookups using the c-ares library. Of note is that c-ares only reads ``/etc/resolv.conf`` when ``ares_init`` is called. In order to see changes to ``resolv.conf``, libten uses the ``inotify`` api to watch ``resolv.conf`` for changes. 64 | 65 | -------------------------------------------------------------------------------- /doc/ioproc.rst: -------------------------------------------------------------------------------- 1 | .. _ioproc: 2 | 3 | ####### 4 | IO Proc 5 | ####### 6 | 7 | Overview 8 | ======== 9 | 10 | ioproc provides a non-blocking api to a thread pool for performing blocking operations without blocking tasks. 11 | 12 | Reference 13 | ========= 14 | 15 | .. type:: iochannel 16 | 17 | channel type used for communicating with ioproc thread-pool. 18 | 19 | .. class:: ioproc 20 | 21 | Reference to an ioproc thread-pool 22 | 23 | .. member:: iochannel ch 24 | 25 | Internal channel used to send operations to thread pool. 26 | 27 | .. function:: ioproc() 28 | 29 | Constructor 30 | 31 | .. function:: iocall(ioproc &io, Function f) 32 | 33 | Call function in thread-pool and wait for result. 34 | 35 | .. function:: iocallasync(ioproc &io, Function f) 36 | 37 | Call function in thread-pool without waiting for a result. 38 | 39 | .. function:: iowait(iochannel reply_chan) 40 | 41 | Wait for result of a previous :func:`iocallasync` call. 42 | 43 | Examples 44 | ======== 45 | 46 | .. code-block:: c++ 47 | 48 | #include 49 | 50 | int main() { 51 | using namespace ten; 52 | ioproc io; 53 | 54 | int ret = iocall(io, [] { 55 | // this will execute in a thread 56 | return usleep(100); 57 | }); 58 | 59 | // make several calls 60 | iochannel reply_chan; 61 | for (int i=0; i<4; ++i) { 62 | iocallasync(io, blocking_work, reply_chan); 63 | } 64 | 65 | // collect results 66 | std::vector results; 67 | for (int i=0; i<4; ++i) { 68 | results.push_back(iowait(reply_chan)); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /doc/kernel.rst: -------------------------------------------------------------------------------- 1 | .. _kernel: 2 | 3 | ###### 4 | Kernel 5 | ###### 6 | 7 | Overview 8 | ======== 9 | 10 | The kernel of the task system. Get information and setup the environment. 11 | 12 | .. _kernel_boot_note: 13 | .. note:: 14 | 15 | :func:`kernel::boot` must be called from the main thread before any other threads are created because it modifies signal handlers and sets an alternate signal stack. This can be done by explicitly calling it from `main()` or implicitely by spawning a task from `main()`. 16 | 17 | 18 | Reference 19 | ========= 20 | 21 | .. type:: kernel::clock 22 | 23 | The clock used for task related time. Currently std::chrono::steady_clock. 24 | 25 | .. type:: kernel::time_point 26 | 27 | A point in time. std::chrono::time_point. 28 | 29 | .. function:: time_point kernel::now() 30 | 31 | Return cached time from scheduler loop. Not precise, but fast. 32 | 33 | .. function:: bool kernel::is_main_thread() 34 | 35 | Returns true if this is the thread main() is called in. 36 | 37 | .. function:: size_t kernel::cpu_count() 38 | 39 | Returns the number of available cpus. 40 | 41 | .. function:: void kernel::boot() 42 | 43 | Bootstrap the task system. :ref:`See note. ` 44 | 45 | .. function:: void kernel::shutdown() 46 | 47 | Perform a clean shutdown of the task system. Cancel all tasks and wait for them to exit. 48 | -------------------------------------------------------------------------------- /doc/net.rst: -------------------------------------------------------------------------------- 1 | .. _net: 2 | 3 | ### 4 | Net 5 | ### 6 | 7 | Overview 8 | ======== 9 | 10 | ``net.hh`` contains task-aware networking apis. 11 | 12 | Reference 13 | ========= 14 | 15 | .. class:: netsock 16 | 17 | Task-aware non-blocking socket class. 18 | 19 | .. class:: netsock_server 20 | 21 | Task-aware socket server. Spawns a new task for each connection. 22 | 23 | Example 24 | ------- 25 | 26 | .. code-block:: c++ 27 | 28 | // TODO: netsock_server echo server example 29 | #include 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | add_executable(prime-sieve EXCLUDE_FROM_ALL prime-sieve.cc) 4 | target_link_libraries(prime-sieve ten) 5 | 6 | add_executable(echo-server EXCLUDE_FROM_ALL echo-server.cc) 7 | target_link_libraries(echo-server ten) 8 | 9 | add_executable(chat-server EXCLUDE_FROM_ALL chat-server.cc) 10 | target_link_libraries(chat-server ten) 11 | 12 | add_executable(stack-guard EXCLUDE_FROM_ALL stack-guard.cc) 13 | target_link_libraries(stack-guard ten) 14 | 15 | add_executable(stack-trace EXCLUDE_FROM_ALL stack-trace.cc) 16 | target_link_libraries(stack-trace ten) 17 | 18 | add_executable(http-get EXCLUDE_FROM_ALL http-get.cc) 19 | target_link_libraries(http-get ten) 20 | 21 | add_executable(http-proxy EXCLUDE_FROM_ALL http-proxy.cc) 22 | target_link_libraries(http-proxy ten) 23 | 24 | add_executable(http-server EXCLUDE_FROM_ALL http-server.cc) 25 | target_link_libraries(http-server ten boost_program_options) 26 | 27 | add_executable(msg-pack EXCLUDE_FROM_ALL msgpack.cc) 28 | target_link_libraries(msg-pack ten jansson msgpack) 29 | 30 | add_executable(rpc-server EXCLUDE_FROM_ALL rpc-server.cc) 31 | target_link_libraries(rpc-server ten msgpack) 32 | 33 | add_executable(json-path EXCLUDE_FROM_ALL json-path.cc) 34 | target_link_libraries(json-path ten jansson msgpack boost_program_options) 35 | 36 | add_executable(memg EXCLUDE_FROM_ALL memg.cc) 37 | target_link_libraries(memg ten boost_program_options) 38 | 39 | add_executable(synch EXCLUDE_FROM_ALL synch.cc) 40 | target_link_libraries(synch ten) 41 | 42 | if (OPENSSL_FOUND) 43 | add_executable(https-get EXCLUDE_FROM_ALL https-get.cc) 44 | target_link_libraries(https-get ten) 45 | set(HTTPS_GET https-get) 46 | endif (OPENSSL_FOUND) 47 | 48 | add_custom_target(examples DEPENDS 49 | prime-sieve 50 | echo-server 51 | chat-server 52 | stack-guard 53 | stack-trace 54 | http-get 55 | http-proxy 56 | http-server 57 | msg-pack 58 | rpc-server 59 | json-path 60 | memg 61 | synch 62 | ${HTTPS_GET} 63 | ) 64 | -------------------------------------------------------------------------------- /examples/chat-server.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | #include "ten/channel.hh" 3 | #include "ten/net.hh" 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace ten; 9 | 10 | struct client { 11 | netsock s; 12 | std::string nick; 13 | 14 | client(int sock) : s(sock), nick("unnamed") { } 15 | }; 16 | typedef std::shared_ptr shared_client; 17 | typedef std::list client_list; 18 | 19 | static client_list clients; 20 | static channel bchan{10}; 21 | 22 | void broadcast(const shared_client &from, const std::string &msg) { 23 | std::stringstream ss; 24 | ss << from->nick << ": " << msg; 25 | std::string chat = ss.str(); 26 | bchan.send(std::move(chat)); 27 | } 28 | 29 | void chat_task(int sock) { 30 | shared_client c{new client(sock)}; 31 | clients.push_back(c); 32 | char buf[4096]; 33 | size_t nw = c->s.send("enter nickname: ", 16); 34 | (void)nw; 35 | ssize_t nr = c->s.recv(buf, sizeof(buf)); 36 | if (nr > 0) { 37 | c->nick.assign(buf, nr); 38 | c->nick.resize(c->nick.find_first_of(" \t\r\n")); 39 | for (;;) { 40 | nr = c->s.recv(buf, sizeof(buf)); 41 | if (nr <= 0) break; 42 | broadcast(c, std::string(buf, nr)); 43 | } 44 | } 45 | clients.remove(c); 46 | } 47 | 48 | void broadcast_task() { 49 | for (;;) { 50 | std::string chat = bchan.recv(); 51 | for (client_list::iterator i=clients.begin(); i != clients.end(); ++i) { 52 | size_t nw = (*i)->s.send(chat.c_str(), chat.size()); 53 | (void)nw; 54 | } 55 | } 56 | } 57 | 58 | void listen_task() { 59 | netsock s{AF_INET, SOCK_STREAM}; 60 | s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1); 61 | address addr{"127.0.0.1", 0}; 62 | s.bind(addr); 63 | s.getsockname(addr); 64 | std::cout << "listening on: " << addr << "\n"; 65 | s.listen(); 66 | 67 | for (;;) { 68 | using namespace std::chrono; 69 | address client_addr; 70 | int sock; 71 | while ((sock = s.accept(client_addr, 0, duration_cast(minutes{1}))) > 0) { 72 | task::spawn([=] { 73 | chat_task(sock); 74 | }); 75 | } 76 | std::cout << "accept timeout reached\n"; 77 | } 78 | } 79 | 80 | int main() { 81 | return task::main([] { 82 | task::spawn(broadcast_task); 83 | task::spawn(listen_task); 84 | }); 85 | } 86 | 87 | -------------------------------------------------------------------------------- /examples/echo-server.cc: -------------------------------------------------------------------------------- 1 | #include "ten/net.hh" 2 | #include "ten/buffer.hh" 3 | #include 4 | 5 | using namespace ten; 6 | 7 | class echo_server : public netsock_server { 8 | public: 9 | echo_server() : netsock_server{"echo"} {} 10 | private: 11 | void on_connection(netsock &s) override { 12 | buffer buf{4*1024}; 13 | for (;;) { 14 | buf.reserve(4*1024); 15 | ssize_t nr = s.recv(buf.back(), buf.available()); 16 | if (nr <= 0) break; 17 | buf.commit(nr); 18 | ssize_t nw = s.send(buf.front(), buf.size()); 19 | if (nw != nr) break; 20 | buf.remove(nw); 21 | } 22 | } 23 | }; 24 | 25 | int main() { 26 | return task::main([] { 27 | address addr{"127.0.0.1", 0}; 28 | std::shared_ptr server = std::make_shared(); 29 | server->serve(addr); 30 | }); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /examples/http-get.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | #include "ten/buffer.hh" 3 | #include "ten/net.hh" 4 | #include "ten/http/http_message.hh" 5 | #include "ten/uri.hh" 6 | 7 | #include 8 | 9 | using namespace ten; 10 | 11 | static void do_get(uri u) { 12 | netsock s{AF_INET, SOCK_STREAM}; 13 | u.normalize(); 14 | if (u.scheme != "http") return; 15 | if (u.port == 0) u.port = 80; 16 | s.dial(u.host.c_str(), u.port); 17 | 18 | http_request r{"GET", u.compose_path()}; 19 | // HTTP/1.1 requires host header 20 | r.append("Host", u.host); 21 | 22 | std::string data = r.data(); 23 | std::cout << "Request:\n" << "--------------\n"; 24 | std::cout << data; 25 | ssize_t nw = s.send(data.c_str(), data.size()); 26 | (void)nw; 27 | 28 | buffer buf{4*1024}; 29 | 30 | http_parser parser; 31 | http_response resp; 32 | resp.parser_init(&parser); 33 | 34 | while (!resp.complete) { 35 | ssize_t nr = s.recv(buf.back(), buf.available()); 36 | if (nr <= 0) { std::cerr << "Error: " << strerror(errno) << "\n"; break; } 37 | buf.commit(nr); 38 | size_t len = buf.size(); 39 | resp.parse(&parser, buf.front(), len); 40 | buf.remove(len); 41 | } 42 | 43 | std::cout << "Response:\n" << "--------------\n"; 44 | std::cout << resp.data(); 45 | std::cout << "Body size: " << resp.body.size() << "\n"; 46 | } 47 | 48 | int main(int argc, char *argv[]) { 49 | if (argc < 2) return -1; 50 | return task::main([&] { 51 | uri u{argv[1]}; 52 | task::spawn([=] { 53 | do_get(u); 54 | }); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /examples/https-get.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | #include "ten/buffer.hh" 3 | #include "ten/net/ssl.hh" 4 | #include "ten/http/http_message.hh" 5 | #include "ten/uri.hh" 6 | 7 | #include 8 | 9 | using namespace ten; 10 | 11 | static void do_get(uri u) { 12 | sslsock s{AF_INET, SOCK_STREAM}; 13 | s.initssl(SSLv23_client_method(), true); 14 | u.normalize(); 15 | if (u.scheme != "https") return; 16 | if (u.port == 0) u.port = 443; 17 | s.dial(u.host.c_str(), u.port); 18 | 19 | http_request r{"GET", u.compose(true)}; 20 | // HTTP/1.1 requires host header 21 | r.append("Host", u.host); 22 | 23 | std::string data = r.data(); 24 | std::cout << "Request:\n" << "--------------\n"; 25 | std::cout << data; 26 | ssize_t nw = s.send(data.c_str(), data.size()); 27 | (void)nw; 28 | 29 | buffer buf{4*1024}; 30 | 31 | http_parser parser; 32 | http_response resp; 33 | resp.parser_init(&parser); 34 | 35 | while (!resp.complete) { 36 | ssize_t nr = s.recv(buf.back(), buf.available()); 37 | if (nr <= 0) { std::cerr << "Error: " << strerror(errno) << "\n"; break; } 38 | buf.commit(nr); 39 | size_t len = buf.size(); 40 | resp.parse(&parser, buf.front(), len); 41 | buf.remove(len); 42 | } 43 | 44 | std::cout << "Response:\n" << "--------------\n"; 45 | std::cout << resp.data(); 46 | std::cout << "Body size: " << resp.body.size() << "\n"; 47 | } 48 | 49 | int main(int argc, char *argv[]) { 50 | if (argc < 2) return -1; 51 | return task::main([&] { 52 | SSL_load_error_strings(); 53 | SSL_library_init(); 54 | 55 | uri u{argv[1]}; 56 | task::spawn([=] { 57 | do_get(u); 58 | }); 59 | }); 60 | } 61 | -------------------------------------------------------------------------------- /examples/msgpack.cc: -------------------------------------------------------------------------------- 1 | #include "msgpack/msgpack.hpp" 2 | #include 3 | #include 4 | #include 5 | #include "ten/jsonpack.hh" 6 | 7 | using namespace msgpack; 8 | using namespace ten; 9 | using namespace std; 10 | 11 | struct myclass { 12 | int num; 13 | string str; 14 | 15 | myclass() : num(616), str("the string") {} 16 | 17 | MSGPACK_DEFINE(num, str); 18 | 19 | friend ostream &operator << (ostream &o, const myclass &m) { 20 | o << "num: " << m.num << " str: " << m.str; 21 | return o; 22 | } 23 | }; 24 | 25 | int main(int argc, char *argv[]) { 26 | sbuffer sbuf; 27 | myclass m; 28 | size_t offset = 0; 29 | 30 | pack(sbuf, m); 31 | pack(sbuf, -1234); 32 | pack(sbuf, -1.5); 33 | pack(sbuf, 3.58); 34 | pack(sbuf, std::string("cool pack")); 35 | 36 | zone z; 37 | object obj; 38 | 39 | unpack_return r = 40 | unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj); 41 | assert(r == UNPACK_EXTRA_BYTES); 42 | cout << "obj: " << obj << "\n"; 43 | cout << obj.as() << "\n"; 44 | 45 | r = unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj); 46 | assert(r == UNPACK_EXTRA_BYTES); 47 | cout << "obj: " << obj << "\n"; 48 | cout << obj.as() << "\n"; 49 | 50 | r = unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj); 51 | assert(r == UNPACK_EXTRA_BYTES); 52 | cout << "obj: " << obj << "\n"; 53 | cout << obj.as() << "\n"; 54 | 55 | r = unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj); 56 | assert(r == UNPACK_EXTRA_BYTES); 57 | cout << "obj: " << obj << "\n"; 58 | cout << obj.as() << "\n"; 59 | 60 | r = unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj); 61 | assert(r == UNPACK_SUCCESS); 62 | cout << "obj: " << obj << "\n"; 63 | cout << obj.as() << "\n"; 64 | 65 | json j{ 66 | {"int", 1234}, 67 | {"double", 1.14}, 68 | {"string", "abcdef"}, 69 | {"array", json::array({"string", 42, true, 9.0})}, 70 | }; 71 | 72 | pack(sbuf, j); 73 | 74 | r = unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj); 75 | assert(r == UNPACK_SUCCESS); 76 | cout << "json: " << obj << "\n"; 77 | cout << obj.as() << "\n"; 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /examples/prime-sieve.cc: -------------------------------------------------------------------------------- 1 | #include "ten/channel.hh" 2 | #include 3 | 4 | using namespace ten; 5 | 6 | // adapted from http://golang.org/doc/go_tutorial.html#tmp_360 7 | 8 | void generate(channel out) { 9 | for (int i=2; ; ++i) { 10 | out.send(std::move(i)); 11 | } 12 | } 13 | 14 | void filter(channel in, channel out, int prime) { 15 | for (;;) { 16 | int i = in.recv(); 17 | if (i % prime != 0) { 18 | out.send(std::move(i)); 19 | } 20 | } 21 | } 22 | 23 | int main() { 24 | return task::main([] { 25 | channel ch; 26 | task::spawn([=] { 27 | generate(ch); 28 | }); 29 | for (int i=0; i<100; ++i) { 30 | int prime = ch.recv(); 31 | std::cout << prime << "\n"; 32 | channel out; 33 | task::spawn([=] { 34 | filter(ch, out, prime); 35 | }); 36 | ch = out; 37 | } 38 | kernel::shutdown(); 39 | }); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /examples/rpc-server.cc: -------------------------------------------------------------------------------- 1 | #include "ten/rpc/server.hh" 2 | #include "ten/rpc/client.hh" 3 | 4 | using namespace ten; 5 | using namespace msgpack::rpc; 6 | 7 | static void client_task() { 8 | rpc_client c{"localhost", 5500}; 9 | c.notify("notify_me"); 10 | c.notify("notify_world", std::string("hi")); 11 | LOG(INFO) << "40+2=" << c.call("add2", 40, 2); 12 | LOG(INFO) << "4-2=" << c.call("subtract2", 4, 2); 13 | try { 14 | LOG(INFO) << "fail: " << c.call("fail"); 15 | } catch (errorx &e) { 16 | LOG(ERROR) << "fail got: " << e.what(); 17 | } 18 | kernel::shutdown(); 19 | } 20 | 21 | static int fail() { 22 | throw std::runtime_error{"fail"}; 23 | } 24 | 25 | static int add2(int a, int b) { 26 | LOG(INFO) << "called add2(" << a << "," << b << ")"; 27 | return a + b; 28 | } 29 | 30 | static int subtract2(int a, int b) { 31 | return a - b; 32 | } 33 | 34 | static void notify_me() { 35 | LOG(INFO) << "NOTIFY ME"; 36 | } 37 | 38 | static void notify_world(std::string s) { 39 | LOG(INFO) << "NOTIFY WORLD " << s; 40 | } 41 | 42 | int main() { 43 | return task::main([] { 44 | auto rpc = std::make_shared(); 45 | rpc->add_command("add2", add2); 46 | rpc->add_command("add2", add2); 47 | rpc->add_command("subtract2", subtract2); 48 | rpc->add_command("fail", fail); 49 | rpc->add_notify("notify_me", notify_me); 50 | rpc->add_notify("notify_world", notify_world); 51 | task::spawn(client_task); 52 | rpc->serve("0.0.0.0", 5500); 53 | }); 54 | } 55 | 56 | -------------------------------------------------------------------------------- /examples/stack-guard.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | 3 | using namespace ten; 4 | 5 | static void stack_overflow() { 6 | char buf[256*1024]; 7 | // this will attempt to write to the guard page 8 | // and cause a segmentation fault 9 | char crash = 1; 10 | 11 | // -O3 reorders buf and crash, so it will crash here 12 | buf[0] = 1; 13 | printf("%i %i\n", buf[0], crash); 14 | } 15 | 16 | int main() { 17 | return task::main([] { 18 | task::spawn(stack_overflow); 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /examples/stack-trace.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | #include "ten/error.hh" 3 | 4 | using namespace ten; 5 | 6 | void go_crazy() { 7 | throw errorx("weee!"); 8 | } 9 | 10 | static void unnamed() { 11 | go_crazy(); 12 | } 13 | 14 | int main() { 15 | return task::main([] { 16 | task::spawn(unnamed); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /examples/synch.cc: -------------------------------------------------------------------------------- 1 | #include "ten/synchronized.hh" 2 | #include 3 | 4 | using namespace ten; 5 | 6 | class A { 7 | private: 8 | int i; 9 | int i_squared; 10 | public: 11 | A(int _i=0) { 12 | set(_i); 13 | } 14 | 15 | void set(int _i) { 16 | i = _i; 17 | i_squared = i*i; 18 | } 19 | 20 | int get_squared() { 21 | return i_squared; 22 | } 23 | }; 24 | 25 | int main() { 26 | synchronized a(1); 27 | A b; 28 | a([&](A &a_) { 29 | a_.set(2); 30 | b = a_; 31 | }); 32 | 33 | a([](A &a_) { 34 | a_.set(3); 35 | std::cout << "a: " << a_.get_squared() << "\n"; 36 | }); 37 | 38 | std::cout << "b: " << b.get_squared() << "\n"; 39 | } 40 | -------------------------------------------------------------------------------- /googletest/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toffaletti/libten/00c6dcc91c8d769c74ed9063277b1120c9084427/googletest/CMakeLists.txt -------------------------------------------------------------------------------- /googletest/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This file contains a list of people who've made non-trivial 2 | # contribution to the Google C++ Testing Framework project. People 3 | # who commit code to the project are encouraged to add their names 4 | # here. Please keep the list sorted by first names. 5 | 6 | Ajay Joshi 7 | Balázs Dán 8 | Bharat Mediratta 9 | Chandler Carruth 10 | Chris Prince 11 | Chris Taylor 12 | Dan Egnor 13 | Eric Roman 14 | Hady Zalek 15 | Jeffrey Yasskin 16 | Jói Sigurðsson 17 | Keir Mierle 18 | Keith Ray 19 | Kenton Varda 20 | Manuel Klimek 21 | Markus Heule 22 | Mika Raento 23 | Miklós Fazekas 24 | Pasi Valminen 25 | Patrick Hanna 26 | Patrick Riley 27 | Peter Kaminski 28 | Preston Jackson 29 | Rainer Klaffenboeck 30 | Russ Cox 31 | Russ Rufer 32 | Sean Mcafee 33 | Sigurður Ásgeirsson 34 | Tracy Bialik 35 | Vadim Berman 36 | Vlad Losev 37 | Zhanyong Wan 38 | -------------------------------------------------------------------------------- /googletest/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2008, Google Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /googletest/build-aux/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toffaletti/libten/00c6dcc91c8d769c74ed9063277b1120c9084427/googletest/build-aux/.keep -------------------------------------------------------------------------------- /googletest/codegear/gtest.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {c1d923e0-6cba-4332-9b6f-3420acbf5091} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Default.Personality 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /googletest/codegear/gtest_all.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2009, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: Josh Kelley (joshkel@gmail.com) 31 | // 32 | // Google C++ Testing Framework (Google Test) 33 | // 34 | // C++Builder's IDE cannot build a static library from files with hyphens 35 | // in their name. See http://qc.codegear.com/wc/qcmain.aspx?d=70977 . 36 | // This file serves as a workaround. 37 | 38 | #include "src/gtest-all.cc" 39 | -------------------------------------------------------------------------------- /googletest/codegear/gtest_link.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2009, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: Josh Kelley (joshkel@gmail.com) 31 | // 32 | // Google C++ Testing Framework (Google Test) 33 | // 34 | // Links gtest.lib and gtest_main.lib into the current project in C++Builder. 35 | // This means that these libraries can't be renamed, but it's the only way to 36 | // ensure that Debug versus Release test builds are linked against the 37 | // appropriate Debug or Release build of the libraries. 38 | 39 | #pragma link "gtest.lib" 40 | #pragma link "gtest_main.lib" 41 | -------------------------------------------------------------------------------- /googletest/configure.ac: -------------------------------------------------------------------------------- 1 | m4_include(m4/acx_pthread.m4) 2 | 3 | # At this point, the Xcode project assumes the version string will be three 4 | # integers separated by periods and surrounded by square brackets (e.g. 5 | # "[1.0.1]"). It also asumes that there won't be any closing parenthesis 6 | # between "AC_INIT(" and the closing ")" including comments and strings. 7 | AC_INIT([Google C++ Testing Framework], 8 | [1.7.0], 9 | [googletestframework@googlegroups.com], 10 | [gtest]) 11 | 12 | # Provide various options to initialize the Autoconf and configure processes. 13 | AC_PREREQ([2.59]) 14 | AC_CONFIG_SRCDIR([./LICENSE]) 15 | AC_CONFIG_MACRO_DIR([m4]) 16 | AC_CONFIG_AUX_DIR([build-aux]) 17 | AC_CONFIG_HEADERS([build-aux/config.h]) 18 | AC_CONFIG_FILES([Makefile]) 19 | AC_CONFIG_FILES([scripts/gtest-config], [chmod +x scripts/gtest-config]) 20 | 21 | # Initialize Automake with various options. We require at least v1.9, prevent 22 | # pedantic complaints about package files, and enable various distribution 23 | # targets. 24 | AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects]) 25 | 26 | # Check for programs used in building Google Test. 27 | AC_PROG_CC 28 | AC_PROG_CXX 29 | AC_LANG([C++]) 30 | AC_PROG_LIBTOOL 31 | 32 | # TODO(chandlerc@google.com): Currently we aren't running the Python tests 33 | # against the interpreter detected by AM_PATH_PYTHON, and so we condition 34 | # HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's 35 | # version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env" 36 | # hashbang. 37 | PYTHON= # We *do not* allow the user to specify a python interpreter 38 | AC_PATH_PROG([PYTHON],[python],[:]) 39 | AS_IF([test "$PYTHON" != ":"], 40 | [AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])]) 41 | AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"]) 42 | 43 | # Configure pthreads. 44 | AC_ARG_WITH([pthreads], 45 | [AS_HELP_STRING([--with-pthreads], 46 | [use pthreads (default is yes)])], 47 | [with_pthreads=$withval], 48 | [with_pthreads=check]) 49 | 50 | have_pthreads=no 51 | AS_IF([test "x$with_pthreads" != "xno"], 52 | [ACX_PTHREAD( 53 | [], 54 | [AS_IF([test "x$with_pthreads" != "xcheck"], 55 | [AC_MSG_FAILURE( 56 | [--with-pthreads was specified, but unable to be used])])]) 57 | have_pthreads="$acx_pthread_ok"]) 58 | AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" = "xyes"]) 59 | AC_SUBST(PTHREAD_CFLAGS) 60 | AC_SUBST(PTHREAD_LIBS) 61 | 62 | # TODO(chandlerc@google.com) Check for the necessary system headers. 63 | 64 | # TODO(chandlerc@google.com) Check the types, structures, and other compiler 65 | # and architecture characteristics. 66 | 67 | # Output the generated files. No further autoconf macros may be used. 68 | AC_OUTPUT 69 | -------------------------------------------------------------------------------- /googletest/include/gtest/gtest_prod.h: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | // 32 | // Google C++ Testing Framework definitions useful in production code. 33 | 34 | #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ 35 | #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ 36 | 37 | // When you need to test the private or protected members of a class, 38 | // use the FRIEND_TEST macro to declare your tests as friends of the 39 | // class. For example: 40 | // 41 | // class MyClass { 42 | // private: 43 | // void MyMethod(); 44 | // FRIEND_TEST(MyClassTest, MyMethod); 45 | // }; 46 | // 47 | // class MyClassTest : public testing::Test { 48 | // // ... 49 | // }; 50 | // 51 | // TEST_F(MyClassTest, MyMethod) { 52 | // // Can call MyClass::MyMethod() here. 53 | // } 54 | 55 | #define FRIEND_TEST(test_case_name, test_name)\ 56 | friend class test_case_name##_##test_name##_Test 57 | 58 | #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ 59 | -------------------------------------------------------------------------------- /googletest/msvc/gtest-md.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 8.00 2 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-md", "gtest-md.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}" 3 | ProjectSection(ProjectDependencies) = postProject 4 | EndProjectSection 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main-md", "gtest_main-md.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862033}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | EndProjectSection 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test-md", "gtest_prod_test-md.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}" 11 | ProjectSection(ProjectDependencies) = postProject 12 | EndProjectSection 13 | EndProject 14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest-md", "gtest_unittest-md.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A2}" 15 | ProjectSection(ProjectDependencies) = postProject 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfiguration) = preSolution 20 | Debug = Debug 21 | Release = Release 22 | EndGlobalSection 23 | GlobalSection(ProjectConfiguration) = postSolution 24 | {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.ActiveCfg = Debug|Win32 25 | {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.Build.0 = Debug|Win32 26 | {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.ActiveCfg = Release|Win32 27 | {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.Build.0 = Release|Win32 28 | {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.ActiveCfg = Debug|Win32 29 | {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.Build.0 = Debug|Win32 30 | {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.ActiveCfg = Release|Win32 31 | {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.Build.0 = Release|Win32 32 | {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.ActiveCfg = Debug|Win32 33 | {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.Build.0 = Debug|Win32 34 | {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.ActiveCfg = Release|Win32 35 | {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.Build.0 = Release|Win32 36 | {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.ActiveCfg = Debug|Win32 37 | {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.Build.0 = Debug|Win32 38 | {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.ActiveCfg = Release|Win32 39 | {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.Build.0 = Release|Win32 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | EndGlobalSection 43 | GlobalSection(ExtensibilityAddIns) = postSolution 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /googletest/msvc/gtest.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 8.00 2 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "gtest.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}" 3 | ProjectSection(ProjectDependencies) = postProject 4 | EndProjectSection 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "gtest_main.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | EndProjectSection 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest", "gtest_unittest.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A1}" 11 | ProjectSection(ProjectDependencies) = postProject 12 | EndProjectSection 13 | EndProject 14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test", "gtest_prod_test.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}" 15 | ProjectSection(ProjectDependencies) = postProject 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfiguration) = preSolution 20 | Debug = Debug 21 | Release = Release 22 | EndGlobalSection 23 | GlobalSection(ProjectConfiguration) = postSolution 24 | {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.ActiveCfg = Debug|Win32 25 | {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.Build.0 = Debug|Win32 26 | {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.ActiveCfg = Release|Win32 27 | {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.Build.0 = Release|Win32 28 | {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.ActiveCfg = Debug|Win32 29 | {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.Build.0 = Debug|Win32 30 | {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.ActiveCfg = Release|Win32 31 | {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.Build.0 = Release|Win32 32 | {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.ActiveCfg = Debug|Win32 33 | {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.Build.0 = Debug|Win32 34 | {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.ActiveCfg = Release|Win32 35 | {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.Build.0 = Release|Win32 36 | {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.ActiveCfg = Debug|Win32 37 | {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.Build.0 = Debug|Win32 38 | {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.ActiveCfg = Release|Win32 39 | {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.Build.0 = Release|Win32 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | EndGlobalSection 43 | GlobalSection(ExtensibilityAddIns) = postSolution 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /googletest/samples/sample1.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // A sample program demonstrating using Google C++ testing framework. 31 | // 32 | // Author: wan@google.com (Zhanyong Wan) 33 | 34 | #include "sample1.h" 35 | 36 | // Returns n! (the factorial of n). For negative n, n! is defined to be 1. 37 | int Factorial(int n) { 38 | int result = 1; 39 | for (int i = 1; i <= n; i++) { 40 | result *= i; 41 | } 42 | 43 | return result; 44 | } 45 | 46 | // Returns true iff n is a prime number. 47 | bool IsPrime(int n) { 48 | // Trivial case 1: small numbers 49 | if (n <= 1) return false; 50 | 51 | // Trivial case 2: even numbers 52 | if (n % 2 == 0) return n == 2; 53 | 54 | // Now, we have that n is odd and n >= 3. 55 | 56 | // Try to divide n by every odd number i, starting from 3 57 | for (int i = 3; ; i += 2) { 58 | // We only have to try i up to the squre root of n 59 | if (i > n/i) break; 60 | 61 | // Now, we have i <= n/i < n. 62 | // If n is divisible by i, n is not prime. 63 | if (n % i == 0) return false; 64 | } 65 | 66 | // n has no integer factor in the range (1, n), and thus is prime. 67 | return true; 68 | } 69 | -------------------------------------------------------------------------------- /googletest/samples/sample1.h: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // A sample program demonstrating using Google C++ testing framework. 31 | // 32 | // Author: wan@google.com (Zhanyong Wan) 33 | 34 | #ifndef GTEST_SAMPLES_SAMPLE1_H_ 35 | #define GTEST_SAMPLES_SAMPLE1_H_ 36 | 37 | // Returns n! (the factorial of n). For negative n, n! is defined to be 1. 38 | int Factorial(int n); 39 | 40 | // Returns true iff n is a prime number. 41 | bool IsPrime(int n); 42 | 43 | #endif // GTEST_SAMPLES_SAMPLE1_H_ 44 | -------------------------------------------------------------------------------- /googletest/samples/sample2.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // A sample program demonstrating using Google C++ testing framework. 31 | // 32 | // Author: wan@google.com (Zhanyong Wan) 33 | 34 | #include "sample2.h" 35 | 36 | #include 37 | 38 | // Clones a 0-terminated C string, allocating memory using new. 39 | const char* MyString::CloneCString(const char* a_c_string) { 40 | if (a_c_string == NULL) return NULL; 41 | 42 | const size_t len = strlen(a_c_string); 43 | char* const clone = new char[ len + 1 ]; 44 | memcpy(clone, a_c_string, len + 1); 45 | 46 | return clone; 47 | } 48 | 49 | // Sets the 0-terminated C string this MyString object 50 | // represents. 51 | void MyString::Set(const char* a_c_string) { 52 | // Makes sure this works when c_string == c_string_ 53 | const char* const temp = MyString::CloneCString(a_c_string); 54 | delete[] c_string_; 55 | c_string_ = temp; 56 | } 57 | -------------------------------------------------------------------------------- /googletest/samples/sample4.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // A sample program demonstrating using Google C++ testing framework. 31 | // 32 | // Author: wan@google.com (Zhanyong Wan) 33 | 34 | #include 35 | 36 | #include "sample4.h" 37 | 38 | // Returns the current counter value, and increments it. 39 | int Counter::Increment() { 40 | return counter_++; 41 | } 42 | 43 | // Prints the current counter value to STDOUT. 44 | void Counter::Print() const { 45 | printf("%d", counter_); 46 | } 47 | -------------------------------------------------------------------------------- /googletest/samples/sample4.h: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // A sample program demonstrating using Google C++ testing framework. 31 | // 32 | // Author: wan@google.com (Zhanyong Wan) 33 | 34 | #ifndef GTEST_SAMPLES_SAMPLE4_H_ 35 | #define GTEST_SAMPLES_SAMPLE4_H_ 36 | 37 | // A simple monotonic counter. 38 | class Counter { 39 | private: 40 | int counter_; 41 | 42 | public: 43 | // Creates a counter that starts at 0. 44 | Counter() : counter_(0) {} 45 | 46 | // Returns the current counter value, and increments it. 47 | int Increment(); 48 | 49 | // Prints the current counter value to STDOUT. 50 | void Print() const; 51 | }; 52 | 53 | #endif // GTEST_SAMPLES_SAMPLE4_H_ 54 | -------------------------------------------------------------------------------- /googletest/samples/sample4_unittest.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | 32 | #include "gtest/gtest.h" 33 | #include "sample4.h" 34 | 35 | // Tests the Increment() method. 36 | TEST(Counter, Increment) { 37 | Counter c; 38 | 39 | // EXPECT_EQ() evaluates its arguments exactly once, so they 40 | // can have side effects. 41 | 42 | EXPECT_EQ(0, c.Increment()); 43 | EXPECT_EQ(1, c.Increment()); 44 | EXPECT_EQ(2, c.Increment()); 45 | } 46 | -------------------------------------------------------------------------------- /googletest/scripts/test/Makefile: -------------------------------------------------------------------------------- 1 | # A Makefile for fusing Google Test and building a sample test against it. 2 | # 3 | # SYNOPSIS: 4 | # 5 | # make [all] - makes everything. 6 | # make TARGET - makes the given target. 7 | # make check - makes everything and runs the built sample test. 8 | # make clean - removes all files generated by make. 9 | 10 | # Points to the root of fused Google Test, relative to where this file is. 11 | FUSED_GTEST_DIR = output 12 | 13 | # Paths to the fused gtest files. 14 | FUSED_GTEST_H = $(FUSED_GTEST_DIR)/gtest/gtest.h 15 | FUSED_GTEST_ALL_CC = $(FUSED_GTEST_DIR)/gtest/gtest-all.cc 16 | 17 | # Where to find the sample test. 18 | SAMPLE_DIR = ../../samples 19 | 20 | # Where to find gtest_main.cc. 21 | GTEST_MAIN_CC = ../../src/gtest_main.cc 22 | 23 | # Flags passed to the preprocessor. 24 | # We have no idea here whether pthreads is available in the system, so 25 | # disable its use. 26 | CPPFLAGS += -I$(FUSED_GTEST_DIR) -DGTEST_HAS_PTHREAD=0 27 | 28 | # Flags passed to the C++ compiler. 29 | CXXFLAGS += -g 30 | 31 | all : sample1_unittest 32 | 33 | check : all 34 | ./sample1_unittest 35 | 36 | clean : 37 | rm -rf $(FUSED_GTEST_DIR) sample1_unittest *.o 38 | 39 | $(FUSED_GTEST_H) : 40 | ../fuse_gtest_files.py $(FUSED_GTEST_DIR) 41 | 42 | $(FUSED_GTEST_ALL_CC) : 43 | ../fuse_gtest_files.py $(FUSED_GTEST_DIR) 44 | 45 | gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GTEST_ALL_CC) 46 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GTEST_DIR)/gtest/gtest-all.cc 47 | 48 | gtest_main.o : $(FUSED_GTEST_H) $(GTEST_MAIN_CC) 49 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_MAIN_CC) 50 | 51 | sample1.o : $(SAMPLE_DIR)/sample1.cc $(SAMPLE_DIR)/sample1.h 52 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1.cc 53 | 54 | sample1_unittest.o : $(SAMPLE_DIR)/sample1_unittest.cc \ 55 | $(SAMPLE_DIR)/sample1.h $(FUSED_GTEST_H) 56 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1_unittest.cc 57 | 58 | sample1_unittest : sample1.o sample1_unittest.o gtest-all.o gtest_main.o 59 | $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ 60 | -------------------------------------------------------------------------------- /googletest/src/gtest-all.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: mheule@google.com (Markus Heule) 31 | // 32 | // Google C++ Testing Framework (Google Test) 33 | // 34 | // Sometimes it's desirable to build Google Test by compiling a single file. 35 | // This file serves this purpose. 36 | 37 | // This line ensures that gtest.h can be compiled on its own, even 38 | // when it's fused. 39 | #include "gtest/gtest.h" 40 | 41 | // The following lines pull in the real gtest *.cc files. 42 | #include "gtest.cc" 43 | #include "gtest-death-test.cc" 44 | #include "gtest-filepath.cc" 45 | #include "gtest-port.cc" 46 | #include "gtest-printers.cc" 47 | #include "gtest-test-part.cc" 48 | #include "gtest-typed-test.cc" 49 | -------------------------------------------------------------------------------- /googletest/src/gtest_main.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | #include 31 | 32 | #include "gtest/gtest.h" 33 | 34 | GTEST_API_ int main(int argc, char **argv) { 35 | printf("Running main() from gtest_main.cc\n"); 36 | testing::InitGoogleTest(&argc, argv); 37 | return RUN_ALL_TESTS(); 38 | } 39 | -------------------------------------------------------------------------------- /googletest/test/gtest-param-test_test.h: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Authors: vladl@google.com (Vlad Losev) 31 | // 32 | // The Google C++ Testing Framework (Google Test) 33 | // 34 | // This header file provides classes and functions used internally 35 | // for testing Google Test itself. 36 | 37 | #ifndef GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ 38 | #define GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ 39 | 40 | #include "gtest/gtest.h" 41 | 42 | #if GTEST_HAS_PARAM_TEST 43 | 44 | // Test fixture for testing definition and instantiation of a test 45 | // in separate translation units. 46 | class ExternalInstantiationTest : public ::testing::TestWithParam { 47 | }; 48 | 49 | // Test fixture for testing instantiation of a test in multiple 50 | // translation units. 51 | class InstantiationInMultipleTranslaionUnitsTest 52 | : public ::testing::TestWithParam { 53 | }; 54 | 55 | #endif // GTEST_HAS_PARAM_TEST 56 | 57 | #endif // GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ 58 | -------------------------------------------------------------------------------- /googletest/test/gtest-typed-test2_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008 Google Inc. 2 | // All Rights Reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | 32 | #include 33 | 34 | #include "test/gtest-typed-test_test.h" 35 | #include "gtest/gtest.h" 36 | 37 | #if GTEST_HAS_TYPED_TEST_P 38 | 39 | // Tests that the same type-parameterized test case can be 40 | // instantiated in different translation units linked together. 41 | // (ContainerTest is also instantiated in gtest-typed-test_test.cc.) 42 | INSTANTIATE_TYPED_TEST_CASE_P(Vector, ContainerTest, 43 | testing::Types >); 44 | 45 | #endif // GTEST_HAS_TYPED_TEST_P 46 | -------------------------------------------------------------------------------- /googletest/test/gtest-typed-test_test.h: -------------------------------------------------------------------------------- 1 | // Copyright 2008 Google Inc. 2 | // All Rights Reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | 32 | #ifndef GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ 33 | #define GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ 34 | 35 | #include "gtest/gtest.h" 36 | 37 | #if GTEST_HAS_TYPED_TEST_P 38 | 39 | using testing::Test; 40 | 41 | // For testing that the same type-parameterized test case can be 42 | // instantiated in different translation units linked together. 43 | // ContainerTest will be instantiated in both gtest-typed-test_test.cc 44 | // and gtest-typed-test2_test.cc. 45 | 46 | template 47 | class ContainerTest : public Test { 48 | }; 49 | 50 | TYPED_TEST_CASE_P(ContainerTest); 51 | 52 | TYPED_TEST_P(ContainerTest, CanBeDefaultConstructed) { 53 | TypeParam container; 54 | } 55 | 56 | TYPED_TEST_P(ContainerTest, InitialSizeIsZero) { 57 | TypeParam container; 58 | EXPECT_EQ(0U, container.size()); 59 | } 60 | 61 | REGISTER_TYPED_TEST_CASE_P(ContainerTest, 62 | CanBeDefaultConstructed, InitialSizeIsZero); 63 | 64 | #endif // GTEST_HAS_TYPED_TEST_P 65 | 66 | #endif // GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ 67 | -------------------------------------------------------------------------------- /googletest/test/gtest_all_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2009, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | // 32 | // Tests for Google C++ Testing Framework (Google Test) 33 | // 34 | // Sometimes it's desirable to build most of Google Test's own tests 35 | // by compiling a single file. This file serves this purpose. 36 | #include "test/gtest-filepath_test.cc" 37 | #include "test/gtest-linked_ptr_test.cc" 38 | #include "test/gtest-message_test.cc" 39 | #include "test/gtest-options_test.cc" 40 | #include "test/gtest-port_test.cc" 41 | #include "test/gtest_pred_impl_unittest.cc" 42 | #include "test/gtest_prod_test.cc" 43 | #include "test/gtest-test-part_test.cc" 44 | #include "test/gtest-typed-test_test.cc" 45 | #include "test/gtest-typed-test2_test.cc" 46 | #include "test/gtest_unittest.cc" 47 | #include "test/production.cc" 48 | -------------------------------------------------------------------------------- /googletest/test/gtest_help_test_.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2009, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | 32 | // This program is meant to be run by gtest_help_test.py. Do not run 33 | // it directly. 34 | 35 | #include "gtest/gtest.h" 36 | 37 | // When a help flag is specified, this program should skip the tests 38 | // and exit with 0; otherwise the following test will be executed, 39 | // causing this program to exit with a non-zero code. 40 | TEST(HelpFlagTest, ShouldNotBeRun) { 41 | ASSERT_TRUE(false) << "Tests shouldn't be run when --help is specified."; 42 | } 43 | 44 | #if GTEST_HAS_DEATH_TEST 45 | TEST(DeathTest, UsedByPythonScriptToDetectSupportForDeathTestsInThisBinary) {} 46 | #endif 47 | -------------------------------------------------------------------------------- /googletest/test/gtest_main_unittest.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | 32 | #include "gtest/gtest.h" 33 | 34 | // Tests that we don't have to define main() when we link to 35 | // gtest_main instead of gtest. 36 | 37 | namespace { 38 | 39 | TEST(GTestMainTest, ShouldSucceed) { 40 | } 41 | 42 | } // namespace 43 | 44 | // We are using the main() function defined in src/gtest_main.cc, so 45 | // we don't define it here. 46 | -------------------------------------------------------------------------------- /googletest/test/gtest_no_test_unittest.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Tests that a Google Test program that has no test defined can run 31 | // successfully. 32 | // 33 | // Author: wan@google.com (Zhanyong Wan) 34 | 35 | #include "gtest/gtest.h" 36 | 37 | int main(int argc, char **argv) { 38 | testing::InitGoogleTest(&argc, argv); 39 | 40 | // An ad-hoc assertion outside of all tests. 41 | // 42 | // This serves three purposes: 43 | // 44 | // 1. It verifies that an ad-hoc assertion can be executed even if 45 | // no test is defined. 46 | // 2. It verifies that a failed ad-hoc assertion causes the test 47 | // program to fail. 48 | // 3. We had a bug where the XML output won't be generated if an 49 | // assertion is executed before RUN_ALL_TESTS() is called, even 50 | // though --gtest_output=xml is specified. This makes sure the 51 | // bug is fixed and doesn't regress. 52 | EXPECT_EQ(1, 2); 53 | 54 | // The above EXPECT_EQ() should cause RUN_ALL_TESTS() to return non-zero. 55 | return RUN_ALL_TESTS() ? 0 : 1; 56 | } 57 | -------------------------------------------------------------------------------- /googletest/test/gtest_prod_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | // 32 | // Unit test for include/gtest/gtest_prod.h. 33 | 34 | #include "gtest/gtest.h" 35 | #include "test/production.h" 36 | 37 | // Tests that private members can be accessed from a TEST declared as 38 | // a friend of the class. 39 | TEST(PrivateCodeTest, CanAccessPrivateMembers) { 40 | PrivateCode a; 41 | EXPECT_EQ(0, a.x_); 42 | 43 | a.set_x(1); 44 | EXPECT_EQ(1, a.x_); 45 | } 46 | 47 | typedef testing::Test PrivateCodeFixtureTest; 48 | 49 | // Tests that private members can be accessed from a TEST_F declared 50 | // as a friend of the class. 51 | TEST_F(PrivateCodeFixtureTest, CanAccessPrivateMembers) { 52 | PrivateCode a; 53 | EXPECT_EQ(0, a.x_); 54 | 55 | a.set_x(2); 56 | EXPECT_EQ(2, a.x_); 57 | } 58 | -------------------------------------------------------------------------------- /googletest/test/gtest_sole_header_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: mheule@google.com (Markus Heule) 31 | // 32 | // This test verifies that it's possible to use Google Test by including 33 | // the gtest.h header file alone. 34 | 35 | #include "gtest/gtest.h" 36 | 37 | namespace { 38 | 39 | void Subroutine() { 40 | EXPECT_EQ(42, 42); 41 | } 42 | 43 | TEST(NoFatalFailureTest, ExpectNoFatalFailure) { 44 | EXPECT_NO_FATAL_FAILURE(;); 45 | EXPECT_NO_FATAL_FAILURE(SUCCEED()); 46 | EXPECT_NO_FATAL_FAILURE(Subroutine()); 47 | EXPECT_NO_FATAL_FAILURE({ SUCCEED(); }); 48 | } 49 | 50 | TEST(NoFatalFailureTest, AssertNoFatalFailure) { 51 | ASSERT_NO_FATAL_FAILURE(;); 52 | ASSERT_NO_FATAL_FAILURE(SUCCEED()); 53 | ASSERT_NO_FATAL_FAILURE(Subroutine()); 54 | ASSERT_NO_FATAL_FAILURE({ SUCCEED(); }); 55 | } 56 | 57 | } // namespace 58 | -------------------------------------------------------------------------------- /googletest/test/gtest_uninitialized_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2008, Google Inc. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following disclaimer 14 | # in the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Google Inc. nor the names of its 17 | # contributors may be used to endorse or promote products derived from 18 | # this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | """Verifies that Google Test warns the user when not initialized properly.""" 33 | 34 | __author__ = 'wan@google.com (Zhanyong Wan)' 35 | 36 | import gtest_test_utils 37 | 38 | 39 | COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_uninitialized_test_') 40 | 41 | 42 | def Assert(condition): 43 | if not condition: 44 | raise AssertionError 45 | 46 | 47 | def AssertEq(expected, actual): 48 | if expected != actual: 49 | print 'Expected: %s' % (expected,) 50 | print ' Actual: %s' % (actual,) 51 | raise AssertionError 52 | 53 | 54 | def TestExitCodeAndOutput(command): 55 | """Runs the given command and verifies its exit code and output.""" 56 | 57 | # Verifies that 'command' exits with code 1. 58 | p = gtest_test_utils.Subprocess(command) 59 | Assert(p.exited) 60 | AssertEq(1, p.exit_code) 61 | Assert('InitGoogleTest' in p.output) 62 | 63 | 64 | class GTestUninitializedTest(gtest_test_utils.TestCase): 65 | def testExitCodeAndOutput(self): 66 | TestExitCodeAndOutput(COMMAND) 67 | 68 | 69 | if __name__ == '__main__': 70 | gtest_test_utils.Main() 71 | -------------------------------------------------------------------------------- /googletest/test/gtest_uninitialized_test_.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | 32 | #include "gtest/gtest.h" 33 | 34 | TEST(DummyTest, Dummy) { 35 | // This test doesn't verify anything. We just need it to create a 36 | // realistic stage for testing the behavior of Google Test when 37 | // RUN_ALL_TESTS() is called without testing::InitGoogleTest() being 38 | // called first. 39 | } 40 | 41 | int main() { 42 | return RUN_ALL_TESTS(); 43 | } 44 | -------------------------------------------------------------------------------- /googletest/test/gtest_xml_outfile1_test_.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: keith.ray@gmail.com (Keith Ray) 31 | // 32 | // gtest_xml_outfile1_test_ writes some xml via TestProperty used by 33 | // gtest_xml_outfiles_test.py 34 | 35 | #include "gtest/gtest.h" 36 | 37 | class PropertyOne : public testing::Test { 38 | protected: 39 | virtual void SetUp() { 40 | RecordProperty("SetUpProp", 1); 41 | } 42 | virtual void TearDown() { 43 | RecordProperty("TearDownProp", 1); 44 | } 45 | }; 46 | 47 | TEST_F(PropertyOne, TestSomeProperties) { 48 | RecordProperty("TestSomeProperty", 1); 49 | } 50 | -------------------------------------------------------------------------------- /googletest/test/gtest_xml_outfile2_test_.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: keith.ray@gmail.com (Keith Ray) 31 | // 32 | // gtest_xml_outfile2_test_ writes some xml via TestProperty used by 33 | // gtest_xml_outfiles_test.py 34 | 35 | #include "gtest/gtest.h" 36 | 37 | class PropertyTwo : public testing::Test { 38 | protected: 39 | virtual void SetUp() { 40 | RecordProperty("SetUpProp", 2); 41 | } 42 | virtual void TearDown() { 43 | RecordProperty("TearDownProp", 2); 44 | } 45 | }; 46 | 47 | TEST_F(PropertyTwo, TestSomeProperties) { 48 | RecordProperty("TestSomeProperty", 2); 49 | } 50 | -------------------------------------------------------------------------------- /googletest/test/production.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | // 32 | // This is part of the unit test for include/gtest/gtest_prod.h. 33 | 34 | #include "production.h" 35 | 36 | PrivateCode::PrivateCode() : x_(0) {} 37 | -------------------------------------------------------------------------------- /googletest/test/production.h: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | // 32 | // This is part of the unit test for include/gtest/gtest_prod.h. 33 | 34 | #ifndef GTEST_TEST_PRODUCTION_H_ 35 | #define GTEST_TEST_PRODUCTION_H_ 36 | 37 | #include "gtest/gtest_prod.h" 38 | 39 | class PrivateCode { 40 | public: 41 | // Declares a friend test that does not use a fixture. 42 | FRIEND_TEST(PrivateCodeTest, CanAccessPrivateMembers); 43 | 44 | // Declares a friend test that uses a fixture. 45 | FRIEND_TEST(PrivateCodeFixtureTest, CanAccessPrivateMembers); 46 | 47 | PrivateCode(); 48 | 49 | int x() const { return x_; } 50 | private: 51 | void set_x(int an_x) { x_ = an_x; } 52 | int x_; 53 | }; 54 | 55 | #endif // GTEST_TEST_PRODUCTION_H_ 56 | -------------------------------------------------------------------------------- /googletest/xcode/Config/DebugProject.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // DebugProject.xcconfig 3 | // 4 | // These are Debug Configuration project settings for the gtest framework and 5 | // examples. It is set in the "Based On:" dropdown in the "Project" info 6 | // dialog. 7 | // This file is based on the Xcode Configuration files in: 8 | // http://code.google.com/p/google-toolbox-for-mac/ 9 | // 10 | 11 | #include "General.xcconfig" 12 | 13 | // No optimization 14 | GCC_OPTIMIZATION_LEVEL = 0 15 | 16 | // Deployment postprocessing is what triggers Xcode to strip, turn it off 17 | DEPLOYMENT_POSTPROCESSING = NO 18 | 19 | // Dead code stripping off 20 | DEAD_CODE_STRIPPING = NO 21 | 22 | // Debug symbols should be on obviously 23 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES 24 | 25 | // Define the DEBUG macro in all debug builds 26 | OTHER_CFLAGS = $(OTHER_CFLAGS) -DDEBUG=1 27 | 28 | // These are turned off to avoid STL incompatibilities with client code 29 | // // Turns on special C++ STL checks to "encourage" good STL use 30 | // GCC_PREPROCESSOR_DEFINITIONS = $(GCC_PREPROCESSOR_DEFINITIONS) _GLIBCXX_DEBUG_PEDANTIC _GLIBCXX_DEBUG _GLIBCPP_CONCEPT_CHECKS 31 | -------------------------------------------------------------------------------- /googletest/xcode/Config/FrameworkTarget.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // FrameworkTarget.xcconfig 3 | // 4 | // These are Framework target settings for the gtest framework and examples. It 5 | // is set in the "Based On:" dropdown in the "Target" info dialog. 6 | // This file is based on the Xcode Configuration files in: 7 | // http://code.google.com/p/google-toolbox-for-mac/ 8 | // 9 | 10 | // Dynamic libs need to be position independent 11 | GCC_DYNAMIC_NO_PIC = NO 12 | 13 | // Dynamic libs should not have their external symbols stripped. 14 | STRIP_STYLE = non-global 15 | 16 | // Let the user install by specifying the $DSTROOT with xcodebuild 17 | SKIP_INSTALL = NO 18 | -------------------------------------------------------------------------------- /googletest/xcode/Config/General.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // General.xcconfig 3 | // 4 | // These are General configuration settings for the gtest framework and 5 | // examples. 6 | // This file is based on the Xcode Configuration files in: 7 | // http://code.google.com/p/google-toolbox-for-mac/ 8 | // 9 | 10 | // Build for PPC and Intel, 32- and 64-bit 11 | ARCHS = i386 x86_64 ppc ppc64 12 | 13 | // Zerolink prevents link warnings so turn it off 14 | ZERO_LINK = NO 15 | 16 | // Prebinding considered unhelpful in 10.3 and later 17 | PREBINDING = NO 18 | 19 | // Strictest warning policy 20 | WARNING_CFLAGS = -Wall -Werror -Wendif-labels -Wnewline-eof -Wno-sign-compare -Wshadow 21 | 22 | // Work around Xcode bugs by using external strip. See: 23 | // http://lists.apple.com/archives/Xcode-users/2006/Feb/msg00050.html 24 | SEPARATE_STRIP = YES 25 | 26 | // Force C99 dialect 27 | GCC_C_LANGUAGE_STANDARD = c99 28 | 29 | // not sure why apple defaults this on, but it's pretty risky 30 | ALWAYS_SEARCH_USER_PATHS = NO 31 | 32 | // Turn on position dependent code for most cases (overridden where appropriate) 33 | GCC_DYNAMIC_NO_PIC = YES 34 | 35 | // Default SDK and minimum OS version is 10.4 36 | SDKROOT = $(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk 37 | MACOSX_DEPLOYMENT_TARGET = 10.4 38 | GCC_VERSION = 4.0 39 | 40 | // VERSIONING BUILD SETTINGS (used in Info.plist) 41 | GTEST_VERSIONINFO_ABOUT = © 2008 Google Inc. 42 | -------------------------------------------------------------------------------- /googletest/xcode/Config/ReleaseProject.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // ReleaseProject.xcconfig 3 | // 4 | // These are Release Configuration project settings for the gtest framework 5 | // and examples. It is set in the "Based On:" dropdown in the "Project" info 6 | // dialog. 7 | // This file is based on the Xcode Configuration files in: 8 | // http://code.google.com/p/google-toolbox-for-mac/ 9 | // 10 | 11 | #include "General.xcconfig" 12 | 13 | // subconfig/Release.xcconfig 14 | 15 | // Optimize for space and size (Apple recommendation) 16 | GCC_OPTIMIZATION_LEVEL = s 17 | 18 | // Deploment postprocessing is what triggers Xcode to strip 19 | DEPLOYMENT_POSTPROCESSING = YES 20 | 21 | // No symbols 22 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO 23 | 24 | // Dead code strip does not affect ObjC code but can help for C 25 | DEAD_CODE_STRIPPING = YES 26 | 27 | // NDEBUG is used by things like assert.h, so define it for general compat. 28 | // ASSERT going away in release tends to create unused vars. 29 | OTHER_CFLAGS = $(OTHER_CFLAGS) -DNDEBUG=1 -Wno-unused-variable 30 | 31 | // When we strip we want to strip all symbols in release, but save externals. 32 | STRIP_STYLE = all 33 | -------------------------------------------------------------------------------- /googletest/xcode/Config/StaticLibraryTarget.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // StaticLibraryTarget.xcconfig 3 | // 4 | // These are static library target settings for libgtest.a. It 5 | // is set in the "Based On:" dropdown in the "Target" info dialog. 6 | // This file is based on the Xcode Configuration files in: 7 | // http://code.google.com/p/google-toolbox-for-mac/ 8 | // 9 | 10 | // Static libs can be included in bundles so make them position independent 11 | GCC_DYNAMIC_NO_PIC = NO 12 | 13 | // Static libs should not have their internal globals or external symbols 14 | // stripped. 15 | STRIP_STYLE = debugging 16 | 17 | // Let the user install by specifying the $DSTROOT with xcodebuild 18 | SKIP_INSTALL = NO 19 | -------------------------------------------------------------------------------- /googletest/xcode/Config/TestTarget.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // TestTarget.xcconfig 3 | // 4 | // These are Test target settings for the gtest framework and examples. It 5 | // is set in the "Based On:" dropdown in the "Target" info dialog. 6 | 7 | PRODUCT_NAME = $(TARGET_NAME) 8 | HEADER_SEARCH_PATHS = ../include 9 | -------------------------------------------------------------------------------- /googletest/xcode/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.google.${PRODUCT_NAME} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | GTEST_VERSIONINFO_LONG 21 | CFBundleShortVersionString 22 | GTEST_VERSIONINFO_SHORT 23 | CFBundleGetInfoString 24 | ${PRODUCT_NAME} GTEST_VERSIONINFO_LONG, ${GTEST_VERSIONINFO_ABOUT} 25 | NSHumanReadableCopyright 26 | ${GTEST_VERSIONINFO_ABOUT} 27 | CSResourcesFileMapped 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /googletest/xcode/Samples/FrameworkSample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.google.gtest.${PRODUCT_NAME:identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | CSResourcesFileMapped 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /googletest/xcode/Samples/FrameworkSample/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2008, Google Inc. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following disclaimer 14 | # in the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Google Inc. nor the names of its 17 | # contributors may be used to endorse or promote products derived from 18 | # this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | # Executes the samples and tests for the Google Test Framework. 33 | 34 | # Help the dynamic linker find the path to the libraries. 35 | export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR 36 | export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR 37 | 38 | # Create some executables. 39 | test_executables=$@ 40 | 41 | # Now execute each one in turn keeping track of how many succeeded and failed. 42 | succeeded=0 43 | failed=0 44 | failed_list=() 45 | for test in ${test_executables[*]}; do 46 | "$test" 47 | result=$? 48 | if [ $result -eq 0 ]; then 49 | succeeded=$(( $succeeded + 1 )) 50 | else 51 | failed=$(( failed + 1 )) 52 | failed_list="$failed_list $test" 53 | fi 54 | done 55 | 56 | # Report the successes and failures to the console. 57 | echo "Tests complete with $succeeded successes and $failed failures." 58 | if [ $failed -ne 0 ]; then 59 | echo "The following tests failed:" 60 | echo $failed_list 61 | fi 62 | exit $failed 63 | -------------------------------------------------------------------------------- /googletest/xcode/Samples/FrameworkSample/widget.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: preston.a.jackson@gmail.com (Preston Jackson) 31 | // 32 | // Google Test - FrameworkSample 33 | // widget.cc 34 | // 35 | 36 | // Widget is a very simple class used for demonstrating the use of gtest 37 | 38 | #include "widget.h" 39 | 40 | Widget::Widget(int number, const std::string& name) 41 | : number_(number), 42 | name_(name) {} 43 | 44 | Widget::~Widget() {} 45 | 46 | float Widget::GetFloatValue() const { 47 | return number_; 48 | } 49 | 50 | int Widget::GetIntValue() const { 51 | return static_cast(number_); 52 | } 53 | 54 | std::string Widget::GetStringValue() const { 55 | return name_; 56 | } 57 | 58 | void Widget::GetCharPtrValue(char* buffer, size_t max_size) const { 59 | // Copy the char* representation of name_ into buffer, up to max_size. 60 | strncpy(buffer, name_.c_str(), max_size-1); 61 | buffer[max_size-1] = '\0'; 62 | return; 63 | } 64 | -------------------------------------------------------------------------------- /googletest/xcode/Samples/FrameworkSample/widget.h: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: preston.a.jackson@gmail.com (Preston Jackson) 31 | // 32 | // Google Test - FrameworkSample 33 | // widget.h 34 | // 35 | 36 | // Widget is a very simple class used for demonstrating the use of gtest. It 37 | // simply stores two values a string and an integer, which are returned via 38 | // public accessors in multiple forms. 39 | 40 | #import 41 | 42 | class Widget { 43 | public: 44 | Widget(int number, const std::string& name); 45 | ~Widget(); 46 | 47 | // Public accessors to number data 48 | float GetFloatValue() const; 49 | int GetIntValue() const; 50 | 51 | // Public accessors to the string data 52 | std::string GetStringValue() const; 53 | void GetCharPtrValue(char* buffer, size_t max_size) const; 54 | 55 | private: 56 | // Data members 57 | float number_; 58 | std::string name_; 59 | }; 60 | -------------------------------------------------------------------------------- /googletest/xcode/Scripts/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2008, Google Inc. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following disclaimer 14 | # in the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Google Inc. nor the names of its 17 | # contributors may be used to endorse or promote products derived from 18 | # this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | # Executes the samples and tests for the Google Test Framework. 33 | 34 | # Help the dynamic linker find the path to the libraries. 35 | export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR 36 | export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR 37 | 38 | # Create some executables. 39 | test_executables=("$BUILT_PRODUCTS_DIR/gtest_unittest-framework" 40 | "$BUILT_PRODUCTS_DIR/gtest_unittest" 41 | "$BUILT_PRODUCTS_DIR/sample1_unittest-framework" 42 | "$BUILT_PRODUCTS_DIR/sample1_unittest-static") 43 | 44 | # Now execute each one in turn keeping track of how many succeeded and failed. 45 | succeeded=0 46 | failed=0 47 | failed_list=() 48 | for test in ${test_executables[*]}; do 49 | "$test" 50 | result=$? 51 | if [ $result -eq 0 ]; then 52 | succeeded=$(( $succeeded + 1 )) 53 | else 54 | failed=$(( failed + 1 )) 55 | failed_list="$failed_list $test" 56 | fi 57 | done 58 | 59 | # Report the successes and failures to the console. 60 | echo "Tests complete with $succeeded successes and $failed failures." 61 | if [ $failed -ne 0 ]; then 62 | echo "The following tests failed:" 63 | echo $failed_list 64 | fi 65 | exit $failed 66 | -------------------------------------------------------------------------------- /include/ten/apply.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_APPLY_HH 2 | #define LIBTEN_APPLY_HH 3 | 4 | // Copyright (c) 2011 Paul Preney. All Rights Reserved. 5 | // see http://preney.ca/paul/archives/574 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace ten { 12 | 13 | template 14 | struct indices; 15 | 16 | template 17 | struct make_indices_impl; 18 | 19 | template 20 | struct make_indices_impl, Type, Types...> 21 | { 22 | typedef 23 | typename make_indices_impl, Types...>::type 24 | type 25 | ; 26 | }; 27 | 28 | template 29 | struct make_indices_impl> 30 | { 31 | typedef indices type; 32 | }; 33 | 34 | template 35 | struct make_indices 36 | { 37 | typedef typename make_indices_impl<0, indices<>, Types...>::type type; 38 | }; 39 | 40 | //=========================================================================== 41 | 42 | template 43 | auto apply(Op&& op, Args&&... args) 44 | -> typename std::result_of::type 45 | { 46 | return op( std::forward(args)... ); 47 | } 48 | 49 | //=========================================================================== 50 | 51 | template < 52 | typename Indices 53 | > 54 | struct apply_tuple_impl; 55 | 56 | template < 57 | template class I, 58 | std::size_t... Indices 59 | > 60 | struct apply_tuple_impl> 61 | { 62 | template < 63 | typename Op, 64 | typename... OpArgs, 65 | template class T = std::tuple 66 | > 67 | static auto apply_tuple(Op&& op, T&& t) 68 | -> typename std::result_of::type 69 | { 70 | return op( std::forward(std::get(t))... ); 71 | } 72 | }; 73 | 74 | template < 75 | typename Op, 76 | typename... OpArgs, 77 | typename Indices = typename make_indices<0, OpArgs...>::type, 78 | template class T = std::tuple 79 | > 80 | auto apply_tuple(Op op, T&& t) 81 | -> typename std::result_of::type 82 | { 83 | return apply_tuple_impl::apply_tuple( 84 | std::forward(op), 85 | std::forward>(t) 86 | ); 87 | } 88 | 89 | } // end namespace ten 90 | 91 | #endif // LIBTEN_APPLY_HH 92 | 93 | -------------------------------------------------------------------------------- /include/ten/backoff.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_BACKOFF_HH 2 | #define LIBTEN_BACKOFF_HH 3 | 4 | #include "ten/error.hh" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace ten { 10 | 11 | //! calculate back off times for retrying operations 12 | //! based on algorithm used by tcp 13 | template class backoff { 14 | private: 15 | const DurationT _min_delay; 16 | const DurationT _max_delay; 17 | uint64_t _try; 18 | std::minstd_rand _eng; 19 | float _scale; 20 | 21 | public: 22 | backoff(DurationT min_delay, DurationT max_delay, float scale = 1.0f) 23 | : _min_delay(min_delay), 24 | _max_delay(max_delay), 25 | _try(0), 26 | _eng((long unsigned int)time(nullptr)), 27 | _scale(scale) 28 | { 29 | if (min_delay.count() < 0 || min_delay > max_delay) 30 | throw_stream() << "invalid backoff(" << min_delay << ", " << max_delay << ")" << endx; 31 | } 32 | 33 | void reset() { _try = 0; } 34 | 35 | DurationT next_delay() { 36 | std::uniform_real_distribution rand_real{0.0f, _scale}; 37 | ++_try; 38 | float r = rand_real(_eng); 39 | float delta = 1.0f + (r * float(_try)); 40 | const auto d = std::chrono::duration_cast(_min_delay * delta); 41 | return std::min(d, _max_delay); 42 | } 43 | }; 44 | 45 | template ::type> 47 | inline backoff make_backoff(D1 d1, D2 d2, float scale = 1.0f) { 48 | return backoff(d1, d2, scale); 49 | } 50 | 51 | } // end namespace ten 52 | 53 | #endif // LIBTEN_BACKOFF_HH 54 | -------------------------------------------------------------------------------- /include/ten/consistent_hash.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_CONSISTENT_HASH_HH 2 | #define LIBTEN_CONSISTENT_HASH_HH 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace ten { 10 | 11 | // Delimiter must not appear in the string representation of Node 12 | // otherwise you risk hash collisions 13 | template 14 | class hash_ring { 15 | private: 16 | typedef std::map map_type; 17 | 18 | map_type _ring; 19 | std::hash _node_hash; 20 | std::hash _data_hash; 21 | public: 22 | void add(const Node &node) { 23 | size_t hash; 24 | for (unsigned r = 0; r < Replicas; ++r) { 25 | std::ostringstream ss; 26 | ss << node << Delimiter << r; 27 | hash = _node_hash(ss.str()); 28 | _ring[hash] = node; 29 | } 30 | } 31 | 32 | unsigned remove(const Node &node) { 33 | size_t hash; 34 | unsigned removed = 0; 35 | for (unsigned r = 0; r < Replicas; ++r) { 36 | std::ostringstream ss; 37 | ss << node << Delimiter << r; 38 | hash = _node_hash(ss.str()); 39 | removed += _ring.erase(hash); 40 | } 41 | return removed; 42 | } 43 | 44 | const Node &get(const Data &data) const { 45 | if (_ring.empty()) { 46 | throw std::runtime_error("empty hash_ring"); 47 | } 48 | size_t hash = _data_hash(data); 49 | // find first node >= hash 50 | auto it = _ring.lower_bound(hash); 51 | if (it == _ring.end()) { 52 | // wrap around to the front 53 | it = _ring.begin(); 54 | } 55 | return it->second; 56 | } 57 | 58 | //! unique set of nodes 59 | std::set nodes() const { 60 | std::set nodes; 61 | for (auto it : _ring) { 62 | nodes.insert(it.second); 63 | } 64 | return nodes; 65 | } 66 | }; 67 | 68 | } // ns ten 69 | #endif 70 | -------------------------------------------------------------------------------- /include/ten/encoders.hh: -------------------------------------------------------------------------------- 1 | #include "stlencoders/base16.hpp" 2 | #include "stlencoders/base32.hpp" 3 | #include "stlencoders/base64.hpp" 4 | -------------------------------------------------------------------------------- /include/ten/ewma.hh: -------------------------------------------------------------------------------- 1 | #ifndef TEN_EWMA_HH 2 | #define TEN_EWMA_HH 3 | 4 | #include 5 | #include 6 | #include 7 | #include "ten/optional.hh" 8 | 9 | namespace ten { 10 | 11 | template 12 | class ewma { 13 | private: 14 | TimeUnit _decay_interval; 15 | double _alpha; 16 | std::atomic _pending {}; 17 | double _rate {}; 18 | public: 19 | ewma(TimeUnit decay_interval, TimeUnit tick_interval = TimeUnit{1}) 20 | : _decay_interval{decay_interval}, 21 | _alpha{exp(-(double)tick_interval.count() / decay_interval.count())} 22 | {} 23 | 24 | void update(uint64_t n) { 25 | _pending.fetch_add(n); 26 | } 27 | 28 | void tick() { 29 | double count = _pending.exchange(0); 30 | double r = _rate; 31 | r *= _alpha; 32 | r += count / (double)_decay_interval.count(); 33 | _rate = r; 34 | } 35 | 36 | template 37 | double rate() { 38 | using cvt = std::ratio_divide< typename RateUnit::period, typename TimeUnit::period >; 39 | return (_rate * cvt::num) / cvt::den; 40 | } 41 | }; 42 | 43 | } // ten 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/ten/http/http_error.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_HTTP_ERROR_HH 2 | #define LIBTEN_HTTP_ERROR_HH 3 | 4 | #include "ten/error.hh" 5 | 6 | namespace ten { 7 | 8 | struct http_error : public errno_error { 9 | template 10 | http_error(Args&&... args) 11 | : errno_error(std::forward(args)...) {} 12 | }; 13 | 14 | //! thrown on http dial errors, which always come with specific messages, 15 | //! and sometimes with errno values 16 | struct http_dial_error : public http_error { 17 | http_dial_error(const char *msg) : http_error(0, msg) {} 18 | http_dial_error(const errno_error &e) : http_error(e) {} 19 | http_dial_error(int err, const char *msg) : http_error(err, msg) {} 20 | }; 21 | 22 | //! thrown on http network errors 23 | struct http_makesock_error : public http_error { 24 | http_makesock_error() : http_error("makesock") {} 25 | }; 26 | 27 | //! thrown on http network errors 28 | struct http_send_error : public http_error { 29 | http_send_error() : http_error("send") {} 30 | }; 31 | 32 | //! thrown on http network errors 33 | struct http_recv_error : public http_error { 34 | http_recv_error() : http_error("recv") {} 35 | }; 36 | 37 | //! thrown on http network errors 38 | struct http_closed_error : public http_error { 39 | http_closed_error() : http_error(0, "closed") {} 40 | }; 41 | 42 | //! thrown on http parsing errors 43 | struct http_parse_error : public http_error { 44 | template 45 | http_parse_error(A&&... a) : http_error(0, std::forward(a)...) {} 46 | }; 47 | 48 | } // end namespace ten 49 | 50 | #endif // LIBTEN_HTTP_ERROR_HH 51 | -------------------------------------------------------------------------------- /include/ten/iter.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_ITER_HH 2 | #define LIBTEN_ITER_HH 3 | 4 | #include 5 | 6 | namespace ten { 7 | 8 | // cyclic iterator 9 | 10 | template 11 | class cycle_iterator { 12 | using itr = typename std::iterator_traits; 13 | 14 | const Iter from, to; 15 | Iter cur; 16 | 17 | public: 18 | using value_type = typename itr::value_type; 19 | using pointer = typename itr::pointer; 20 | using reference = typename itr::reference; 21 | using iterator_category = std::forward_iterator_tag; 22 | 23 | cycle_iterator(Iter from_, Iter to_) : from(std::move(from_)), to(std::move(to_)), cur(from) {} 24 | 25 | bool empty() const { 26 | return from == to; 27 | } 28 | reference operator * () const { 29 | if (empty()) throw std::out_of_range("empty cycle_iterator"); 30 | return *cur; 31 | } 32 | cycle_iterator & operator ++ () { 33 | if (empty()) throw std::out_of_range("empty cycle_iterator"); 34 | if (++cur == to) 35 | cur = from; 36 | return *this; 37 | } 38 | cycle_iterator operator ++ (int) { 39 | cycle_iterator orig(*this); 40 | ++*this; 41 | return orig; 42 | } 43 | }; 44 | 45 | template 46 | inline cycle_iterator make_cycle_iterator(T &coll) { return cycle_iterator(begin(coll), end(coll)); } 47 | 48 | template 49 | inline cycle_iterator make_cycle_iterator(const T &coll) { return cycle_iterator(begin(coll), end(coll)); } 50 | 51 | template 52 | void make_cycle_iterator(RRef); // that should prevent using temporaries 53 | 54 | } // ten 55 | 56 | #endif // LIBTEN_ITER_HH 57 | -------------------------------------------------------------------------------- /include/ten/logging.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_LOGGING_HH 2 | #define LIBTEN_LOGGING_HH 3 | 4 | #include 5 | #include 6 | 7 | #endif // LIBTEN_LOGGING_HH 8 | -------------------------------------------------------------------------------- /include/ten/msgpack.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_MSGPACK_HH 2 | #define LIBTEN_MSGPACK_HH 3 | 4 | #include "msgpack/msgpack.hpp" 5 | #include "ten/optional.hh" 6 | 7 | namespace msgpack { 8 | 9 | template 10 | inline ten::optional & operator>> (object o, ten::optional& v) { 11 | switch (o.type) { 12 | case type::NIL: 13 | v = ten::nullopt; 14 | return v; 15 | default: 16 | { 17 | T t; 18 | o >> t; 19 | v = t; 20 | return v; 21 | } 22 | } 23 | } 24 | 25 | template 26 | packer& operator<< (packer& o, const ten::optional& v) { 27 | if (v) { 28 | o << *v; 29 | } else { 30 | o.pack_nil(); 31 | } 32 | return o; 33 | } 34 | 35 | } // end msgpack 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/ten/net/ssl.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_NET_SSL_HH 2 | #define LIBTEN_NET_SSL_HH 3 | 4 | #include 5 | #include 6 | #include "ten/net.hh" 7 | #include "ten/error.hh" 8 | 9 | namespace ten { 10 | 11 | struct sslerror : public backtrace_exception { 12 | char errstr[128]; 13 | long err; 14 | 15 | sslerror(); 16 | const char *what() const noexcept override { return errstr; } 17 | }; 18 | 19 | BIO_METHOD *BIO_s_netfd(void); 20 | BIO *BIO_new_netfd(int fd, int close_flag); 21 | 22 | //! task io aware SSL wrapper 23 | class sslsock : public sockbase { 24 | public: 25 | SSL_CTX *ctx = nullptr; 26 | BIO *bio = nullptr; 27 | 28 | sslsock(int fd=-1); 29 | sslsock(netsock ns); 30 | sslsock(int domain, int type, int protocol=0); 31 | 32 | sslsock(sslsock &&other) = default; 33 | sslsock & operator = (sslsock &&other) = default; 34 | 35 | ~sslsock() override; 36 | 37 | //! false for server mode 38 | void initssl(SSL_CTX *ctx_, bool client); 39 | void initssl(const SSL_METHOD *method, bool client); 40 | 41 | //! dial requires a large 8MB stack size for getaddrinfo 42 | void dial(const char *addr, 43 | uint16_t port, 44 | optional_timeout timeout_ms=nullopt) override; 45 | 46 | int connect(const address &addr, 47 | optional_timeout timeout_ms=nullopt) override 48 | __attribute__((warn_unused_result)) 49 | { 50 | return netconnect(s.fd, addr, timeout_ms); 51 | } 52 | 53 | int accept(address &addr, 54 | int flags=0, optional_timeout timeout_ms=nullopt) override 55 | __attribute__((warn_unused_result)) 56 | { 57 | return netaccept(s.fd, addr, flags, timeout_ms); 58 | } 59 | 60 | ssize_t recv(void *buf, 61 | size_t len, int flags=0, optional_timeout timeout_ms=nullopt) override 62 | __attribute__((warn_unused_result)) 63 | { 64 | return BIO_read(bio, buf, len); 65 | } 66 | 67 | ssize_t send(const void *buf, 68 | size_t len, int flags=0, optional_timeout timeout_ms=nullopt) override 69 | __attribute__((warn_unused_result)) 70 | { 71 | return BIO_write(bio, buf, len); 72 | } 73 | 74 | void handshake(); 75 | 76 | }; 77 | 78 | } // end namespace ten 79 | 80 | #endif // LIBTEN_NET_SSL_HH 81 | -------------------------------------------------------------------------------- /include/ten/optional.hh: -------------------------------------------------------------------------------- 1 | #ifndef TEN_OPTIONAL_HH 2 | #define TEN_OPTIONAL_HH 3 | 4 | #include "ten/bits/optional.hpp" 5 | 6 | namespace ten { 7 | using std::experimental::optional; 8 | using std::experimental::nullopt; 9 | using std::experimental::in_place; 10 | using std::experimental::in_place_t; 11 | using std::experimental::is_not_optional; 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/ten/rpc/protocol.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_RPC_PROTOCOL_HH 2 | #define LIBTEN_RPC_PROTOCOL_HH 3 | 4 | #include 5 | 6 | namespace msgpack { 7 | namespace rpc { 8 | 9 | 10 | typedef uint32_t msgid_t; 11 | typedef uint32_t method_t; 12 | 13 | typedef uint8_t message_type_t; 14 | typedef uint8_t error_type_t; 15 | 16 | static const message_type_t REQUEST = 0; 17 | static const message_type_t RESPONSE = 1; 18 | static const message_type_t NOTIFY = 2; 19 | 20 | static const error_type_t NO_METHOD_ERROR = 0x01; 21 | static const error_type_t ARGUMENT_ERROR = 0x02; 22 | 23 | 24 | struct msg_rpc { 25 | msg_rpc() { } 26 | 27 | message_type_t type; 28 | 29 | bool is_request() const { return type == REQUEST; } 30 | bool is_response() const { return type == RESPONSE; } 31 | bool is_notify() const { return type == NOTIFY; } 32 | 33 | MSGPACK_DEFINE(type); 34 | }; 35 | 36 | template 37 | struct msg_request { 38 | msg_request() : 39 | type(REQUEST), 40 | msgid(0) { } 41 | 42 | msg_request( 43 | Method method, 44 | typename msgpack::type::tuple_type::transparent_reference param, 45 | msgid_t msgid) : 46 | type(REQUEST), 47 | msgid(msgid), 48 | method(method), 49 | param(param) { } 50 | 51 | message_type_t type; 52 | msgid_t msgid; 53 | Method method; 54 | Parameter param; 55 | 56 | MSGPACK_DEFINE(type, msgid, method, param); 57 | }; 58 | 59 | template 60 | struct msg_response { 61 | msg_response() : 62 | type(RESPONSE), 63 | msgid(0) { } 64 | 65 | msg_response( 66 | typename msgpack::type::tuple_type::transparent_reference result, 67 | typename msgpack::type::tuple_type::transparent_reference error, 68 | msgid_t msgid) : 69 | type(RESPONSE), 70 | msgid(msgid), 71 | error(error), 72 | result(result) { } 73 | 74 | message_type_t type; 75 | msgid_t msgid; 76 | Error error; 77 | Result result; 78 | 79 | MSGPACK_DEFINE(type, msgid, error, result); 80 | }; 81 | 82 | template 83 | struct msg_notify { 84 | msg_notify() : 85 | type(NOTIFY) { } 86 | 87 | msg_notify( 88 | Method method, 89 | typename msgpack::type::tuple_type::transparent_reference param) : 90 | type(NOTIFY), 91 | method(method), 92 | param(param) { } 93 | 94 | message_type_t type; 95 | Method method; 96 | Parameter param; 97 | 98 | MSGPACK_DEFINE(type, method, param); 99 | }; 100 | 101 | 102 | } // namespace rpc 103 | } // namespace msgpack 104 | 105 | #endif // LIBTEN_RPC_PROTOCOL_HH 106 | -------------------------------------------------------------------------------- /include/ten/semaphore.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_SEMAPHORE_HH 2 | #define LIBTEN_SEMAPHORE_HH 3 | 4 | #include "ten/logging.hh" 5 | #include "ten/error.hh" 6 | #include 7 | 8 | namespace ten { 9 | 10 | //! wrapper around anonymous POSIX semaphore 11 | class semaphore { 12 | private: 13 | sem_t _s; 14 | public: 15 | explicit semaphore(unsigned int value = 0) { 16 | throw_if(sem_init(&_s, 0, value) == -1); 17 | } 18 | 19 | semaphore(const semaphore &) = delete; 20 | semaphore &operator =(const semaphore &) = delete; 21 | 22 | //! increment (unlock) the semaphore 23 | void post() { 24 | throw_if(sem_post(&_s) == -1); 25 | } 26 | 27 | //! decrement (lock) the semaphore 28 | // 29 | //! blocks if the value drops below 0 30 | void wait() { 31 | throw_if(sem_wait(&_s) == -1); 32 | } 33 | 34 | // TODO: sem_trywait and sem_timedwait 35 | 36 | ~semaphore() { 37 | PCHECK(sem_destroy(&_s) == 0); 38 | } 39 | }; 40 | 41 | } // end namespace ten 42 | 43 | #endif // LIBTEN_SEMAPHORE_HH 44 | -------------------------------------------------------------------------------- /include/ten/striped.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_STRIPED_HH 2 | #define LIBTEN_STRIPED_HH 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ten { 9 | 10 | template class striped { 11 | public: 12 | typedef typename std::vector::size_type size_type; 13 | private: 14 | std::vector _stripes; 15 | 16 | template 17 | std::vector _mget(std::vector &indexes, const Key key, const Keys... keys) 18 | { 19 | std::hash hasher; 20 | size_t hash = hasher(key); 21 | indexes.push_back(hash % _stripes.size()); 22 | return _mget(indexes, keys...); 23 | } 24 | 25 | std::vector _mget(std::vector &indexes) { 26 | std::sort(begin(indexes), end(indexes)); 27 | return indexes; 28 | } 29 | public: 30 | striped(size_type size) : _stripes(size) {} 31 | 32 | template 33 | std::vector multi_get(const Key key, const Keys... keys) 34 | { 35 | std::vector indexes; 36 | std::hash hasher; 37 | size_t hash = hasher(key); 38 | indexes.push_back(hash % _stripes.size()); 39 | return _mget(indexes, keys...); 40 | } 41 | 42 | 43 | template T &get(const Key &key) { 44 | std::hash hasher; 45 | size_t hash = hasher(key); 46 | return at(hash % _stripes.size()); 47 | } 48 | 49 | T &at(const size_type index) { 50 | return _stripes.at(index); 51 | } 52 | 53 | size_type size() const { 54 | return _stripes.size(); 55 | } 56 | }; 57 | 58 | } // ten 59 | 60 | #endif // LIBTEN_STRIPED_HH 61 | -------------------------------------------------------------------------------- /include/ten/task.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_TASK_HH 2 | #define LIBTEN_TASK_HH 3 | 4 | #include "ten/logging.hh" 5 | #include "ten/task/task.hh" 6 | #include "ten/task/compat.hh" 7 | #include "ten/task/deadline.hh" 8 | 9 | #endif // LIBTEN_TASK_HH 10 | -------------------------------------------------------------------------------- /include/ten/task/compat.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_TASK_COMPAT_HH 2 | #define LIBTEN_TASK_COMPAT_HH 3 | 4 | #include 5 | 6 | // XXX: old task api has been moved here to be deprecated 7 | // all of these apis will eventially be replaced 8 | 9 | namespace ten { 10 | 11 | extern void netinit(); 12 | 13 | //! set/get current task state 14 | const char *taskstate(const char *fmt=nullptr, ...); 15 | //! set/get current task name 16 | const char * taskname(const char *fmt=nullptr, ...); 17 | 18 | //! suspend task waiting for io on pollfds 19 | int taskpoll(pollfd *fds, nfds_t nfds, optional_timeout ms=nullopt); 20 | //! suspend task waiting for io on fd 21 | bool fdwait(int fd, int rw, optional_timeout ms=nullopt); 22 | 23 | } // ten 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/ten/task/deadline.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_TASK_DEADLINE_HH 2 | #define LIBTEN_TASK_DEADLINE_HH 3 | 4 | namespace ten { 5 | 6 | // inherit from task_interrupted so lock/rendez/poll canceling 7 | // doesn't need to be duplicated 8 | struct deadline_reached : task_interrupted {}; 9 | 10 | // forward decl 11 | struct deadline_pimpl; 12 | 13 | //! schedule a deadline to interrupt task with 14 | //! deadline_reached exception after given time 15 | class deadline { 16 | private: 17 | std::unique_ptr _pimpl; 18 | void _set_deadline(kernel::duration dur); 19 | public: 20 | deadline(optional_timeout timeout); 21 | deadline(std::chrono::milliseconds ms); // deprecated 22 | 23 | deadline(const deadline &) = delete; 24 | deadline &operator =(const deadline &) = delete; 25 | 26 | //! milliseconds remaining on the deadline 27 | optional_timeout remaining() const; 28 | 29 | //! cancel the deadline 30 | void cancel(); 31 | 32 | ~deadline(); 33 | }; 34 | 35 | } // ten 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/ten/task/kernel.hh: -------------------------------------------------------------------------------- 1 | #ifndef TEN_KERNEL_HH 2 | #define TEN_KERNEL_HH 3 | 4 | #include "ten/ptr.hh" 5 | #include "ten/optional.hh" 6 | #include 7 | 8 | namespace ten { 9 | 10 | class kernel { 11 | public: 12 | using clock = std::chrono::steady_clock; 13 | using time_point = clock::time_point; 14 | using duration = clock::duration; 15 | 16 | //! return cached time from event loop, not precise 17 | static time_point now(); 18 | 19 | //! is this the main thread? 20 | static bool is_main_thread(); 21 | 22 | //! number of available cpus 23 | static size_t cpu_count(); 24 | 25 | //! perform setup 26 | static void boot(); 27 | 28 | //! wait for all tasks 29 | static void wait_for_tasks(); 30 | 31 | //! perform clean shutdown 32 | static void shutdown(); 33 | 34 | //! this is only a tribute 35 | static int32_t is_computer_on(); 36 | static double is_computer_on_fire(); 37 | 38 | kernel(optional stacksize=nullopt); 39 | ~kernel(); 40 | }; 41 | 42 | } // ten 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/ten/task/qutex.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_TASK_QUTEX_HH 2 | #define LIBTEN_TASK_QUTEX_HH 3 | 4 | #include "ten/task.hh" 5 | #include "ten/ptr.hh" 6 | #include 7 | #include 8 | 9 | namespace ten { 10 | 11 | //! task aware mutex 12 | class qutex { 13 | private: 14 | std::mutex _m; 15 | std::deque> _waiting; 16 | ptr _owner; 17 | 18 | void unlock_or_giveup(std::lock_guard &lk) noexcept; 19 | public: 20 | enum lock_type_t { interruptable_lock, safe_lock }; 21 | 22 | qutex() : _owner(nullptr) { 23 | // a simple memory barrier would be sufficient here 24 | std::unique_lock lk(_m); 25 | } 26 | qutex(const qutex &) = delete; 27 | qutex &operator =(const qutex &) = delete; 28 | 29 | ~qutex() {} 30 | 31 | void lock(lock_type_t lt = interruptable_lock); 32 | void unlock(); 33 | bool try_lock(); 34 | }; 35 | 36 | // almost surely, Mutex = qutex 37 | template 38 | class safe_lock { 39 | Mutex &_mut; 40 | 41 | public: 42 | safe_lock(Mutex &mut) noexcept : _mut(mut) { 43 | _mut.lock(qutex::safe_lock); 44 | } 45 | ~safe_lock() noexcept { 46 | _mut.unlock(); 47 | } 48 | 49 | //! no copy (and no move) 50 | safe_lock(const safe_lock &) = delete; 51 | safe_lock & operator = (const safe_lock &) = delete; 52 | }; 53 | 54 | } // namespace 55 | 56 | #endif // LIBTEN_TASK_QUTEX_HH 57 | -------------------------------------------------------------------------------- /include/ten/task/rendez.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_TASK_RENDEZ_HH 2 | #define LIBTEN_TASK_RENDEZ_HH 3 | 4 | #include "ten/task/qutex.hh" 5 | 6 | namespace ten { 7 | 8 | //! task aware condition rendezvous point 9 | class rendez { 10 | private: 11 | std::mutex _m; 12 | std::deque> _waiting; 13 | public: 14 | rendez() {} 15 | rendez(const rendez &) = delete; 16 | rendez &operator =(const rendez &) = delete; 17 | 18 | ~rendez(); 19 | 20 | void sleep(std::unique_lock &lk); 21 | 22 | template 23 | void sleep(std::unique_lock &lk, Predicate pred) { 24 | while (!pred()) { 25 | sleep(lk); 26 | } 27 | } 28 | 29 | void wakeup(); 30 | void wakeupall(); 31 | }; 32 | 33 | } // namespace 34 | 35 | #endif // LIBTEN_TASK_RENDEZ_HH 36 | -------------------------------------------------------------------------------- /include/ten/term.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_TERM_HH 2 | #define LIBTEN_TERM_HH 3 | 4 | namespace ten { 5 | 6 | unsigned terminal_width(); 7 | 8 | } // ten 9 | 10 | #endif // LIBTEN_TERM_HH 11 | -------------------------------------------------------------------------------- /include/ten/thread_guard.hh: -------------------------------------------------------------------------------- 1 | #ifndef TEN_THREAD_GUARD_HH 2 | #define TEN_THREAD_GUARD_HH 3 | 4 | #include 5 | #include 6 | 7 | namespace ten { 8 | 9 | //! wrapper that calls join on joinable threads in the destructor 10 | class thread_guard { 11 | private: 12 | std::thread _thread; 13 | public: 14 | template 15 | thread_guard(Args&&... args) : _thread{std::forward(args)...} {} 16 | 17 | thread_guard(std::thread t) : _thread{std::move(t)} {} 18 | thread_guard() {} 19 | thread_guard(const thread_guard &) = delete; 20 | thread_guard &operator =(const thread_guard &) = delete; 21 | thread_guard(thread_guard &&other) { 22 | if (this != &other) { 23 | std::swap(_thread, other._thread); 24 | } 25 | } 26 | thread_guard &operator=(thread_guard &&other) { 27 | if (this != &other) { 28 | std::swap(_thread, other._thread); 29 | } 30 | return *this; 31 | } 32 | 33 | ~thread_guard() { 34 | try { 35 | if (_thread.joinable()) { 36 | _thread.join(); 37 | } 38 | } catch (std::system_error &e) { 39 | } 40 | } 41 | }; 42 | 43 | } // ten 44 | 45 | #endif // TEN_THREAD_GUARD_HH 46 | 47 | -------------------------------------------------------------------------------- /include/ten/thread_local.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_THREAD_LOCAL_HH 2 | #define LIBTEN_THREAD_LOCAL_HH 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace ten { 11 | 12 | // TODO: use kernel::is_main_thread after default_stacksize is gone 13 | inline bool is_main_thread() noexcept { 14 | return getpid() == syscall(SYS_gettid); 15 | } 16 | 17 | //! thread local storage because thread_local keyword isn't well supported yet 18 | template 19 | class thread_cached { 20 | private: 21 | struct holder { 22 | bool *allocated; 23 | void *ptr; 24 | }; 25 | 26 | typedef typename std::aligned_storage::value>::type storage_type; 28 | 29 | static void thread_cleanup(void *v) { 30 | std::unique_ptr h{static_cast(v)}; 31 | placement_delete(h.get()); 32 | } 33 | 34 | static void placement_delete(holder *h) { 35 | static_cast(h->ptr)->~T(); 36 | *(h->allocated) = false; 37 | } 38 | 39 | // only used by main thread 40 | // other threads will use heap allocated holder 41 | // and do cleanup in thread_cleanup 42 | struct holder _main_holder = {}; 43 | public: 44 | ~thread_cached() { 45 | if (_main_holder.allocated && *_main_holder.allocated) { 46 | placement_delete(&_main_holder); 47 | } 48 | } 49 | 50 | T *get() { 51 | static __thread bool allocated = false; 52 | static __thread storage_type storage; 53 | if (!allocated) { 54 | new (&storage) T(); 55 | allocated = true; 56 | if (is_main_thread()) { 57 | _main_holder.allocated = &allocated; 58 | _main_holder.ptr = &storage; 59 | } else { 60 | static pthread_key_t key; 61 | pthread_key_create(&key, thread_cached::thread_cleanup); 62 | std::unique_ptr hp{new holder{&allocated, &storage}}; 63 | pthread_setspecific(key, hp.release()); 64 | } 65 | } 66 | return reinterpret_cast(&storage); 67 | } 68 | 69 | T &operator* () { 70 | return *get(); 71 | } 72 | 73 | T *operator-> () { 74 | return get(); 75 | } 76 | }; 77 | 78 | } // ten 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /include/ten/zip.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_ZIP_HH 2 | #define LIBTEN_ZIP_HH 3 | 4 | #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES 1 5 | #define MINIZ_HEADER_FILE_ONLY 1 6 | #include "bits/miniz.c" 7 | #undef MINIZ_HEADER_FILE_ONLY 8 | 9 | #include "ten/logging.hh" 10 | #include "ten/error.hh" 11 | #include 12 | #include 13 | 14 | namespace ten { 15 | 16 | //! read a zip archive 17 | struct zip_reader { 18 | mz_zip_archive arc; 19 | 20 | zip_reader(const void *buf, size_t len) { 21 | memset(&arc, 0, sizeof(mz_zip_archive)); 22 | if (!mz_zip_reader_init_mem(&arc, buf, len, 0)) { 23 | throw errorx("mz_zip_reader_init_mem"); 24 | } 25 | } 26 | 27 | int begin() { return 0; } 28 | int end() { return mz_zip_reader_get_num_files(&arc); } 29 | 30 | 31 | bool stat(int file_index, mz_zip_archive_file_stat &file_stat) { 32 | return mz_zip_reader_file_stat(&arc, file_index, &file_stat); 33 | } 34 | std::string extract(int index, mz_uint flags=0); 35 | std::string extract(const std::string &file_name, mz_uint flags=0); 36 | 37 | ~zip_reader() { 38 | CHECK(mz_zip_reader_end(&arc)); 39 | } 40 | }; 41 | 42 | 43 | //! write a zip archive 44 | struct zip_writer { 45 | mz_zip_archive arc; 46 | 47 | zip_writer(size_t reserve) { 48 | memset(&arc, 0, sizeof(mz_zip_archive)); 49 | if (!mz_zip_writer_init_heap(&arc, reserve, reserve)) { 50 | throw errorx("mz_zip_writer_init_heap"); 51 | } 52 | } 53 | 54 | void add(const std::string &name, const void *buf, size_t len, 55 | mz_uint level = 7, mz_uint flags = MZ_ZIP_FLAG_COMPRESSED_DATA) 56 | { 57 | if (!mz_zip_writer_add_mem(&arc, name.c_str(), buf, len, level & flags)) { 58 | throw errorx("mz_zip_writer_add_mem"); 59 | } 60 | } 61 | 62 | std::unique_ptr finalize(size_t &len) { 63 | void *buf = 0; 64 | if (!mz_zip_writer_finalize_heap_archive(&arc, &buf, &len)) { 65 | throw errorx("mz_zip_writer_finalize_heap_archive"); 66 | } 67 | return std::unique_ptr(buf, free); 68 | } 69 | 70 | ~zip_writer() { 71 | CHECK(mz_zip_writer_end(&arc)); 72 | } 73 | 74 | }; 75 | 76 | } // end namespace ten 77 | 78 | #endif // LIBTEN_ZIP_HH 79 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (CMAKE_BUILD_TYPE STREQUAL "Release") 2 | ragel_gen(uri_parser -G2) 3 | else (CMAKE_BUILD_TYPE STREQUAL "Release") 4 | ragel_gen(uri_parser) 5 | endif (CMAKE_BUILD_TYPE STREQUAL "Release") 6 | -------------------------------------------------------------------------------- /src/chrono_io.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/chrono_io" 2 | 3 | namespace std 4 | { 5 | namespace chrono 6 | { 7 | 8 | locale::id durationpunct::id; 9 | template <> locale::id timepunct::id; 10 | template <> locale::id timepunct::id; 11 | template <> locale::id timepunct::id; 12 | template <> locale::id timepunct::id; 13 | 14 | } // chrono 15 | 16 | } // std 17 | -------------------------------------------------------------------------------- /src/compat.cc: -------------------------------------------------------------------------------- 1 | #include "thread_context.hh" 2 | 3 | namespace ten { 4 | 5 | bool fdwait(int fd, int rw, optional_timeout ms) { 6 | task::impl::cancellation_point cancellable; 7 | return this_ctx->scheduler.get_io().fdwait(fd, rw, ms); 8 | } 9 | 10 | int taskpoll(pollfd *fds, nfds_t nfds, optional_timeout ms) { 11 | task::impl::cancellation_point cancellable; 12 | return this_ctx->scheduler.get_io().poll(fds, nfds, ms); 13 | } 14 | 15 | const char *taskname(const char *fmt, ...) 16 | { 17 | const auto t = scheduler::current_task(); 18 | if (fmt && strlen(fmt)) { 19 | va_list arg; 20 | va_start(arg, fmt); 21 | t->vsetname(fmt, arg); 22 | va_end(arg); 23 | } 24 | return t->getname(); 25 | } 26 | 27 | const char *taskstate(const char *fmt, ...) 28 | { 29 | const auto t = scheduler::current_task(); 30 | if (fmt && strlen(fmt)) { 31 | va_list arg; 32 | va_start(arg, fmt); 33 | t->vsetstate(fmt, arg); 34 | va_end(arg); 35 | } 36 | return t->getstate(); 37 | } 38 | 39 | void taskdump() { 40 | thread_context::dump_all(); 41 | } 42 | 43 | } // ten 44 | -------------------------------------------------------------------------------- /src/context.cc: -------------------------------------------------------------------------------- 1 | #include "context.hh" 2 | 3 | namespace ten { 4 | 5 | context::context() noexcept : _ctx{_os_ctx.get()} {} 6 | 7 | //! make a new context and stack 8 | context::context(func_type f, size_t stack_size) { 9 | void *stack = stack_allocator::allocate(stack_size); 10 | #ifndef NVALGRIND 11 | valgrind_stack_id = 12 | VALGRIND_STACK_REGISTER(stack, reinterpret_cast(stack)-stack_size); 13 | #endif 14 | 15 | #if BOOST_VERSION == 105100 16 | _ctx = new ctx::fcontext_t(); 17 | _ctx->fc_stack.base = stack; 18 | _ctx->fc_stack.limit = reinterpret_cast(reinterpret_cast(stack)-stack_size); 19 | ctx::make_fcontext(_ctx, f); 20 | #elif BOOST_VERSION >= 105200 21 | _ctx = ctx::make_fcontext(stack, stack_size, f); 22 | #endif 23 | } 24 | 25 | context::~context() { 26 | #if BOOST_VERSION == 105100 27 | if (_ctx->fc_stack.base) { 28 | void *stack = _ctx->fc_stack.base; 29 | #ifndef NVALGRIND 30 | VALGRIND_STACK_DEREGISTER(valgrind_stack_id); 31 | #endif 32 | stack_allocator::deallocate(stack, stack_size()); 33 | delete _ctx; 34 | } 35 | 36 | #elif BOOST_VERSION >= 105200 37 | if (_ctx->fc_stack.sp) { 38 | void *stack = _ctx->fc_stack.sp; 39 | #ifndef NVALGRIND 40 | VALGRIND_STACK_DEREGISTER(valgrind_stack_id); 41 | #endif 42 | stack_allocator::deallocate(stack, stack_size()); 43 | } 44 | #endif 45 | } 46 | 47 | intptr_t context::swap(context &other, intptr_t arg) noexcept { 48 | return ctx::jump_fcontext(_ctx, 49 | other._ctx, 50 | arg); 51 | } 52 | 53 | size_t context::stack_size() const { 54 | #if BOOST_VERSION == 105100 55 | return reinterpret_cast(_ctx->fc_stack.base) - 56 | reinterpret_cast(_ctx->fc_stack.limit); 57 | #elif BOOST_VERSION >= 105200 58 | return _ctx->fc_stack.size; 59 | #endif 60 | } 61 | 62 | } // ten 63 | -------------------------------------------------------------------------------- /src/context.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_TASK_CONTEXT_HH 2 | #define LIBTEN_TASK_CONTEXT_HH 3 | 4 | #include "stack_alloc.hh" 5 | #include "ten/thread_local.hh" 6 | #include 7 | 8 | #if BOOST_VERSION == 105100 9 | #include 10 | #include 11 | namespace ctx = boost::ctx; 12 | #elif BOOST_VERSION >= 105200 13 | #include 14 | namespace ctx = boost::context; 15 | #endif 16 | 17 | #ifndef NVALGRIND 18 | #include 19 | #endif 20 | 21 | namespace ten { 22 | 23 | class context { 24 | private: 25 | struct os_fctx; 26 | // XXX: defined in thread_context.cc for global ordering 27 | static thread_cached _os_ctx; 28 | ctx::fcontext_t *_ctx; 29 | #ifndef NVALGRIND 30 | //! stack id so valgrind doesn't freak when stack swapping happens 31 | int valgrind_stack_id; 32 | #endif 33 | public: 34 | typedef void (*func_type)(intptr_t); 35 | public: 36 | context(const context &) = delete; 37 | context(const context &&) = delete; 38 | 39 | //! make context for existing stack 40 | context() noexcept; 41 | 42 | //! make a new context and stack 43 | explicit context(func_type f, size_t stack_size); 44 | 45 | intptr_t swap(context &other, intptr_t arg=0) noexcept; 46 | 47 | size_t stack_size() const; 48 | 49 | ~context(); 50 | }; 51 | 52 | } // ten 53 | 54 | #endif 55 | 56 | -------------------------------------------------------------------------------- /src/deadline.cc: -------------------------------------------------------------------------------- 1 | #include "ten/task.hh" 2 | #include "thread_context.hh" 3 | #include 4 | 5 | namespace ten { 6 | 7 | struct deadline_pimpl { 8 | scheduler::alarm_clock::scoped_alarm alarm; 9 | }; 10 | 11 | deadline::deadline(optional_timeout timeout) { 12 | if (timeout) { 13 | if (timeout->count() == 0) 14 | throw errorx("zero optional_deadline - misuse of optional"); 15 | _set_deadline(*timeout); 16 | } 17 | } 18 | 19 | deadline::deadline(milliseconds ms) { 20 | _set_deadline(ms); 21 | } 22 | 23 | void deadline::_set_deadline(kernel::duration dur) { 24 | if (dur.count() < 0) 25 | throw_stream() << "negative deadline: " << dur << endx; 26 | if (dur.count() > 0) { 27 | const auto t = scheduler::current_task(); 28 | auto now = kernel::now(); 29 | _pimpl.reset(new deadline_pimpl{ 30 | this_ctx->scheduler.arm_alarm(t, now + dur, deadline_reached{}) 31 | }); 32 | DVLOG(5) << "deadline alarm armed: " << _pimpl->alarm._armed << " in " << dur; 33 | } 34 | } 35 | 36 | void deadline::cancel() { 37 | if (_pimpl) { 38 | _pimpl->alarm.cancel(); 39 | } 40 | } 41 | 42 | deadline::~deadline() { 43 | cancel(); 44 | } 45 | 46 | optional_timeout deadline::remaining() const { 47 | if (_pimpl) { 48 | // TODO: define optional_timeout in terms of kernel::duration, so this is not lossy 49 | return duration_cast(_pimpl->alarm.remaining()); 50 | } 51 | return nullopt; 52 | } 53 | 54 | } // ten 55 | -------------------------------------------------------------------------------- /src/io.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_IO_HH 2 | #define LIBTEN_IO_HH 3 | 4 | #include "task_impl.hh" 5 | #include "ten/descriptors.hh" 6 | 7 | namespace ten { 8 | 9 | class io { 10 | private: 11 | struct task_poll_state { 12 | ptr t; 13 | pollfd *pfd; 14 | 15 | task_poll_state(ptr t_, pollfd *pfd_) 16 | : t{t_}, pfd{pfd_} {} 17 | }; 18 | 19 | struct fd_poll_state { 20 | std::vector tasks; 21 | uint32_t events = 0; // events this fd is registered for 22 | }; 23 | 24 | typedef std::vector fd_array; 25 | typedef std::vector event_vector; 26 | private: 27 | //! array of tasks waiting on fds, indexed by the fd for speedy lookup 28 | fd_array _pollfds; 29 | //! epoll events 30 | event_vector _events; 31 | //! using for breaking out of epoll 32 | event_fd _evfd; 33 | //! timerfd used for breaking epoll_wait for timeouts 34 | // required because the timeout value for epoll_wait is not accurate 35 | timer_fd _tfd; 36 | //! the epoll fd used for io in this runner 37 | epoll_fd _efd; 38 | //! number of fds we've been asked to wait on 39 | size_t _npollfds = 0; 40 | private: 41 | void add_pollfds(ptr t, pollfd *fds, nfds_t nfds); 42 | int remove_pollfds(pollfd *fds, nfds_t nfds); 43 | public: 44 | io(); 45 | 46 | bool fdwait(int fd, int rw, optional_timeout ms); 47 | int poll(pollfd *fds, nfds_t nfds, optional_timeout ms); 48 | 49 | void wakeup(); 50 | void wait(optional when); 51 | }; 52 | 53 | } // end namespace ten 54 | 55 | #endif // LIBTEN_IO_HH 56 | -------------------------------------------------------------------------------- /src/ioproc.cc: -------------------------------------------------------------------------------- 1 | #include "ten/ioproc.hh" 2 | #include "ten/logging.hh" 3 | 4 | namespace ten { 5 | 6 | void ioproctask(iochannel &ch) { 7 | taskname("ioproctask"); 8 | for (;;) { 9 | std::unique_ptr call; 10 | try { 11 | taskstate("waiting for recv"); 12 | call = ch.recv(); 13 | } catch (channel_closed_error &e) { 14 | taskstate("recv channel closed"); 15 | break; 16 | } 17 | if (!call) break; 18 | if (call->ch.is_closed()) { 19 | DVLOG(5) << "ioproc reply channel closed. not doing work."; 20 | continue; 21 | } 22 | taskstate("executing call"); 23 | errno = 0; 24 | try { 25 | DVLOG(5) << "ioproc calling op"; 26 | call->ret = call->op(); 27 | call->op = 0; 28 | } catch (std::exception &e) { 29 | DVLOG(5) << "ioproc caught exception: " << e.what(); 30 | call->exception = std::current_exception(); 31 | } 32 | 33 | // scope for reply iochannel 34 | { 35 | DVLOG(5) << "sending reply"; 36 | iochannel creply = call->ch; 37 | taskstate("sending reply"); 38 | try { 39 | creply.send(std::move(call)); 40 | } catch (channel_closed_error &e) { 41 | // ignore this 42 | } 43 | DVLOG(5) << "done sending reply"; 44 | } 45 | } 46 | DVLOG(5) << "exiting ioproc"; 47 | } 48 | 49 | 50 | } // end namespace ten 51 | -------------------------------------------------------------------------------- /src/jsonstream.cc: -------------------------------------------------------------------------------- 1 | #include "ten/jsonstream.hh" 2 | #include "ten/logging.hh" 3 | #include "double-conversion.h" 4 | 5 | namespace ten { 6 | 7 | std::string jsonstream::double_to_string(double val) { 8 | using ::double_conversion::DoubleToStringConverter; 9 | using ::double_conversion::StringBuilder; 10 | constexpr char infinity_symbol[] = "null"; 11 | constexpr char nan_symbol[] = "null"; 12 | constexpr char exponent_symbol = 'e'; 13 | 14 | DoubleToStringConverter conv( 15 | DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN | 16 | DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT | 17 | DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT | 18 | DoubleToStringConverter::UNIQUE_ZERO, 19 | infinity_symbol, 20 | nan_symbol, 21 | exponent_symbol, 22 | -6, 21, 23 | 0, 0); 24 | 25 | char buf[128]; 26 | StringBuilder builder(buf, sizeof(buf)); 27 | conv.ToShortest(val, &builder); 28 | DCHECK_GT(builder.position(), 0); 29 | builder.Finalize(); 30 | return buf; 31 | } 32 | 33 | std::string jsonstream::float_to_string(float val) { 34 | using ::double_conversion::DoubleToStringConverter; 35 | using ::double_conversion::StringBuilder; 36 | constexpr char infinity_symbol[] = "null"; 37 | constexpr char nan_symbol[] = "null"; 38 | constexpr char exponent_symbol = 'e'; 39 | 40 | DoubleToStringConverter conv( 41 | DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN | 42 | DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT | 43 | DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT | 44 | DoubleToStringConverter::UNIQUE_ZERO, 45 | infinity_symbol, 46 | nan_symbol, 47 | exponent_symbol, 48 | -6, 21, 49 | 0, 0); 50 | 51 | char buf[128]; 52 | StringBuilder builder(buf, sizeof(buf)); 53 | conv.ToShortestSingle(val, &builder); 54 | DCHECK_GT(builder.position(), 0); 55 | builder.Finalize(); 56 | return buf; 57 | } 58 | 59 | } // ten 60 | 61 | -------------------------------------------------------------------------------- /src/kernel.cc: -------------------------------------------------------------------------------- 1 | #include "thread_context.hh" 2 | #include 3 | 4 | namespace ten { 5 | 6 | bool glog_inited; 7 | 8 | namespace { 9 | std::once_flag boot_flag; 10 | void *signal_stack; // for valgrind 11 | } 12 | 13 | static void kernel_boot() { 14 | CHECK(kernel::is_main_thread()) << "must call in main thread before anything else"; 15 | 16 | InitGoogleLogging(program_invocation_short_name); 17 | glog_inited = true; 18 | 19 | // default to logging everything to stderr only. 20 | // ten::application turns this off again in favor of finer control. 21 | FLAGS_logtostderr = true; 22 | 23 | signal_stack = calloc(1, SIGSTKSZ); 24 | #ifndef NVALGRIND 25 | (void)VALGRIND_STACK_REGISTER(static_cast(signal_stack) + SIGSTKSZ, signal_stack); 26 | #endif 27 | stack_t ss; 28 | ss.ss_sp = signal_stack; 29 | ss.ss_size = SIGSTKSZ; 30 | ss.ss_flags = 0; 31 | throw_if(sigaltstack(&ss, NULL) == -1); 32 | 33 | InstallFailureSignalHandler(); 34 | 35 | struct sigaction act; 36 | 37 | // ignore SIGPIPE 38 | memset(&act, 0, sizeof(act)); 39 | throw_if(sigaction(SIGPIPE, NULL, &act) == -1); 40 | if (act.sa_handler == SIG_DFL) { 41 | act.sa_handler = SIG_IGN; 42 | throw_if(sigaction(SIGPIPE, &act, NULL) == -1); 43 | } 44 | 45 | netinit(); 46 | } 47 | 48 | kernel::time_point kernel::now() { 49 | return this_ctx->scheduler._now; 50 | } 51 | 52 | bool kernel::is_main_thread() { 53 | // TODO: could cache this in thread_context 54 | return getpid() == syscall(SYS_gettid); 55 | } 56 | 57 | size_t kernel::cpu_count() { 58 | return sysconf(_SC_NPROCESSORS_ONLN); 59 | } 60 | 61 | void kernel::shutdown() { 62 | this_ctx->cancel_all(); 63 | } 64 | 65 | int32_t kernel::is_computer_on() { return 1; } 66 | 67 | double kernel::is_computer_on_fire() { 68 | // TODO: implement 69 | return 7.0; 70 | } 71 | 72 | void kernel::boot() { 73 | std::call_once(boot_flag, kernel_boot); 74 | } 75 | 76 | void kernel::wait_for_tasks() { 77 | this_ctx->scheduler.wait_for_all(); 78 | } 79 | 80 | kernel::kernel(optional stacksize) { 81 | if (stacksize) { 82 | CHECK(*stacksize >= stack_allocator::min_stacksize); 83 | (void)stack_allocator::initialize(); // ensure static init done 84 | stack_allocator::default_stacksize = *stacksize; 85 | } 86 | boot(); 87 | } 88 | 89 | kernel::~kernel() { 90 | } 91 | 92 | } // ten 93 | 94 | -------------------------------------------------------------------------------- /src/stack_alloc.hh: -------------------------------------------------------------------------------- 1 | #ifndef LIBTEN_TASK_STACK_ALLOC_HH_ 2 | #define LIBTEN_TASK_STACK_ALLOC_HH_ 3 | 4 | #include 5 | 6 | namespace ten { 7 | 8 | struct bad_stack_alloc : std::bad_alloc { 9 | const char *what() const noexcept override { 10 | return "ten::bad_stack_alloc"; 11 | } 12 | }; 13 | 14 | namespace stack_allocator { 15 | constexpr size_t page_size = 4096; 16 | constexpr size_t min_stacksize = page_size * 2; 17 | 18 | extern size_t default_stacksize; 19 | 20 | int initialize(); 21 | 22 | void *allocate(size_t stack_size); 23 | void deallocate(void *stack_end, size_t stack_size) noexcept; 24 | }; 25 | 26 | } // ten 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/task_impl.hh: -------------------------------------------------------------------------------- 1 | #ifndef TASK_PRIVATE_HH 2 | #define TASK_PRIVATE_HH 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "ten/task.hh" 9 | #include "ten/logging.hh" 10 | #include "ten/error.hh" 11 | #include "ten/ptr.hh" 12 | #include "ten/synchronized.hh" 13 | #include "context.hh" 14 | 15 | using namespace std::chrono; 16 | 17 | namespace ten { 18 | 19 | class scheduler; 20 | 21 | void taskdumpf(FILE *of = stderr); 22 | 23 | class task::impl { 24 | friend class scheduler; 25 | friend std::ostream &operator << (std::ostream &o, ptr t); 26 | private: 27 | static constexpr size_t namesize = 16; 28 | static constexpr size_t statesize = 32; 29 | public: 30 | struct cancellation_point { 31 | cancellation_point(); 32 | ~cancellation_point(); 33 | }; 34 | private: 35 | // order is important here 36 | // to get most used in the first cache line 37 | context _ctx; 38 | ptr _scheduler; 39 | std::exception_ptr _exception; 40 | uint64_t _cancel_points; 41 | struct auxinfo { char name[namesize]; char state[statesize]; }; 42 | std::unique_ptr _aux; 43 | #ifdef TEN_TASK_TRACE 44 | saved_backtrace _trace; 45 | #endif 46 | const uint64_t _id; 47 | std::function _fn; 48 | std::atomic _ready; 49 | std::atomic _canceled; 50 | struct joininfo { 51 | bool finished = false; 52 | ptr joiner; 53 | }; 54 | synchronized _join; 55 | public: 56 | impl(); 57 | impl(std::function f, size_t stacksize); 58 | 59 | void setname(const char *fmt, ...) __attribute__((format (printf, 2, 3))); 60 | void vsetname(const char *fmt, va_list arg); 61 | void setstate(const char *fmt, ...) __attribute__((format (printf, 2, 3))); 62 | void vsetstate(const char *fmt, va_list arg); 63 | 64 | const char *getname() const { return _aux->name; } 65 | const char *getstate() const { return _aux->state; } 66 | 67 | void ready(bool front=false); 68 | void ready_for_io(); 69 | 70 | void safe_swap() noexcept; 71 | void swap(); 72 | 73 | void yield(); 74 | 75 | void cancel(); 76 | bool cancelable() const; 77 | 78 | uint64_t get_id() const { return _id; } 79 | 80 | void join() noexcept; 81 | private: 82 | static void trampoline(intptr_t arg); 83 | void check_canceled(); 84 | }; 85 | 86 | std::ostream &operator << (std::ostream &o, ptr t); 87 | 88 | } // end namespace ten 89 | 90 | #endif // TASK_PRIVATE_HH 91 | 92 | -------------------------------------------------------------------------------- /src/term.cc: -------------------------------------------------------------------------------- 1 | #include "ten/term.hh" 2 | #include 3 | 4 | namespace ten { 5 | 6 | unsigned terminal_width() { 7 | #ifdef TIOCGWINSZ 8 | winsize sz; 9 | if (ioctl(2, TIOCGWINSZ, &sz) == 0 && sz.ws_col) 10 | return sz.ws_col; 11 | #endif 12 | return 80; 13 | } 14 | 15 | } // ten 16 | -------------------------------------------------------------------------------- /src/thread_context.cc: -------------------------------------------------------------------------------- 1 | #include "thread_context.hh" 2 | #include "ten/synchronized.hh" 3 | 4 | namespace ten { 5 | 6 | // ** begin global ordering ** 7 | // XXX: order of these globals is important 8 | // threads and cache are potentially used by 9 | // ~thread_context because of scheduler 10 | // so they must be declared *before* this_ctx 11 | extern bool glog_inited; 12 | 13 | namespace { 14 | struct stoplog_t { 15 | ~stoplog_t() { if (glog_inited) ShutdownGoogleLogging(); } 16 | } stoplog; 17 | 18 | using tvec_t = std::vector>; 19 | static synchronized threads; 20 | 21 | int dummy = stack_allocator::initialize(); 22 | } // anon namespace 23 | 24 | thread_cached context::_os_ctx; 25 | inotify_fd resolv_conf_watch_fd{IN_NONBLOCK}; 26 | __thread thread_context *this_ctx = nullptr; 27 | // *** end global ordering ** 28 | 29 | thread_context::thread_context() { 30 | CHECK(this_ctx == nullptr); 31 | this_ctx = this; 32 | const ptr me(this); 33 | threads([me](tvec_t &tvec) { 34 | tvec.push_back(me); 35 | }); 36 | } 37 | 38 | thread_context::~thread_context() { 39 | scheduler.wait_for_all(); 40 | const ptr me(this); 41 | threads([me](tvec_t &tvec) { 42 | auto i = find(begin(tvec), end(tvec), me); 43 | if (i == end(tvec)) 44 | LOG(FATAL) << "BUG: thread " << (void*)me.get() << " escaped the thread list"; 45 | tvec.erase(i); 46 | }); 47 | this_ctx = nullptr; 48 | } 49 | 50 | size_t thread_context::count() { 51 | return threads([](const tvec_t &tvec) { 52 | return tvec.size(); 53 | }); 54 | } 55 | 56 | void thread_context::cancel_all() { 57 | threads([](const tvec_t &tvec) { 58 | for (auto &ctx : tvec) { 59 | ctx->scheduler.cancel(); 60 | } 61 | }); 62 | } 63 | 64 | void thread_context::dump_all() { 65 | threads([](const tvec_t &tvec) { 66 | for (auto &ctx : tvec) { 67 | ctx->scheduler.dump(); 68 | } 69 | }); 70 | } 71 | 72 | } // ten 73 | -------------------------------------------------------------------------------- /src/thread_context.hh: -------------------------------------------------------------------------------- 1 | #ifndef TEN_THREAD_CONTEXT_HH 2 | #define TEN_THREAD_CONTEXT_HH 3 | #include "scheduler.hh" 4 | #include 5 | 6 | namespace ten { 7 | 8 | //! per-thread context for runtime 9 | struct thread_context { 10 | // XXX: the downside to having one ares_channel per thread 11 | // is that if resolv.conf ever changes we won't see the changes 12 | // because c-ares only reads it when ares_init is called. 13 | // we address this by using an inotify watch on /etc/resolv.conf 14 | // and reset the shared_ptr on changes 15 | 16 | // ensure this is freed *after* scheduler 17 | // so all tasks will have exited 18 | std::shared_ptr dns_channel; 19 | 20 | ten::scheduler scheduler; 21 | 22 | thread_context(); 23 | ~thread_context(); 24 | 25 | void cancel_all(); 26 | 27 | 28 | static void dump_all(); 29 | static size_t count(); 30 | }; 31 | 32 | extern __thread thread_context *this_ctx; 33 | 34 | } // ten 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/zip.cc: -------------------------------------------------------------------------------- 1 | #include "ten/zip.hh" 2 | 3 | #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES 1 4 | #include "ten/bits/miniz.c" 5 | 6 | namespace ten { 7 | 8 | std::string zip_reader::extract(int file_index, mz_uint flags) { 9 | if (file_index < 0) { 10 | throw errorx("file not found"); 11 | } 12 | 13 | mz_uint64 comp_size, uncomp_size, alloc_size; 14 | const mz_uint8 *p = mz_zip_reader_get_cdh(&arc, file_index); 15 | if (!p) { 16 | throw errorx("mz_zip_reader_get_cdh"); 17 | } 18 | 19 | comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); 20 | uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); 21 | 22 | alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; 23 | 24 | std::string data; 25 | data.resize(alloc_size); 26 | 27 | if (!mz_zip_reader_extract_to_mem(&arc, file_index, (void *)data.data(), (size_t)alloc_size, flags)) { 28 | throw errorx("mz_zip_reader_extract_to_mem"); 29 | } 30 | 31 | return data; 32 | } 33 | 34 | std::string zip_reader::extract(const std::string &file_name, mz_uint flags) { 35 | int file_index = mz_zip_reader_locate_file(&arc, file_name.c_str(), NULL, flags); 36 | return extract(file_index, flags); 37 | } 38 | 39 | } // end namespace ten 40 | 41 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | include(${TEN_SOURCE_DIR}/cmake/ExternalProject.cmake) 3 | include(${TEN_SOURCE_DIR}/cmake/ParseArguments.cmake) 4 | 5 | if (TEN_SUBPROJECT) 6 | include(${TEN_SOURCE_DIR}/cmake/prog.cmake) 7 | endif () 8 | 9 | ExternalProject_Add(googletest 10 | SVN_REPOSITORY http://googletest.googlecode.com/svn/trunk 11 | # release 1.7.0 12 | SVN_REVISION -r664 13 | # Disable install 14 | INSTALL_COMMAND "" 15 | # Disable update 16 | UPDATE_COMMAND "" 17 | ) 18 | 19 | ExternalProject_Get_Property(googletest source_dir binary_dir) 20 | include_directories(${source_dir}/include) 21 | link_directories(${binary_dir}) 22 | 23 | function(add_gtest gtest_name) 24 | PARSE_ARGUMENTS(GTEST "LIBS" "" ${ARGN}) 25 | add_executable(${gtest_name} "${gtest_name}.cc") 26 | add_dependencies(${gtest_name} googletest) 27 | target_link_libraries(${gtest_name} gtest gtest_main ${GTEST_LIBS}) 28 | add_test(${gtest_name} ${gtest_name} --gtest_shuffle) 29 | endfunction(add_gtest) 30 | 31 | add_gtest(test_descriptors LIBS ten) 32 | add_gtest(test_task LIBS ten) 33 | add_gtest(test_channel LIBS ten) 34 | add_gtest(test_ioproc LIBS ten) 35 | add_gtest(test_backoff LIBS ten) 36 | add_gtest(test_zip LIBS ten) 37 | add_gtest(test_json LIBS ten jansson) 38 | add_gtest(test_buffer LIBS ten) 39 | add_gtest(test_qutex LIBS ten) 40 | add_gtest(test_net LIBS ten) 41 | add_gtest(test_http LIBS ten) 42 | add_gtest(test_uri LIBS ten) 43 | add_gtest(test_hash_ring LIBS ten) 44 | add_gtest(test_llqueue LIBS ten) 45 | add_gtest(test_thread_local LIBS ten) 46 | add_gtest(test_metrics LIBS ten jansson) 47 | add_gtest(test_mpmc_queue LIBS ten) 48 | add_gtest(test_mpsc_queue LIBS ten) 49 | add_gtest(test_striped LIBS ten) 50 | add_gtest(test_work_deque LIBS ten) 51 | 52 | -------------------------------------------------------------------------------- /tests/test_backoff.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/backoff.hh" 3 | #include "ten/logging.hh" 4 | #include 5 | 6 | using namespace ten; 7 | using namespace std::chrono; 8 | 9 | TEST(BackoffTest, Test1) { 10 | auto b = make_backoff(seconds{1}, seconds{60}); 11 | for (auto i=0; i<1000; ++i) { 12 | seconds delay = b.next_delay(); 13 | EXPECT_TRUE(delay.count() >= 1); 14 | EXPECT_TRUE(delay.count() <= 60); 15 | } 16 | } 17 | 18 | TEST(BackoffTest, TestMin) { 19 | auto b = make_backoff(milliseconds{1500}, seconds{60}, 2); 20 | for (int x = 0; x < 10; ++x) { 21 | auto delay = b.next_delay(); 22 | VLOG(1) << "delay = " << delay; 23 | EXPECT_TRUE(delay >= milliseconds{1500} && delay < seconds{60}); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tests/test_buffer.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/buffer.hh" 3 | 4 | using namespace ten; 5 | 6 | TEST(Buffer, Test1) { 7 | static std::vector aa(500, 0x41); 8 | static std::vector bb(1000, 0x42); 9 | EXPECT_TRUE(std::is_pod::value); 10 | 11 | buffer b{100}; 12 | b.reserve(1000); // force a realloc 13 | EXPECT_TRUE(b.end() - b.back() >= 1000); 14 | std::fill(b.back(), b.end(1000), 0x41); 15 | b.commit(1000); 16 | EXPECT_EQ(1000u, b.size()); 17 | b.remove(500); 18 | b.reserve(1000); 19 | EXPECT_TRUE(b.end() - b.back() >= 1000); 20 | EXPECT_TRUE(std::equal(b.front(), b.back(), aa.begin())); 21 | std::fill(b.front(), b.end(500), 0x42); 22 | b.commit(500); 23 | EXPECT_EQ(1000u, b.size()); 24 | EXPECT_TRUE(std::equal(b.front(), b.back(), bb.begin())); 25 | b.remove(500); 26 | b.reserve(1000); 27 | EXPECT_TRUE(b.end() - b.back() >= 1000); 28 | EXPECT_THROW(b.remove(20000), std::runtime_error); 29 | EXPECT_THROW(b.commit(20000), std::runtime_error); 30 | } 31 | 32 | TEST(Buffer, Test2) { 33 | // this is just to see if realloc is returning new pointers 34 | { 35 | buffer b{100000}; 36 | b.reserve(100001); 37 | } 38 | 39 | { 40 | buffer b{100000}; 41 | b.reserve(100001); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /tests/test_descriptors.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/descriptors.hh" 3 | 4 | using namespace ten; 5 | 6 | TEST(DescriptorTest, MoveTest) { 7 | fd_base fd1{0}; 8 | fd_base fd2{std::move(fd1)}; 9 | EXPECT_EQ(fd1.fd, -1); 10 | EXPECT_EQ(fd2.fd, 0); 11 | } 12 | 13 | TEST(DescriptorTest, SocketPairCXX11) { 14 | auto sp = socket_fd::pair(AF_UNIX, SOCK_STREAM); 15 | { 16 | char a = 1; 17 | EXPECT_EQ(sp.first.write(&a, 1), 1); 18 | EXPECT_EQ(sp.second.read(&a, 1), 1); 19 | EXPECT_EQ(a, 1); 20 | } 21 | } 22 | 23 | TEST(DescriptorTest, SocketPair) { 24 | int sv[2]; 25 | EXPECT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0); 26 | socket_fd sp1{sv[0]}; 27 | socket_fd sp2{sv[1]}; 28 | char a = 1; 29 | EXPECT_EQ(sp1.write(&a, 1), 1); 30 | EXPECT_EQ(sp2.read(&a, 1), 1); 31 | EXPECT_EQ(a, 1); 32 | } 33 | 34 | TEST(DescriptorTest, pipe_test) { 35 | char a = 1; 36 | pipe_fd pipe; 37 | EXPECT_EQ(pipe.write(&a, 1), 1); 38 | EXPECT_EQ(pipe.read(&a, 1), 1); 39 | EXPECT_EQ(a, 1); 40 | } 41 | 42 | 43 | TEST(DescriptorTest, timer_fd_test) { 44 | timer_fd t; 45 | itimerspec ts; 46 | itimerspec prev; 47 | memset(&ts, 0, sizeof(ts)); 48 | ts.it_value.tv_sec = 1; 49 | ts.it_value.tv_nsec = 50; 50 | t.settime(ts, prev); 51 | } 52 | 53 | TEST(DescriptorTest, socket_listen_test) { 54 | socket_fd s{AF_INET, SOCK_STREAM}; 55 | s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1); 56 | address addr{"0.0.0.0", 0}; 57 | s.bind(addr); 58 | s.listen(); 59 | } 60 | 61 | TEST(DescriptorTest, udp_socket_test) { 62 | socket_fd us{AF_INET, SOCK_DGRAM}; 63 | us.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1); 64 | address uaddr{"0.0.0.0", 0}; 65 | us.bind(uaddr); 66 | } 67 | 68 | TEST(DescriptorTest, signal_fd_test) { 69 | sigset_t sigset; 70 | sigemptyset(&sigset); 71 | sigaddset(&sigset, SIGINT); 72 | signal_fd sig{sigset}; 73 | } 74 | 75 | TEST(DescriptorTest, event_fd_test) { 76 | event_fd efd; 77 | efd.write(1); 78 | EXPECT_EQ(efd.read(), 1u); 79 | efd.write(1); 80 | efd.write(2); 81 | efd.write(3); 82 | EXPECT_EQ(efd.read(), (unsigned)(1+2+3)); 83 | } 84 | -------------------------------------------------------------------------------- /tests/test_hash_ring.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include 3 | #include "ten/consistent_hash.hh" 4 | #include "ten/logging.hh" 5 | 6 | using namespace ten; 7 | 8 | struct server { 9 | std::unordered_map cache; 10 | 11 | void put(const std::string &key, const std::string &value) { 12 | cache[key] = value; 13 | } 14 | 15 | std::string get(const std::string &key) const { 16 | std::string value; 17 | auto it = cache.find(key); 18 | if (it != cache.end()) { 19 | value = it->second; 20 | } 21 | return value; 22 | } 23 | }; 24 | 25 | static const std::map data = { 26 | {"zero", "0"}, 27 | {"one", "1"}, 28 | {"two", "2"}, 29 | {"three", "3"}, 30 | {"four", "4"}, 31 | {"five", "5"}, 32 | {"six", "6"}, 33 | {"seven", "7"}, 34 | {"eight", "8"}, 35 | {"nine", "9"}, 36 | {"ten", "10"}, 37 | }; 38 | 39 | TEST(HashRing, Basic) { 40 | std::unordered_map servers = { 41 | {"server1.example.com", server()}, 42 | {"server2.example.com", server()}, 43 | {"server3.example.com", server()}, 44 | }; 45 | 46 | hash_ring ring; 47 | for (auto it : servers) { 48 | ring.add(it.first); 49 | } 50 | 51 | for (auto it : data) { 52 | auto host = ring.get(it.first); 53 | VLOG(1) << "storing " << it.first << "=" << it.second << " on " << host; 54 | servers[host].put(it.first, it.second); 55 | } 56 | 57 | for (auto it : data) { 58 | auto h = ring.get(it.first); 59 | auto d = servers[h].get(it.first); 60 | EXPECT_EQ(it.second, d); 61 | } 62 | 63 | // remove a server 64 | EXPECT_EQ(3u, ring.remove("server3.example.com")); 65 | 66 | unsigned found = 0; 67 | for (auto it : data) { 68 | auto h = ring.get(it.first); 69 | auto d = servers[h].get(it.first); 70 | if (it.second == d) { 71 | ++found; 72 | } 73 | } 74 | // more than 30% of the keys should still be found 75 | // after removing one server 76 | EXPECT_TRUE(found / (float)data.size() > 0.30) 77 | << "Found " << found << " data size: " << data.size(); 78 | } 79 | 80 | TEST(HashRing, Remove) { 81 | hash_ring ring; 82 | ring.add("test1"); 83 | ring.add("test2"); 84 | ring.add("test3"); 85 | EXPECT_EQ(100u, ring.remove("test1")); 86 | EXPECT_EQ(100u, ring.remove("test3")); 87 | EXPECT_EQ(100u, ring.remove("test2")); 88 | } 89 | 90 | -------------------------------------------------------------------------------- /tests/test_ioproc.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/ioproc.hh" 3 | #include "ten/descriptors.hh" 4 | 5 | using namespace ten; 6 | 7 | static void ioproc_sleeper() { 8 | ioproc io; 9 | int ret = iocall(io, std::bind(usleep, 100)); 10 | EXPECT_EQ(ret, 0); 11 | } 12 | 13 | TEST(IoProc, Sleep) { 14 | task::main([] { 15 | task::spawn(ioproc_sleeper); 16 | }); 17 | } 18 | 19 | static void test_pool() { 20 | ioproc io{nostacksize, 4}; 21 | iochannel reply_chan; 22 | 23 | for (int i=0; i<4; ++i) { 24 | iocallasync(io, std::bind(usleep, 100), reply_chan); 25 | } 26 | 27 | for (int i=0; i<4; ++i) { 28 | int r = iowait(reply_chan); 29 | // usleep should return 0 30 | EXPECT_EQ(0, r); 31 | } 32 | } 33 | 34 | TEST(IoProc, ThreadPool) { 35 | task::main([] { 36 | task::spawn(test_pool); 37 | }); 38 | } 39 | 40 | static void fail() { 41 | throw std::runtime_error("fail has failed"); 42 | } 43 | 44 | static void ioproc_failure() { 45 | ioproc io; 46 | std::string errmsg; 47 | EXPECT_THROW(iocall(io, fail), std::runtime_error); 48 | } 49 | 50 | TEST(IoProc, Failure) { 51 | task::main([] { 52 | task::spawn(ioproc_failure); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /tests/test_llqueue.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/llqueue.hh" 3 | 4 | using namespace ten; 5 | 6 | TEST(LowLockQueue, Test) { 7 | llqueue q; 8 | q.push(20); 9 | q.push(21); 10 | q.push(22); 11 | q.push(23); 12 | intptr_t v = 0; 13 | ASSERT_TRUE(q.pop(v)); 14 | EXPECT_EQ(20, v); 15 | 16 | ASSERT_TRUE(q.pop(v)); 17 | EXPECT_EQ(21, v); 18 | 19 | ASSERT_TRUE(q.pop(v)); 20 | EXPECT_EQ(22, v); 21 | 22 | ASSERT_TRUE(q.pop(v)); 23 | EXPECT_EQ(23, v); 24 | 25 | ASSERT_TRUE(!q.pop(v)); 26 | } 27 | -------------------------------------------------------------------------------- /tests/test_mpmc_queue.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/mpmc_bounded_queue.hh" 3 | #include 4 | #include 5 | 6 | using namespace ten; 7 | using std::size_t; 8 | 9 | typedef mpmc_bounded_queue queue_t; 10 | 11 | static size_t const thread_count = 4; 12 | static size_t const batch_size = 1; 13 | static size_t const iter_count = 1000000; 14 | 15 | static void thread_func(queue_t &queue) { 16 | int data; 17 | 18 | for (size_t iter = 0; iter != iter_count; ++iter) { 19 | for (size_t i = 0; i != batch_size; i += 1) { 20 | while (!queue.enqueue(i)) { 21 | std::this_thread::yield(); 22 | } 23 | } 24 | for (size_t i = 0; i != batch_size; i += 1) { 25 | while (!queue.dequeue(data)) { 26 | std::this_thread::yield(); 27 | } 28 | } 29 | } 30 | } 31 | 32 | TEST(MPMCQueue, Test) { 33 | queue_t queue; 34 | 35 | std::array threads; 36 | for (size_t i = 0; i != thread_count; ++i) { 37 | threads[i] = std::move(std::thread( 38 | std::bind(thread_func, std::ref(queue)) 39 | )); 40 | } 41 | 42 | for (size_t i = 0; i != thread_count; ++i) { 43 | threads[i].join(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/test_mpsc_queue.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/mpsc_queue.hh" 3 | #include 4 | #include 5 | 6 | using namespace ten; 7 | 8 | TEST(MPSCQueue, Test) { 9 | mpsc_queue q; 10 | size_t batch_size = 1000000; 11 | size_t num_producers = 8; 12 | 13 | std::vector threads; 14 | 15 | auto producer = [&] { 16 | for (size_t i=0; i 3 | #include "ten/semaphore.hh" 4 | #include "ten/synchronized.hh" 5 | #include "ten/thread_guard.hh" 6 | #include "ten/task/rendez.hh" 7 | 8 | using namespace ten; 9 | 10 | struct state { 11 | qutex q; 12 | rendez r; 13 | int x; 14 | 15 | state() : x(0) {} 16 | }; 17 | 18 | void qlocker(std::shared_ptr st) { 19 | for (int i=0; i<1000; ++i) { 20 | std::unique_lock lk{st->q}; 21 | ++(st->x); 22 | } 23 | st->r.wakeup(); 24 | } 25 | 26 | bool is_done(int &x) { return x == 20*1000; } 27 | 28 | void qutex_task_spawn() { 29 | 30 | std::shared_ptr st = std::make_shared(); 31 | std::vector threads; 32 | for (int i=0; i<20; ++i) { 33 | threads.emplace_back(task::spawn_thread([=] { 34 | qlocker(st); 35 | })); 36 | this_task::yield(); 37 | } 38 | std::unique_lock lk{st->q}; 39 | st->r.sleep(lk, std::bind(is_done, std::ref(st->x))); 40 | EXPECT_EQ(st->x, 20*1000); 41 | } 42 | 43 | TEST(Qutex, Test1) { 44 | task::main([=] { 45 | task::spawn(qutex_task_spawn); 46 | }); 47 | } 48 | 49 | TEST(Qutex, Synchronized) { 50 | synchronized s("empty"); 51 | 52 | s([](std::string &str) { 53 | EXPECT_EQ("empty", str); 54 | str = "test"; 55 | }); 56 | 57 | sync(s, [](std::string &str) { 58 | EXPECT_EQ("test", str); 59 | str = "test2"; 60 | }); 61 | 62 | EXPECT_EQ(*sync_view(s), "test2"); 63 | } 64 | -------------------------------------------------------------------------------- /tests/test_striped.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/striped.hh" 3 | #include 4 | 5 | using namespace ten; 6 | 7 | TEST(StripedLock, Test) { 8 | striped striped_lock{10}; 9 | 10 | for (int i=0; i<100; ++i) { 11 | std::unique_lock lock{striped_lock.get(i)}; 12 | } 13 | } 14 | 15 | TEST(StripedMultiGet, Test) { 16 | striped striped_int{10}; 17 | 18 | { 19 | std::vector r1 = striped_int.multi_get(1, 2, 3, 4); 20 | std::vector r2 = striped_int.multi_get(4, 3, 1, 2); 21 | EXPECT_EQ(r1, r2); 22 | } 23 | 24 | { 25 | std::vector r1 = striped_int.multi_get(1, 21, 305, 49); 26 | std::vector r2 = striped_int.multi_get(49, 305, 1, 21); 27 | EXPECT_EQ(r1, r2); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /tests/test_thread_local.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/thread_local.hh" 3 | #include 4 | #include 5 | 6 | using namespace ten; 7 | 8 | struct X { 9 | static std::atomic new_count; 10 | static std::atomic del_count; 11 | 12 | X() { 13 | ++new_count; 14 | } 15 | 16 | ~X() { 17 | ++del_count; 18 | } 19 | }; 20 | 21 | std::atomic X::new_count(0); 22 | std::atomic X::del_count(0); 23 | 24 | struct tag1 {}; 25 | struct tag2 {}; 26 | 27 | thread_cached x1; 28 | thread_cached x2; 29 | 30 | void my_thread() { 31 | EXPECT_EQ(x1.get(), x2.get()); 32 | // unique tag, this will create a new X 33 | thread_cached x3; 34 | EXPECT_NE(x1.get(), x3.get()); 35 | // same tag, we'll get the x3 pointer again 36 | thread_cached x4; 37 | EXPECT_EQ(x3.get(), x4.get()); 38 | } 39 | 40 | TEST(ThreadLocal, Test1) { 41 | std::thread t(my_thread); 42 | t.join(); 43 | 44 | EXPECT_EQ(X::new_count, 2); 45 | EXPECT_EQ(X::del_count, 2); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /tests/test_work_deque.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "ten/work_deque.hh" 3 | #include "ten/logging.hh" 4 | #include 5 | #include 6 | 7 | using namespace ten; 8 | 9 | TEST(WorkDeque, Test) { 10 | using namespace std::chrono; 11 | work_deque q{100}; 12 | const size_t work_units = 1000; 13 | const size_t stealers = 8; 14 | std::atomic completed{0}; 15 | 16 | std::vector threads; 17 | 18 | auto producer = [&] { 19 | for (size_t i=0; i work = q.take(); 25 | if (work) { 26 | ++count; 27 | std::this_thread::sleep_for(milliseconds(1)); 28 | } else { 29 | completed.fetch_add(count); 30 | VLOG(1) << "did " << count << " work"; 31 | break; 32 | } 33 | } 34 | }; 35 | 36 | auto stealer = [&] { 37 | size_t count = 0; 38 | for (;;) { 39 | auto r = q.steal(); 40 | if (r.first) { 41 | if (r.second) { 42 | ++count; 43 | std::this_thread::sleep_for(milliseconds(1)); 44 | } else { 45 | completed.fetch_add(count); 46 | VLOG(1) << "stole " << count << " work"; 47 | return; 48 | } 49 | } else { 50 | std::this_thread::yield(); 51 | } 52 | } 53 | }; 54 | 55 | threads.emplace_back(producer); 56 | for (size_t i=0; i