Equivalent of exec

49 просмотров
Перейти к первому непрочитанному сообщению

Norman Gray

не прочитано,
3 авг. 2021 г., 12:14:2303.08.2021
– Racket-Users List

Greetings.

I can't find a way of doing something equivalent to exec in Racket. Is
this Hard, or am I just missing it?

By 'exec', I mean the equivalent of replacing the process with a new
image, as distinct from `system` (and friends) or `process` (and
friends), which are concerned with creating a subprocess, controlling
it, and handling its exit.

In my particular case, I want to call vi at the end of a Racket script.
I'm sure it's possible to do that with process and friends, but it would
require being careful about input and output ports, worrying about
buffering, whether things are terminals or not, and so on and on.

I can imagine this isn't trivial as an implementation issue -- I can see
there would potentially be custodians to worry about (*waves hands
vaguely*), but I'd be surprised if it were impossible. However I'm
completely failing to find anything on [1], searching for eg 'exec' or
'return' (as in 'does not return'); and 'exec' isn't a very handy search
term on the web.

Thanks for any pointers,

Norman


[1] https://docs.racket-lang.org/reference/subprocess.html

--
Norman Gray : https://nxg.me.uk
SUPA School of Physics and Astronomy, University of Glasgow, UK

George Neuner

не прочитано,
3 авг. 2021 г., 12:38:5703.08.2021
– Norman Gray, racket users
Hi Norman,

Racket is multi-platform and tries to present a common API for dealing
with underlying operating systems.  Windows is an important platform,
but Windows does not have the concept of fork/exec ... so Racket doesn't
offer it either.  The closest (and simplest) you can achieve, I think,
would to start Vi asynchronously using 'process*' and then terminate the
Racket script.

Hope this helps,
George

Norman Gray

не прочитано,
3 авг. 2021 г., 13:03:3403.08.2021
– George Neuner, racket users

George, hello.

On 3 Aug 2021, at 17:38, George Neuner wrote:

> Racket is multi-platform and tries to present a common API for dealing
> with underlying operating systems.  Windows is an important platform,
> but Windows does not have the concept of fork/exec ... so Racket
> doesn't offer it either. 

Ah: good point. That said, I'd have guessed that similar behaviour --
'invoke and don't return' -- would be at least emulatable on Windows,
though.

> The closest (and simplest) you can achieve, I think, would to start Vi
> asynchronously using 'process*' and then terminate the Racket script.

