LCOV - code coverage report
Current view: top level - pgm/util - RuntimeShutdown.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 35 48 72.9 %
Date: 2022-11-19 15:00:39 Functions: 8 10 80.0 %

          Line data    Source code
       1             : // Copyright (C) 2009 The Android Open Source Project
       2             : //
       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             : package com.google.gerrit.pgm.util;
      16             : 
      17             : import com.google.common.flogger.FluentLogger;
      18             : import java.util.ArrayList;
      19             : import java.util.List;
      20             : 
      21             : public class RuntimeShutdown {
      22          15 :   private static final ShutdownCallback cb = new ShutdownCallback();
      23             : 
      24             :   /** Add a task to be performed when graceful shutdown is requested. */
      25             :   public static void add(Runnable task) {
      26          15 :     if (!cb.add(task)) {
      27             :       // If the shutdown has already begun we cannot enqueue a new
      28             :       // task. Instead trigger the task in the caller, without any
      29             :       // of our locks held.
      30             :       //
      31           0 :       task.run();
      32             :     }
      33          15 :   }
      34             : 
      35             :   /** Wait for the JVM shutdown to occur. */
      36             :   public static void waitFor() {
      37          15 :     cb.waitForShutdown();
      38          15 :   }
      39             : 
      40             :   public static void manualShutdown() {
      41           0 :     cb.manualShutdown();
      42           0 :   }
      43             : 
      44             :   private RuntimeShutdown() {}
      45             : 
      46             :   private static class ShutdownCallback extends Thread {
      47          15 :     private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      48             : 
      49          15 :     private final List<Runnable> tasks = new ArrayList<>();
      50             :     private boolean shutdownStarted;
      51             :     private boolean shutdownComplete;
      52             : 
      53          15 :     ShutdownCallback() {
      54          15 :       setName("ShutdownCallback");
      55          15 :     }
      56             : 
      57             :     boolean add(Runnable newTask) {
      58          15 :       synchronized (this) {
      59          15 :         if (!shutdownStarted && !shutdownComplete) {
      60          15 :           if (tasks.isEmpty()) {
      61          15 :             Runtime.getRuntime().addShutdownHook(this);
      62             :           }
      63          15 :           tasks.add(newTask);
      64          15 :           return true;
      65             :         }
      66             :         // We don't permit adding a task once shutdown has started.
      67             :         //
      68           0 :         return false;
      69             :       }
      70             :     }
      71             : 
      72             :     @Override
      73             :     public void run() {
      74          14 :       logger.atFine().log("Graceful shutdown requested");
      75             : 
      76             :       List<Runnable> taskList;
      77          14 :       synchronized (this) {
      78          14 :         shutdownStarted = true;
      79          14 :         taskList = tasks;
      80          14 :       }
      81             : 
      82          14 :       for (Runnable task : taskList) {
      83             :         try {
      84          13 :           task.run();
      85           0 :         } catch (Exception err) {
      86           0 :           logger.atSevere().withCause(err).log("Cleanup task failed");
      87          13 :         }
      88          13 :       }
      89             : 
      90          13 :       logger.atFine().log("Shutdown complete");
      91             : 
      92          13 :       synchronized (this) {
      93          13 :         shutdownComplete = true;
      94          13 :         notifyAll();
      95          13 :       }
      96          13 :     }
      97             : 
      98             :     void manualShutdown() {
      99           0 :       Runtime.getRuntime().removeShutdownHook(this);
     100           0 :       run();
     101           0 :     }
     102             : 
     103             :     void waitForShutdown() {
     104          15 :       synchronized (this) {
     105          15 :         while (!shutdownComplete) {
     106             :           try {
     107           0 :             wait();
     108          15 :           } catch (InterruptedException e) {
     109          15 :             return;
     110           0 :           }
     111             :         }
     112           0 :       }
     113           0 :     }
     114             :   }
     115             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750