1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #pragma once
8 
9 #include "td/utils/port/thread.h"
10 
11 #include <atomic>
12 #include <memory>
13 
14 namespace td {
15 
16 class SpinLock {
17   struct Unlock {
operatorUnlock18     void operator()(SpinLock *ptr) {
19       ptr->unlock();
20     }
21   };
22 
23   class InfBackoff {
24     int cnt = 0;
25 
26    public:
next()27     bool next() {
28       cnt++;
29       if (cnt < 50) {
30         //TODO pause
31         return true;
32       } else {
33         td::this_thread::yield();
34         return true;
35       }
36     }
37   };
38 
39  public:
40   using Lock = std::unique_ptr<SpinLock, Unlock>;
41 
lock()42   Lock lock() {
43     InfBackoff backoff;
44     while (!try_lock()) {
45       backoff.next();
46     }
47     return Lock(this);
48   }
try_lock()49   bool try_lock() {
50     return !flag_.test_and_set(std::memory_order_acquire);
51   }
52 
53  private:
54   std::atomic_flag flag_ = ATOMIC_FLAG_INIT;
unlock()55   void unlock() {
56     flag_.clear(std::memory_order_release);
57   }
58 };
59 
60 }  // namespace td
61