labath wrote:

I would start looking at this from the other end. Let's identify logical pieces 
of functionality that can be shared between the various modes of operation 
(fork/exec/singleserver), and try to refactor to code to fit that. While doing 
that, I think an important criteria should be whether some of the code is 
platform-specific. If it is, the function containing that should be as small as 
possible so that the ifdef doesn't occur in a deeply nested code (deeply nested 
ifdefs are much harder to reason about than one that occurs at the top level.

The first obvious piece of functionality I see is the one which serves a single 
connection. This is something we need to execute in all three code paths. It 
should definitely be a function of its own (I'm going to call it 
`ServeSingleConnection` here, but there may be a name that better fits local 
conventions), so that we can just call it, instead of reaching it through a web 
of compile and runtime conditionals.

The second one is the piece that serves multiple connections (let's call it 
`ServeManyConnections`) and handles handing them off to subprocesses. This one 
is tricky because it going to be platform specific. I'm not clear on whether it 
should be a single function with embedded ifdefs or two implementations of a 
single function, but I think it should be as small as possible so that the 
platform specificities really stand out.

I would try to implement it as something like this (where the two functions in 
the while loop are platform-specific code):
```
void ServeManyConnections(...) {
  while (conn = AcceptNewConnection()) {
    ServeInSubprocess(conn);
    ReapSubprocessesIfNeeded();
  }
}
```

... but I can also image other schemes. (BTW, I don't think you can get rid of 
the waitpid calls completely, as you need to reap the zombies even if you're 
not going to do anything with them).

Then I think we can structure the main (or something main-like) function as 
something like:
```
int main() {
  ...

  if (getting_connection_from_parent)
    return AcceptConnectionFromParent(...); // retrieves the connection and 
calls ServeSingleConnection

  if (!server_mode) // no --server flag
    return ServeSingleConnection(...)

  return ServeManyConnections(...);
}
```

I know this is handwavy, but that's sort of the goal I think we should aim for. 
It will get messier once all of the arguments (which I've conveniently ignored 
here) get added, but feel free to add structs or classes to group things as 
they make sense. Once we have this, I think it will also be clearer which code 
(if any) we want to put in some common libraries. Doing everything at once also 
may not be the best idea -- I can totally see how a preparatory patch which 
just refactors things without adding windows support would make sense here.

(Also @DavidSpickett, feel free to chime in, I shouldn't be the only one 
dictating conditions here.:)

https://github.com/llvm/llvm-project/pull/101283
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to