I don't think that works, since terminating the Racket process would
also terminate its child (unless I were to do something similar to the
usual extra fork to disconnect the child from its parent, and... hmmm,
this isn't sounding very rackety).

Doing the next simplest thing -- using (process* "/usr/bin/vi" '("foo"))
and calling (control 'wait) using the result -- doesn't seem to work,
but instead just hangs, until I kill the vi child process. Without
digging into it too deeply, I'd guess that's because of the usual
problems about wiring up FDs and buffers and so on, which I was rather
hoping to avoid.

Best wishes,

Norman


--
Norman Gray : http://www.astro.gla.ac.uk/users/norman/it/
Research IT Coordinator : School of Physics and Astronomy

George Neuner

не прочитано,
3 авг. 2021 г., 14:13:4603.08.2021
– Norman Gray, racket users

On 8/3/2021 1:03 PM, Norman Gray wrote:
> On 3 Aug 2021, at 17:38, George Neuner wrote:
>
>> Racket is multi-platform and tries to present a common API for
>> dealing with underlying operating systems.  Windows is an important
>> platform, but Windows does not have the concept of fork/exec ... so
>> Racket doesn't offer it either.
>
> Ah: good point.  That said, I'd have guessed that similar behaviour --
> 'invoke and don't return' -- would be at least emulatable on Windows,
> though.

Well, yes, but the behavior of  'CreateProcess'  is quite different from
the combination of  'forkv/execv'.

In Windows, the new child is not (even virtually) a copy of its parent -
it is a completely new process context.  Although it is possible for the
parent to pass to and/or share resources with the child, this doesn't
include a copy of its memory context [so no 'fork'].  The parent
receives several handles to the new child process that must explicitly
be closed in order to detach it.

As a technical matter, emulating Unix 'fork' in Windows ... i.e. making
an independent copy of the parent process that continues running from
where the parent stopped ... is possible, but it is difficult and
requires debugger like behavior to manipulate the child's memory map and
copy data from one process to the other.


>> The closest (and simplest) you can achieve, I think, would to start
>> Vi asynchronously using 'process*' and then terminate the Racket script.
>
> I don't think that works, since terminating the Racket process would
> also terminate its child (unless I were to do something similar to the
> usual extra fork to disconnect the child from its parent, and... hmmm,
> this isn't sounding very rackety).
>
> Doing the next simplest thing -- using (process* "/usr/bin/vi"
> '("foo")) and calling (control 'wait) using the result -- doesn't seem
> to work, but instead just hangs, until I kill the vi child process. 
> Without digging into it too deeply, I'd guess that's because of the
> usual problems about wiring up FDs and buffers and so on, which I was
> rather hoping to avoid.
>

Hmm.  According to the docs  'process'  (no asterisk) executes the
command asynchronously ... I assumed  'process*' would do the same.
Unfortunately 'process' returns ports that must be closed explicitly.

Sorry if I led you astray.


> Best wishes,
>
> Norman

George

Shu-Hung You

не прочитано,
3 авг. 2021 г., 15:23:1603.08.2021
– George Neuner, Norman Gray, racket users
I tried directly passing the current input port and the current output
port in Racket to the subprocess. As long as they are the original
standard input and the standard output ports, the program seems to
work.

*However*, I am not sure if Racket's runtime still manages the input
and the output.

#lang racket/base

(require racket/match
racket/system)

(match-define (list subprocess-stdout subprocess-stdin system-pid
subprocess-stderr procctl)
(process*/ports (current-output-port) (current-input-port)
(current-error-port)
"/usr/bin/vim"))

(procctl 'wait)

The following variant prevents Racket from terminating the spawn
subprocess. Sadly, it did not work when I changed sh to vim. The error
message from vim was 'Vim: Error reading input, exiting...'.

#lang racket/base

(require racket/match
racket/system)

(match-define (list subprocess-stdout subprocess-stdin system-pid
subprocess-stderr procctl)
(parameterize ([current-subprocess-custodian-mode #f])
(process*/ports (current-output-port) (current-input-port)
(current-error-port)
"/bin/sh"
"-c"
"echo sh sleeping; sleep 5; echo sh alive and well")))

(displayln "leave racket")



>
> > Best wishes,
> >
> > Norman
>
> George
>
> --
> You received this message because you are subscribed to the Google Groups "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/720fc753-7972-b8c1-76ec-4d2a65a763f2%40comcast.net.

Norman Gray

не прочитано,
4 авг. 2021 г., 10:36:2604.08.2021
– racket users, George Neuner, shh...@u.northwestern.edu

Many thanks for your thoughts, George and Shu-Hung.

Rather embarassingly, I've found my answer in what's almost the simplest
subprocess procedure:

(exit (system*/exit-code "/usr/bin/vi" "filename"))

exhibits the behaviour I want. That does all the required plumbing
flawlessly.

I'm not sure how I missed this! When I've needed to manage subprocesses
in the past, the `system` procedure (and its analogues in other
languages) has always been a bit too simple-minded to provide the
control I've required in a particular situation, so I think I
automatically skipped over it when looking here. Also, this illustrates
the perennial mistake of focusing on one solution -- how do I exec? --
rather than stepping back and asking 'what am I actually trying to do?'

Sorry for the noise....

D. Ben Knoble

не прочитано,
4 авг. 2021 г., 11:45:2304.08.2021
– Racket Users
> (exit (system*/exit-code "/usr/bin/vi" "filename")) 

On a slightly unrelated note, if this for consumption by anyone other than just you, I would use (getenv "EDITOR") (or VISUAL, if you prefer) rather than hard-code the path to vi.

Best,
D. Ben Knoble

Norman Gray

не прочитано,
4 авг. 2021 г., 13:36:2104.08.2021
– D. Ben Knoble, Racket Users

Ben, hello.

On 4 Aug 2021, at 16:45, D. Ben Knoble wrote:

> On a slightly unrelated note, if this for consumption by anyone other
> than
> just you, I would use (getenv "EDITOR") (or VISUAL, if you prefer)
> rather
> than hard-code the path to vi.

An excellent point.

In fact this is indeed a program just for me. It's a little
diary/journal/notes tool which started as a quick experiment with scsh a
number of years ago, which I then ported to Chicken when scsh died
(boo-hoo), and which I'm now porting to Racket because I"m having
difficulty getting Chicken to work on a new machine (and I need some
urgent procrastination). It's slightly unfortunate that Racket's
start-up time make it slightly suboptimal as a command-line tool, but
raco make helps with that.

D. Ben Knoble

не прочитано,
4 авг. 2021 г., 15:13:5504.08.2021
– Norman Gray, Racket Users
Hi Norman,

> It's slightly unfortunate that Racket's
> start-up time make it slightly suboptimal as a command-line tool, but
> raco make helps with that.

With 8.0+/CS, even without make I've had a good experience. As you
say, setup or make makes things even faster, though.

If you weren't already aware, using #lang racket/base has a faster
startup-time than #lang racket, though you have to (require) things
not provided by the smaller base language.

Kieron Hardy

не прочитано,
4 авг. 2021 г., 17:04:1204.08.2021
– Racket Users, D. Ben Knoble, Norman Gray

started as a quick experiment with scsh a number of years ago,

I’m surprised no one has mentioned Rash so I will ... perhaps Rash will be a useful tool for you ...


“2 Rash Guide ... Rash is a shell language embedded in Racket. “


Cheers,

Kieron

Norman Gray

не прочитано,
5 авг. 2021 г., 08:07:2305.08.2021
– Kieron Hardy, Racket Users, D. Ben Knoble

Kieron, hello.

On 4 Aug 2021, at 22:04, Kieron Hardy wrote:

> I’m surprised no one has mentioned Rash so I will ... perhaps Rash
> will be a useful tool for you ...
>
> https://docs.racket-lang.org/rash/
>
> “2 Rash Guide ... Rash is a shell language embedded in Racket. “

Thanks for pointing this out. I've looked at rash before, when you or
someone else has mentioned it on-list.

The thing that I really enjoyed about scsh was that it was convenient in
a different direction from rash, which aims to be nice to use
interactively. Scsh didn't aim for interactive use -- it was purely for
scripts -- but it provided really well thought-out bindings for lots of
POSIX, plus sane syntax (and a fast start-up), so that it was a _very_
effective alternative to sh scripts. Unfortunately scsh last got some
love about five years ago [1].

It also has a sentimental attachment for me, because it was the first
Scheme implementation I played with.

Best wishes,

Norman


[1] https://github.com/scheme/scsh and https://scsh.net
Ответить всем
Отправить сообщение автору
Переслать
0 новых сообщений