From: Cyrill Gorcunov <gorcunov@gmail.com> To: Konstantin Osipov <kostja.osipov@gmail.com> Cc: tml <tarantool-patches@dev.tarantool.org> Subject: Re: [Tarantool-patches] [PATCH v6 2/4] popen: Introduce a backend engine Date: Fri, 20 Dec 2019 14:52:57 +0300 [thread overview] Message-ID: <20191220115257.GA10179@uranus> (raw) In-Reply-To: <20191220081159.GG30445@atlas> On Fri, Dec 20, 2019 at 11:11:59AM +0300, Konstantin Osipov wrote: > * Cyrill Gorcunov <gorcunov@gmail.com> [19/12/17 15:57]: > > +/* Children pids map popen_handle map */ > > map popen_handle map? > Even if I remove double "map" I don't undesrtand the ocmment. > > Is it pid -> popen_handle() map? How is it used? For waitpid? > Please explain in the comment. Yes, it was s typo, should be "Mapping of children pids to popen_handle". The map may be used for several reasons: 1) to waitpid 2) to fetch information about specific pid (lua interface). I don't think we should point every reason for this pid <=> handle mapping here in comment, but instead the comment (probably) should be "Mapping of children pids to popen_handle for fast lookup"? > > +static struct mh_i32ptr_t *popen_pids_map = NULL; > > + > > +/* All popen handles to be able to cleanup them on exit */ > at exit Both variants are correct, but I'll update to match atexit libc helper in a meaning. > > +/* /dev/null to be used inside children if requested */ > > This is a bit too sketchy. Please explain: how it is requested, > what it is used for, etc. I can of course guess that it's used > as children stdin/stdout, if there is an option to popen(), but > that's it. Yes, exactly, it is used as stdX. When first attempt to implement popen hit the mailing list there were comments that we should provide /dev/null as stdX (I presume because some of programs might require stdX presence even if they're not writting anything). I'll update the comment to point the reason. Thanks! > > +static void > > +handle_free(struct popen_handle *handle) > > +{ > > + say_debug("popen: handle %p free %p", handle); > > + free(handle); > > +} > > I don't understand who owns char *command and why > it's not freed here. Could you please clarify? Look, the command is compiled from argv array into a single string dynamically allocated. The handle just carries a reference to it. If you think it will be more suitable to allocate command together with handle itself in one place then sure I'll update. > > > + return coio_write_fd_timeout(handle->fds[idx], > > + buf, count, timeout); > > You could store struct coio for each child stream in the handle, > it's pretty cheap. I don't have a strong opinion on this, > your implementation looks tidy (although has some overhead). I'll take a look. Thanks! > > + if (WIFEXITED(wstatus) || WIFSIGNALED(wstatus)) { > > + assert(handle->pid == pid); > > + /* > > + * libev calls for waitpid by self so > > + * we don't have to wait here. > > + */ > > + popen_unregister(handle); > > + /* > > + * Since SIGCHLD may come to us not > > + * due to exit/kill reason (consider > > + * a case when someone stopped a child > > + * process) we should continue wathcing > > + * state changes, thus we stop monitoring > > + * dead children only. > > + */ > > + say_debug("popen: ev_child_stop %d", handle->pid); > > + ev_child_stop(EV_DEFAULT_ &handle->ev_sigchld); > > + handle->pid = -1; > > + } > > I don't understand how the code matches the comment. > > You write "we should continue watching state changes" inside > a branch that handles termination. How is this comment relevant to > what you are doing in this branch? You know, internally every child inside libev is kept in own hashmap. When SIGCHLD happens libev walks over the hash and findis a child process. When I said "we should continue watching state changes" I mean that we should not affect any other watcher libev carries and should stop watching only our pid (remember that in future we might need to create other child process for some reason, unrelated to popen). Thus we should call libev's "stop" on the pid we're interested in, and in result libev will drop own hash entry matching to this pid. I'll rework the comment. At first I tried to make libev to watch every children pid but this caused problems with compilation. Maybe I should look into this area again. > > Why do you have to cast handle->ev_sigchld to EV_DEFAULT_? Otherwise it doesn't compile. > > +} > > + > > +/** > > + * ev_sigchld_cb - handle SIGCHLD from a child process > > + * @w: a child exited > > + * @revents: unused > > + */ > > +static void > > +ev_sigchld_cb(EV_P_ ev_child *w, int revents) > > +{ > > + (void)revents; > > + /* > > + * Stop watching this child, libev will > > + * remove it from own hashtable. > > + */ > > + ev_child_stop(EV_A_ w); > > + > > + /* > > + * The reason for a separate helper is that > > + * we might need to notify more subsystems > > + * in future. > > + */ > > + popen_notify_sigchld(w->rpid, w->rstatus); > > I think ev_sigchld_cb is a too general name. Besides, why do you > need two functions, and call one from another? Would handle_child_exit() sound better? As to nesting -- this is just in case if we need to send more notifiers in future. I can inline popen_notify_sigchld here if you prefer. Or even rename ev_sigchld_cb to popen_notify_sigchld and use it instead. > > > + if (handle->flags & POPEN_FLAGS_SETSID) { > > + if (signo == SIGKILL || signo == SIGTERM) { > > + say_debug("popen: killpg %d signo %d", > > + handle->pid, signo); > > + ret = killpg(handle->pid, signo); > > I don't understand why you need to use killpg() here. > > Could you please explain? > I suspect that you don't, you're just trying to be safe, > and there is no need to. After thinking more I think you're right, plain kill should be enough. > > > + if (handle->fds[i] != -1) { > > + /* > > + * We might did some i/o on > > + * this fd, so make sure > > + * libev removed it from > > + * watching before close. > > + * > > + * Calling coio_close on > > + * fd which never been watched > > + * if safe. > > + */ > > + coio_close(handle->fds[i]); > > Ugh. This definitely suggests you need a coio object > in popen_handle(), this coio_close() looks like a hack. Will look into this. Thanks a huge for review, Kostya! Cyrill
next prev parent reply other threads:[~2019-12-20 11:53 UTC|newest] Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-12-17 12:54 [Tarantool-patches] [PATCH v6 0/4] popen: Add ability to run external process Cyrill Gorcunov 2019-12-17 12:54 ` [Tarantool-patches] [PATCH v6 1/4] coio: Export helpers and provide coio_read_fd_timeout Cyrill Gorcunov 2019-12-20 7:48 ` Konstantin Osipov 2019-12-20 14:50 ` Cyrill Gorcunov 2019-12-17 12:54 ` [Tarantool-patches] [PATCH v6 2/4] popen: Introduce a backend engine Cyrill Gorcunov 2019-12-20 8:11 ` Konstantin Osipov 2019-12-20 11:52 ` Cyrill Gorcunov [this message] 2019-12-20 12:04 ` Konstantin Osipov 2019-12-20 12:10 ` Cyrill Gorcunov 2019-12-20 12:11 ` Alexander Turenko 2019-12-26 7:14 ` Konstantin Osipov 2019-12-26 7:19 ` Cyrill Gorcunov 2020-01-09 11:23 ` Cyrill Gorcunov 2019-12-17 12:54 ` [Tarantool-patches] [PATCH v6 3/4] popen/lua: Add popen module Cyrill Gorcunov 2019-12-20 15:41 ` Maxim Melentiev 2019-12-17 12:54 ` [Tarantool-patches] [PATCH v6 4/4] popen/test: Add base test cases Cyrill Gorcunov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20191220115257.GA10179@uranus \ --to=gorcunov@gmail.com \ --cc=kostja.osipov@gmail.com \ --cc=tarantool-patches@dev.tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH v6 2/4] popen: Introduce a backend engine' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox