|
Edit: Dupe post, whoops!
|
# ? Feb 6, 2015 05:14 |
|
|
# ? Jun 8, 2024 05:51 |
|
The ability to fork your own process and not exec is nice. What I would want is the ability to safely reload ones own executable fresh from disk but with different command line arguments or a different entry point and an explicit enumeration of file descriptors to keep open. Actually this would be useless because you'd target the lowest common denominator anyway and just spawn a pristine worker process at startup. And heck if you're serializing process arguments you might as well send them over a pipe anyway. So yeah just fork.
|
# ? Feb 6, 2015 05:29 |
|
Suspicious Dish posted:I would prefer a system where fork(); took a function pointer, the child process inherited all the VM maps from the parent process but were set readonly, Suspicious Dish posted:and POSIX specified the mind-blowingly-useless vfork();. Before BSD implemented COW fork, vfork was implemented as an optimization for the common fork-then-exec case to avoid the expense of copying rw pages. Now, if you were chummy with your compiler, you didn't have to immediately exec, but instead could call functions in the child process to set fds, etc., so long as the stack was not modified or unwound above the vfork call--hence, it was still strictly more useful than a spawn (fork-then-immediately-exec). Of course, use of vfork is pretty darn dangerous and not worth the benefit after COW fork came around. It's not clear to me if vfork persisted in its vestigial form in POSIX because vfork-exec was still common in code or because they wanted POSIX to support MMU-less systems. Possibly both. ExcessBLarg! fucked around with this message at 05:59 on Feb 6, 2015 |
# ? Feb 6, 2015 05:56 |
|
POSIX vfork() is specified that you literally cannot do anything other than immediately exec(). fork() without exec() is really bad and you shouldn't ever do it.
|
# ? Feb 6, 2015 06:57 |
|
Sounds a little like my first ever hack, At college they had set /dev/tty root:root -rwx-------- Which meant for less and more to work they had to be Setuid Which meant that will more you could do !csh at the next page prompt and get a Root shell We knew that wouldnt last long so i (not knowing any sourcecode for unix Berkley SysV) worked out how the su command worked and rewrote it with a back door in it. And would you know - It worked. Except if you did an su then ps -ef showed something like aprofessor (su) csh this is because we hadn't been taught about fork/exec so i had exec'd the user shell instead of forking it Still they didn't notice until after I left the college. su - username worked su worked su - worked su username worked but if after typing su you pressed Ctrl-Y then pressed enter, it would give you root shell and not log that you used Su either
|
# ? Feb 6, 2015 07:53 |
|
LeftistMuslimObama posted:Yeah, the whole time they were explaining fork and how elegant it was in the lecture, I kinda kept wondering to myself "am I the only person in here who thinks this is really stupid?". Glad to know I'm not alone. Dunning–Kruger effect in action. If you think it's obvious why fork is "really stupid" when it's first explained to you, then it's probably caused by a lack of understanding on your end rather than Ken Thompson and Dennis Ritchie being incompetent.
|
# ? Feb 6, 2015 09:54 |
|
Someone's got a vfork() up their rear end in a top hat
|
# ? Feb 6, 2015 10:58 |
|
Suspicious Dish posted:fork() without exec() is really bad and you shouldn't ever do it.
|
# ? Feb 6, 2015 14:03 |
|
Less Fat Luke posted:Can you elaborate on that a bit? I'm familiar with both and I'm used to having applications in the Ruby world that generally load an application and fork a bunch of worker processes (because LOL at Ruby threading) but I'm not sure what it means to fork() without exec(). quote:The environment in the child process is harsh and makes it difficult to write correct code to run there. Anything you do beyond a direct call to an exec function has to be done with great care. That's why the error handling code is written the way it is. quote:In my opinion there are so many problems with fork(2) in multi-threaded programs that it's almost impossible to do it right. The only clear case is to call execve(2) in the child process just after fork(2). If you want to do something more, just do it some other way, really. From my experience it's not worth trying to make the fork(2) call save, even with pthread_atfork().
|
# ? Feb 6, 2015 15:12 |
|
So when, let's say, Apache fork()s, does it exec() to httpd?
|
# ? Feb 6, 2015 15:17 |
|
No. Apache prefork isn't multithreaded and thus can fork all day long practically worry-free.
|
# ? Feb 6, 2015 15:22 |
|
Oh, it's only an issue if the parent is multithreaded. Some of the posts made it sound like not quickly exec()ing was always bad. This all reminds me of my "make a shell" assignment in my OS class, where I was trying out vork() to spawn processes. I was developing on OS X 10.7, and if I attached gdb to the vfork()ed process before exec(), the kernel would panic 100% of the time. So I wrote a small program to exploit that. I have the code, but the bug was patched by 10.8. My final solution was gently caress vfork()
|
# ? Feb 6, 2015 16:17 |
|
It's also an issue if the parent has any global state. I know of a few libraries that allocate a giant chunk of contiguous memory with mmap() -- when the child forks, that memory isn't copy-on-write, since it's supposed to work like shared memory. This caused a hard-to-track-down bug with Python's multiprocessing module (which forks w/out exec) and libffi/ctypes (which allocates a giant page with mmap) where customers got various memory corruption.
|
# ? Feb 6, 2015 16:42 |
|
Skuto posted:Dunning–Kruger effect in action. If you think it's obvious why fork is "really stupid" when it's first explained to you, then it's probably caused by a lack of understanding on your end rather than Ken Thompson and Dennis Ritchie being incompetent. I understand fork() extremely well and still think it's a poor abstraction for many reasons. I don't think there's any part of "the child process inherits all the parent's global state and references to kernel objects" that's particularly sane, because you can easily end up with weird corruption issues if you forget to reset some state.
|
# ? Feb 6, 2015 16:44 |
|
Am I safe from this poo poo if I just use default thread / mutex libraries in perl/ruby/python because the thinking has already been done for me? Or is this something I really need to sit down and understand for the future. Because I really hope not.
|
# ? Feb 6, 2015 16:45 |
|
Suspicious Dish posted:I understand fork() extremely well and still think it's a poor abstraction for many reasons. You are preaching to the choir. I'm just pointing out that the issues with it, which you highlighted very well, are actually far from obvious.
|
# ? Feb 6, 2015 17:10 |
|
Bhodi posted:Am I safe from this poo poo if I just use default thread / mutex libraries in perl/ruby/python because the thinking has already been done for me? Or is this something I really need to sit down and understand for the future. Because I really hope not. You don't need to care about this in those languages. These fork issues are fairly low-level and not actually that well understood even by experienced Unix programmers. Even Chrome had bugs with this because they use(d) STL after fork but before exec in their IPC library.
|
# ? Feb 6, 2015 17:20 |
|
Skuto posted:Even Chrome had bugs with this because they use(d) STL after fork but before exec in their IPC library. https://code.google.com/p/chromium/issues/detail?id=36678 (2010) https://code.google.com/p/chromium/issues/detail?id=179923 (same issue again 3 years later)
|
# ? Feb 6, 2015 17:24 |
|
I'm struggling to see what bizarre set of circumstances where it would make sense to fork() and not exec() in a multithreaded process. It's like I want another independent thread of execution accessing the same resources but I can't use a thread since I also want batshit insane memory semantics to spice things up.
|
# ? Feb 6, 2015 17:32 |
|
Skuto posted:https://code.google.com/p/chromium/issues/detail?id=36678 (2010) That must be amenable to static analysis.
|
# ? Feb 6, 2015 17:35 |
|
1337JiveTurkey posted:I'm struggling to see what bizarre set of circumstances where it would make sense to fork() and not exec() in a multithreaded process. I'm not sure what those would be either, but it's not "fork and not exec", that's causing the bugs, it's "fork and not exec *immediately*". As for the latter, for example Chromium closes off a bunch of FDs in the child processes, and I think you can probably guess why you want to do that.
|
# ? Feb 6, 2015 17:40 |
|
Skuto posted:Dunning–Kruger effect in action. If you think it's obvious why fork is "really stupid" when it's first explained to you, then it's probably caused by a lack of understanding on your end rather than Ken Thompson and Dennis Ritchie being incompetent. Regarding being a noob and hearing somebody saying something that makes no sense and thinking "oh there must be some reason why they are right, they surely would know what they are talking about": that's a fallacy that has hit me again and again and again. If there are obvious problems with an idea and the person introducing the idea is not signalling knowledge of objections that people might have, it's a good idea not to give them the benefit of the doubt.
|
# ? Feb 6, 2015 18:50 |
|
Yeah, I just basically didn't see why fork() is useful by itself, because it seemed like you'd pretty much always need to exec() right afterward.In my mind, a more straightforward way to do it would be to spin off a process using some sort of process constructor syntax where you could pass the child process any data it needs that way, rather than dealing with copy-on-write memory and having code in side of a process that exists just to call another process after the process duplicates itself with fork(). It just seems like for most use cases fork() just adds an extra step to calling another process. Fork() is probably quite lovely if you really do just want a copy of the currently running process, but why fork()+exec() instead of just something like spawnProcess(<function pointer>,<parameters>)? I'm totally willing to accept that I'm just totally wrong about all of this, but fork() just seems to be extraneous to most of the cases where you'd spawn off another process.
|
# ? Feb 6, 2015 18:57 |
|
Fork is grand as an extensible way to set up the environment before exec. File redirections and pipelines work because of all the descriptor juggling between fork and exec. Same with stuff like dropping capabilities and entering new name spaces. If you couldn't do this between fork and exec you would need an ever growing CreateProcess syscall or different syscalls for changing the current processes state and changing the state of any new subprocesses you spawn. Using it for anything that isn't setting up for another exec pretty much requires you to build your whole runtime around the idea.
|
# ? Feb 6, 2015 19:10 |
|
Those are "completely" different because exec is a different thing than calling a function through a function pointer. It is still useful to know that your process's executable has not been replaced, which is why being able to make a process out of yourself without using a file name is good. Maybe you can actually self-exec somehow on the same file on some OSes, even if something else has been moved in its place. But I think spawning a worker process early on to fork pristinely over is a mild inconvenience.
|
# ? Feb 6, 2015 19:13 |
|
sarehu posted:Maybe you can actually self-exec somehow on the same file on some OSes, even if something else has been moved in its place. Exec /proc/self/exe maybe. I know the CRIU guys have found a way to do it, but it might involve reading /proc/self/maps and serialising all the executable pages used by your process.
|
# ? Feb 6, 2015 19:23 |
|
sarehu posted:Those are "completely" different because exec is a different thing than calling a function through a function pointer. It is still useful to know that your process's executable has not been replaced, which is why being able to make a process out of yourself without using a file name is good. Maybe you can actually self-exec somehow on the same file on some OSes, even if something else has been moved in its place. But I think spawning a worker process early on to fork pristinely over is a mild inconvenience. I guess what confuses me, though, is why there isn't a command that's just "Make a new process with this program/function and these arguments and then link it to me as a child". It seems like it would do the same thing as fork()+exec() with fewer lines of code, unless the lecturer for my class simply didn't explain the nuances well at all.
|
# ? Feb 6, 2015 20:01 |
|
LeftistMuslimObama posted:Yeah, I just basically didn't see why fork() is useful by itself, because it seemed like you'd pretty much always need to exec() right afterward. No, you don't. Fork() without exec is the archetypal way to make a multiprocessing server in Unix. And that other thing you disliked (COW) is pretty important for that.
|
# ? Feb 6, 2015 20:40 |
|
sarehu posted:the person introducing the idea is not signalling knowledge of objections that people might have, it's a good idea not to give them the benefit of the doubt. We could've done away with all the security holes from string processing and memory handling in C if we just hadn't given those same guys the benefit of the doubt and stuck with LISP machines.
|
# ? Feb 6, 2015 20:44 |
|
LeftistMuslimObama posted:I guess what confuses me, though, is why there isn't a command that's just "Make a new process with this program/function and these arguments and then link it to me as a child". It seems like it would do the same thing as fork()+exec() with fewer lines of code, unless the lecturer for my class simply didn't explain the nuances well at all. If it would do the same thing then you can just define such a function yourself, if saving lines of code is your goal.
|
# ? Feb 6, 2015 20:52 |
|
Disabling COW is great because it means big processes can't launch other processes at all
|
# ? Feb 6, 2015 20:54 |
|
Skuto posted:No, you don't. Fork() without exec is the archetypal way to make a multiprocessing server in Unix. And that other thing you disliked (COW) is pretty important for that. Cool. It seems like I'm just not getting the whole picture in this class then. Hopefully it's something they plan to circle back to as an advanced topic, rather than just a deficiency in the material covered.
|
# ? Feb 6, 2015 21:01 |
|
LeftistMuslimObama posted:I guess what confuses me, though, is why there isn't a command that's just "Make a new process with this program/function and these arguments and then link it to me as a child". It seems like it would do the same thing as fork()+exec() with fewer lines of code, unless the lecturer for my class simply didn't explain the nuances well at all. There is, on some Unixen. Google posix_spawn.
|
# ? Feb 7, 2015 02:49 |
|
Vanadium posted:Disabling COW is great because it means big processes can't launch other processes at all How so?
|
# ? Feb 7, 2015 04:35 |
|
Speaking of LISP, I've been meaning to learn me a functional programming, for evaluation of possible good, but the online materials I've found are kinda quirky and go on at length about trivial stuff in a self-deprecating tone (this syntax sure is weird huh, it is not what you are used to, ha ha, it's like talking with a ...lisp... *badum-tish* but don't you worry, *wink*, this will all feel natural to you as you quickly become an ~expert LISPER~ , droooone blah blah blather blah, now here is a description of how you unpack nested return values only we call it "pattern matching" like no sensible people would, and we go on for pages about it) like a prolonged windup to the real subject matter, which never comes, but instead they're like "welp now you know basic syntax good luck here's a link to the STL bye now". So yeah, I actually do want to collectively call them a horror, because none of this functional programming stuff is really that hard, and this tiptoeing around it just paints it weird. I just want a resource that hits me in the face with it, like the go tour. Here, this is how you make a list. Here is how you pass it to a function. Here is map, here is reduce. Here is how you load a chunk of structured data and this is how you write it to disk, in various formats. Here's a realistic example that solves a common problem, so that you can compare performance with whatever you can hack together in your favorite language. This is how you write idiomatic code in this language. And yes, this goes for that goon haskell site as well *throws glove* and no, I don't want a paper book about programming. This is where you get to call me an idiot and prove me wrong by fulfilling my needs.
|
# ? Feb 7, 2015 08:38 |
|
Karate Bastard posted:and no, I don't want a paper book about programming. SICP is available online.
|
# ? Feb 7, 2015 09:06 |
Karate Bastard posted:Speaking of LISP, I've been meaning to learn me a functional programming I really liked Real World Haskell, although I'll occasionally use Learn You A Haskell as a reference (for those sections where he lists a bunch of useful functions relating to something). It's not a perfect book but I learned a ton from it. quote:now here is a description of how you unpack nested return values only we call it "pattern matching" like no sensible people would Also everyone calls it pattern matching.
|
|
# ? Feb 7, 2015 09:09 |
|
Thanks for the tips you guys!VikingofRock posted:Also everyone calls it pattern matching. They do? Is this a lisp thing, because I've only ever heard it in connection to string parsing, like globbing and regexes and the like?
|
# ? Feb 7, 2015 09:20 |
|
Karate Bastard posted:They do? Is this a lisp thing, because I've only ever heard it in connection to string parsing, like globbing and regexes and the like? It's a "thing" in languages that provide actual pattern matching functionality. I'm going to take a stab that the reason you referred to it as "unpacking nested return values" is because you saw something like: code:
Python code:
code:
|
# ? Feb 7, 2015 09:37 |
|
|
# ? Jun 8, 2024 05:51 |
In functional languages, any construct that lets you compare a value against several different, partially or fully filled out structures, with optional placeholders for capturing partial contents, is called a pattern matching construct.
|
|
# ? Feb 7, 2015 09:38 |