Skip to content

Commit 9e73460

Browse files
committed
Re-indent all the comments
1 parent 81b58e0 commit 9e73460

17 files changed

+232
-312
lines changed

Doc/signal-tests/run-tests.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ set -uo pipefail
33

44
readonly LINUX_SWIFT_IMAGE="swift:5.3.3"
55

6-
# This can only be run on macOS
6+
# This can only be run on macOS.
77
test "$(uname -s)" = "Darwin"
88

99
cd "$(dirname "$0")"
@@ -36,7 +36,7 @@ docker run --rm -it -v "$(pwd):/tmp/cwd" --workdir /tmp/cwd --security-opt=secco
3636
echo
3737
echo
3838
echo "*** RUNNING GENERIC TESTS (SWIFT) ON MACOS"
39-
# We must compile, when run via swift as a script, some signal are handled by Swift itself
39+
# We must compile, when run via swift as a script, some signal are handled by Swift itself.
4040
swiftc ./signal-tests-macos.swift && ./signal-tests-macos
4141
rm signal-tests-macos
4242

Doc/signal-tests/signal-test-blocked.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,10 @@ int main(int argc, const char * argv[]) {
105105
fprintf(stderr, "✊ Main thread pending: %d\n", sigismember(&set, s));
106106

107107
sleep(3);
108-
/* On macOS, when all threads block the signal, the system chooses one thread
109-
* and assigns the signal to it. Unblocking in another thread won’t move the
110-
* signal to it, and we won’t be able to access it.
111-
* On Linux, when a process-wide signal is pending, it is pending on all
112-
* the threads. If a thread unblocks the signal, it will handle it. */
108+
/* On macOS, when all threads block the signal, the system chooses one thread and assigns the signal to it.
109+
* Unblocking in another thread won’t move the signal to it, and we won’t be able to access it.
110+
* On Linux, when a process-wide signal is pending, it is pending on all the threads.
111+
* If a thread unblocks the signal, it will handle it. */
113112
fprintf(stderr, "✊ Unblocking signal\n");
114113
pthread_mutex_lock(&mutex);
115114
thread_action = UNBLOCK_SIGNAL;

Doc/signal-tests/signal-test-sigaction.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ int main(void) {
2424
struct sigaction newAction = {};
2525
newAction.sa_flags = 0;
2626
sigemptyset(&newAction.sa_mask);
27-
/* We do not use sa_sigaction because it generates a warning on Linux w/
28-
* function signature `void action(int, struct __siginfo *, void *)` because
29-
* args are not exactly the same as on macOS, but would work too */
27+
/* We do not use sa_sigaction because it generates a warning on Linux w/ function signature `void action(int, struct __siginfo *, void *)`
28+
* because args are not exactly the same as on macOS, but would work too. */
3029
newAction.sa_handler = &action;
3130
sigaction(15, &newAction, NULL);
3231
fprintf(stderr, "%p\n", newAction.sa_handler);

Doc/signal-tests/signal-tests-linux.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ if doFirstTest {
8080
print("after dispatch and delay: newAction: \(oldActionHandlerPtr == newActionHandlerPtr)")
8181
print("after dispatch and delay: mask: \(oldAction.sa_mask)")
8282
print("after dispatch and delay: flags: \(oldAction.sa_flags)")
83-
/* raise and kill are not the same in a multi-threaded env */
83+
/* raise and kill are not the same in a multi-threaded env. */
8484
//raise(15)
8585
kill(getpid(), 15)
8686
sleep(1)
@@ -116,7 +116,7 @@ if doSecondTest {
116116
pthread_cond_wait(&cond, &mutex)
117117
pthread_mutex_unlock(&mutex);
118118

119-
/* Thread is initialized and running */
119+
/* Thread is initialized and running. */
120120
print("thread initialized and running")
121121

122122
sigaction(15, &defaultAction, nil)

Doc/signal-tests/signal-tests-macos.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ if doFirstTest {
6464
print("after dispatch: flags: \(oldAction.sa_flags)")
6565

6666
usleep(500)
67-
/* raise and kill are not the same in a multi-threaded env */
67+
/* raise and kill are not the same in a multi-threaded env. */
6868
//raise(15)
6969
kill(getpid(), 15)
7070
sleep(1)
@@ -100,7 +100,7 @@ if doSecondTest {
100100
pthread_cond_wait(&cond, &mutex)
101101
pthread_mutex_unlock(&mutex);
102102

103-
/* Thread is initialized and running */
103+
/* Thread is initialized and running. */
104104
print("thread initialized and running")
105105

106106
sigaction(15, &defaultAction, nil)

Readme.adoc

Lines changed: 40 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
= Signal Handling in Swift
22
François Lamboley <francois[email protected]>
33

4-
This package provides a Swift syntax for the low-level C `sigaction` function
5-
and a way to delay or cancel sigaction handlers.
4+
This package provides a Swift syntax for the low-level C `sigaction` function and a way to delay or cancel sigaction handlers.
65

7-
It is compatible with macOS and Linux. Read the documentation carefully before
8-
using the sigaction handler delaying capabilities.
6+
It is compatible with macOS and Linux. Read the documentation carefully before using the sigaction handler delaying capabilities.
97

108
== Example of Use
119

@@ -34,8 +32,7 @@ let delayedSigaction = try SigactionDelayer_Unsig.registerDelayedSigaction(Signa
3432
})
3533
----
3634

37-
With both examples in the same code, when the program receives the terminated
38-
signal (15 on macOS), the following will be logged:
35+
With both examples in the same code, when the program receives the terminated signal (15 on macOS), the following will be logged:
3936

4037
[source,text]
4138
----
@@ -46,94 +43,75 @@ Handling signal SIGTERM from sigaction
4643

4744
== How Does Delaying the Sigaction Work?
4845

49-
Delaying a signal is an unusual process and you should be aware of the inner
50-
workings of this method before using it.
46+
Delaying a signal is an unusual process and you should be aware of the inner workings of this method before using it.
5147

52-
We have two delaying strategies. One sets the signal as ignored until the signal
53-
is allowed to go through (`SigactionDelayer_Unsig`); the other blocks the
54-
incoming signal until the signal is allowed to go through
55-
(`SigactionDelayer_Block`).
48+
We have two delaying strategies.
49+
One sets the signal as ignored until the signal is allowed to go through (`SigactionDelayer_Unsig`);
50+
the other blocks the incoming signal until the signal is allowed to go through (`SigactionDelayer_Block`).
5651

5752
Both strategies have pros and cons.
5853

59-
While the signal is blocked or ignored, it is also monitored using `libdispatch`
60-
(aka. GCD), which itself monitors the signals using `kqueue` on BSD and
61-
`signalfd` on Linux. This allows unblocking the signal or setting the sigaction
62-
handler when needed.
54+
While the signal is blocked or ignored, it is also monitored using `libdispatch` (aka. GCD),
55+
which itself monitors the signals using `kqueue` on BSD and `signalfd` on Linux.
56+
This allows unblocking the signal or setting the sigaction handler when needed.
6357

64-
**Important caveat of both methods**: `libdispatch` can only detect signals sent
65-
to the whole process, not threads. A delayed signal sent to a thread is thus
66-
blocked or ignored forever.
58+
**Important caveat of both methods**:
59+
`libdispatch` can only detect signals sent to the whole process, not threads.
60+
A delayed signal sent to a thread is thus blocked or ignored forever.
6761

6862
=== Details of the Unsigaction Strategy (`SigactionDelayer_Unsig`)
6963

7064
This is the recommended method.
7165

72-
This method does not require any particular bootstrap. You can delay a signal
73-
whenever you want.
66+
This method does not require any particular bootstrap.
67+
You can delay a signal whenever you want.
7468

75-
Once a signal has been registered for delay though, the sigaction should not be
76-
manually changed. (Exception being made of the `install` method provided by the
77-
`Sigaction` struct in this project, which is aware of the possible unsigactions
78-
on the signal and can update them accordingly.)
69+
Once a signal has been registered for delay though, the sigaction should not be manually changed.
70+
(Exception being made of the `install` method provided by the `Sigaction` struct in this project,
71+
which is aware of the possible unsigactions on the signal and can update them accordingly.)
7972

8073
When a signal is first registered for delay a few things happen:
8174

8275
* The sigaction handler is saved in an internal structure;
8376
* The signal is set to be ignored;
84-
* A dedicated thread is spawned (if not already spawned), which unblocks all
85-
signals;
77+
* A dedicated thread is spawned (if not already spawned), which unblocks all signals;
8678
* A dispatch source is created to monitor the incoming signal using GCD.
8779

8880
Then, when a signal is received, this happens:
8981

9082
* `libdispatch` notifies the sigaction delayer, which will in turn
91-
* Reinstall temporarily the saved sigaction for the signal (after the clients
92-
say it’s ok), and
93-
* Send the signal to the dedicated thread. This triggers the sigaction but does
94-
not notify `libdispatch`.
83+
* Reinstall temporarily the saved sigaction for the signal (after the clients say it’s ok), and
84+
* Send the signal to the dedicated thread. This triggers the sigaction but does not notify `libdispatch`.
9585
* Finally, the delayer sets the signal back to being ignored.
9686

9787
**Caveats of this method**:
9888

99-
* There is a non-avoidable race-condition (AFAICT) between the time the signal
100-
is sent and set back to ignored;
89+
* There is a non-avoidable race-condition (AFAICT) between the time the signal is sent and set back to ignored;
10190
* The signal that is sent back has lost the siginfo of the original signal;
102-
* On Linux signal delaying is fragile. See Linux caveat of the blocking strategy
103-
for more information.
91+
* On Linux signal delaying is fragile. See Linux caveat of the blocking strategy for more information.
10492

10593
=== Details of the Blocking Strategy (`SigactionDelayer_Block`)
10694

107-
You must bootstrap this method before using it, giving the bootstrap method all
108-
the signals you’ll want to delay, _before any threads are created_.
109-
The bootstrap will first block all the given signals on the current (main)
110-
thread, then spawn a thread on which all these signals will be unblocked.
95+
You must bootstrap this method before using it, giving the bootstrap method all the signals you’ll want to delay, _before any threads are created_.
96+
The bootstrap will first block all the given signals on the current (main) thread,
97+
then spawn a thread on which all these signals will be unblocked.
11198

112-
This allows our dedicated thread to be the only one allowed to receive the
113-
signals that are to be monitored.
99+
This allows our dedicated thread to be the only one allowed to receive the signals that are to be monitored.
114100

115-
When a signal is registered for delay, the delayer will block the signal on the
116-
dedicated thread too!
101+
When a signal is registered for delay, the delayer will block the signal on the dedicated thread too!
117102

118-
When the signal is received, `libdispatch` will notify the delayer, which will
119-
unblock the signal, thus allowing it to be delivered.
103+
When the signal is received, `libdispatch` will notify the delayer, which will unblock the signal, thus allowing it to be delivered.
120104

121105
**Caveats of this method**:
122106

123-
* On macOS, when a signal blocked on all threads is received, it seems to be
124-
assigned to an arbitrary thread. Unblocking the signal on another thread will
125-
not unblock it at all. To workaround this problem we check if the signal is
126-
pending on the dedicated thread before unblocking it. If it is not, we send the
127-
signal to our thread, thus losing the sigaction again, exactly like when using
128-
the unsigaction strategy. Plus the original signal will stay pending on the
129-
affected thread forever.
130-
* On Linux, there is an issue where contrary to what the man page says,
131-
`libdispatch` https://github.com/apple/swift-corelibs-libdispatch/pull/560[does
132-
modify the sigaction of a signal when a dispatch source for this signal is first
133-
installed].
134-
So in theory this strategy should not work (and to be honest, the other one
135-
should not either). However, it has been noticed that changing the sigaction
136-
_after_ the signal source has been installed is enough to avoid this problem. So
137-
we save the sigaction before installing the signal source, then restore it after
138-
the source is installed, and we’re good. This solution seems fragile though, and
139-
might break in the future, or not even work reliably right now.
107+
* On macOS, when a signal blocked on all threads is received, it seems to be assigned to an arbitrary thread.
108+
Unblocking the signal on another thread will not unblock it at all.
109+
To workaround this problem we check if the signal is pending on the dedicated thread before unblocking it.
110+
If it is not, we send the signal to our thread, thus losing the sigaction again, exactly like when using the unsigaction strategy.
111+
Plus the original signal will stay pending on the affected thread forever.
112+
* On Linux, there is an issue where contrary to what the man page says, `libdispatch`
113+
https://github.com/apple/swift-corelibs-libdispatch/pull/560[does modify the sigaction of a signal when a dispatch source for this signal is first installed].
114+
So in theory this strategy should not work (and to be honest, the other one should not either).
115+
However, it has been noticed that changing the sigaction _after_ the signal source has been installed is enough to avoid this problem.
116+
So we save the sigaction before installing the signal source, then restore it after the source is installed, and we’re good.
117+
This solution seems fragile though, and might break in the future, or not even work reliably right now.

Sources/SignalHandling/CStructsInSwift/Sigaction.swift

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ public struct Sigaction : Equatable, RawRepresentable {
4141
/**
4242
Create a `Sigaction` from a `sigaction`.
4343

44-
If the handler of the sigaction is `SIG_IGN` or `SIG_DFL`, we check the
45-
`sa_flags` not to contains the `SA_SIGINFO` bit. If they do, we log an
46-
error, as this is invalid. */
44+
If the handler of the sigaction is `SIG_IGN` or `SIG_DFL`, we check the `sa_flags` not to contains the `SA_SIGINFO` bit.
45+
If they do, we log an error, as this is invalid. */
4746
public init(rawValue: sigaction) {
4847
self.mask = Signal.set(from: rawValue.sa_mask)
4948
self.flags = SigactionFlags(rawValue: rawValue.sa_flags)
@@ -108,22 +107,21 @@ public struct Sigaction : Equatable, RawRepresentable {
108107
}
109108

110109
/**
111-
Only one check: do the flags **not** contain `siginfo` if handler is either
112-
`.ignoreHandler` or `.defaultHandler`. */
110+
Only one check: do the flags **not** contain `siginfo` if handler is either `.ignoreHandler` or `.defaultHandler`. */
113111
public var isValid: Bool {
114112
return !flags.contains(.siginfo) || (handler != .ignoreHandler && handler != .defaultHandler)
115113
}
116114

117115
/**
118116
Installs the sigaction and returns the old one if different.
119117

120-
It is impossible for a sigaction handler to be `nil`. If the method returns
121-
`nil`, the previous handler was exactly the same as the one you installed.
118+
It is impossible for a sigaction handler to be `nil`.
119+
If the method returns `nil`, the previous handler was exactly the same as the one you installed.
122120
Note however the sigaction function is always called in this method.
123121

124-
If `updateUnsigRegistrations` is true (default), If there are delayed
125-
sigactions registered with `SigactionDelayer_Unsig`, these registrations
126-
will be updated and `sigaction` will not be called. */
122+
If `updateUnsigRegistrations` is true (default),
123+
if there are delayed sigactions registered with `SigactionDelayer_Unsig`,
124+
these registrations will be updated and `sigaction` will not be called. */
127125
@discardableResult
128126
public func install(on signal: Signal, revertIfIgnored: Bool = true, updateUnsigRegistrations: Bool = true) throws -> Sigaction? {
129127
if updateUnsigRegistrations, let oldSigaction = SigactionDelayer_Unsig.updateOriginalSigaction(for: signal, to: self) {

Sources/SignalHandling/CStructsInSwift/SigactionFlag.swift

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,37 @@ import Foundation
66
public struct SigactionFlags : OptionSet {
77

88
/**
9-
If this bit is set when installing a catching function for the `SIGCHLD`
10-
signal, the `SIGCHLD` signal will be generated only when a child process
11-
exits, not when a child process stops. */
9+
If this bit is set when installing a catching function for the `SIGCHLD` signal,
10+
the `SIGCHLD` signal will be generated only when a child process exits, not when a child process stops. */
1211
public static let noChildStop = SigactionFlags(rawValue: SA_NOCLDSTOP)
1312

1413
/**
15-
If this bit is set when calling `sigaction()` for the `SIGCHLD` signal, the
16-
system will not create zombie processes when children of the calling process
17-
exit. If the calling process subsequently issues a `wait(2)` (or
18-
equivalent), it blocks until all of the calling process’s child processes
19-
terminate, and then returns a value of -1 with errno set to ECHILD. */
14+
If this bit is set when calling `sigaction()` for the `SIGCHLD` signal,
15+
the system will not create zombie processes when children of the calling process exit.
16+
If the calling process subsequently issues a `wait(2)` (or equivalent),
17+
it blocks until all of the calling process’s child processes terminate,
18+
and then returns a value of -1 with errno set to ECHILD. */
2019
public static let noChildWait = SigactionFlags(rawValue: SA_NOCLDWAIT)
2120

2221
/**
23-
If this bit is set, the system will deliver the signal to the process on a
24-
signal stack, specified with `sigaltstack(2)`. */
22+
If this bit is set, the system will deliver the signal to the process on a signal stack, specified with `sigaltstack(2)`. */
2523
public static let onStack = SigactionFlags(rawValue: SA_ONSTACK)
2624

2725
/**
28-
If this bit is set, further occurrences of the delivered signal are not
29-
masked during the execution of the handler. */
26+
If this bit is set, further occurrences of the delivered signal are not masked during the execution of the handler. */
3027
public static let noDefer = SigactionFlags(rawValue: SA_NODEFER)
3128

3229
/**
33-
If this bit is set, the handler is reset back to `SIG_DFL` at the moment the
34-
signal is delivered. */
30+
If this bit is set, the handler is reset back to `SIG_DFL` at the moment the signal is delivered. */
3531
public static let resetHandler = SigactionFlags(rawValue: CInt(SA_RESETHAND) /* On Linux, an UInt32 instead of Int32, so we cast… */)
3632

3733
/** See `sigaction(2)`. */
3834
public static let restart = SigactionFlags(rawValue: SA_RESTART)
3935

4036
/**
41-
If this bit is set, the handler function is assumed to be pointed to by the
42-
`sa_sigaction` member of struct sigaction and should match the matching
43-
prototype. This bit should not be set when assigning `SIG_DFL` or `SIG_IGN`. */
37+
If this bit is set, the handler function is assumed to be pointed to by the `sa_sigaction` member of struct sigaction
38+
and should match the matching prototype.
39+
This bit should not be set when assigning `SIG_DFL` or `SIG_IGN`. */
4440
public static let siginfo = SigactionFlags(rawValue: SA_SIGINFO)
4541

4642
public let rawValue: CInt

Sources/SignalHandling/CStructsInSwift/SigactionHandler.swift

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,12 @@ import Foundation
55
/**
66
A `sigaction` handler.
77

8-
Two `SigactionHandler`s are equal iif their cases are equal and the handler
9-
they contain point to the same address (if applicable). */
8+
Two `SigactionHandler`s are equal iif their cases are equal and the handler they contain point to the same address (if applicable). */
109
public enum SigactionHandler : Equatable {
1110

12-
/* The ignore and default handlers are special cases represented respectively
13-
* by the `SIG_IGN` and `SIG_DFL` values in C.
14-
* We choose the represent them using a special case in the enum. You should
15-
* not (though you could) use `.ansiC(SIG_IGN)` (it is not possible with
16-
* `SIG_DFL` because `SIG_DFL` is optional… and nil).
11+
/* The ignore and default handlers are special cases represented respectively by the `SIG_IGN` and `SIG_DFL` values in C.
12+
* We choose the represent them using a special case in the enum.
13+
* You should not (though you could) use `.ansiC(SIG_IGN)` (it is not possible with `SIG_DFL` because `SIG_DFL` is optional… and nil).
1714
* In particular, `.ignoreHandler != .ansiC(SIG_IGN)` */
1815
case ignoreHandler
1916
case defaultHandler
@@ -29,8 +26,8 @@ public enum SigactionHandler : Equatable {
2926
case (.ansiC, .ansiC), (.posix, .posix):
3027
return lhs.asOpaquePointer == rhs.asOpaquePointer
3128

32-
/* Using this matching patterns instead of simply default, we force
33-
* a compilation error in case more cases are added later. */
29+
/* Using this matching patterns instead of simply default,
30+
* we force a compilation error in case more cases are added later. */
3431
case (.ignoreHandler, _), (.defaultHandler, _), (.ansiC, _), (.posix, _):
3532
return false
3633
}

0 commit comments

Comments
 (0)