On 09-Feb-16, Bram Moolenaar wrote:
> 
> Olaf Dabrunz wrote:
> 
> > > > On 08-Feb-16, Bram Moolenaar wrote:
> > > > > Some parts that we still need that require some thougths:
> > > > > 
> > > > > - Communicating over a socket requires knowing the port number.  For a
> > > > >   deamon this would be a known number.  For a server started by Vim 
> > > > > it's
> > > > >   best to let the server pick an available port.  Then how does it 
> > > > > tell
> > > > >   Vim what port it picked?  In test_channel we write the port number 
> > > > > in
> > > > >   a file.  That's not ideal, but perhaps there is no better solution.
> > > > >   Having Vim pick a free port and pass it to the server has race 
> > > > > conditions
> > > > >   (but it might still be an acceptable solution).
> > > > 
> > > > To avoid the race, Vim could open the server's listening socket before
> > > > forking off the server, then close the socket descriptor on Vim's side.
> > > 
> > > I don't think that works.  If Vim keeps the socket open the server can't
> > > open it again, gives an "already in use" error.
> > 
> > James already answered it, more concisely.
> > 
> > My mid-air collision version, and longer...:
> > 
> > The socket descriptor opened in Vim will be inherited to the child
> > process, the server.  The child process / server does not need to
> > re-open it, it simply uses the already open descriptor.  (Trying to
> > re-open the socket would indeed give "already in use".)
> > 
> > The parent process (Vim) closes its copy of the socket descriptor after
> > the fork because it does not need the listening socket, and because the
> > socket should really shut down whenever the child (the server) closes it.
> 
> Hmm, OK.  But that only works for a process that was specifically
> written to do this.  Not something that takes a --port argument.
> 
> Also, how does the child process know which file descriptor has the
> socket?  For example, how would this work with the demo server?

The server could take a --socket-fd <nr> argument.  If there is an open
socket on that file descriptor, then it can use that.

    struct stat statbuf;
    int fd;

    // get fd from argv

    fstat(fd, &statbuf);
    if (S_ISSOCK(statbuf.st_mode))
        ...;

Some tools already use a --<something>-fd <nr> option for file
descriptors, so there is some precedent here.

> Does this work for MS-Windows?  Probably not, since it doesn't use
> fork().

Not an expert there.  According to the information I gathered [1] this
used to work (across CreateProcess(), instead of fork()), and well
enough on WinNT/2000 [2], but cannot be relied upon, because MS broke it
[3, 1].

A solution could be to pass the socket *after* creating the child, by
using WSADuplicateSocket() [4], but this requires some other form of IPC
(e.g. a named pipe) between parent and child to pass the socket over it.

I think this could better be answered by someone who has experience with
socket passing on Windows.

[1] 
http://stackoverflow.com/questions/11847793/are-tcp-socket-handles-inheritable
[2] https://support.microsoft.com/en-us/kb/150523
[3] 
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724251(v=vs.85).aspx
    (look for "socket")
[4] 
https://msdn.microsoft.com/en-us/library/windows/desktop/ms741565(v=vs.85).aspx

> > Inheriting the descriptor of the listening socket is done regularly in
> > pre-forked multiprocess servers.
> > 
> >     The "prefork" bullet summarizes it:
> >     
> > http://freeprogrammersblog.vhex.net/post/linux-39-introduced-new-way-of-writing-socket-servers/2
> > 
> > > > > One problem that I haven't figured out yet: When starting a job using 
> > > > > a
> > > > > shell, we get the PID of the shell.  So we can kill the shell, but not
> > > > > the process that it started. 
> > > > 
> > > > Put the shell in a new session with setsid().  Killing all processes in
> > > > the session is done by sending the signal to the session leader (here:
> > > > the shell).
> > > > 
> > > > Similar to daemon-izing a job.
> > > > 
> > > >     http://www.win.tue.nl/~aeb/linux/lk/lk-10.html#ss10.3
> > > 
> > > Unfortunately that doesn't work.  I used that in the test at first:
> > > 
> > >   let job = job_start(['/bin/sh', '-c', 'python test_channel.py 
> > > </dev/null >/dev/null'])
> > >   call getchar()
> > >   call job_stop(job)
> > > 
> > > While it's waiting for a character, check the processes.  You should see
> > > both the shell and the python process.  After pressing Enter the shell
> > > is gone but the python process keeps running.  At least on my Ubuntu
> > > system.
> > 
> > Ah right, you already use this in 7.4.1274.
> > 
> > To correct myself: kill the negative of the PID of the session leader,
> > this sends the signal to all processes in its process group (!), see
> > kill(2):
> > 
> > mch_stop_job():
> > 
> >         sig = atoi((char *)how);
> >       else
> >         return FAIL;
> > -     kill(job->jv_pid, sig);
> > +     kill(-job->jv_pid, sig);
> >       return OK;
> >   }
> >   #endif
> 
> Ah, forgot about that way.  It's actually in os_unix.c.
> 
> > This also triggers a sort of chain reaction that should bring down the
> > other process groups in the session (if any), unless they ignore SIGHUP:
> > 
> >     When the session leader exits, all processes in the foreground
> >     process receive a SIGHUP.
> > 
> >     When the parent (typically the session leader) of a background
> >     process group with at least one stopped process exits, all processes
> >     in that background process group receive a SIGHUP.  (And a SIGCONT,
> >     which makes them continue running in the background in case they
> >     ignore SIGHUP.)
> > 
> > See more details in
> >     - http://www.win.tue.nl/~aeb/linux/lk/lk-10.html#ss10.3
> >     - man 2 setpgid
> 
> So, should we do this always or make it an option?  I think we should
> make this the default and have an option to only kill the process
> itself.  Although the child of the child could use setsid() if it
> doesn't want to be killed.

I also think it should be the default.  And probably it is overkill to
have an option that only kills the PID, because as you say, a child of a
child can use setsid() to avoid being killed.

But starting the server with "exec" when started from a shell should be
documented, as the server may otherwise not get killed (mentioned by
Gary and in one of my other mails).

-- 
Olaf Dabrunz (oda <at> fctrace.org)

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui