Skip to content

Commit 6c1e7ea

Browse files
authored
Log proper names for POSIX signals (#6228)
The integer values that OCaml uses for signals should never be printed as integers. They can cause confusion because they don't match the C POSIX values. Change the unixext function that converts them to string to stop building a list and finding a value in the list to instead use pattern-matching. Also added some more values that got introduced in OCaml 4.03, and return a more compact value for unknown signals, following the same format as Fmt.Dump.signal. Typically, engineers see signal -11 and assume it's SIGSEGV, when it's SIGTERM. Fixes #6225
2 parents b41cfea + c0fbb69 commit 6c1e7ea

File tree

21 files changed

+66
-94
lines changed

21 files changed

+66
-94
lines changed

doc/content/design/coverage/index.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ revision: 2
88

99
We would like to add optional coverage profiling to existing [OCaml]
1010
projects in the context of [XenServer] and [XenAPI]. This article
11-
presents how we do it.
11+
presents how we do it.
1212

1313
Binaries instrumented for coverage profiling in the XenServer project
1414
need to run in an environment where several services act together as
@@ -21,7 +21,7 @@ isolation.
2121
To build binaries with coverage profiling, do:
2222

2323
./configure --enable-coverage
24-
make
24+
make
2525

2626
Binaries will log coverage data to `/tmp/bisect*.out` from which a
2727
coverage report can be generated in `coverage/`:
@@ -38,7 +38,7 @@ and logs during execution data to in-memory data structures. Before an
3838
instrumented binary terminates, it writes the logged data to a file.
3939
This data can then be analysed with the `bisect-ppx-report` tool, to
4040
produce a summary of annotated code that highlights what part of a
41-
codebase was executed.
41+
codebase was executed.
4242

4343
[BisectPPX] has several desirable properties:
4444

@@ -65,13 +65,13 @@ abstracted by OCamlfind (OCaml's library manager) and OCamlbuild
6565

6666
# build it with instrumentation from bisect_ppx
6767
ocamlbuild -use-ocamlfind -pkg bisect_ppx -pkg unix example.native
68-
68+
6969
# execute it - generates files ./bisect*.out
7070
./example.native
71-
71+
7272
# generate report
7373
bisect-ppx-report -I _build -html coverage bisect000*
74-
74+
7575
# view coverage/index.html
7676

7777
Summary:
@@ -86,7 +86,7 @@ will be instrumented during compilation. Behind the scenes `ocamlfind`
8686
makes sure that the compiler uses a preprocessing step that instruments
8787
the code.
8888

89-
## Signal Handling
89+
## Signal Handling
9090

9191
During execution the code instrumentation leads to the collection of
9292
data. This code registers a function with `at_exit` that writes the data
@@ -98,7 +98,7 @@ terminated by receiving the `TERM` signal, a signal handler must be
9898
installed:
9999

100100
let stop signal =
101-
printf "caught signal %d\n" signal;
101+
printf "caught signal %a\n" Debug.Pp.signal signal;
102102
exit 0
103103

104104
Sys.set_signal Sys.sigterm (Sys.Signal_handle stop)
@@ -149,8 +149,8 @@ environment variable. This can happen on the command line:
149149

150150
BISECT_FILE=/tmp/example ./example.native
151151

152-
In the context of XenServer we could do this in startup scripts.
153-
However, we added a bit of code
152+
In the context of XenServer we could do this in startup scripts.
153+
However, we added a bit of code
154154

155155
val Coverage.init: string -> unit
156156

@@ -176,12 +176,12 @@ Goals for instrumentation are:
176176

177177
* what files are instrumented should be obvious and easy to manage
178178
* instrumentation must be optional, yet easy to activate
179-
* avoid methods that require to keep several files in sync like multiple
179+
* avoid methods that require to keep several files in sync like multiple
180180
`_oasis` files
181181
* avoid separate Git branches for instrumented and non-instrumented
182182
code
183183

184-
In the ideal case, we could introduce a configuration switch
184+
In the ideal case, we could introduce a configuration switch
185185
`./configure --enable-coverage` that would prepare compilation for
186186
coverage instrumentation. While [Oasis] supports the creation of such
187187
switches, they cannot be used to control build dependencies like
@@ -196,7 +196,7 @@ rules in file `_tags.coverage` that cause files to be instrumented:
196196

197197
leads to the execution of this code during preparation:
198198

199-
coverage: _tags _tags.coverage
199+
coverage: _tags _tags.coverage
200200
test ! -f _tags.orig && mv _tags _tags.orig || true
201201
cat _tags.coverage _tags.orig > _tags
202202

@@ -207,7 +207,7 @@ could be tweaked to instrument only some files:
207207
<**/*.native>: pkg_bisect_ppx
208208

209209
When `make coverage` is not called, these rules are not active and
210-
hence, code is not instrumented for coverage. We believe that this
210+
hence, code is not instrumented for coverage. We believe that this
211211
solution to control instrumentation meets the goals from above. In
212212
particular, what files are instrumented and when is controlled by very
213213
few lines of declarative code that lives in the main repository of a
@@ -226,14 +226,14 @@ coverage analysis are:
226226
The `_oasis` file bundles the files under `profiling/` into an internal
227227
library which executables then depend on:
228228

229-
# Support files for profiling
229+
# Support files for profiling
230230
Library profiling
231231
CompiledObject: best
232232
Path: profiling
233233
Install: false
234234
Findlibname: profiling
235235
Modules: Coverage
236-
BuildDepends:
236+
BuildDepends:
237237

238238
Executable set_domain_uuid
239239
CompiledObject: best
@@ -243,16 +243,16 @@ library which executables then depend on:
243243
MainIs: set_domain_uuid.ml
244244
Install: false
245245
BuildDepends:
246-
xenctrl,
247-
uuidm,
246+
xenctrl,
247+
uuidm,
248248
cmdliner,
249249
profiling # <-- here
250250

251251
The `Makefile` target `coverage` primes the project for a profiling build:
252252

253253
# make coverage - prepares for building with coverage analysis
254254

255-
coverage: _tags _tags.coverage
255+
coverage: _tags _tags.coverage
256256
test ! -f _tags.orig && mv _tags _tags.orig || true
257257
cat _tags.coverage _tags.orig > _tags
258258

ocaml/forkexecd/src/child.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@ let report_child_exit comms_sock args child_pid status =
111111
Fe.WEXITED n
112112
| Unix.WSIGNALED n ->
113113
log_failure args child_pid
114-
(Printf.sprintf "exited with signal: %s" (Unixext.string_of_signal n)) ;
114+
(Printf.sprintf "exited with signal: %a" Debug.Pp.signal n) ;
115115
Fe.WSIGNALED n
116116
| Unix.WSTOPPED n ->
117117
log_failure args child_pid
118-
(Printf.sprintf "stopped with signal: %s" (Unixext.string_of_signal n)) ;
118+
(Printf.sprintf "stopped with signal: %a" Debug.Pp.signal n) ;
119119
Fe.WSTOPPED n
120120
in
121121
let result = Fe.Finished pr in

ocaml/libs/log/debug.ml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,4 +353,8 @@ functor
353353
with e -> log_backtrace_internal ~level:Syslog.Debug ~msg:"debug" e ()
354354
end
355355

356-
module Pp = struct let mtime_span () = Fmt.str "%a" Mtime.Span.pp end
356+
module Pp = struct
357+
let mtime_span () = Fmt.to_to_string Mtime.Span.pp
358+
359+
let signal () = Fmt.(to_to_string Dump.signal)
360+
end

ocaml/libs/log/debug.mli

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,8 @@ val is_disabled : string -> Syslog.level -> bool
9191

9292
module Pp : sig
9393
val mtime_span : unit -> Mtime.Span.t -> string
94+
95+
val signal : unit -> int -> string
96+
(** signal pretty-prints an ocaml signal number as its POSIX name, see
97+
{Fmt.Dump.signal} *)
9498
end

ocaml/libs/xapi-compression/xapi_compression.ml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,22 +123,17 @@ module Make (Algorithm : ALGORITHM) = struct
123123
error "%s" msg ; failwith msg
124124
in
125125
Unixfd.safe_close close_later ;
126-
let open Xapi_stdext_unix in
127126
match snd (Forkhelpers.waitpid pid) with
128127
| Unix.WEXITED 0 ->
129128
()
130129
| Unix.WEXITED i ->
131130
failwith_error (Printf.sprintf "exit code %d" i)
132131
| Unix.WSIGNALED i ->
133132
failwith_error
134-
(Printf.sprintf "killed by signal: %s"
135-
(Unixext.string_of_signal i)
136-
)
133+
(Printf.sprintf "killed by signal: %a" Debug.Pp.signal i)
137134
| Unix.WSTOPPED i ->
138135
failwith_error
139-
(Printf.sprintf "stopped by signal: %s"
140-
(Unixext.string_of_signal i)
141-
)
136+
(Printf.sprintf "stopped by signal: %a" Debug.Pp.signal i)
142137
)
143138

144139
let compress fd f = go Compress Active fd f

ocaml/libs/xapi-stdext/lib/xapi-stdext-unix/unixext.ml

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -371,36 +371,6 @@ let kill_and_wait ?(signal = Sys.sigterm) ?(timeout = 10.) pid =
371371
raise Process_still_alive
372372
)
373373

374-
let string_of_signal x =
375-
let table =
376-
[
377-
(Sys.sigabrt, "SIGABRT")
378-
; (Sys.sigalrm, "SIGALRM")
379-
; (Sys.sigfpe, "SIGFPE")
380-
; (Sys.sighup, "SIGHUP")
381-
; (Sys.sigill, "SIGILL")
382-
; (Sys.sigint, "SIGINT")
383-
; (Sys.sigkill, "SIGKILL")
384-
; (Sys.sigpipe, "SIGPIPE")
385-
; (Sys.sigquit, "SIGQUIT")
386-
; (Sys.sigsegv, "SIGSEGV")
387-
; (Sys.sigterm, "SIGTERM")
388-
; (Sys.sigusr1, "SIGUSR1")
389-
; (Sys.sigusr2, "SIGUSR2")
390-
; (Sys.sigchld, "SIGCHLD")
391-
; (Sys.sigcont, "SIGCONT")
392-
; (Sys.sigstop, "SIGSTOP")
393-
; (Sys.sigttin, "SIGTTIN")
394-
; (Sys.sigttou, "SIGTTOU")
395-
; (Sys.sigvtalrm, "SIGVTALRM")
396-
; (Sys.sigprof, "SIGPROF")
397-
]
398-
in
399-
if List.mem_assoc x table then
400-
List.assoc x table
401-
else
402-
Printf.sprintf "(ocaml signal %d with an unknown name)" x
403-
404374
let with_polly f =
405375
let polly = Polly.create () in
406376
let finally () = Polly.close polly in

ocaml/libs/xapi-stdext/lib/xapi-stdext-unix/unixext.mli

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,6 @@ exception Process_still_alive
122122

123123
val kill_and_wait : ?signal:int -> ?timeout:float -> int -> unit
124124

125-
val string_of_signal : int -> string
126-
(** [string_of_signal x] translates an ocaml signal number into
127-
* a string suitable for logging. *)
128-
129125
val proxy : Unix.file_descr -> Unix.file_descr -> unit
130126

131127
val really_read : Unix.file_descr -> bytes -> int -> int -> unit

ocaml/nbd/src/cleanup.ml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,21 @@ module Runtime = struct
218218
Printf.eprintf "SIGINT received - exiting" ;
219219
flush stderr ;
220220
exit 0
221+
| Signal n ->
222+
Printf.eprintf "unexpected signal %s in signal handler - exiting"
223+
Fmt.(to_to_string Dump.signal n) ;
224+
flush stderr ;
225+
exit 1
221226
| e ->
222227
Printf.eprintf "unexpected exception %s in signal handler - exiting"
223228
(Printexc.to_string e) ;
224229
flush stderr ;
225230
exit 1
226231

227232
let cleanup_resources signal =
233+
let name = Fmt.(to_to_string Dump.signal signal) in
228234
let cleanup () =
229-
Lwt_log.warning_f "Caught signal %d, cleaning up" signal >>= fun () ->
235+
Lwt_log.warning_f "Caught signal %s, cleaning up" name >>= fun () ->
230236
(* First we have to close the open file descriptors corresponding to the
231237
VDIs we plugged to dom0. Otherwise the VDI.unplug call would hang. *)
232238
ignore_exn_log_error "Caught exception while closing open block devices"

ocaml/nbd/src/dune

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
(libraries
55
cmdliner
66
consts
7-
7+
fmt
88
local_xapi_session
99
lwt
1010
lwt.unix

ocaml/networkd/bin/network_server.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ let on_shutdown signal =
5353
let dbg = "shutdown" in
5454
Debug.with_thread_associated dbg
5555
(fun () ->
56-
debug "xcp-networkd caught signal %d; performing cleanup actions." signal ;
56+
debug "xcp-networkd caught signal %a; performing cleanup actions."
57+
Debug.Pp.signal signal ;
5758
write_config ()
5859
)
5960
()

ocaml/xapi-guard/lib/server_interface.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ let shutdown = Lwt_switch.create ()
3838

3939
let () =
4040
let cleanup n =
41-
debug "Triggering cleanup on signal %d, and waiting for servers to stop" n ;
41+
debug "Triggering cleanup on signal %a, and waiting for servers to stop"
42+
Debug.Pp.signal n ;
4243
Lwt.async (fun () ->
4344
let* () = Lwt_switch.turn_off shutdown in
4445
info "Cleanup complete, exiting" ;

ocaml/xapi/helpers.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ let call_script ?(log_output = Always) ?env ?stdin ?timeout script args =
109109
| Unix.WEXITED n ->
110110
Printf.sprintf "exited with code %d" n
111111
| Unix.WSIGNALED n ->
112-
Printf.sprintf "was killed by signal %d" n
112+
Printf.sprintf "was killed by signal %a" Debug.Pp.signal n
113113
| Unix.WSTOPPED n ->
114-
Printf.sprintf "was stopped by signal %d" n
114+
Printf.sprintf "was stopped by signal %a" Debug.Pp.signal n
115115
in
116116
if should_log_output_on_failure then
117117
debug "%s %s %s [stdout = '%s'; stderr = '%s']" script

ocaml/xapi/sm_exec.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ let exec_xmlrpc ~dbg ?context:_ ?(needs_session = true) (driver : string)
393393
(Backend_error
394394
( Api_errors.sr_backend_failure
395395
, [
396-
"received signal: " ^ Unixext.string_of_signal i
396+
Printf.sprintf "received signal: %a" Debug.Pp.signal i
397397
; output
398398
; log
399399
]

ocaml/xapi/xapi_extensions.ml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ let call_extension rpc =
5050
( Api_errors.internal_error
5151
, [
5252
path
53-
; Printf.sprintf "signal: %s"
54-
(Xapi_stdext_unix.Unixext.string_of_signal i)
53+
; Printf.sprintf "signal: %a" Debug.Pp.signal i
5554
; output
5655
; log
5756
]

ocaml/xapi/xapi_plugins.ml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,7 @@ let call_plugin session_id plugin_name fn_name args =
4949
raise
5050
(Api_errors.Server_error
5151
( Api_errors.xenapi_plugin_failure
52-
, [
53-
Printf.sprintf "signal: %s"
54-
(Xapi_stdext_unix.Unixext.string_of_signal i)
55-
; output
56-
; log
57-
]
52+
, [Printf.sprintf "signal: %a" Debug.Pp.signal i; output; log]
5853
)
5954
)
6055
| Forkhelpers.Spawn_internal_error (log, output, Unix.WEXITED _) ->

ocaml/xcp-rrdd/bin/rrdd/dune

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
(modules (:standard \ xcp_rrdd))
66
(libraries
77
astring
8-
98
ezxenstore
109
gzip
1110
http_lib
@@ -41,7 +40,6 @@
4140
(modules xcp_rrdd)
4241
(libraries
4342
astring
44-
4543
ezxenstore.core
4644
ezxenstore.watch
4745
forkexec

ocaml/xcp-rrdd/bin/rrdd/xcp_rrdd.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ let configure_writers () =
735735
(** we need to make sure we call exit on fatal signals to make sure profiling
736736
data is dumped *)
737737
let stop err writers signal =
738-
debug "caught signal %d" signal ;
738+
debug "caught signal %a" Debug.Pp.signal signal ;
739739
List.iter (fun (_, writer) -> writer.Rrd_writer.cleanup ()) writers ;
740740
exit err
741741

ocaml/xcp-rrdd/lib/plugin/utils.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ let exec_cmd (module D : Debug.DEBUG) ~cmdstring ~(f : string -> 'a option) =
6363
| Unix.WEXITED n ->
6464
D.debug "Process %d exited normally with code %d" pid n
6565
| Unix.WSIGNALED s ->
66-
D.debug "Process %d was killed by signal %d" pid s
66+
D.debug "Process %d was killed by signal %a" pid Debug.Pp.signal s
6767
| Unix.WSTOPPED s ->
68-
D.debug "Process %d was stopped by signal %d" pid s
68+
D.debug "Process %d was stopped by signal %a" pid Debug.Pp.signal s
6969
) ;
7070
List.rev !vals

0 commit comments

Comments
 (0)