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 
34 class 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 
69 template <class WorkerType>
add_workers(WorkerType * holder,uint active_workers,uint total_workers,uint created_workers,os::ThreadType worker_type,bool initializing)70 uint 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 
105 template <class WorkerType>
log_worker_creation(WorkerType * holder,uint previous_created_workers,uint active_workers,uint created_workers,bool initializing)106 void 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