src/share/vm/utilities/taskqueue.hpp
Index Unified diffs Context diffs Sdiffs Wdiffs Patch New Old Previous File Next File hotspot-hs24 Sdiff src/share/vm/utilities

src/share/vm/utilities/taskqueue.hpp

Print this page




 374     // install new_age, thus claiming the element.
 375     Age tempAge = _age.cmpxchg(newAge, oldAge);
 376     if (tempAge == oldAge) {
 377       // We win.
 378       assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
 379       TASKQUEUE_STATS_ONLY(stats.record_pop_slow());
 380       return true;
 381     }
 382   }
 383   // We lose; a completing pop_global gets the element.  But the queue is empty
 384   // and top is greater than bottom.  Fix this representation of the empty queue
 385   // to become the canonical one.
 386   _age.set(newAge);
 387   assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
 388   return false;
 389 }
 390 
 391 template<class E, MEMFLAGS F, unsigned int N>
 392 bool GenericTaskQueue<E, F, N>::pop_global(E& t) {
 393   Age oldAge = _age.get();
 394   uint localBot = _bottom;







 395   uint n_elems = size(localBot, oldAge.top());
 396   if (n_elems == 0) {
 397     return false;
 398   }
 399 
 400   const_cast<E&>(t = _elems[oldAge.top()]);
 401   Age newAge(oldAge);
 402   newAge.increment();
 403   Age resAge = _age.cmpxchg(newAge, oldAge);
 404 
 405   // Note that using "_bottom" here might fail, since a pop_local might
 406   // have decremented it.
 407   assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity");
 408   return resAge == oldAge;
 409 }
 410 
 411 template<class E, MEMFLAGS F, unsigned int N>
 412 GenericTaskQueue<E, F, N>::~GenericTaskQueue() {
 413   FREE_C_HEAP_ARRAY(E, _elems, F);
 414 }


 660   // Reset the terminator, so that it may be reused again.
 661   // The caller is responsible for ensuring that this is done
 662   // in an MT-safe manner, once the previous round of use of
 663   // the terminator is finished.
 664   void reset_for_reuse();
 665   // Same as above but the number of parallel threads is set to the
 666   // given number.
 667   void reset_for_reuse(int n_threads);
 668 
 669 #ifdef TRACESPINNING
 670   static uint total_yields() { return _total_yields; }
 671   static uint total_spins() { return _total_spins; }
 672   static uint total_peeks() { return _total_peeks; }
 673   static void print_termination_counts();
 674 #endif
 675 };
 676 
 677 template<class E, MEMFLAGS F, unsigned int N> inline bool
 678 GenericTaskQueue<E, F, N>::push(E t) {
 679   uint localBot = _bottom;
 680   assert((localBot >= 0) && (localBot < N), "_bottom out of range.");
 681   idx_t top = _age.top();
 682   uint dirty_n_elems = dirty_size(localBot, top);
 683   assert(dirty_n_elems < N, "n_elems out of range.");
 684   if (dirty_n_elems < max_elems()) {
 685     // g++ complains if the volatile result of the assignment is unused.
 686     const_cast<E&>(_elems[localBot] = t);
 687     OrderAccess::release_store(&_bottom, increment_index(localBot));
 688     TASKQUEUE_STATS_ONLY(stats.record_push());
 689     return true;
 690   } else {
 691     return push_slow(t, dirty_n_elems);
 692   }
 693 }
 694 
 695 template<class E, MEMFLAGS F, unsigned int N> inline bool
 696 GenericTaskQueue<E, F, N>::pop_local(E& t) {
 697   uint localBot = _bottom;
 698   // This value cannot be N-1.  That can only occur as a result of
 699   // the assignment to bottom in this method.  If it does, this method
 700   // resets the size to 0 before the next call (which is sequential,




 374     // install new_age, thus claiming the element.
 375     Age tempAge = _age.cmpxchg(newAge, oldAge);
 376     if (tempAge == oldAge) {
 377       // We win.
 378       assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
 379       TASKQUEUE_STATS_ONLY(stats.record_pop_slow());
 380       return true;
 381     }
 382   }
 383   // We lose; a completing pop_global gets the element.  But the queue is empty
 384   // and top is greater than bottom.  Fix this representation of the empty queue
 385   // to become the canonical one.
 386   _age.set(newAge);
 387   assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
 388   return false;
 389 }
 390 
 391 template<class E, MEMFLAGS F, unsigned int N>
 392 bool GenericTaskQueue<E, F, N>::pop_global(E& t) {
 393   Age oldAge = _age.get();
 394   // Architectures with weak memory model require a fence here. The
 395   // fence has a cumulative effect on getting age and getting bottom.
 396   // This way it is guaranteed that bottom is not older than age,
 397   // which is crucial for the correctness of the algorithm.
 398 #if !(defined SPARC || defined IA32 || defined AMD64)
 399   OrderAccess::fence();
 400 #endif
 401   uint localBot = OrderAccess::load_acquire((volatile juint*)&_bottom);
 402   uint n_elems = size(localBot, oldAge.top());
 403   if (n_elems == 0) {
 404     return false;
 405   }
 406 
 407   const_cast<E&>(t = _elems[oldAge.top()]);
 408   Age newAge(oldAge);
 409   newAge.increment();
 410   Age resAge = _age.cmpxchg(newAge, oldAge);
 411 
 412   // Note that using "_bottom" here might fail, since a pop_local might
 413   // have decremented it.
 414   assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity");
 415   return resAge == oldAge;
 416 }
 417 
 418 template<class E, MEMFLAGS F, unsigned int N>
 419 GenericTaskQueue<E, F, N>::~GenericTaskQueue() {
 420   FREE_C_HEAP_ARRAY(E, _elems, F);
 421 }


 667   // Reset the terminator, so that it may be reused again.
 668   // The caller is responsible for ensuring that this is done
 669   // in an MT-safe manner, once the previous round of use of
 670   // the terminator is finished.
 671   void reset_for_reuse();
 672   // Same as above but the number of parallel threads is set to the
 673   // given number.
 674   void reset_for_reuse(int n_threads);
 675 
 676 #ifdef TRACESPINNING
 677   static uint total_yields() { return _total_yields; }
 678   static uint total_spins() { return _total_spins; }
 679   static uint total_peeks() { return _total_peeks; }
 680   static void print_termination_counts();
 681 #endif
 682 };
 683 
 684 template<class E, MEMFLAGS F, unsigned int N> inline bool
 685 GenericTaskQueue<E, F, N>::push(E t) {
 686   uint localBot = _bottom;
 687   assert(localBot < N, "_bottom out of range.");
 688   idx_t top = _age.top();
 689   uint dirty_n_elems = dirty_size(localBot, top);
 690   assert(dirty_n_elems < N, "n_elems out of range.");
 691   if (dirty_n_elems < max_elems()) {
 692     // g++ complains if the volatile result of the assignment is unused.
 693     const_cast<E&>(_elems[localBot] = t);
 694     OrderAccess::release_store(&_bottom, increment_index(localBot));
 695     TASKQUEUE_STATS_ONLY(stats.record_push());
 696     return true;
 697   } else {
 698     return push_slow(t, dirty_n_elems);
 699   }
 700 }
 701 
 702 template<class E, MEMFLAGS F, unsigned int N> inline bool
 703 GenericTaskQueue<E, F, N>::pop_local(E& t) {
 704   uint localBot = _bottom;
 705   // This value cannot be N-1.  That can only occur as a result of
 706   // the assignment to bottom in this method.  If it does, this method
 707   // resets the size to 0 before the next call (which is sequential,


src/share/vm/utilities/taskqueue.hpp
Index Unified diffs Context diffs Sdiffs Wdiffs Patch New Old Previous File Next File