1/*
2 * Copyright (c) 2016, 2019, 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 *
23 */
24
25#ifndef SHARE_GC_SHARED_WORKERMANAGER_HPP
26#define SHARE_GC_SHARED_WORKERMANAGER_HPP
27
28#include "logging/log.hpp"
29#include "memory/allocation.hpp"
30#include "runtime/os.hpp"
31#include "runtime/thread.hpp"
32#include "utilities/globalDefinitions.hpp"
33
34class WorkerManager : public AllStatic {
35 public:
36 // Create additional workers as needed.
37 // active_workers - number of workers being requested for an upcoming
38 // parallel task.
39 // total_workers - total number of workers. This is the maximum
40 // number possible.
41 // created_workers - number of workers already created. This maybe
42 // less than, equal to, or greater than active workers. If greater than
43 // or equal to active_workers, nothing is done.
44 // worker_type - type of thread.
45 // initializing - true if this is called to get the initial number of
46 // GC workers.
47 // If initializing is true, do a vm exit if the workers cannot be created.
48 // The initializing = true case is for JVM start up and failing to
49 // create all the worker at start should considered a problem so exit.
50 // If initializing = false, there are already some number of worker
51 // threads and a failure would not be optimal but should not be fatal.
52 template <class WorkerType>
53 static uint add_workers (WorkerType* holder,
54 uint active_workers,
55 uint total_workers,
56 uint created_workers,
57 os::ThreadType worker_type,
58 bool initializing);
59
60 // Log (at trace level) a change in the number of created workers.
61 template <class WorkerType>
62 static void log_worker_creation(WorkerType* holder,
63 uint previous_created_workers,
64 uint active_workers,
65 uint created_workers,
66 bool initializing);
67};
68
69template <class WorkerType>
70uint WorkerManager::add_workers(WorkerType* holder,
71 uint active_workers,
72 uint total_workers,
73 uint created_workers,
74 os::ThreadType worker_type,
75 bool initializing) {
76 uint start = created_workers;
77 uint end = MIN2(active_workers, total_workers);
78 for (uint worker_id = start; worker_id < end; worker_id += 1) {
79 WorkerThread* new_worker = NULL;
80 if (initializing || !InjectGCWorkerCreationFailure) {
81 new_worker = holder->install_worker(worker_id);
82 }
83 if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
84 log_trace(gc, task)("WorkerManager::add_workers() : "
85 "creation failed due to failed allocation of native %s",
86 new_worker == NULL ? "memory" : "thread");
87 if (new_worker != NULL) {
88 delete new_worker;
89 }
90 if (initializing) {
91 vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create worker GC thread. Out of system resources.");
92 }
93 break;
94 }
95 created_workers++;
96 os::start_thread(new_worker);
97 }
98
99 log_trace(gc, task)("WorkerManager::add_workers() : "
100 "created_workers: %u", created_workers);
101
102 return created_workers;
103}
104
105template <class WorkerType>
106void WorkerManager::log_worker_creation(WorkerType* holder,
107 uint previous_created_workers,
108 uint active_workers,
109 uint created_workers,
110 bool initializing) {
111 if (previous_created_workers < created_workers) {
112 const char* initializing_msg = initializing ? "Adding initial" : "Creating additional";
113 log_trace(gc, task)("%s %s(s) previously created workers %u active workers %u total created workers %u",
114 initializing_msg, holder->group_name(), previous_created_workers, active_workers, created_workers);
115 }
116}
117
118#endif // SHARE_GC_SHARED_WORKERMANAGER_HPP
119