Zero  0.1.0
mcs_lock.h
Go to the documentation of this file.
1 #ifndef __MCS_LOCK_H
2 #define __MCS_LOCK_H
3 /* -*- mode:C++; c-basic-offset:4 -*-
4  Shore-MT -- Multi-threaded port of the SHORE storage manager
5 
6  Copyright (c) 2007-2009
7  Data Intensive Applications and Systems Labaratory (DIAS)
8  Ecole Polytechnique Federale de Lausanne
9 
10  All Rights Reserved.
11 
12  Permission to use, copy, modify and distribute this software and
13  its documentation is hereby granted, provided that both the
14  copyright notice and this permission notice appear in all copies of
15  the software, derivative works or modified versions, and any
16  portions thereof, and that both notices appear in supporting
17  documentation.
18 
19  This code is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
22  DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
23  RESULTING FROM THE USE OF THIS SOFTWARE.
24 */
25 
26 // -*- mode:c++; c-basic-offset:4 -*-
27 #include "AtomicCounter.hpp"
28 #include "w_defines.h"
29 
34 union qnode_status {
35  struct {
36  int32_t _waiting;
37  int32_t _delegated;
38  } individual;
39  int64_t _combined;
40 };
41 
42 const qnode_status QNODE_IDLE = {{0, 0}};
43 
44 const qnode_status QNODE_WAITING = {{1, 0}};
45 
46 const qnode_status QNODE_DELEGATED = {{1, 1}};
47 
61 struct mcs_lock {
62  struct qnode;
63 
64  struct qnode {
66 
68 
69  // int32_t _waiting;
70  // int32_t _delegated;
71  qnode volatile* vthis() {
72  return this;
73  }
74  };
75 
76  struct ext_qnode {
78 
80 
81  operator qnode*() {
82  return &_node;
83  }
84  };
85 
86 #define MCS_EXT_QNODE_INITIALIZER {{NULL,false},NULL}
87 #define MCS_EXT_QNODE_INITIALIZE(x) \
88 { (x)._node._next = NULL; (x)._node._waiting = 0; (x)._node._delegated = 0; (x)._held = NULL; }
89 
91 
92  mcs_lock() : _tail(nullptr) {}
93 
94  /* This spinning occurs whenever there are critical sections ahead
95  of us.
96  */
97  void spin_on_waiting(qnode* me) {
98  while (me->vthis()->_status.individual._waiting) {}
99  }
100 
101  /* Only acquire the lock if it is free...
102  */
103  bool attempt(ext_qnode* me) {
104  if (attempt((qnode*)me)) {
105  me->_held = this;
106  return true;
107  }
108  return false;
109  }
110 
111  bool attempt(qnode* me) {
112  me->_next = nullptr;
113  me->_status.individual._waiting = 1;
114  // lock held?
115  qnode* null_cas_tmp = nullptr;
116  if (!lintel::unsafe::atomic_compare_exchange_strong<qnode*>(
117  &_tail, &null_cas_tmp, (qnode*)me)) {
118  return false;
119  }
121  return true;
122  }
123 
124  // return true if the lock was free
125  void* acquire(ext_qnode* me) {
126  me->_held = this;
127  return acquire((qnode*)me);
128  }
129 
130  void* acquire(qnode* me) {
131  return __unsafe_end_acquire(me, __unsafe_begin_acquire(me));
132  }
133 
135  me->_next = nullptr;
136  me->_status.individual._waiting = 1;
137  qnode* pred = lintel::unsafe::atomic_exchange<qnode*>(&_tail, me);
138  if (pred) {
139  pred->_next = me;
140  }
141  return pred;
142  }
143 
144  void* __unsafe_end_acquire(qnode* me, qnode* pred) {
145  if (pred) {
146  spin_on_waiting(me);
147  }
149  return (void*)pred;
150  }
151 
152  /* This spinning only occurs when we are at _tail and catch a
153  thread trying to enqueue itself.
154 
155  CC mangles this as __1cImcs_lockMspin_on_next6Mpon0AFqnode__3_
156  */
158  qnode* next;
159  while (!(next = me->vthis()->_next)) {}
160  return next;
161  }
162 
163  void release(ext_qnode* me) {
164  w_assert1(is_mine(me));
165  me->_held = 0;
166  release((qnode*)me);
167  }
168 
169  void release(ext_qnode& me) {
170  w_assert1(is_mine(&me));
171  release(&me);
172  }
173 
174  void release(qnode& me) {
175  release(&me);
176  }
177 
178  void release(qnode* me) {
180 
181  qnode* next;
182  if (!(next = me->_next)) {
183  qnode* me_cas_tmp = me;
184  if (me == _tail &&
185  lintel::unsafe::atomic_compare_exchange_strong<qnode*>(&_tail, &me_cas_tmp, (qnode*)nullptr)) {
186  return;
187  }
188  next = spin_on_next(me);
189  }
190  next->_status.individual._waiting = 0;
191  }
192 
193  // bool is_mine(qnode* me) { return me->_held == this; }
194  bool is_mine(ext_qnode* me) {
195  return me->_held == this;
196  }
197 };
198 
201 
202 #endif // __MCS_LOCK_H
void atomic_thread_fence(memory_order order)
Definition: AtomicCounter.hpp:223
void * acquire(qnode *me)
Definition: mcs_lock.h:130
void release(qnode *me)
Definition: mcs_lock.h:178
const qnode_status QNODE_IDLE
Definition: mcs_lock.h:42
#define w_assert1(x)
Level 1 should not add significant extra time.
Definition: w_base.h:198
qnode * _tail
Definition: mcs_lock.h:90
void release(ext_qnode *me)
Definition: mcs_lock.h:163
qnode volatile * vthis()
Definition: mcs_lock.h:71
Header file for lintel::Atomic class.
qnode * _next
Definition: mcs_lock.h:65
qnode * __unsafe_begin_acquire(qnode *me)
Definition: mcs_lock.h:134
int32_t _delegated
Definition: mcs_lock.h:37
void * acquire(ext_qnode *me)
Definition: mcs_lock.h:125
bool attempt(qnode *me)
Definition: mcs_lock.h:111
void * __unsafe_end_acquire(qnode *me, qnode *pred)
Definition: mcs_lock.h:144
bool attempt(ext_qnode *me)
Definition: mcs_lock.h:103
const qnode_status QNODE_DELEGATED
Definition: mcs_lock.h:46
const size_t CACHELINE_MCS_PADDING
Definition: mcs_lock.h:200
bool is_mine(ext_qnode *me)
Definition: mcs_lock.h:194
void spin_on_waiting(qnode *me)
Definition: mcs_lock.h:97
qnode * spin_on_next(qnode *me)
Definition: mcs_lock.h:157
An MCS queuing spinlock.
Definition: mcs_lock.h:61
void release(qnode &me)
Definition: mcs_lock.h:174
mcs_lock()
Definition: mcs_lock.h:92
Definition: AtomicCounter.hpp:114
void release(ext_qnode &me)
Definition: mcs_lock.h:169
Definition: mcs_lock.h:64
const qnode_status QNODE_WAITING
Definition: mcs_lock.h:44
int64_t _combined
Definition: mcs_lock.h:39
mcs_lock * _held
Definition: mcs_lock.h:79
struct qnode_status::@8 individual
Definition: mcs_lock.h:34
int32_t _waiting
Definition: mcs_lock.h:36
qnode _node
Definition: mcs_lock.h:77
qnode_status _status
Definition: mcs_lock.h:67
Definition: mcs_lock.h:76
Definition: AtomicCounter.hpp:113
const size_t CACHELINE_SIZE
CPU Cache line size in bytes.
Definition: w_defines.h:183