2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
10 (** Responsible for starting up a Hack server process. *)
12 module SP
= ServerProcess
17 | Force_dormant_start_only
19 let pipe_type_to_string = function
20 | Default
-> "default"
21 | Priority
-> "priority"
22 | Force_dormant_start_only
-> "force_dormant_start_only"
24 let start_server_daemon ~informant_managed options log_link daemon_entry
=
26 let in_fd = Daemon.null_fd
() in
27 if ServerArgs.should_detach options
then (
29 let old_log_name i
= Printf.sprintf
"%s.%d.old" log_link i
in
30 let max_n_log_files = 20 in
31 for i
= max_n_log_files - 1 downto 1 do
32 if Sys.file_exists
(old_log_name i
) then
33 Sys.rename
(old_log_name i
) (old_log_name (i
+ 1))
35 let old = log_link ^
".old" in
36 if Sys.file_exists
old then Sys.rename
old (old_log_name 1);
37 if Sys.file_exists log_link
then Sys.rename log_link
old
39 let log_file = Sys_utils.make_link_of_timestamped log_link
in
41 "About to spawn typechecker daemon. Logs will go to %s\n%!"
46 let fd = Daemon.fd_of_path
log_file in
49 Hh_logger.log
"About to spawn typechecker daemon. Logs will go here.";
50 (in_fd, Unix.stdout
, Unix.stderr
)
53 let start_t = Unix.time
() in
54 let state = ServerGlobalState.save ~logging_init
:(fun () -> ()) in
55 let monitor_pid = Unix.getpid
() in
56 (* Setting some additional channels between monitor and server *)
57 let (parent_priority_fd
, child_priority_fd
) =
58 Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0
60 let () = Unix.set_close_on_exec parent_priority_fd
in
61 let () = Unix.clear_close_on_exec child_priority_fd
in
62 let ( parent_force_dormant_start_only_fd
,
63 child_force_dormant_start_only_force_fd
) =
64 Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0
66 let () = Unix.set_close_on_exec parent_force_dormant_start_only_fd
in
67 let () = Unix.clear_close_on_exec child_force_dormant_start_only_force_fd
in
68 let { Daemon.pid
; Daemon.channels
= (ic
, oc
) } =
78 child_force_dormant_start_only_force_fd
)
80 Unix.close child_priority_fd
;
81 Unix.close child_force_dormant_start_only_force_fd
;
82 Hh_logger.log
"Just started typechecker server with pid: %d." pid
;
84 (* We'll write an initial progress message to guarantee that the client will
85 certainly be able to read the progress file as soon as it learns the progress filename.
86 There's a benign race as to whether our message is written first, or whether the server
87 started up quickly enough to write its initial message first. It's benign because
88 either message will communicate the right intent to the user, and in any case the server
89 will always have further progress updates to write. *)
90 let server_progress_file = ServerFiles.server_progress_file pid
in
94 server_progress = "starting hh_server";
95 server_warning
= None
;
96 server_timestamp
= Unix.gettimeofday
();
99 ServerCommandTypesUtils.write_progress_file
100 ~
server_progress_file
107 server_specific_files
=
109 ServerCommandTypes.server_finale_file
=
110 ServerFiles.server_finale_file pid
;
111 server_progress_file;
113 in_fd = Daemon.descr_of_in_channel ic
;
116 (pipe_type_to_string Default
, Daemon.descr_of_out_channel oc
);
117 (pipe_type_to_string Priority
, parent_priority_fd
);
118 ( pipe_type_to_string Force_dormant_start_only
,
119 parent_force_dormant_start_only_fd
);
122 last_request_handoff
= ref (Unix.time
());
127 let start_hh_server ~informant_managed options
=
128 let log_link = ServerFiles.log_link (ServerArgs.root options
) in
129 start_server_daemon ~informant_managed options
log_link ServerMain.entry
131 module HhServerConfig
= struct
132 type server_start_options
= ServerArgs.options
134 let start_server ~informant_managed ~prior_exit_status options
=
135 match prior_exit_status
with
137 when (c
= Exit_status.(exit_code Sql_assertion_failure
))
138 || (c
= Exit_status.(exit_code Sql_cantopen
))
139 || (c
= Exit_status.(exit_code Sql_corrupt
))
140 || c
= Exit_status.(exit_code Sql_misuse
) ->
141 start_hh_server ~informant_managed
(ServerArgs.set_no_load options
true)
142 | _
-> start_hh_server ~informant_managed options
144 let kill_server process
=
145 try Unix.kill process
.ServerProcess.pid
Sys.sigusr2
148 "Failed to send sigusr2 signal to server process. Trying violently";
149 (try Unix.kill process
.ServerProcess.pid
Sys.sigkill
151 let stack = Printexc.get_backtrace
() in
153 ~prefix
:"Failed to violently kill server process: "
157 let rec wait_for_server_exit process
start_t =
159 Unix.waitpid
[Unix.WNOHANG
; Unix.WUNTRACED
] process
.ServerProcess.pid
161 match exit_status with
164 wait_for_server_exit process
start_t
167 (Hh_logger.log_duration
168 (Printf.sprintf
"typechecker has exited. Time since sigterm: ")
171 let wait_pid process
=
172 Unix.waitpid
[Unix.WNOHANG
; Unix.WUNTRACED
] process
.ServerProcess.pid
174 let is_saved_state_precomputed = ServerArgs.is_using_precomputed_saved_state