├── .github
├── CONTRIBUTING.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .swift-version
├── .swiftlint.yml
├── .travis.yml
├── BlueSignals.podspec
├── LICENSE
├── Package.swift
├── Package@swift-4.swift
├── README.md
├── Signals-Framework
├── Info.plist
└── Signals_Framework.h
├── Signals.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ ├── Signals-Framework.xcscheme
│ ├── Signals.xcscheme
│ └── xcschememanagement.plist
└── Sources
└── Signals
├── SignalWatch.swift
├── SignalWatchHandler.swift
└── Signals.swift
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to IBM-Swift
2 |
3 | We welcome contributions, and request you follow these guidelines.
4 |
5 | - [Raising issues](#raising-issues)
6 | - [Contributor License Agreement](#contributor-license-agreement)
7 | - [Coding Standards](#coding-standards)
8 |
9 |
10 | ## Raising issues
11 |
12 | Please raise any bug reports on the issue tracker. Be sure to
13 | search the list to see if your issue has already been raised.
14 |
15 | A good bug report is one that make it easy for us to understand what you were
16 | trying to do and what went wrong. Provide as much context as possible so we can try to recreate the issue.
17 |
18 | ### Contributor License Agreement
19 |
20 | In order for us to accept pull-requests, the contributor must first complete
21 | a Contributor License Agreement (CLA). Please see our [CLA repo](http://github.com/IBM-Swift/CLA) for more information.
22 |
23 | This clarifies the intellectual property license granted with any contribution. It is for your protection as a
24 | Contributor as well as the protection of IBM and its customers; it does not
25 | change your rights to use your own Contributions for any other purpose.
26 |
27 | ### Coding standards
28 |
29 | Please ensure you follow the coding standards used throughout the existing
30 | code base. Some basic rules include:
31 |
32 | - all files must have the Apache license in the header.
33 | - all PRs must have passing builds for all operating systems.
34 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Description
4 |
5 |
6 | ## Motivation and Context
7 |
8 |
9 |
10 | ## How Has This Been Tested?
11 |
12 |
13 |
14 |
15 | ## Checklist:
16 |
17 |
18 | - [ ] I have submitted a [CLA form](https://github.com/IBM-Swift/CLA)
19 | - [ ] If applicable, I have updated the documentation accordingly.
20 | - [ ] If applicable, I have added tests to cover my changes.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata
19 |
20 | ## Other
21 | *.xccheckout
22 | *.moved-aside
23 | *.xcuserstate
24 | *.xcscmblueprint
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 |
34 | # Swift Package Manager
35 | #
36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
37 | # Packages/
38 | .build/
39 | .swiftpm
40 |
41 | # CocoaPods
42 | #
43 | # We recommend against adding the Pods directory to your .gitignore. However
44 | # you should judge for yourself, the pros and cons are mentioned at:
45 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
46 | #
47 | # Pods/
48 |
49 | # Carthage
50 | #
51 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
52 | # Carthage/Checkouts
53 |
54 | Carthage/Build
55 |
56 | # fastlane
57 | #
58 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
59 | # screenshots whenever they are needed.
60 | # For more information about the recommended setup visit:
61 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
62 |
63 | fastlane/report.xml
64 | fastlane/screenshots
65 |
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 5.1
2 |
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | included:
2 | - Sources
3 | - Tests
4 | disabled_rules:
5 | - trailing_newline
6 | - force_cast
7 | - function_body_length
8 | - variable_name
9 | - line_length
10 | - trailing_whitespace
11 | - type_name
12 | - type_body_length
13 | - todo
14 | - file_length
15 | - leading_whitespace
16 | - mark
17 | - function_parameter_count
18 | - cyclomatic_complexity
19 | - colon
20 | - fallthrough
21 | - empty_enum_arguments
22 | - unused_optional_binding
23 | - empty_parentheses_with_trailing_closure
24 | - closure_parameter_position
25 | - vertical_whitespace
26 | - trailing_comma
27 | - xctfail_message
28 | - class_delegate_protocol
29 | - redundant_optional_initialization
30 | custom_rules:
31 | double_space:
32 | include: "*.swift"
33 | name: "Double space"
34 | regex: "([a-z,A-Z] \\s+)"
35 | message: "Double space between keywords"
36 | match_kinds: keyword
37 | severity: warning
38 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Travis CI build file.
2 |
3 | # whitelist (branches that should be built)
4 | branches:
5 | only:
6 | - master
7 | - /^issue.*$/
8 |
9 | # the matrix of builds should cover each combination of Swift version
10 | # and platform that is supported. The version of Swift used is specified
11 | # by .swift-version, unless SWIFT_SNAPSHOT is specified.
12 | matrix:
13 | include:
14 | - os: linux
15 | dist: xenial
16 | sudo: required
17 | services: docker
18 | env: DOCKER_IMAGE=docker.kitura.net/kitura/swift-ci-ubuntu16.04:5.1.5
19 | - os: linux
20 | dist: bionic
21 | sudo: required
22 | services: docker
23 | env: DOCKER_IMAGE=docker.kitura.net/kitura/swift-ci-ubuntu18.04:5.4
24 | - os: linux
25 | dist: xenial
26 | sudo: required
27 | services: docker
28 | env: DOCKER_IMAGE=docker.kitura.net/kitura/swift-ci-ubuntu18.04:latest USE_SWIFT_DEVELOPMENT_SNAPSHOT=1
29 | - os: osx
30 | osx_image: xcode11
31 | sudo: required
32 | env: SWIFT_SNAPSHOT=5.1.5 JAZZY_ELIGIBLE=true
33 | - os: osx
34 | osx_image: xcode12.2
35 | sudo: required
36 | - os: osx
37 | osx_image: xcode12.5
38 | sudo: required
39 | env: USE_SWIFT_DEVELOPMENT_SNAPSHOT=1
40 |
41 | before_install:
42 | - git clone https://github.com/Kitura/Package-Builder.git
43 |
44 | script:
45 | - ./Package-Builder/build-package.sh -projectDir $TRAVIS_BUILD_DIR
46 |
--------------------------------------------------------------------------------
/BlueSignals.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "BlueSignals"
3 | s.version = "2.0.0"
4 | s.summary = "Swift cross-platform OS signals handler."
5 | s.homepage = "https://github.com/Kitura/BlueSignals"
6 | s.license = { :type => "Apache License, Version 2.0" }
7 | s.author = "IBM"
8 | s.module_name = 'Signals'
9 |
10 | s.requires_arc = true
11 | s.osx.deployment_target = "10.11"
12 | s.ios.deployment_target = "10.0"
13 | s.tvos.deployment_target = "10.0"
14 | s.source = { :git => "https://github.com/Kitura/BlueSignals.git", :tag => s.version }
15 | s.source_files = "Sources/Signals/*.swift"
16 | s.pod_target_xcconfig = {
17 | 'SWIFT_VERSION' => '5.0',
18 | }
19 | end
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.1
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | /**
5 | * Copyright IBM Corporation and the Kitura project authors 2016-2020
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | **/
19 |
20 | import PackageDescription
21 |
22 | #if os(Linux) || os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
23 |
24 | let package = Package(
25 | name: "Signals",
26 | platforms: [.macOS(.v10_15), .iOS(.v13), .watchOS(.v6), .tvOS(.v13)],
27 | products: [
28 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
29 | .library(
30 | name: "Signals",
31 | targets: ["Signals"]
32 | )
33 | ],
34 | targets: [
35 | .target(
36 | name: "Signals"
37 | ),
38 | ]
39 | )
40 |
41 | #else
42 |
43 | fatalError("Unsupported OS")
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/Package@swift-4.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:4.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | /**
5 | * Copyright IBM Corporation and the Kitura project authors 2016-2020
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | **/
19 |
20 | import PackageDescription
21 |
22 | #if os(Linux) || os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
23 |
24 | let package = Package(
25 | name: "Signals",
26 | products: [
27 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
28 | .library(
29 | name: "Signals",
30 | targets: ["Signals"]
31 | )
32 | ],
33 | targets: [
34 | .target(
35 | name: "Signals",
36 | exclude: ["Signals.xcodeproj", "README.md", "Sources/Info.plist", "Sources/Signals.h", "Tests"]
37 | ),
38 | ]
39 | )
40 |
41 | #else
42 |
43 | fatalError("Unsupported OS")
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | # Signals
18 |
19 | Generic Cross Platform Signal Handler.
20 |
21 | ## Prerequisites
22 |
23 | ### Swift
24 |
25 | * Swift Open Source `swift-5.1-RELEASE` toolchain (**Minimum REQUIRED for latest release**)
26 | * Swift Open Source `swift-5.4-RELEASE` toolchain (**Recommended**)
27 | * Swift toolchain included in *Xcode Version 11.0 or higher*.
28 |
29 | BlueSignals version 2.0 and above supports Swift 5.1+. See older versions of BlueSSLService for older versions of Swift.
30 |
31 | ### macOS
32 |
33 | * macOS 10.14.6 (*Mojave*) or higher.
34 | * Xcode Version 11.0 or higher using one of the above toolchains.
35 | * Xcode Version 12.5 or higher using the included toolchain (*Recommended*).
36 |
37 | ### iOS
38 |
39 | * iOS 10.0 or higher
40 | * Xcode Version 11.0 or higher using one of the above toolchains.
41 | * Xcode Version 12.5 or higher using the included toolchain (*Recommended*).
42 |
43 | ### Linux
44 |
45 | * Ubuntu 16.04 (or 16.10 but only tested on 16.04) and 18.04.
46 | * One of the Swift Open Source toolchain listed above.
47 |
48 |
49 | ## Build
50 |
51 | To build Signals from the command line:
52 |
53 | ```
54 | % cd
55 | % swift build
56 | ```
57 |
58 | ## Using Signals
59 |
60 | ### Including in your project
61 |
62 | #### Swift Package Manager
63 |
64 | To include BlueSignals into a Swift Package Manager package, add it to the `dependencies` attribute defined in your `Package.swift` file. You can select the version using the `majorVersion` and `minor` parameters. For example:
65 | ```
66 | dependencies: [
67 | .Package(url: "https://github.com/Kitura/BlueSignals.git", majorVersion: , minor: )
68 | ]
69 | ```
70 |
71 | #### Carthage
72 | To include BlueSignals in a project using Carthage, add a line to your `Cartfile` with the GitHub organization and project names and version. For example:
73 | ```
74 | github "Kitura/BlueSignals" ~> .
75 | ```
76 |
77 | #### CocoaPods
78 | To include BlueSignals in a project using CocoaPods, you just add `BlueSignals` to your `Podfile`, for example:
79 | ```
80 | platform :ios, '10.0'
81 |
82 | target 'MyApp' do
83 | use_frameworks!
84 | pod 'BlueSignals'
85 | end
86 | ```
87 |
88 | ### Before starting
89 |
90 | The first thing you need to do is import the Signals framework. This is done by the following:
91 | ```
92 | import Signals
93 | ```
94 |
95 | ### Provided APIs
96 |
97 | Signals provides four (4) class level APIs. Three (3) are used for trapping and handling operating system signals. The other function allows for the raising of a signal.
98 |
99 | #### Watching a signal
100 |
101 | ``SignalWatch`` provides an interface that allows a trapped signal to notify multiple "signal watchers". In this way, signal traps can be shared across libraries in the same application. In most cases this can be used as a direct replacement for `trap()`.
102 |
103 | When a signal is added via ``SignalWatch``, it will install it's own handler on that signal via `trap()`. As such, it is important to not use `trap()` directly when using ``SignalWatch``. If all watchers of a signal are removed, ``SignalWatch`` will intelligently restore the handler that was installed before ``SignalWatch``.
104 |
105 | ```swift
106 | import Signals
107 |
108 | ...
109 | let server: SomeServer = ...
110 |
111 |
112 | SignalWatch.shared.on(signal: .int) { _ in
113 | server.shutdownServer()
114 | }
115 |
116 | server.run()
117 |
118 | ```
119 |
120 |
121 | #### Trapping a signal
122 | - `trap(signal signal: Signal, action: SigActionHandler)` - This basic API allows you to set and specific handler for a specific signal.
123 |
124 | The example below shows how to add a trap handler to a server in order to perform and orderly shutdown in the event that user press `^C` which sends the process a `SIGINT`.
125 | ```swift
126 | import Signals
127 |
128 | ...
129 |
130 | let server: SomeServer = ...
131 |
132 | Signals.trap(signal: .int) { signal in
133 |
134 | server.shutdownServer()
135 | }
136 |
137 | server.run()
138 | ```
139 | Additionally, convenience API's that build on the basic API specified above are provided that will allow for trapping multiple signals, each to a separate handler or to a single handler.
140 | - `trap(signals signals: [(signal: Signal, action: SigActionHandler)])` - This lets you trap multiple signals to separate handlers in a single function call.
141 | - `trap(signals signals: [Signal], action: SigActionHandler)` - This API lets you trap multiple signals to a common handler.
142 |
143 | #### Raising a signal
144 | - `raise(signal signal: Signal)` - This API is used to send an operating system signal to your application.
145 |
146 | This example illustrates how to use Signals to raise a signal with the OS, in this case `SIGABRT`.
147 | ```swift
148 | import Signals
149 |
150 | ...
151 |
152 | Signals.raise(signal: .abrt)
153 | ```
154 |
155 | #### Ignoring a signal
156 | - `func ignore(signal: Signal)` - This API is used to ignore an operating system signal.
157 |
158 | This example illustrates how to use Signals to ignore a signal with the OS, in this case `SIGPIPE`.
159 | ```swift
160 | import Signals
161 |
162 | ...
163 |
164 | Signals.ignore(signal: .pipe)
165 | ```
166 |
167 | #### Restoring a signals default handler
168 | - `func restore(signal: Signal)` - This API is used to restore an operating system signals default handler.
169 |
170 | This example illustrates how to use Signals to restore a signals default handler, in this case `SIGPIPE`.
171 | ```swift
172 | import Signals
173 |
174 | ...
175 |
176 | Signals.restore(signal: .pipe)
177 | ```
178 |
179 | #### Adding a USER-DEFINED signal
180 |
181 | This example shows how to add a user defined signal, add a trap handler for it and then raise the signal.
182 | ```swift
183 | import Signals
184 |
185 | let mySignal = Signals.Signal.user(20)
186 |
187 | Signals.trap(signal: mySignal) { signal in
188 |
189 | print("Received signal \(signal)")
190 | }
191 |
192 | Signals.raise(signal: mySignal)
193 |
194 | ```
195 | The output of the above snippet is:
196 | ```
197 | Received signal 20
198 | ```
199 |
200 | ## Community
201 |
202 | We love to talk server-side Swift and Kitura. Join our [Slack](http://swift-at-ibm-slack.mybluemix.net/) to meet the team!
203 |
204 | ## License
205 |
206 | This library is licensed under Apache 2.0. Full license text is available in [LICENSE](https://github.com/Kitura/BlueSignals/blob/master/LICENSE).
207 |
--------------------------------------------------------------------------------
/Signals-Framework/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Signals-Framework/Signals_Framework.h:
--------------------------------------------------------------------------------
1 | //
2 | // Signals_Framework.h
3 | // Signals-Framework
4 | //
5 | // Created by Bill Abt on 10/19/18.
6 | //
7 |
8 | #import
9 |
10 | //! Project version number for Signals_Framework.
11 | FOUNDATION_EXPORT double Signals_FrameworkVersionNumber;
12 |
13 | //! Project version string for Signals_Framework.
14 | FOUNDATION_EXPORT const unsigned char Signals_FrameworkVersionString[];
15 |
16 | // In this header, you should import all the public headers of your framework using statements like #import
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Signals.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 8C6EF7FA217A1D6D00D74FA1 /* Signals_Framework.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C6EF7F8217A1D6D00D74FA1 /* Signals_Framework.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | __src_cc_ref_Sources/Signals.swift /* Signals.swift in Sources */ = {isa = PBXBuildFile; fileRef = __PBXFileRef_Sources/Signals.swift /* Signals.swift */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXFileReference section */
15 | 8C2D91E1215EEEA1000E2D9C /* BlueSignals.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = BlueSignals.podspec; sourceTree = ""; };
16 | 8C30FB321CAAE0E000113F9D /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
17 | 8C30FB331CAAE0E000113F9D /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
18 | 8C6EF7F6217A1D6D00D74FA1 /* Signals_Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Signals_Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
19 | 8C6EF7F8217A1D6D00D74FA1 /* Signals_Framework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Signals_Framework.h; sourceTree = ""; };
20 | 8C6EF7F9217A1D6D00D74FA1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
21 | __PBXFileRef_Package.swift /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
22 | __PBXFileRef_Sources/Signals.swift /* Signals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Signals.swift; path = Sources/Signals/Signals.swift; sourceTree = ""; };
23 | "_____Product_Signals" /* libSignals.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; path = libSignals.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
24 | /* End PBXFileReference section */
25 |
26 | /* Begin PBXFrameworksBuildPhase section */
27 | 8C6EF7F3217A1D6D00D74FA1 /* Frameworks */ = {
28 | isa = PBXFrameworksBuildPhase;
29 | buildActionMask = 2147483647;
30 | files = (
31 | );
32 | runOnlyForDeploymentPostprocessing = 0;
33 | };
34 | "___LinkPhase_Signals" /* Frameworks */ = {
35 | isa = PBXFrameworksBuildPhase;
36 | buildActionMask = 0;
37 | files = (
38 | );
39 | runOnlyForDeploymentPostprocessing = 0;
40 | };
41 | /* End PBXFrameworksBuildPhase section */
42 |
43 | /* Begin PBXGroup section */
44 | 8C6EF7F7217A1D6D00D74FA1 /* Signals-Framework */ = {
45 | isa = PBXGroup;
46 | children = (
47 | 8C6EF7F8217A1D6D00D74FA1 /* Signals_Framework.h */,
48 | 8C6EF7F9217A1D6D00D74FA1 /* Info.plist */,
49 | );
50 | path = "Signals-Framework";
51 | sourceTree = "";
52 | };
53 | "___RootGroup_" = {
54 | isa = PBXGroup;
55 | children = (
56 | 8C2D91E1215EEEA1000E2D9C /* BlueSignals.podspec */,
57 | 8C30FB321CAAE0E000113F9D /* LICENSE */,
58 | __PBXFileRef_Package.swift /* Package.swift */,
59 | 8C30FB331CAAE0E000113F9D /* README.md */,
60 | "_____Sources_" /* Sources */,
61 | "_______Tests_" /* Tests */,
62 | 8C6EF7F7217A1D6D00D74FA1 /* Signals-Framework */,
63 | "____Products_" /* Products */,
64 | );
65 | sourceTree = "";
66 | };
67 | "____Products_" /* Products */ = {
68 | isa = PBXGroup;
69 | children = (
70 | "_____Product_Signals" /* libSignals.dylib */,
71 | 8C6EF7F6217A1D6D00D74FA1 /* Signals_Framework.framework */,
72 | );
73 | name = Products;
74 | sourceTree = "";
75 | };
76 | "_____Sources_" /* Sources */ = {
77 | isa = PBXGroup;
78 | children = (
79 | __PBXFileRef_Sources/Signals.swift /* Signals.swift */,
80 | );
81 | name = Sources;
82 | sourceTree = "";
83 | };
84 | "_______Tests_" /* Tests */ = {
85 | isa = PBXGroup;
86 | children = (
87 | );
88 | name = Tests;
89 | sourceTree = "";
90 | };
91 | /* End PBXGroup section */
92 |
93 | /* Begin PBXHeadersBuildPhase section */
94 | 8C6EF7F1217A1D6D00D74FA1 /* Headers */ = {
95 | isa = PBXHeadersBuildPhase;
96 | buildActionMask = 2147483647;
97 | files = (
98 | 8C6EF7FA217A1D6D00D74FA1 /* Signals_Framework.h in Headers */,
99 | );
100 | runOnlyForDeploymentPostprocessing = 0;
101 | };
102 | /* End PBXHeadersBuildPhase section */
103 |
104 | /* Begin PBXNativeTarget section */
105 | 8C6EF7F5217A1D6D00D74FA1 /* Signals-Framework */ = {
106 | isa = PBXNativeTarget;
107 | buildConfigurationList = 8C6EF7FD217A1D6D00D74FA1 /* Build configuration list for PBXNativeTarget "Signals-Framework" */;
108 | buildPhases = (
109 | 8C6EF7F1217A1D6D00D74FA1 /* Headers */,
110 | 8C6EF7F2217A1D6D00D74FA1 /* Sources */,
111 | 8C6EF7F3217A1D6D00D74FA1 /* Frameworks */,
112 | 8C6EF7F4217A1D6D00D74FA1 /* Resources */,
113 | );
114 | buildRules = (
115 | );
116 | dependencies = (
117 | );
118 | name = "Signals-Framework";
119 | productName = "Signals-Framework";
120 | productReference = 8C6EF7F6217A1D6D00D74FA1 /* Signals_Framework.framework */;
121 | productType = "com.apple.product-type.framework";
122 | };
123 | "______Target_Signals" /* Signals */ = {
124 | isa = PBXNativeTarget;
125 | buildConfigurationList = "_______Confs_Signals" /* Build configuration list for PBXNativeTarget "Signals" */;
126 | buildPhases = (
127 | CompilePhase_Signals /* Sources */,
128 | "___LinkPhase_Signals" /* Frameworks */,
129 | );
130 | buildRules = (
131 | );
132 | dependencies = (
133 | );
134 | name = Signals;
135 | productName = Signals;
136 | productReference = "_____Product_Signals" /* libSignals.dylib */;
137 | productType = "com.apple.product-type.library.dynamic";
138 | };
139 | /* End PBXNativeTarget section */
140 |
141 | /* Begin PBXProject section */
142 | __RootObject_ /* Project object */ = {
143 | isa = PBXProject;
144 | attributes = {
145 | LastUpgradeCheck = 1020;
146 | TargetAttributes = {
147 | 8C6EF7F5217A1D6D00D74FA1 = {
148 | CreatedOnToolsVersion = 10.0;
149 | ProvisioningStyle = Automatic;
150 | };
151 | "______Target_Signals" = {
152 | LastSwiftMigration = 1000;
153 | };
154 | };
155 | };
156 | buildConfigurationList = "___RootConfs_" /* Build configuration list for PBXProject "Signals" */;
157 | compatibilityVersion = "Xcode 3.2";
158 | developmentRegion = en;
159 | hasScannedForEncodings = 0;
160 | knownRegions = (
161 | en,
162 | Base,
163 | );
164 | mainGroup = "___RootGroup_";
165 | productRefGroup = "____Products_" /* Products */;
166 | projectDirPath = "";
167 | projectRoot = "";
168 | targets = (
169 | "______Target_Signals" /* Signals */,
170 | 8C6EF7F5217A1D6D00D74FA1 /* Signals-Framework */,
171 | );
172 | };
173 | /* End PBXProject section */
174 |
175 | /* Begin PBXResourcesBuildPhase section */
176 | 8C6EF7F4217A1D6D00D74FA1 /* Resources */ = {
177 | isa = PBXResourcesBuildPhase;
178 | buildActionMask = 2147483647;
179 | files = (
180 | );
181 | runOnlyForDeploymentPostprocessing = 0;
182 | };
183 | /* End PBXResourcesBuildPhase section */
184 |
185 | /* Begin PBXSourcesBuildPhase section */
186 | 8C6EF7F2217A1D6D00D74FA1 /* Sources */ = {
187 | isa = PBXSourcesBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | );
191 | runOnlyForDeploymentPostprocessing = 0;
192 | };
193 | CompilePhase_Signals /* Sources */ = {
194 | isa = PBXSourcesBuildPhase;
195 | buildActionMask = 0;
196 | files = (
197 | __src_cc_ref_Sources/Signals.swift /* Signals.swift in Sources */,
198 | );
199 | runOnlyForDeploymentPostprocessing = 0;
200 | };
201 | /* End PBXSourcesBuildPhase section */
202 |
203 | /* Begin XCBuildConfiguration section */
204 | 8C6EF7FB217A1D6D00D74FA1 /* Debug */ = {
205 | isa = XCBuildConfiguration;
206 | buildSettings = {
207 | ALWAYS_SEARCH_USER_PATHS = NO;
208 | CLANG_ANALYZER_NONNULL = YES;
209 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
210 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
211 | CLANG_CXX_LIBRARY = "libc++";
212 | CLANG_ENABLE_MODULES = YES;
213 | CLANG_ENABLE_OBJC_ARC = YES;
214 | CLANG_ENABLE_OBJC_WEAK = YES;
215 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
216 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
217 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
218 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
219 | CODE_SIGN_IDENTITY = "-";
220 | CODE_SIGN_STYLE = Automatic;
221 | COMBINE_HIDPI_IMAGES = YES;
222 | COPY_PHASE_STRIP = NO;
223 | CURRENT_PROJECT_VERSION = 1;
224 | DEBUG_INFORMATION_FORMAT = dwarf;
225 | DEFINES_MODULE = YES;
226 | DYLIB_COMPATIBILITY_VERSION = 1;
227 | DYLIB_CURRENT_VERSION = 1;
228 | DYLIB_INSTALL_NAME_BASE = "@rpath";
229 | FRAMEWORK_VERSION = A;
230 | GCC_C_LANGUAGE_STANDARD = gnu11;
231 | GCC_DYNAMIC_NO_PIC = NO;
232 | GCC_OPTIMIZATION_LEVEL = 0;
233 | GCC_PREPROCESSOR_DEFINITIONS = (
234 | "DEBUG=1",
235 | "$(inherited)",
236 | );
237 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
238 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
239 | INFOPLIST_FILE = "Signals-Framework/Info.plist";
240 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
241 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
242 | MACOSX_DEPLOYMENT_TARGET = 10.14;
243 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
244 | MTL_FAST_MATH = YES;
245 | PRODUCT_BUNDLE_IDENTIFIER = "com.ibm.oss.Signals-Framework";
246 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
247 | SDKROOT = macosx;
248 | SKIP_INSTALL = YES;
249 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
250 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
251 | SWIFT_VERSION = 4.2;
252 | VERSIONING_SYSTEM = "apple-generic";
253 | VERSION_INFO_PREFIX = "";
254 | };
255 | name = Debug;
256 | };
257 | 8C6EF7FC217A1D6D00D74FA1 /* Release */ = {
258 | isa = XCBuildConfiguration;
259 | buildSettings = {
260 | ALWAYS_SEARCH_USER_PATHS = NO;
261 | CLANG_ANALYZER_NONNULL = YES;
262 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
263 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
264 | CLANG_CXX_LIBRARY = "libc++";
265 | CLANG_ENABLE_MODULES = YES;
266 | CLANG_ENABLE_OBJC_ARC = YES;
267 | CLANG_ENABLE_OBJC_WEAK = YES;
268 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
269 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
270 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
271 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
272 | CODE_SIGN_IDENTITY = "-";
273 | CODE_SIGN_STYLE = Automatic;
274 | COMBINE_HIDPI_IMAGES = YES;
275 | COPY_PHASE_STRIP = NO;
276 | CURRENT_PROJECT_VERSION = 1;
277 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
278 | DEFINES_MODULE = YES;
279 | DYLIB_COMPATIBILITY_VERSION = 1;
280 | DYLIB_CURRENT_VERSION = 1;
281 | DYLIB_INSTALL_NAME_BASE = "@rpath";
282 | ENABLE_NS_ASSERTIONS = NO;
283 | FRAMEWORK_VERSION = A;
284 | GCC_C_LANGUAGE_STANDARD = gnu11;
285 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
286 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
287 | INFOPLIST_FILE = "Signals-Framework/Info.plist";
288 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
289 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
290 | MACOSX_DEPLOYMENT_TARGET = 10.14;
291 | MTL_ENABLE_DEBUG_INFO = NO;
292 | MTL_FAST_MATH = YES;
293 | PRODUCT_BUNDLE_IDENTIFIER = "com.ibm.oss.Signals-Framework";
294 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
295 | SDKROOT = macosx;
296 | SKIP_INSTALL = YES;
297 | SWIFT_VERSION = 4.2;
298 | VERSIONING_SYSTEM = "apple-generic";
299 | VERSION_INFO_PREFIX = "";
300 | };
301 | name = Release;
302 | };
303 | _ReleaseConf_Signals /* Release */ = {
304 | isa = XCBuildConfiguration;
305 | buildSettings = {
306 | ALWAYS_SEARCH_USER_PATHS = NO;
307 | CLANG_ENABLE_OBJC_WEAK = YES;
308 | COMBINE_HIDPI_IMAGES = YES;
309 | DYLIB_INSTALL_NAME_BASE = "$(CONFIGURATION_BUILD_DIR)";
310 | ENABLE_TESTABILITY = YES;
311 | LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
312 | MACOSX_DEPLOYMENT_TARGET = 10.10;
313 | OTHER_SWIFT_FLAGS = "-DXcode";
314 | PRODUCT_MODULE_NAME = Signals;
315 | PRODUCT_NAME = "lib$(TARGET_NAME)";
316 | SWIFT_VERSION = 5.0;
317 | };
318 | name = Release;
319 | };
320 | "___DebugConf_Signals" /* Debug */ = {
321 | isa = XCBuildConfiguration;
322 | buildSettings = {
323 | ALWAYS_SEARCH_USER_PATHS = NO;
324 | CLANG_ENABLE_OBJC_WEAK = YES;
325 | COMBINE_HIDPI_IMAGES = YES;
326 | DYLIB_INSTALL_NAME_BASE = "$(CONFIGURATION_BUILD_DIR)";
327 | ENABLE_TESTABILITY = YES;
328 | LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
329 | MACOSX_DEPLOYMENT_TARGET = 10.10;
330 | OTHER_SWIFT_FLAGS = "-DXcode";
331 | PRODUCT_MODULE_NAME = Signals;
332 | PRODUCT_NAME = "lib$(TARGET_NAME)";
333 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
334 | SWIFT_VERSION = 5.0;
335 | };
336 | name = Debug;
337 | };
338 | "_____Release_" /* Release */ = {
339 | isa = XCBuildConfiguration;
340 | buildSettings = {
341 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
342 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
343 | CLANG_WARN_BOOL_CONVERSION = YES;
344 | CLANG_WARN_COMMA = YES;
345 | CLANG_WARN_CONSTANT_CONVERSION = YES;
346 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
347 | CLANG_WARN_EMPTY_BODY = YES;
348 | CLANG_WARN_ENUM_CONVERSION = YES;
349 | CLANG_WARN_INFINITE_RECURSION = YES;
350 | CLANG_WARN_INT_CONVERSION = YES;
351 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
352 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
353 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
354 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
355 | CLANG_WARN_STRICT_PROTOTYPES = YES;
356 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
357 | CLANG_WARN_UNREACHABLE_CODE = YES;
358 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
359 | ENABLE_STRICT_OBJC_MSGSEND = YES;
360 | GCC_NO_COMMON_BLOCKS = YES;
361 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
362 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
363 | GCC_WARN_UNDECLARED_SELECTOR = YES;
364 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
365 | GCC_WARN_UNUSED_FUNCTION = YES;
366 | GCC_WARN_UNUSED_VARIABLE = YES;
367 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
368 | SWIFT_VERSION = 3.0;
369 | };
370 | name = Release;
371 | };
372 | "_______Debug_" /* Debug */ = {
373 | isa = XCBuildConfiguration;
374 | buildSettings = {
375 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
376 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
377 | CLANG_WARN_BOOL_CONVERSION = YES;
378 | CLANG_WARN_COMMA = YES;
379 | CLANG_WARN_CONSTANT_CONVERSION = YES;
380 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
381 | CLANG_WARN_EMPTY_BODY = YES;
382 | CLANG_WARN_ENUM_CONVERSION = YES;
383 | CLANG_WARN_INFINITE_RECURSION = YES;
384 | CLANG_WARN_INT_CONVERSION = YES;
385 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
386 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
387 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
388 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
389 | CLANG_WARN_STRICT_PROTOTYPES = YES;
390 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
391 | CLANG_WARN_UNREACHABLE_CODE = YES;
392 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
393 | ENABLE_STRICT_OBJC_MSGSEND = YES;
394 | ENABLE_TESTABILITY = YES;
395 | GCC_NO_COMMON_BLOCKS = YES;
396 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
397 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
398 | GCC_WARN_UNDECLARED_SELECTOR = YES;
399 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
400 | GCC_WARN_UNUSED_FUNCTION = YES;
401 | GCC_WARN_UNUSED_VARIABLE = YES;
402 | ONLY_ACTIVE_ARCH = YES;
403 | SWIFT_VERSION = 3.0;
404 | };
405 | name = Debug;
406 | };
407 | /* End XCBuildConfiguration section */
408 |
409 | /* Begin XCConfigurationList section */
410 | 8C6EF7FD217A1D6D00D74FA1 /* Build configuration list for PBXNativeTarget "Signals-Framework" */ = {
411 | isa = XCConfigurationList;
412 | buildConfigurations = (
413 | 8C6EF7FB217A1D6D00D74FA1 /* Debug */,
414 | 8C6EF7FC217A1D6D00D74FA1 /* Release */,
415 | );
416 | defaultConfigurationIsVisible = 0;
417 | defaultConfigurationName = Debug;
418 | };
419 | "___RootConfs_" /* Build configuration list for PBXProject "Signals" */ = {
420 | isa = XCConfigurationList;
421 | buildConfigurations = (
422 | "_______Debug_" /* Debug */,
423 | "_____Release_" /* Release */,
424 | );
425 | defaultConfigurationIsVisible = 0;
426 | defaultConfigurationName = Debug;
427 | };
428 | "_______Confs_Signals" /* Build configuration list for PBXNativeTarget "Signals" */ = {
429 | isa = XCConfigurationList;
430 | buildConfigurations = (
431 | "___DebugConf_Signals" /* Debug */,
432 | _ReleaseConf_Signals /* Release */,
433 | );
434 | defaultConfigurationIsVisible = 0;
435 | defaultConfigurationName = Debug;
436 | };
437 | /* End XCConfigurationList section */
438 | };
439 | rootObject = __RootObject_ /* Project object */;
440 | }
441 |
--------------------------------------------------------------------------------
/Signals.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Signals.xcodeproj/xcshareddata/xcschemes/Signals-Framework.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
66 |
67 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/Signals.xcodeproj/xcshareddata/xcschemes/Signals.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Signals.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SchemeUserState
5 |
6 | Signals.xcscheme
7 |
8 |
9 | SuppressBuildableAutocreation
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Sources/Signals/SignalWatch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignalWatch.swift
3 | //
4 | //
5 | // Created by Danny Sung on 05/14/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | /// ``SignalWatch`` provides an interface around ``Signals`` that allows for multiple handlers to be registered for any given signal.
11 | public class SignalWatch {
12 | public static let shared = SignalWatch()
13 |
14 | typealias SignalNumber = Int32
15 | private var signalsWatched: [SignalNumber:[SignalWatchHandler]]
16 | private let queue: DispatchQueue
17 | private var currentSignalId = 0
18 |
19 | init() {
20 | self.signalsWatched = [:]
21 | self.queue = DispatchQueue(label: "SignalWatch Internal")
22 | }
23 |
24 | /// Add a handler for a signal
25 | /// - Parameters:
26 | /// - signal: Signal to watch
27 | /// - handler: Closure to call when the signal is recieved
28 | /// - Returns: A handle that can be used to remove the watcher
29 | @discardableResult
30 | public func on(signal: Signals.Signal, perform handler: @escaping (SignalWatchHandler)->Void) -> SignalWatchHandler {
31 |
32 | let signalWatchHandler = SignalWatchHandler(id: self.getNextSignalHandlerId(), signal: signal, userInfo: Void.self, handler: .noUserInfo(handler))
33 |
34 | return self.addHandler(signal: signal, signalWatchHandler: signalWatchHandler)
35 | }
36 |
37 | /// Add a handler for a signal
38 | /// - Parameters:
39 | /// - signal: Signal to watch
40 | /// - handler: Closure to call when the signal is recieved
41 | /// - userInfo: Additional data that will be passed to the handler
42 | /// - Returns: A handle that can be used to remove the watcher
43 | @discardableResult
44 | public func on(signal: Signals.Signal, perform handler: @escaping (SignalWatchHandler, Any)->Void, userInfo: Any) -> SignalWatchHandler {
45 |
46 | let signalWatchHandler = SignalWatchHandler(id: self.getNextSignalHandlerId(), signal: signal, userInfo: userInfo, handler: .userInfo(handler))
47 |
48 | return self.addHandler(signal: signal, signalWatchHandler: signalWatchHandler)
49 | }
50 |
51 | /// Remove the a signal handler
52 | /// - Parameter handler: ``SignalWatchHandler`` to remove
53 | public func remove(handler: SignalWatchHandler) {
54 | self.queue.sync {
55 | guard var handlerList = self.signalsWatched[handler.signal.rawValue] else { return }
56 |
57 | handlerList = handlerList.filter({ $0.id != handler.id })
58 | if handlerList.isEmpty {
59 | Signals.restore(signal: handler.signal)
60 | self.signalsWatched.removeValue(forKey: handler.signal.rawValue)
61 | } else {
62 | self.signalsWatched[handler.signal.rawValue] = handlerList
63 | }
64 | }
65 | }
66 |
67 | // MARK: - Private methods
68 |
69 | private func addHandler(signal: Signals.Signal, signalWatchHandler: SignalWatchHandler) -> SignalWatchHandler {
70 | return self.queue.sync {
71 |
72 | var handlerList = self.signalsWatched[signal.rawValue] ?? []
73 | handlerList.append(signalWatchHandler)
74 |
75 | self.signalsWatched[signal.rawValue] = handlerList
76 |
77 | Signals.trap(signal: signal) { signalValue in
78 | let signal = Signals.Signal(rawValue: signalValue)
79 | SignalWatch.shared.didRecieve(signal: signal)
80 | }
81 |
82 | return signalWatchHandler
83 | }
84 |
85 | }
86 |
87 |
88 | private func didRecieve(signal: Signals.Signal) {
89 | return self.queue.async {
90 | guard let signalWatchHandlerList = self.signalsWatched[signal.rawValue] else { return }
91 |
92 | for signalHandler in signalWatchHandlerList {
93 | signalHandler.callHandler()
94 | }
95 | }
96 | }
97 |
98 | private func getNextSignalHandlerId() -> Int {
99 | let currentSignalId = self.currentSignalId
100 | self.currentSignalId += 1
101 | return currentSignalId
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Sources/Signals/SignalWatchHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignalWatchHandler.swift
3 | //
4 | //
5 | // Created by Danny Sung on 05/14/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct SignalWatchHandler: Identifiable {
11 | public let id: Int
12 | public let signal: Signals.Signal
13 | let userInfo: Any
14 |
15 | enum HandlerType {
16 | case noUserInfo((SignalWatchHandler) -> Void)
17 | case userInfo((SignalWatchHandler, Any) -> Void)
18 | }
19 | let handler: HandlerType
20 |
21 | internal func callHandler() {
22 | switch self.handler {
23 | case .noUserInfo(let handler):
24 | handler(self)
25 | case .userInfo(let handler):
26 | handler(self, self.userInfo)
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/Signals/Signals.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Signals.swift
3 | // BlueSignals
4 | //
5 | // Created by Bill Abt on 3/29/16.
6 | // Copyright © 2016 IBM. All rights reserved.
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //
20 |
21 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
22 | import Darwin
23 | #elseif os(Linux)
24 | import Glibc
25 | #endif
26 |
27 | import Foundation
28 |
29 | // MARK: Signals
30 |
31 | /// ``Signals`` provides a type-safe Swift interface around POSIX Signals via `sigaction`. As such, only one handler may be active per Signal.
32 | public class Signals {
33 |
34 | // MARK: Enums
35 |
36 | ///
37 | /// Common OS Signals
38 | ///
39 | public enum Signal {
40 | case hup
41 | case int
42 | case quit
43 | case abrt
44 | case kill
45 | case alrm
46 | case term
47 | case pipe
48 | case cont
49 | case chld
50 | case io
51 | case prof
52 | case winch
53 | case info
54 | case user(Int)
55 |
56 | @available(*, renamed: "rawValue")
57 | public var valueOf: Int32 {
58 | return self.rawValue
59 | }
60 |
61 | ///
62 | /// Obtain the OS dependent value of a Signal
63 | ///
64 | public var rawValue: Int32 {
65 |
66 | switch self {
67 | case .hup:
68 | return Int32(SIGHUP)
69 | case .int:
70 | return Int32(SIGINT)
71 | case .quit:
72 | return Int32(SIGQUIT)
73 | case .abrt:
74 | return Int32(SIGABRT)
75 | case .kill:
76 | return Int32(SIGKILL)
77 | case .alrm:
78 | return Int32(SIGALRM)
79 | case .term:
80 | return Int32(SIGTERM)
81 | case .pipe:
82 | return Int32(SIGPIPE)
83 | case .cont:
84 | return Int32(SIGCONT)
85 | case .chld:
86 | return Int32(SIGCHLD)
87 | case .io:
88 | return Int32(SIGIO)
89 | case .prof:
90 | return Int32(SIGPROF)
91 | case .winch:
92 | return Int32(SIGWINCH)
93 | case .info:
94 | return Int32(SIGINFO)
95 | case .user(let sig):
96 | return Int32(sig)
97 |
98 | }
99 | }
100 |
101 | init(rawValue: Int32) {
102 | self.init(rawValue: Int(rawValue))
103 | }
104 |
105 | init(rawValue: Int) {
106 | switch rawValue {
107 | case Int(SIGHUP): self = .hup
108 | case Int(SIGINT): self = .int
109 | case Int(SIGQUIT): self = .quit
110 | case Int(SIGABRT): self = .abrt
111 | case Int(SIGKILL): self = .kill
112 | case Int(SIGALRM): self = .alrm
113 | case Int(SIGTERM): self = .term
114 | case Int(SIGPIPE): self = .pipe
115 | case Int(SIGCONT): self = .cont
116 | case Int(SIGCHLD): self = .chld
117 | case Int(SIGIO): self = .io
118 | case Int(SIGPROF): self = .prof
119 | case Int(SIGWINCH): self = .winch
120 | case Int(SIGINFO): self = .info
121 |
122 | default:
123 | self = .user(rawValue)
124 | }
125 | }
126 | }
127 |
128 |
129 | // MARK: Typealiases
130 |
131 | ///
132 | /// Action handler signature.
133 | ///
134 | public typealias SigActionHandler = @convention(c)(Int32) -> Void
135 |
136 |
137 | // MARK: Class Methods
138 |
139 | ///
140 | /// Trap an operating system signal.
141 | ///
142 | /// - Parameters:
143 | /// - signal: The signal to catch.
144 | /// - action: The action handler.
145 | ///
146 | public class func trap(signal: Signal, action: @escaping SigActionHandler) {
147 |
148 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
149 |
150 | var signalAction = sigaction(__sigaction_u: unsafeBitCast(action, to: __sigaction_u.self), sa_mask: 0, sa_flags: 0)
151 |
152 | _ = withUnsafePointer(to: &signalAction) { actionPointer in
153 |
154 | sigaction(signal.rawValue, actionPointer, nil)
155 | }
156 |
157 | #elseif os(Linux)
158 |
159 | var sigAction = sigaction()
160 |
161 | sigAction.__sigaction_handler = unsafeBitCast(action, to: sigaction.__Unnamed_union___sigaction_handler.self)
162 |
163 | _ = sigaction(signal.rawValue, &sigAction, nil)
164 |
165 | #endif
166 | }
167 |
168 | ///
169 | /// Trap multiple signals to individual handlers
170 | ///
171 | /// - Parameter signals: An array of tuples each containing a signal and signal handler.
172 | ///
173 | public class func trap(signals: [(signal: Signal, action: SigActionHandler)]) {
174 |
175 | for sighandler in signals {
176 |
177 | Signals.trap(signal: sighandler.signal, action: sighandler.action)
178 | }
179 | }
180 |
181 | ///
182 | /// Trap multiple signals to a single handler
183 | ///
184 | /// - Parameters:
185 | /// - signals: An array of signals to catch.
186 | /// - action: The action handler that will handle these signals.
187 | ///
188 | public class func trap(signals: [Signal], action: @escaping SigActionHandler) {
189 |
190 | for signal in signals {
191 |
192 | Signals.trap(signal: signal, action: action)
193 | }
194 | }
195 |
196 | ///
197 | /// Raise an operating system signal
198 | ///
199 | /// - Parameter signal: The signal to raise.
200 | ///
201 | public class func raise(signal: Signal) {
202 |
203 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
204 |
205 | _ = Darwin.raise(signal.rawValue)
206 |
207 | #elseif os(Linux)
208 |
209 | _ = Glibc.raise(signal.rawValue)
210 |
211 | #endif
212 | }
213 |
214 | ///
215 | /// Ignore a signal
216 | ///
217 | /// - Parameter signal: The signal to ignore.
218 | ///
219 | public class func ignore(signal: Signal) {
220 |
221 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
222 |
223 | _ = Darwin.signal(signal.rawValue, SIG_IGN)
224 |
225 | #elseif os(Linux)
226 |
227 | _ = Glibc.signal(signal.rawValue, SIG_IGN)
228 |
229 | #endif
230 | }
231 |
232 | ///
233 | /// Restore default signal handling
234 | ///
235 | /// - Parameter signal: The signal to restore.
236 | ///
237 | public class func restore(signal: Signal) {
238 |
239 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
240 |
241 | _ = Darwin.signal(signal.rawValue, SIG_DFL)
242 |
243 | #elseif os(Linux)
244 |
245 | _ = Glibc.signal(signal.rawValue, SIG_DFL)
246 |
247 | #endif
248 | }
249 |
250 | }
251 |
--------------------------------------------------------------------------------