1 /*
2 * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
581 for (uint j = 0; j < _n; j++) {
582 if (_queues[j]->peek())
583 return true;
584 }
585 return false;
586 }
587
588 // When to terminate from the termination protocol.
589 class TerminatorTerminator: public CHeapObj<mtInternal> {
590 public:
591 virtual bool should_exit_termination() = 0;
592 };
593
594 // A class to aid in the termination of a set of parallel tasks using
595 // TaskQueueSet's for work stealing.
596
597 #undef TRACESPINNING
598
599 class ParallelTaskTerminator: public StackObj {
600 private:
601 int _n_threads;
602 TaskQueueSetSuper* _queue_set;
603 int _offered_termination;
604
605 #ifdef TRACESPINNING
606 static uint _total_yields;
607 static uint _total_spins;
608 static uint _total_peeks;
609 #endif
610
611 bool peek_in_queue_set();
612 protected:
613 virtual void yield();
614 void sleep(uint millis);
615
616 public:
617
618 // "n_threads" is the number of threads to be terminated. "queue_set" is a
619 // queue sets of work queues of other threads.
620 ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set);
621
622 // The current thread has no work, and is ready to terminate if everyone
623 // else is. If returns "true", all threads are terminated. If returns
624 // "false", available work has been observed in one of the task queues,
625 // so the global task is not complete.
626 bool offer_termination() {
627 return offer_termination(NULL);
628 }
629
630 // As above, but it also terminates if the should_exit_termination()
631 // method of the terminator parameter returns true. If terminator is
632 // NULL, then it is ignored.
633 bool offer_termination(TerminatorTerminator* terminator);
634
635 // Reset the terminator, so that it may be reused again.
636 // The caller is responsible for ensuring that this is done
637 // in an MT-safe manner, once the previous round of use of
638 // the terminator is finished.
639 void reset_for_reuse();
640 // Same as above but the number of parallel threads is set to the
641 // given number.
642 void reset_for_reuse(int n_threads);
643
644 #ifdef TRACESPINNING
645 static uint total_yields() { return _total_yields; }
646 static uint total_spins() { return _total_spins; }
647 static uint total_peeks() { return _total_peeks; }
648 static void print_termination_counts();
649 #endif
650 };
651
652 template<class E, MEMFLAGS F, unsigned int N> inline bool
653 GenericTaskQueue<E, F, N>::push(E t) {
654 uint localBot = _bottom;
655 assert(localBot < N, "_bottom out of range.");
656 idx_t top = _age.top();
657 uint dirty_n_elems = dirty_size(localBot, top);
658 assert(dirty_n_elems < N, "n_elems out of range.");
659 if (dirty_n_elems < max_elems()) {
660 // g++ complains if the volatile result of the assignment is
661 // unused, so we cast the volatile away. We cannot cast directly
662 // to void, because gcc treats that as not using the result of the
|
1 /*
2 * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
581 for (uint j = 0; j < _n; j++) {
582 if (_queues[j]->peek())
583 return true;
584 }
585 return false;
586 }
587
588 // When to terminate from the termination protocol.
589 class TerminatorTerminator: public CHeapObj<mtInternal> {
590 public:
591 virtual bool should_exit_termination() = 0;
592 };
593
594 // A class to aid in the termination of a set of parallel tasks using
595 // TaskQueueSet's for work stealing.
596
597 #undef TRACESPINNING
598
599 class ParallelTaskTerminator: public StackObj {
600 private:
601 uint _n_threads;
602 TaskQueueSetSuper* _queue_set;
603 uint _offered_termination;
604
605 #ifdef TRACESPINNING
606 static uint _total_yields;
607 static uint _total_spins;
608 static uint _total_peeks;
609 #endif
610
611 bool peek_in_queue_set();
612 protected:
613 virtual void yield();
614 void sleep(uint millis);
615
616 public:
617
618 // "n_threads" is the number of threads to be terminated. "queue_set" is a
619 // queue sets of work queues of other threads.
620 ParallelTaskTerminator(uint n_threads, TaskQueueSetSuper* queue_set);
621
622 // The current thread has no work, and is ready to terminate if everyone
623 // else is. If returns "true", all threads are terminated. If returns
624 // "false", available work has been observed in one of the task queues,
625 // so the global task is not complete.
626 bool offer_termination() {
627 return offer_termination(NULL);
628 }
629
630 // As above, but it also terminates if the should_exit_termination()
631 // method of the terminator parameter returns true. If terminator is
632 // NULL, then it is ignored.
633 bool offer_termination(TerminatorTerminator* terminator);
634
635 // Reset the terminator, so that it may be reused again.
636 // The caller is responsible for ensuring that this is done
637 // in an MT-safe manner, once the previous round of use of
638 // the terminator is finished.
639 void reset_for_reuse();
640 // Same as above but the number of parallel threads is set to the
641 // given number.
642 void reset_for_reuse(uint n_threads);
643
644 #ifdef TRACESPINNING
645 static uint total_yields() { return _total_yields; }
646 static uint total_spins() { return _total_spins; }
647 static uint total_peeks() { return _total_peeks; }
648 static void print_termination_counts();
649 #endif
650 };
651
652 template<class E, MEMFLAGS F, unsigned int N> inline bool
653 GenericTaskQueue<E, F, N>::push(E t) {
654 uint localBot = _bottom;
655 assert(localBot < N, "_bottom out of range.");
656 idx_t top = _age.top();
657 uint dirty_n_elems = dirty_size(localBot, top);
658 assert(dirty_n_elems < N, "n_elems out of range.");
659 if (dirty_n_elems < max_elems()) {
660 // g++ complains if the volatile result of the assignment is
661 // unused, so we cast the volatile away. We cannot cast directly
662 // to void, because gcc treats that as not using the result of the
|