1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "mem/gc/gc_queue.h"
17
18 #include "include/runtime.h"
19 #include "libpandabase/utils/time.h"
20 #include "runtime/mem/gc/gc.h"
21
22 namespace panda::mem {
23
24 const int64_t NANOSECONDS_PER_MILLISEC = 1000000;
25
GetTask()26 GCTask *GCQueueWithTime::GetTask()
27 {
28 os::memory::LockHolder lock(lock_);
29 while (queue_.empty()) {
30 if (!gc_->IsGCRunning()) {
31 LOG(DEBUG, GC) << "GetTask() Return INVALID_CAUSE";
32 return nullptr;
33 }
34 LOG(DEBUG, GC) << "Empty " << queue_name_ << ", waiting...";
35 cond_var_.Wait(&lock_);
36 }
37 GCTask *task = queue_.top();
38 auto current_time = time::GetCurrentTimeInNanos();
39 while (gc_->IsGCRunning() && (task->GetTargetTime() >= current_time)) {
40 auto delta = task->GetTargetTime() - current_time;
41 uint64_t ms = delta / NANOSECONDS_PER_MILLISEC;
42 uint64_t ns = delta % NANOSECONDS_PER_MILLISEC;
43 LOG(DEBUG, GC) << "GetTask TimedWait";
44 cond_var_.TimedWait(&lock_, ms, ns);
45 task = queue_.top();
46 current_time = time::GetCurrentTimeInNanos();
47 }
48 queue_.pop();
49 LOG(DEBUG, GC) << "Extract a task from a " << queue_name_;
50 return task;
51 }
52
AddTask(GCTask * task)53 void GCQueueWithTime::AddTask(GCTask *task)
54 {
55 os::memory::LockHolder lock(lock_);
56 if (finalized) {
57 LOG(DEBUG, GC) << "Skip AddTask to queue: " << queue_name_ << " cause it's finalized already";
58 task->Release(gc_->GetInternalAllocator());
59 return;
60 }
61 LOG(DEBUG, GC) << "Add task to a " << queue_name_;
62 if (!queue_.empty()) {
63 auto last_elem = queue_.top();
64 if (last_elem->reason_ == task->reason_) {
65 // do not duplicate GC task with the same reason.
66 task->Release(gc_->GetInternalAllocator());
67 return;
68 }
69 }
70 queue_.push(task);
71 cond_var_.Signal();
72 }
73
Finalize()74 void GCQueueWithTime::Finalize()
75 {
76 os::memory::LockHolder lock(lock_);
77 finalized = true;
78 LOG(DEBUG, GC) << "Clear a " << queue_name_;
79 InternalAllocatorPtr allocator = gc_->GetInternalAllocator();
80 while (!queue_.empty()) {
81 auto task = queue_.top();
82 task->Release(allocator);
83 queue_.pop();
84 }
85 }
86
87 } // namespace panda::mem
88