206 |
206 |
207 // ScopedCS |
207 // ScopedCS |
208 template <typename VALUE, typename CONFIG, MEMFLAGS F> |
208 template <typename VALUE, typename CONFIG, MEMFLAGS F> |
209 inline ConcurrentHashTable<VALUE, CONFIG, F>:: |
209 inline ConcurrentHashTable<VALUE, CONFIG, F>:: |
210 ScopedCS::ScopedCS(Thread* thread, ConcurrentHashTable<VALUE, CONFIG, F>* cht) |
210 ScopedCS::ScopedCS(Thread* thread, ConcurrentHashTable<VALUE, CONFIG, F>* cht) |
211 : _thread(thread), _cht(cht) |
211 : _thread(thread), |
212 { |
212 _cht(cht), |
213 GlobalCounter::critical_section_begin(_thread); |
213 _cs_context(GlobalCounter::critical_section_begin(_thread)) |
|
214 { |
214 // This version is published now. |
215 // This version is published now. |
215 if (OrderAccess::load_acquire(&_cht->_invisible_epoch) != NULL) { |
216 if (OrderAccess::load_acquire(&_cht->_invisible_epoch) != NULL) { |
216 OrderAccess::release_store_fence(&_cht->_invisible_epoch, (Thread*)NULL); |
217 OrderAccess::release_store_fence(&_cht->_invisible_epoch, (Thread*)NULL); |
217 } |
218 } |
218 } |
219 } |
219 |
220 |
220 template <typename VALUE, typename CONFIG, MEMFLAGS F> |
221 template <typename VALUE, typename CONFIG, MEMFLAGS F> |
221 inline ConcurrentHashTable<VALUE, CONFIG, F>:: |
222 inline ConcurrentHashTable<VALUE, CONFIG, F>:: |
222 ScopedCS::~ScopedCS() |
223 ScopedCS::~ScopedCS() |
223 { |
224 { |
224 GlobalCounter::critical_section_end(_thread); |
225 GlobalCounter::critical_section_end(_thread, _cs_context); |
225 } |
226 } |
226 |
227 |
227 // BaseConfig |
228 // BaseConfig |
228 template <typename VALUE, typename CONFIG, MEMFLAGS F> |
229 template <typename VALUE, typename CONFIG, MEMFLAGS F> |
229 inline void* ConcurrentHashTable<VALUE, CONFIG, F>:: |
230 inline void* ConcurrentHashTable<VALUE, CONFIG, F>:: |
500 // Here manual do critical section since we don't want to take the cost of |
501 // Here manual do critical section since we don't want to take the cost of |
501 // locking the bucket if there is nothing to delete. But we can have |
502 // locking the bucket if there is nothing to delete. But we can have |
502 // concurrent single deletes. The _invisible_epoch can only be used by the |
503 // concurrent single deletes. The _invisible_epoch can only be used by the |
503 // owner of _resize_lock, us here. There we should not changed it in our |
504 // owner of _resize_lock, us here. There we should not changed it in our |
504 // own read-side. |
505 // own read-side. |
505 GlobalCounter::critical_section_begin(thread); |
506 GlobalCounter::CSContext cs_context = GlobalCounter::critical_section_begin(thread); |
506 for (size_t bucket_it = start_idx; bucket_it < stop_idx; bucket_it++) { |
507 for (size_t bucket_it = start_idx; bucket_it < stop_idx; bucket_it++) { |
507 Bucket* bucket = table->get_bucket(bucket_it); |
508 Bucket* bucket = table->get_bucket(bucket_it); |
508 Bucket* prefetch_bucket = (bucket_it+1) < stop_idx ? |
509 Bucket* prefetch_bucket = (bucket_it+1) < stop_idx ? |
509 table->get_bucket(bucket_it+1) : NULL; |
510 table->get_bucket(bucket_it+1) : NULL; |
510 |
511 |
512 have_deletable(bucket, eval_f, prefetch_bucket)) { |
513 have_deletable(bucket, eval_f, prefetch_bucket)) { |
513 // Nothing to remove in this bucket. |
514 // Nothing to remove in this bucket. |
514 continue; |
515 continue; |
515 } |
516 } |
516 |
517 |
517 GlobalCounter::critical_section_end(thread); |
518 GlobalCounter::critical_section_end(thread, cs_context); |
518 // We left critical section but the bucket cannot be removed while we hold |
519 // We left critical section but the bucket cannot be removed while we hold |
519 // the _resize_lock. |
520 // the _resize_lock. |
520 bucket->lock(); |
521 bucket->lock(); |
521 size_t nd = delete_check_nodes(bucket, eval_f, BULK_DELETE_LIMIT, ndel); |
522 size_t nd = delete_check_nodes(bucket, eval_f, BULK_DELETE_LIMIT, ndel); |
522 bucket->unlock(); |
523 bucket->unlock(); |
528 for (size_t node_it = 0; node_it < nd; node_it++) { |
529 for (size_t node_it = 0; node_it < nd; node_it++) { |
529 del_f(ndel[node_it]->value()); |
530 del_f(ndel[node_it]->value()); |
530 Node::destroy_node(ndel[node_it]); |
531 Node::destroy_node(ndel[node_it]); |
531 DEBUG_ONLY(ndel[node_it] = (Node*)POISON_PTR;) |
532 DEBUG_ONLY(ndel[node_it] = (Node*)POISON_PTR;) |
532 } |
533 } |
533 GlobalCounter::critical_section_begin(thread); |
534 cs_context = GlobalCounter::critical_section_begin(thread); |
534 } |
535 } |
535 GlobalCounter::critical_section_end(thread); |
536 GlobalCounter::critical_section_end(thread, cs_context); |
536 } |
537 } |
537 |
538 |
538 template <typename VALUE, typename CONFIG, MEMFLAGS F> |
539 template <typename VALUE, typename CONFIG, MEMFLAGS F> |
539 template <typename LOOKUP_FUNC> |
540 template <typename LOOKUP_FUNC> |
540 inline void ConcurrentHashTable<VALUE, CONFIG, F>:: |
541 inline void ConcurrentHashTable<VALUE, CONFIG, F>:: |