This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch remove-spawnkiller-crutch
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit bf27b2c1e9269c3a5248a0ed1ee30a1cc1ad44c7
Author: Nick Vatamaniuc <vatam...@apache.org>
AuthorDate: Fri Sep 13 16:02:10 2024 -0400

    Remove spawnkillable
    
    os_pid is available since at least 19.0 and we never noticed [1]
    
    This should make our releses easily relocatable to paths which have
    spaces.
    
    [1] 
https://github.com/erlang/otp/blob/3ff36ef6f6f20749b5a03b3667206ede0fdb5791/erts/doc/src/erlang_port_info.md?plain=1#L27
---
 src/couch/priv/spawnkillable/couchspawnkillable.sh |  20 ---
 .../priv/spawnkillable/couchspawnkillable_win.c    | 145 ---------------------
 src/couch/rebar.config.script                      |  15 +--
 src/couch/src/couch_os_process.erl                 |  24 ++--
 4 files changed, 16 insertions(+), 188 deletions(-)

diff --git a/src/couch/priv/spawnkillable/couchspawnkillable.sh 
b/src/couch/priv/spawnkillable/couchspawnkillable.sh
deleted file mode 100755
index f8d042e36..000000000
--- a/src/couch/priv/spawnkillable/couchspawnkillable.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#! /bin/sh -e
-
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not
-# use this file except in compliance with the License. You may obtain a copy of
-# the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations under
-# the License.
-
-# The purpose of this script is to echo an OS specific command before launching
-# the actual process. This provides a way for Erlang to hard-kill its external
-# processes.
-
-echo "kill -9 $$"
-exec $*
diff --git a/src/couch/priv/spawnkillable/couchspawnkillable_win.c 
b/src/couch/priv/spawnkillable/couchspawnkillable_win.c
deleted file mode 100644
index 067823159..000000000
--- a/src/couch/priv/spawnkillable/couchspawnkillable_win.c
+++ /dev/null
@@ -1,145 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License.  You may obtain a copy 
of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-// License for the specific language governing permissions and limitations 
under
-// the License.
-
-// Do what 2 lines of shell script in couchspawnkillable does...
-// * Create a new suspended process with the same (duplicated) standard 
-//   handles as us.
-// * Write a line to stdout, consisting of the path to ourselves, plus
-//   '--kill {pid}' where {pid} is the PID of the newly created process.
-// * Un-suspend the new process.
-// * Wait for the process to terminate.
-// * Terminate with the child's exit-code.
-
-// Later, couch will call us with --kill and the PID, so we dutifully
-// terminate the specified PID.
-
-#include <stdlib.h>
-#include "windows.h"
-
-char *get_child_cmdline(int argc, char **argv)
-{
-    // make a new command-line, but skipping me.
-    // XXX - todo - spaces etc in args???
-    int i;
-    char *p, *cmdline;
-    int nchars = 0;
-    int nthis = 1;
-    for (i=1;i<argc;i++)
-        nchars += strlen(argv[i])+1;
-    cmdline = p = malloc(nchars+1);
-    if (!cmdline)
-        return NULL;
-    for (i=1;i<argc;i++) {
-        nthis = strlen(argv[i]);
-        strncpy(p, argv[i], nthis);
-        p[nthis] = ' ';
-        p += nthis+1;
-    }
-    // Replace the last space we added above with a '\0'
-    cmdline[nchars-1] = '\0';
-    return cmdline;
-}
-
-// create the child process, returning 0, or the exit-code we will
-// terminate with.
-int create_child(int argc, char **argv, PROCESS_INFORMATION *pi)
-{
-    char buf[1024];
-    DWORD dwcreate;
-    STARTUPINFO si;
-    char *cmdline;
-    if (argc < 2)
-        return 1;
-    cmdline = get_child_cmdline(argc, argv);
-    if (!cmdline)
-        return 2;
-
-    memset(&si, 0, sizeof(si));
-    si.cb = sizeof(si);
-    // depending on how *our* parent is started, we may or may not have
-    // a valid stderr stream - so although we try and duplicate it, only
-    // failing to duplicate stdin and stdout are considered fatal.
-    if (!DuplicateHandle(GetCurrentProcess(),
-                       GetStdHandle(STD_INPUT_HANDLE),
-                       GetCurrentProcess(),
-                       &si.hStdInput,
-                       0,
-                       TRUE, // inheritable
-                       DUPLICATE_SAME_ACCESS) ||
-       !DuplicateHandle(GetCurrentProcess(),
-                       GetStdHandle(STD_OUTPUT_HANDLE),
-                       GetCurrentProcess(),
-                       &si.hStdOutput,
-                       0,
-                       TRUE, // inheritable
-                       DUPLICATE_SAME_ACCESS)) {
-        return 3;
-    }
-    DuplicateHandle(GetCurrentProcess(),
-                   GetStdHandle(STD_ERROR_HANDLE),
-                   GetCurrentProcess(),
-                   &si.hStdError,
-                   0,
-                   TRUE, // inheritable
-                   DUPLICATE_SAME_ACCESS);
-
-    si.dwFlags = STARTF_USESTDHANDLES;
-    dwcreate = CREATE_SUSPENDED;
-    if (!CreateProcess( NULL, cmdline,
-                        NULL,
-                        NULL,
-                        TRUE, // inherit handles
-                        dwcreate,
-                        NULL, // environ
-                        NULL, // cwd
-                        &si,
-                        pi))
-        return 4;
-    return 0;
-}
-
-// and here we go...
-int main(int argc, char **argv)
-{
-    char out_buf[1024];
-    int rc;
-    DWORD cbwritten;
-    DWORD exitcode;
-    PROCESS_INFORMATION pi;
-    if (argc==3 && strcmp(argv[1], "--kill")==0) {
-        HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, atoi(argv[2]));
-        if (!h)
-            return 1;
-        if (!TerminateProcess(h, 0))
-            return 2;
-        CloseHandle(h);
-        return 0;
-    }
-    // spawn the new suspended process
-    rc = create_child(argc, argv, &pi);
-    if (rc)
-        return rc;
-    // Write the 'terminate' command, which includes this PID, back to couch.
-    // *sob* - what about spaces etc?
-    sprintf_s(out_buf, sizeof(out_buf), "%s --kill %d\n", 
-              argv[0], pi.dwProcessId);
-    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), out_buf, strlen(out_buf), 
-              &cbwritten, NULL);
-    // Let the child process go...
-    ResumeThread(pi.hThread);
-    // Wait for the process to terminate so we can reflect the exit code
-    // back to couch.
-    WaitForSingleObject(pi.hProcess, INFINITE);
-    if (!GetExitCodeProcess(pi.hProcess, &exitcode))
-        return 6;
-    return exitcode;
-}
diff --git a/src/couch/rebar.config.script b/src/couch/rebar.config.script
index 5efe238c2..7034f29ce 100644
--- a/src/couch/rebar.config.script
+++ b/src/couch/rebar.config.script
@@ -236,7 +236,7 @@ SpidermonkeySpecs = case WithSpidermonkey of
     false -> []
 end.
 
-BaseSpecs = SpidermonkeySpecs ++ [
+PortSpecs = SpidermonkeySpecs ++ [
         % ejson_compare
         {"darwin", ComparePath, CompareSrc, [{env, IcuEnv ++ IcuDarwinEnv}]},
         {"linux",  ComparePath, CompareSrc, [{env, IcuEnv}]},
@@ -244,25 +244,12 @@ BaseSpecs = SpidermonkeySpecs ++ [
         {"win32",  ComparePath, CompareSrc, [{env, IcuWinEnv}]}
 ].
 
-SpawnSpec = [
-    {"priv/couchspawnkillable", ["priv/spawnkillable/*.c"]}
-].
-
 %% hack required until switch to enc/rebar3
 PortEnvOverrides = [
     {"win32", "EXE_LINK_CXX_TEMPLATE",
     "$LINKER $PORT_IN_FILES $LDFLAGS $EXE_LDFLAGS /OUT:$PORT_OUT_FILE"}
 ].
 
-PortSpecs = case os:type() of
-    {win32, _} ->
-        BaseSpecs ++ SpawnSpec;
-    _ ->
-        {ok, CSK} = file:read_file("priv/spawnkillable/couchspawnkillable.sh"),
-        ok = CopyIfDifferent("priv/couchspawnkillable", CSK),
-        os:cmd("chmod +x priv/couchspawnkillable"),
-        BaseSpecs
-end.
 PlatformDefines = [
    {platform_define, "win32", 'WINDOWS'}
 ].
diff --git a/src/couch/src/couch_os_process.erl 
b/src/couch/src/couch_os_process.erl
index 225ce3d53..59ceeca13 100644
--- a/src/couch/src/couch_os_process.erl
+++ b/src/couch/src/couch_os_process.erl
@@ -130,31 +130,30 @@ pick_command1(_) ->
 
 % gen_server API
 init([Command]) ->
-    PrivDir = couch_util:priv_dir(),
-    Spawnkiller = "\"" ++ filename:join(PrivDir, "couchspawnkillable") ++ "\"",
     V = config:get("query_server_config", "os_process_idle_limit", "300"),
     IdleLimit = list_to_integer(V) * 1000,
     LogLevel = log_level(os:getenv("COUCHDB_IO_LOG_LEVEL")),
     T0 = erlang:monotonic_time(),
+    Port = open_port({spawn, Command}, ?PORT_OPTIONS),
+    {os_pid, OsPid} = erlang:port_info(Port, os_pid),
     OsProc = #os_proc{
         command = Command,
-        port = open_port({spawn, Spawnkiller ++ " " ++ Command}, 
?PORT_OPTIONS),
+        port = Port,
         idle = IdleLimit,
         log_level = LogLevel
     },
-    KillCmd = iolist_to_binary(readline(OsProc)),
     T1 = erlang:monotonic_time(),
     DtUSec = erlang:convert_time_unit(T1 - T0, native, microsecond),
     bump_time_stat(spawn_proc, DtUSec),
     Pid = self(),
     [CmdLog | _] = string:split(Command, " "),
     CmdLog1 = filename:basename(CmdLog),
-    log(OsProc, "OS Process ~p Started :: ~p", [OsProc#os_proc.port, CmdLog1]),
+    log(OsProc, "OS Process pid:~p port:~p Started :: ~p", [OsPid, Port, 
CmdLog1]),
     couch_stats:increment_counter([couchdb, query_server, process_starts]),
     spawn(fun() ->
         % this ensure the real os process is killed when this process dies.
         erlang:monitor(process, Pid),
-        killer(?b2l(KillCmd))
+        killer(OsPid)
     end),
     {ok, OsProc, IdleLimit}.
 
@@ -216,12 +215,19 @@ handle_info(Msg, #os_proc{idle = Idle} = OsProc) ->
     log(OsProc, "OS Process ~p Unknown info :: ~p", [OsProc#os_proc.port, 
Msg]),
     {noreply, OsProc, Idle}.
 
-killer(KillCmd) ->
+kill_command(OsPid) ->
+    OsPid1 = integer_to_list(OsPid),
+    case os:type() of
+        {win32, _} -> "taskkill /f /pid " ++ OsPid1;
+        {_, _} -> "kill -9 " ++ OsPid1
+    end.
+
+killer(OsPid) when is_integer(OsPid), OsPid > 0 ->
     receive
         _ ->
-            os:cmd(KillCmd)
+            os:cmd(kill_command(OsPid))
     after 1000 ->
-        killer(KillCmd)
+        killer(OsPid)
     end.
 
 bump_cmd_time_stat(Cmd, USec) when is_list(Cmd), is_integer(USec) ->

Reply via email to