Git Product home page Git Product logo

Comments (17)

candid82 avatar candid82 commented on June 2, 2024

joker.os/sh, joker.os/sh-from and joker.os/exec are the only functions that spawn new processes. They are blocking and do not allow for fine-grained control over child processes. You can use go macro to run child processes in non-blocking way. However, there is no API to send signals to child processes. You may have to resort to using pgrep and kill for that, e.g.

(go
  (pprint (joker.os/sh "joker" "sleep.joke"))) ;; start a child process
(joker.time/sleep 1000000000) ;; simulate i/o to let the goroutine a chance to start
(let [pgrep-out (:out (joker.os/sh "pgrep" "-P" (str (joker.os/pid)))) ;; find child pid by parent pid
      child-pid-str (subs pgrep-out 0 (dec (count pgrep-out))) ;; delete trailing \n
      ]
  (joker.os/sh "kill" child-pid-str))

from joker.

amano-kenji avatar amano-kenji commented on June 2, 2024

I wanted to emulate something like this in joker.

#!/bin/sh

cmd1 arg1 arg2 ... &
pid=$!

cmd2 arg1 arg2 ...

kill $pid

from joker.

candid82 avatar candid82 commented on June 2, 2024

I added two functions in start-kill-process branch: joker.os/start-process and joker.os/kill-process. Usage example:

(let [pid1 (joker.os/start-process "/bin/sleep" "1000")
      pid2 (joker.os/start-process "/bin/sleep" "1000")]
  (joker.os/kill-process pid1)
  (println "done!"))

@amano-kenji Do you think this will work? Would you be willing to build that branch locally and try it for your use case?

from joker.

amano-kenji avatar amano-kenji commented on June 2, 2024

I compiled and tested it. That seems to do the job, but what about control over stdout, stderr, stdin, and current working directory?

from joker.

jcburley avatar jcburley commented on June 2, 2024

I wonder if it'd make sense to enhance joker.os/exec, or provide an alternate, that doesn't Wait for the process to finish, but instead returns the underlying os.Process object (perhaps among other things) returned by os.exec/Start()?

That way, the features provided by joker.os/exec to prepare a process would be available, with the flexibility of being able to manipulate the returned os.Process object such as your proposed joker.os/kill-process provides.

I think an alternate to joker.os/exec, like joker.os/exec-nowait, makes more sense at least to simplify the returned value, which wouldn't have to contain things that make sense only due to the current implementation calling os.Wait.

from joker.

candid82 avatar candid82 commented on June 2, 2024

Yes, I think it makes sense. I was not sure how useful it would be to be able to set up stdin/out/err for processes that are started asynchronously and how this would behave when the process is killed by the parent program. I'll experiment with this on the weekend.
I also went for a simpler (perhaps too simple?) approach of returning a PID rather than a os.Process wrapper since os.Process can always be obtained by PID with os.FindProcess.

from joker.

amano-kenji avatar amano-kenji commented on June 2, 2024

I may want to redirect stdout and stderr to /dev/null and feed some input to stdin.

from joker.

candid82 avatar candid82 commented on June 2, 2024

@amano-kenji , @jcburley I made the change so that now joker.os/start-process accepts the same arguments as exec (and shares most of its implementation). Example:

(let [pid1 (joker.os/start-process "joker" {:args ["/Users/candid/sleep.joke"]
                                            :stdout *out*})
      pid2 (joker.os/start-process "/bin/sleep" {:args ["1000"]})]
  (joker.time/sleep (* 5 joker.time/second))
  (joker.os/kill-process pid1)
  (println "done!"))

Please let me know what you think.

from joker.

amano-kenji avatar amano-kenji commented on June 2, 2024

That should do the job although being able to send other signals than TERM to a process is going to be useful.

from joker.

candid82 avatar candid82 commented on June 2, 2024

@amano-kenji Fair enough. I added signal function (takes pid and signal as arguments). I also renamed start-process to start and kill-process to kill. Please give it a try and let me know what you think.

from joker.

amano-kenji avatar amano-kenji commented on June 2, 2024

I just tested. If I start a process and kill its PID in joker REPL, the PID becomes defunct until I quit REPL. After I quit REPL, the PID actually dies. Is this normal?

Also, it would be cool to have predefined SIGNALs for signal function.

from joker.

candid82 avatar candid82 commented on June 2, 2024

@amano-kenji Zombie processes are sort of normal: https://www.baeldung.com/linux/clean-zombie-process
They appear if the parent process doesn't wait on them after they finish execution. My initial implementation of joker.os/kill did not wait on the process being killed. I changed that, so now joker.os/kill waits after killing the process: baefcf5 This solves the issue with zombie processes (although I am not 100% it was a real issue).

As for predefined signals, they are platform specific. We would have to expose different set of constants on different platforms (at least on three officially supported platformes: Linux, macOS and Windows). I don't believe we do this anywhere else in Joker's codebase. @jcburley do you have any input on this (perhaps you've done this in your fork?)

from joker.

jcburley avatar jcburley commented on June 2, 2024

As for predefined signals, they are platform specific. We would have to expose different set of constants on different platforms (at least on three officially supported platformes: Linux, macOS and Windows). I don't believe we do this anywhere else in Joker's codebase. @jcburley do you have any input on this (perhaps you've done this in your fork?)

My fork's gostd tool, which "wraps" much of the Go standard library for direct access via Joker code, is run as part of the build process for a specific target.

So it doesn't really handle this in any particularly sophisticated way, in that the constants and variables that get wrapped, for a specific Joker executable, are just whatever happen to apply to that particular target.

I.e. the Joker namespaces that get exposed, along with their contents, in a particular executable, depend on what makes sense for that executable's target. Things that are Mac-OS-specific will appear, as namespaces and/or entities within them, in a Joker executable built for the Mac OS platform, but not on one built for a Linux nor Windows platform.

Early on, I thought it might be possible to someday make gostd smart enough to generate wrappers for all namespaces (packages in the Go standard library) and their contents, and use build tags and such to parallel how the Go standard library itself does.

But that seems very difficult, with little (if any) benefit, other than that my "fork" could then just be a source distribution without any need to run gostd for a particular build, at least in the vanilla case of wrapping the Go standard library.

So I've punted that capability, which is Issue jcburley#10.

from joker.

candid82 avatar candid82 commented on June 2, 2024

@jcburley thank you for the input! Here is my attempt to add support for platform-dependent declarations (non-functions) in std library: 2db1f41

This means that, e.g. joker.os/SIGBUS will be 0xa on macOS and 0x7 on Linux and Windows. joker.os/SIGCHLD will be 0x14 on macOS, 0x11 on Linux and won't exist on Windows.

This complicates build process a bit since now you have to generate std library for specific OS. Not sure how I feel about it... I guess it's useful to be able to write (joker.os/signal 1234 joker.os/SIGBUS) and the right signal will be sent on macOS and Linux... @jcburley any thoughts on this?

from joker.

candid82 avatar candid82 commented on June 2, 2024

I guess the alternative to this would be to only define signals that have the same value across all platforms. Now that I look at it, most common/useful signals fall into that category (e.g. SIGKILL, SIGTERM, SIGABRT). So perhaps it makes sense to punt on platform-dependent declaration for now until there is a more compelling use case for it?

from joker.

amano-kenji avatar amano-kenji commented on June 2, 2024

It's sufficient to add only platform-independent signals.

from joker.

candid82 avatar candid82 commented on June 2, 2024

OK, I've removed OS-dependent signals for now and merged everything to master. Closing.

from joker.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.