libfoedus-core
FOEDUS Core Library
shared_polling.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2015, Hewlett-Packard Development Company, LP.
3  * This program is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU General Public License as published by the Free
5  * Software Foundation; either version 2 of the License, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11  * more details. You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14  *
15  * HP designates this particular file as subject to the "Classpath" exception
16  * as provided by HP in the LICENSE.txt file that accompanied this code.
17  */
19 
20 #include <algorithm>
21 #include <atomic>
22 #include <chrono>
23 #include <thread>
24 
25 #include "foedus/assert_nd.hpp"
28 
29 namespace foedus {
30 namespace soc {
31 
33  cur_ticket_ = 0;
35 }
36 
37 void ugly_atomic_inc(uint64_t* address) {
38  reinterpret_cast< std::atomic<uint64_t>* >(address)->operator++();
39 }
40 
41 
43  uint64_t demanded_ticket,
44  uint64_t polling_spins,
45  uint64_t max_interval_us) const {
46  if (cur_ticket_ >= demanded_ticket) {
47  return;
48  }
49  spin_poll(demanded_ticket, polling_spins);
50 
51  uint64_t interval_us = kInitialPollingIntervalUs;
52  while (cur_ticket_ < demanded_ticket) {
53  std::this_thread::sleep_for(std::chrono::microseconds(interval_us));
54  interval_us = std::min<uint64_t>(interval_us * 2ULL, max_interval_us);
55  }
56 }
57 
58 uint64_t get_now_microsec() {
59  std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();
60  return std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
61 }
62 
64  uint64_t demanded_ticket,
65  uint64_t timeout_microsec,
66  uint64_t polling_spins,
67  uint64_t max_interval_us) const {
68  if (cur_ticket_ >= demanded_ticket) {
69  return true;
70  }
71  uint64_t start_us = get_now_microsec();
72  uint64_t end_us = start_us + timeout_microsec; // might overflow as a rare case, but not an issue
73  spin_poll(demanded_ticket, polling_spins);
74 
75  uint64_t interval_us = kInitialPollingIntervalUs;
76  while (cur_ticket_ < demanded_ticket) {
77  uint64_t now_us = get_now_microsec();
78  if (now_us > end_us) {
79  return false; // ah, oh, timeout
80  }
81  std::this_thread::sleep_for(std::chrono::microseconds(interval_us));
82  interval_us = std::min<uint64_t>(interval_us * 2ULL, max_interval_us);
83  }
84  return true;
85 }
86 
87 void SharedPolling::spin_poll(uint64_t demanded_ticket, uint64_t polling_spins) const {
88  for (uint64_t i = 0; i < polling_spins; ++i) {
89  if (cur_ticket_ >= demanded_ticket) {
90  return;
91  }
92  if (i % 256 == 0) {
95  }
96  }
97 }
98 
99 
101  assorted::memory_fence_acq_rel(); // well, atomic op implies a full barrier, but to make sure.
102  ugly_atomic_inc(&cur_ticket_);
103 }
104 
106  uint64_t ret = cur_ticket_ + 1ULL;
108  return ret;
109 }
110 
111 } // namespace soc
112 } // namespace foedus
uint64_t get_now_microsec()
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
Definition: assert_nd.hpp:44
void wait(uint64_t demanded_ticket, uint64_t polling_spins=kDefaultPollingSpins, uint64_t max_interval_us=kDefaultPollingMaxIntervalUs) const
Unconditionally wait for signal.
uint64_t acquire_ticket() const
Gives the ticket to.
const uint64_t kInitialPollingIntervalUs
Initial value of sleep interval in us.
void spinlock_yield()
Invoke _mm_pause(), x86 PAUSE instruction, or something equivalent in the env.
Atomic fence methods and load/store with fences that work for both C++11/non-C++11 code...
void ugly_atomic_inc(uint32_t *address)
Definition: shared_cond.cpp:83
void memory_fence_acquire()
Equivalent to std::atomic_thread_fence(std::memory_order_acquire).
bool timedwait(uint64_t demanded_ticket, uint64_t timeout_microsec, uint64_t polling_spins=kDefaultPollingSpins, uint64_t max_interval_us=kDefaultPollingMaxIntervalUs) const
Wait for signal up to the given timeout.
void signal()
Signal it to let waiters exit.
void memory_fence_acq_rel()
Equivalent to std::atomic_thread_fence(std::memory_order_acq_rel).