git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 0/2] Another squash on run-command: add an asynchronous parallel child processor

From
Junio C Hamano <gitster@pobox.com>
Date
Sep 25, 2015, 19:32 UTC
Message-ID
<xmqq1tdm47nj.fsf@gitster.mtv.corp.google.com>
In-Reply-To
<CAGZ79kbpLwODzPrGcuvz2oY+XMMPAy9SRh1s_5wV8cvY-J79iw@mail.gmail.com>
Stefan Beller <sbeller@google.com> writes:
Show 14 quoted lines
> We could also offer more access to the pp machinery and an implementation for
> (2) might look like this:
>
> static void fictious_start_failure(void *data,
>                                 void *pp,
>                                 struct child_process *cp,
>                                 struct strbuf *err)
> {
>         struct mydata *m = data;
>
>         if (m->failstrategy == 1)
>                 ; /* nothing here */
>         else if (m->failstrategy == 2)
>                 killall_children(pp);

That looks nice and clean in theory, but I highly doubt that it is a good idea to have killall_children(pp) in a client code of the API like this, especially if you are envisioning that that function merely goes through the list of children and does kill on the processes. If killall_children(pp) is supplied by the API, it makes things less insane (now it can know and keep up with the evolution of the API implementation detail, such as how buffered output are kept and such), but still such an API constrains the structure of the overall scheduling loop and the helper functions that live on the API side. You need to make absolutely sure that calling killall_children() is something that can be sanely done from inside start_failure() callback, for example.

If you signal the "emergency" with a return value, the callchain on the API side can choose to do the killing at a place it knows is safe to do so in a more controlled way. For example, the main loop of the API side IIRC (I do not bother checking out 'pu' to read it as my working tree is busy on another topic right now) is

    while (1) {
    	for (cnt = 0; cnt < 4 && we still have slots; cnt++)
		start_one();
	collect_output();
	drain_output_for_foreground();
	wait_and_flush();
    }

Imagine that you have 0 or more processes running and start another iteration of this loop. The first task started by start_one() fails and the above fictitious_start_failure() calls killall_children() itself. What happens to the other three iteration of the inner loop? After existing ones are killed, it adds three more?

And to prevent that from happening, you also need to tell your fictitious_next_task() that no more processes are desired. The client of the API is forced to coordinate across its multiple callback functions.

And you did that to gain what? One major thing I can think of is that that way, the main scheduling loop does not have to know why after attempting to spawn but failing, fictitious_next_task() started saying "no more tasks". For somebody who is coming from "The main loop is a dumb bullet-list of things to do. All smarts are inside the callee", that might appear to be a good thing.

But I do not think it is a good thing at all. That forces the reader of the code to not just follow the API layer but even down to its individual clients of the API to understand what is going on.

If you propagate the return from start_failure() callback upwards, then the main scheduler would *know* that the client application does not want any more new tasks, and it does want to abort even the running tasks, so it will not call fictitious_next_task() in the first place after the client application declares an "emergency exit".

And that would make the overall logic a lot easier to follow.
	
Previous: Stefan BellerNext: Stefan Beller
Message 30 of 39 in “[PATCHv4 00/14] fetch submodules in parallel and a preview on parallel "submodule update"”
  1. Stefan BellerSep 23, 2015
  2. 01/14 submodule: Send "Fetching submodule <foo>" to standard errorStefan Beller, Sep 23, 2015
  3. 02/14 xread: poll on non blocking fdsStefan Beller, Sep 23, 2015
  4. 03/14 xread_nonblock: add functionality to read from fds without blockingStefan Beller, Sep 23, 2015
  5. 04/14 strbuf: add strbuf_read_once to read without blockingStefan Beller, Sep 23, 2015
  6. 05/14 run-command: factor out return value computationStefan Beller, Sep 23, 2015
  7. 06/14 run-command: add an asynchronous parallel child processorStefan Beller, Sep 23, 2015
  8. Junio C HamanoSep 23, 2015
  9. Stefan BellerSep 23, 2015
  10. Junio C HamanoSep 23, 2015
  11. Junio C HamanoSep 23, 2015
  12. Stefan BellerSep 23, 2015
  13. Junio C HamanoSep 23, 2015
  14. Junio C HamanoSep 23, 2015
  15. Junio C HamanoSep 23, 2015
  16. Junio C HamanoSep 23, 2015
  17. [PATCHv5] Another squash on run-command: add an asynchronous parallel child processorStefan Beller, Sep 23, 2015
  18. Junio C HamanoSep 24, 2015
  19. 0/2 Another squash on run-command: add an asynchronous parallel child processorStefan Beller, Sep 24, 2015
  20. 2/2 SQUASH for "fetch_populated_submodules: use new parallel job processing"Stefan Beller, Sep 24, 2015
  21. 1/2 SQUASH???Stefan Beller, Sep 24, 2015
  22. Junio C HamanoSep 25, 2015
  23. Junio C HamanoSep 25, 2015
  24. Stefan BellerSep 25, 2015
  25. Junio C HamanoSep 25, 2015
  26. Junio C HamanoSep 25, 2015
  27. Stefan BellerSep 25, 2015
  28. Junio C HamanoSep 25, 2015
  29. Stefan BellerSep 25, 2015
  30. Junio C HamanoSep 25, 2015
  31. 07/14 fetch_populated_submodules: use new parallel job processingStefan Beller, Sep 23, 2015
  32. 08/14 submodules: allow parallel fetching, add tests and documentationStefan Beller, Sep 23, 2015
  33. 09/14 submodule-config: Untangle logic in parse_configStefan Beller, Sep 23, 2015
  34. 10/14 submodule config: keep update strategy aroundStefan Beller, Sep 23, 2015
  35. 11/14 git submodule update: cmd_update_recursiveStefan Beller, Sep 23, 2015
  36. 12/14 git submodule update: cmd_update_cloneStefan Beller, Sep 23, 2015
  37. Junio C HamanoSep 23, 2015
  38. 13/14 git submodule update: cmd_update_fetchStefan Beller, Sep 23, 2015
  39. 14/14 Rewrite submodule update in CStefan Beller, Sep 23, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.