capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

thread-test.c++ (3564B)


      1 // Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #include "thread.h"
     23 #include "test.h"
     24 #include <atomic>
     25 
     26 #if _WIN32
     27 #define NOGDI
     28 #include <windows.h>
     29 #undef NOGDI
     30 #else
     31 #include <unistd.h>
     32 #endif
     33 
     34 namespace kj {
     35 namespace {
     36 
     37 #if _WIN32
     38 inline void delay() { Sleep(10); }
     39 #else
     40 inline void delay() { usleep(10000); }
     41 #endif
     42 
     43 KJ_TEST("detaching thread doesn't delete function") {
     44   struct Functor {
     45     // Functor that sets *b = true on destruction, not counting moves.
     46 
     47     std::atomic<bool>* destroyed;
     48     const std::atomic<bool>* canExit;
     49 
     50     Functor(std::atomic<bool>* destroyed, const std::atomic<bool>* canExit)
     51         : destroyed(destroyed), canExit(canExit) {}
     52 
     53     ~Functor() {
     54       if (destroyed != nullptr) *destroyed = true;
     55     }
     56     KJ_DISALLOW_COPY(Functor);
     57     Functor(Functor&& other): destroyed(other.destroyed), canExit(other.canExit) {
     58       other.destroyed = nullptr;
     59     }
     60     Functor& operator=(Functor&& other) = delete;
     61 
     62     void operator()() {
     63       while (!*canExit) delay();
     64     }
     65   };
     66 
     67   std::atomic<bool> destroyed(false);
     68   std::atomic<bool> canExit(false);
     69   Functor f(&destroyed, &canExit);
     70 
     71   kj::Thread(kj::mv(f)).detach();
     72 
     73   // detach() should not have destroyed the function.
     74   KJ_ASSERT(!destroyed);
     75 
     76   // Delay a bit to make sure the thread has had time to start up, and then make sure the function
     77   // still isn't destroyed.
     78   delay();
     79   delay();
     80   KJ_ASSERT(!destroyed);
     81 
     82   // Notify the thread that it's safe to exit.
     83   canExit = true;
     84   while (!destroyed) {
     85     delay();
     86   }
     87 }
     88 
     89 class CapturingExceptionCallback final: public ExceptionCallback {
     90 public:
     91   CapturingExceptionCallback(String& target): target(target) {}
     92 
     93   void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
     94                   String&& text) {
     95     target = kj::mv(text);
     96   }
     97 
     98 private:
     99   String& target;
    100 };
    101 
    102 class ThreadedExceptionCallback final: public ExceptionCallback {
    103 public:
    104   Function<void(Function<void()>)> getThreadInitializer() override {
    105     return [this](Function<void()> func) {
    106       CapturingExceptionCallback context(captured);
    107       func();
    108     };
    109   }
    110 
    111   String captured;
    112 };
    113 
    114 KJ_TEST("threads pick up exception callback initializer") {
    115   ThreadedExceptionCallback context;
    116   KJ_EXPECT(context.captured != "foobar");
    117   Thread([]() {
    118     KJ_LOG(ERROR, "foobar");
    119   });
    120   KJ_EXPECT(context.captured == "foobar", context.captured);
    121 }
    122 
    123 }  // namespace
    124 }  // namespace kj