mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

* Update project.pbxproj files to say Flutter rather than Chromium Also, the templates now have an empty organization so that we don't cause people to give their apps a Flutter copyright. * Update the copyright notice checker to require a standard notice on all files * Update copyrights on Dart files. (This was a mechanical commit.) * Fix weird license headers on Dart files that deviate from our conventions; relicense Shrine. Some were already marked "The Flutter Authors", not clear why. Their dates have been normalized. Some were missing the blank line after the license. Some were randomly different in trivial ways for no apparent reason (e.g. missing the trailing period). * Clean up the copyrights in non-Dart files. (Manual edits.) Also, make sure templates don't have copyrights. * Fix some more ORGANIZATIONNAMEs
135 lines
4.4 KiB
Dart
135 lines
4.4 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
|
|
import 'async_guard.dart';
|
|
import 'context.dart';
|
|
import 'io.dart';
|
|
|
|
typedef SignalHandler = FutureOr<void> Function(ProcessSignal signal);
|
|
|
|
Signals get signals => Signals.instance;
|
|
|
|
// The default list of signals that should cause the process to exit.
|
|
const List<ProcessSignal> _defaultExitSignals = <ProcessSignal>[
|
|
ProcessSignal.SIGTERM,
|
|
ProcessSignal.SIGINT,
|
|
ProcessSignal.SIGKILL,
|
|
];
|
|
|
|
/// A class that manages signal handlers
|
|
///
|
|
/// Signal handlers are run in the order that they were added.
|
|
abstract class Signals {
|
|
factory Signals({
|
|
List<ProcessSignal> exitSignals = _defaultExitSignals,
|
|
}) => _DefaultSignals._(exitSignals);
|
|
|
|
static Signals get instance => context.get<Signals>();
|
|
|
|
/// Adds a signal handler to run on receipt of signal.
|
|
///
|
|
/// The handler will run after all handlers that were previously added for the
|
|
/// signal. The function returns an abstract token that should be provided to
|
|
/// removeHandler to remove the handler.
|
|
Object addHandler(ProcessSignal signal, SignalHandler handler);
|
|
|
|
/// Removes a signal handler.
|
|
///
|
|
/// Removes the signal handler for the signal identified by the abstract
|
|
/// token parameter. Returns true if the handler was removed and false
|
|
/// otherwise.
|
|
Future<bool> removeHandler(ProcessSignal signal, Object token);
|
|
|
|
/// If a [SignalHandler] throws an error, either synchronously or
|
|
/// asynchronously, it will be added to this stream instead of propagated.
|
|
Stream<Object> get errors;
|
|
}
|
|
|
|
class _DefaultSignals implements Signals {
|
|
_DefaultSignals._(this.exitSignals);
|
|
|
|
final List<ProcessSignal> exitSignals;
|
|
|
|
// A table mapping (signal, token) -> signal handler.
|
|
final Map<ProcessSignal, Map<Object, SignalHandler>> _handlersTable =
|
|
<ProcessSignal, Map<Object, SignalHandler>>{};
|
|
|
|
// A table mapping (signal) -> signal handler list. The list is in the order
|
|
// that the signal handlers should be run.
|
|
final Map<ProcessSignal, List<SignalHandler>> _handlersList =
|
|
<ProcessSignal, List<SignalHandler>>{};
|
|
|
|
// A table mapping (signal) -> low-level signal event stream.
|
|
final Map<ProcessSignal, StreamSubscription<ProcessSignal>> _streamSubscriptions =
|
|
<ProcessSignal, StreamSubscription<ProcessSignal>>{};
|
|
|
|
// The stream controller for errors coming from signal handlers.
|
|
final StreamController<Object> _errorStreamController = StreamController<Object>.broadcast();
|
|
|
|
@override
|
|
Stream<Object> get errors => _errorStreamController.stream;
|
|
|
|
@override
|
|
Object addHandler(ProcessSignal signal, SignalHandler handler) {
|
|
final Object token = Object();
|
|
_handlersTable.putIfAbsent(signal, () => <Object, SignalHandler>{});
|
|
_handlersTable[signal][token] = handler;
|
|
|
|
_handlersList.putIfAbsent(signal, () => <SignalHandler>[]);
|
|
_handlersList[signal].add(handler);
|
|
|
|
// If we added the first one, then call signal.watch(), listen, and cache
|
|
// the stream controller.
|
|
if (_handlersList[signal].length == 1) {
|
|
_streamSubscriptions[signal] = signal.watch().listen(_handleSignal);
|
|
}
|
|
return token;
|
|
}
|
|
|
|
@override
|
|
Future<bool> removeHandler(ProcessSignal signal, Object token) async {
|
|
// We don't know about this signal.
|
|
if (!_handlersTable.containsKey(signal)) {
|
|
return false;
|
|
}
|
|
// We don't know about this token.
|
|
if (!_handlersTable[signal].containsKey(token)) {
|
|
return false;
|
|
}
|
|
final SignalHandler handler = _handlersTable[signal][token];
|
|
final bool removed = _handlersList[signal].remove(handler);
|
|
if (!removed) {
|
|
return false;
|
|
}
|
|
|
|
// If _handlersList[signal] is empty, then lookup the cached stream
|
|
// controller and unsubscribe from the stream.
|
|
if (_handlersList.isEmpty) {
|
|
await _streamSubscriptions[signal].cancel();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Future<void> _handleSignal(ProcessSignal s) async {
|
|
for (SignalHandler handler in _handlersList[s]) {
|
|
try {
|
|
await asyncGuard<void>(() async => handler(s));
|
|
} catch (e) {
|
|
if (_errorStreamController.hasListener) {
|
|
_errorStreamController.add(e);
|
|
}
|
|
}
|
|
}
|
|
// If this was a signal that should cause the process to go down, then
|
|
// call exit();
|
|
if (_shouldExitFor(s)) {
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
bool _shouldExitFor(ProcessSignal signal) => exitSignals.contains(signal);
|
|
}
|