Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
VikingofRock
Aug 24, 2008





Yeah. It's super powerful too, and is used for a lot more than unpacking values (see Jabor's post). IMO you should think of it as more of a beefed-up switch statement than an unpacking mechanism. I actually think most Haskell code gets compiled down to pattern matches internally, but I am far from an expert on Haskell compilation so don't quote me on that.

Adbot
ADBOT LOVES YOU

Karate Bastard
Jul 31, 2007

Soiled Meat

Neat, it has a "We make the content freely available online. If you like it, please buy a copy" policy. That's promising. I've only ever seen awesome people do that.

Jabor posted:

Awesome and constructive effortpost

Now that's what I'm talking about, that's how you do it! That's time spent teaching nontrivial stuff instead of taking an awesome and powerful functionality (as I'm now learning it is) and dressing it up as a gimped down error prone syntax sugar. Thanks man!

Vanadium
Jan 8, 2005


I had it the wrong way around and was thinking about how you can disable overcommit, so a process that's using over half the available memory and tries to fork immediately commits all that memory again and welp there's not enough of it.

KaneTW
Dec 2, 2011

Karate Bastard posted:

Neat, it has a "We make the content freely available online. If you like it, please buy a copy" policy. That's promising. I've only ever seen awesome people do that.


Now that's what I'm talking about, that's how you do it! That's time spent teaching nontrivial stuff instead of taking an awesome and powerful functionality (as I'm now learning it is) and dressing it up as a gimped down error prone syntax sugar. Thanks man!

Bryan O'Sullivan is a pretty awesome person.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
If you want to learn an actual lisp I've been really enjoying Clojure for the Brave and True.

Can't go wrong with a tutorial that has you sorting suspected vampires by their glitter factor.

Clojure is really useful because it runs on the JVM (and some other places too), so you get access to the vast Java ecosystem without having to, you know, Java.

Karate Bastard
Jul 31, 2007

Soiled Meat
I've heard nice things about clojure, but also that it has terrible startup time, unrelated to jvm starup times. True/false?

more like dICK
Feb 15, 2010

This is inevitable.

Karate Bastard posted:

I've heard nice things about clojure, but also that it has terrible startup time, unrelated to jvm starup times. True/false?

Definitely true. It's less of an issue for the kind of long running services you'd typically write in clojure, but it makes the language unsuitable for quick command line utilities.

Hiowf
Jun 28, 2013

We don't do .DOC in my cave.

Vanadium posted:

I had it the wrong way around and was thinking about how you can disable overcommit, so a process that's using over half the available memory and tries to fork immediately commits all that memory again and welp there's not enough of it.

No, i think you were right. If you disable COW your overcommit is going to be in pain as you're going to be *actually writing* to *all* the overcommited RAM.

ToxicFrog
Apr 26, 2008


Karate Bastard posted:

I've heard nice things about clojure, but also that it has terrible startup time, unrelated to jvm starup times. True/false?

Very true. It's great for long-running processes (daemons, GUI tools) but rubbish for anything where startup time is a factor.

Clojure is the only lisp I've actually gotten poo poo done with, and the tooling is fantastic, but I wish it didn't take so long to start up (and use so much memory, although that's as much a JVM thing as a clojure thing) so I could use it for more things.

ToxicFrog fucked around with this message at 17:16 on Feb 7, 2015

necrotic
Aug 2, 2005
I owe my brother big time for this!

ToxicFrog posted:

Very true. It's great for long-running processes (daemons, GUI tools) but rubbish for anything where startup time is a factor.

Clojure is the only lisp I've actually gotten poo poo done with, and the tooling is fantastic, but I wish it didn't take so long to start up (and use so much memory, although that's as much a JVM thing as a clojure thing) so I could use it for more things.

I've been trying to mess around with Lisp as well, and from what I've seen SBCL is the way to go for CLIs or other "short run" things. Is that the case still, or is there something better? Most of the material I can find is from like 2012 or before.

comedyblissoption
Mar 15, 2006

I would go with Haskell over Lisp if you just want a perspective on functional programming for pedagogical reasons.

Haskell is pure compared to Lisp. This requires that you are explicit in side effects and mutability while Lisp does not.

Haskell's type system will also demonstrate how powerful a good static type system can be in removing certain types of common programming errors and boilerplate.

Since many popular languages have adopted features like tail call optimizations, higher order functions, lambdas, and closures, I feel like Lisp is not left with much to deliver on insight in regards to functional programming.

The main thing Lisp has to demonstrate for pedagogy is meta-programming. Lisp code is essentially an abstract syntax tree. You can pass Lisp code into a Lisp function that will parse and arbitrarily manipulate this syntax tree to produce another syntax tree. This is conceptually how compilers do code transformations as far as I'm aware. The amazing thing with Lisp is how easy this is and that this is all done using Lisp code. You don't escape into a special meta-programming world with different syntax. You aren't burdened with insane unreadability of the meta-programming facilities. You can essentially trivially define your own syntax for Lisp.

I really like Learn You a Haskell for Great Good.

comedyblissoption fucked around with this message at 21:10 on Feb 7, 2015

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
I wouldn't say that one second startup times make anything "unusable" for command line utilities, really. Those benchmarks are much more damning for Android apps, where a 5 second startup time would make me want to launch my device out a window, but a couple of extra seconds to parse an XML file or whatever isn't so bad. It probably took me longer to type the command in the first place.

ed: He was able to get Android start times down to 1.7s by disabling some nonessential things, but that's still really bad as a mandatory cost to startup the runtime, especially on a mobile environment where you're extra sensitive to delays.

Dessert Rose fucked around with this message at 21:17 on Feb 7, 2015

Hughlander
May 11, 2005

Dessert Rose posted:

I wouldn't say that one second startup times make anything "unusable" for command line utilities, really. Those benchmarks are much more damning for Android apps, where a 5 second startup time would make me want to launch my device out a window, but a couple of extra seconds to parse an XML file or whatever isn't so bad. It probably took me longer to type the command in the first place.

Depends. Someone at work went crazy over a one second startup time because it was a script that was run in response to a UI button that then acted on the output to open a new window for the output. Yes it shouldn't had been a script like that in any sane universe but when startup time became 2ms the perception went away

ExcessBLarg!
Sep 1, 2001

LeftistMuslimObama posted:

Yeah, I just basically didn't see why fork() is useful by itself,
In my book, fork has three main uses:

1. As a means of task parallelism, particularly I/O parallelism where a process spends lots of time in blocking syscalls. Its use here is mostly archaic with newer/better mechanisms like threads and asynchronous I/O, but was still a common approach through the 90s.

2. As a means of providing process supervision and/or sandboxing. Daemons sometimes run supervisor processes to catch crashes of child processes, or to facilitate privileged operations of sandboxed children. This use is starting to go (partially) away as more powerful init systems are becoming common (launchd, upstart, systemd, etc.). However it's still useful in sandboxing where it's faster to fork off a seed process than it is to create runtime environments from scratch (e.g., Android's zygote).

3. Combined with exec, to provide a simple two-step kernel abstraction to facilitate a crapload number of ways to "spawn" other programs.

LeftistMuslimObama posted:

but why fork()+exec() instead of just something like spawnProcess(<function pointer>,<parameters>)?
There was once a rule of thought that the kernel should provide simple abstractions to enable userspace to do everything that userspace needs to do. There's two reasons for this. First, kernel code is privileged (by definition), while userspace code is generally protected; so it's better to make the kernel code simpler where possible to mitigate the risk of introducing bugs. Granted, we're still largely using monolithic kernels, so this idea isn't taken too seriously. Second, the kernel-userspace (syscall) interface is considered to be very stable and having a long life, so as to remain compatible with decades old programs. Thus, the simpler the syscall interface is, the more likely it won't have to change to facilitate some new need.

Now, there's a lot of details involved in spawning a new program. Some of these, like where you locate the code, stack, and parameters, are defined as part of an ABI that the kernel and userspace agree on. However, other of these, like what files should be open, where should fds point to, what user and process group should the program run under, should any resource limits be set, what signals should be ignored, etc., are conventions of userspace and even change depending on what's spawning what. fork+exec allow all these things to be configured as part of spawning a child program without having to create a massive CreateProcess interface to specify all these things. Another alternative is to spawn children in a paused state, to allow the parent process to configure the children before launching them. My guess is that, that approach may have been considered, but the combination of fork+exec could handle that case without having to introduce a set of "change this behavior about this other process" syscalls.

ExcessBLarg! fucked around with this message at 04:55 on Feb 8, 2015

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
CreateProcess takes 10 arguments. Two of them are structs with three fields each. One is a bitmask with 16 possible values. One is a struct with 19 fields.

fork()+exec() is a 0-arg function and a a 1+ arg function that give you equivalent functionality.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Except for the giant list of pitfalls where the tradeoff isn't as great.

pseudorandom name
May 6, 2007

Preaching the virtues of the simplicity of fork()+exec() falls flat when basic things like race-free close-on-exec file descriptors were first introduced a couple years ago.

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer
I feel like I learn more from reading this thread than I do from my lecturers. Everything ExcessBLarg! pointed out makes perfect sense to me, but my university classes just don't seem to want to facilitate this sort of discussion at all. They're content to just tell us "X is the canonical way to program Y functionality, now here's a project where you reimplement this solved problem but doubtlessly with much worse code." I don't feel like I'm getting the actual nuts-and-bolts of the machine, just a snapshot of the machine itself. The lecture about fork never really branched (hah) out into any discussion of why it was designed that way, what sorts of considerations we might make when designing our own OS, or anything like that. He just explained what fork did and said it was elegant, and I was left thinking "Wait, did you just read me a manpage? This is supposed to be an OS design and programming class, not a "here's what Unix does" class."

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Suspicious Dish posted:

Except for the giant list of pitfalls where the tradeoff isn't as great.

There's certainly things to be said for CreateProcess. It just isn't as obviously simpler than the more roundabout fork+exec as many seem to expect it to be.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

LeftistMuslimObama posted:

This is supposed to be an OS design and programming class, not a "here's what Unix does" class."
As a general rule, OS classes fall into two categories: "Here's what unix does. No operating systems other than unix exist or will ever exist", and "gently caress unix; a good OS would do this thing (which would probably work terribly in practice) instead".

If you're "lucky" the first might also include some snide comments that acknowledge the existence of Windows, but it still won't mention any of the interesting things that NT does which aren't commonly seen in unixen.

pseudorandom name
May 6, 2007

Plorkyeran posted:

If you're "lucky" the first might also include some snide comments that acknowledge the existence of Windows, but it still won't mention any of the interesting things that NT does which aren't commonly seen in unixen.

For instance, CreateProcess() is implemented entirely in userspace built on kernel primitives like NtCreateRemoteThread() and NtMapViewOfSection().

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Plorkyeran posted:

There's certainly things to be said for CreateProcess. It just isn't as obviously simpler than the more roundabout fork+exec as many seem to expect it to be.

It's not simple, no, but it solves a lot of the race conditions and other ugliness of fork/exec. I prefer an ugly API that always gets things right over a seductively beautiful one with hard, fundamentally unsolvable and tricky issues.

sarehu
Apr 20, 2007

(call/cc call/cc)
They're not unsolvable, I've mentioned a solution to them twice already.

ExcessBLarg!
Sep 1, 2001

LeftistMuslimObama posted:

I don't feel like I'm getting the actual nuts-and-bolts of the machine, just a snapshot of the machine itself. The lecture about fork never really branched (hah) out into any discussion of why it was designed that way, what sorts of considerations we might make when designing our own OS, or anything like that.
Generally a graduate-level OS course would go more into the "why" on various topics and involve reading of the papers that originally described these things. In some ways undergraduate CS is all about bootstrapping--getting broad enough knowledge of the discipline to be conversant with just enough depth in various topics so that you can be successful in graduate school or your first job in the field. Unfortunately the quality of CS programs is all over the map and even at respected institutions, the quality of a specific class depends greatly on who is teaching it.

There's also a bias towards Unix in academia. It's a combination of its age, prevalence, academic roots (BSD was a graduate research project), availability of source code, and vendor neutrality. But it's true, it's not the only system out there, an comparing Unix to how VMS did or NT does things can be enlightening.

Zopotantor
Feb 24, 2013

...und ist er drin dann lassen wir ihn niemals wieder raus...

Spatial posted:

Someone's got a vfork() up their rear end in a top hat

:nms:http://i.imgur.com/JV5cpXs.jpg:nms:
(from the Schadenfreude thread.)

Xenoveritas
May 9, 2010
Dinosaur Gum
The amusing thing about this "do the right thing" discussion is that Unix is the classic example of the Worse is Better design philosophy, and fork() sounds like a great example. It's a simple API and a simple concept. Rather than doing the right thing, it goes for "simple" and simply doesn't worry about the problems it causes. The caller can deal with those on their own.

ToxicFrog
Apr 26, 2008


Dessert Rose posted:

I wouldn't say that one second startup times make anything "unusable" for command line utilities, really. Those benchmarks are much more damning for Android apps, where a 5 second startup time would make me want to launch my device out a window, but a couple of extra seconds to parse an XML file or whatever isn't so bad. It probably took me longer to type the command in the first place.

The machine those benchmarks were taken on was much faster than the server I'm usually running Clojure code on.

Yeah, it depends on the tool. If it's a package manager or something, disk and network IO from the actual package management is going to dominate. But it means I can't write short scripts in clojure, or sprinkle it into my bash scripts the way I would awk or lua, because it takes the runtime from a few milliseconds to multiple seconds.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

sarehu posted:

They're not unsolvable, I've mentioned a solution to them twice already.

You can't malloc in between fork and exec. By loving definition, that's pure insanity and a really stupid solution to a really common problem. One that people repeatedly get wrong. It's the definition of "pit of failure".

Zopotantor
Feb 24, 2013

...und ist er drin dann lassen wir ihn niemals wieder raus...

Xenoveritas posted:

The amusing thing about this "do the right thing" discussion is that Unix is the classic example of the Worse is Better design philosophy, and fork() sounds like a great example. It's a simple API and a simple concept. Rather than doing the right thing, it goes for "simple" and simply doesn't worry about the problems it causes. The caller can deal with those on their own.

fork() actually is older than Unix (it came from a system called GENIE).

ExcessBLarg!
Sep 1, 2001

Ender.uNF posted:

You can't malloc in between fork and exec.
You can in a single-threaded program.

So, fork gets a lot more challenging in multithreaded programs. fork+exec still works fine, although some care is needed in the event exec fails. Even in multithreaded programs the restrictions on child process code are the same as those on signal handlers. They're inconvenient, but it's still workable. My recommendation, since you already have threading as a means to achieve parallelism, is to avoid using fork after spawning secondary threads, except for fork+exec.

Part of the problem is that threading support is a total bolt-on in Unix systems. Linux didn't have decent POSIX threads support until Linux 2.6, (and as previously noted) things like the close-on-exec race issue persisted for some time after. Bashing in threading support also disrupted far more APIs and conventions than just fork.

nielsm
Jun 1, 2009



Isn't the conclusion just the obvious, either you use fork() for multiprocessing, or you use pthreads, but never both.
And if you do use fork() then you drat better avoid depending on any multithreaded libraries.

pseudorandom name
May 6, 2007

nielsm posted:

Isn't the conclusion just the obvious, either you use fork() for multiprocessing, or you use pthreads, but never both.
And if you do use fork() then you drat better avoid depending on any multithreaded libraries.

And your libraries better tell you whether or not they're multithreaded and the new versions better not suddenly become threaded.

EssOEss
Oct 23, 2006
128-bit approved
How do you execute another process without fork()? I mean, say your app needs to use some external tool to do a part of its job.

Athas
Aug 6, 2007

fuck that joker

pseudorandom name posted:

And your libraries better tell you whether or not they're multithreaded and the new versions better not suddenly become threaded.

This doesn't seem like an unacceptable requirement to me. Threads are a bit of a complicated thing (not just due to fork() issues), so I don't think they should be considered an implementation detail.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Athas posted:

This doesn't seem like an unacceptable requirement to me. Threads are a bit of a complicated thing (not just due to fork() issues), so I don't think they should be considered an implementation detail.

In sane languages, libraries are capable of using threads completely safely, as an implementation detail that users of the library don't actually have to worry about.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

It's not a language issue. No language on Unix can paper over the fork() damage, and C on other OSes can create processes like a grownup.

Vanadium
Jan 8, 2005

Sane languages don't expose fork(). :v:

ExcessBLarg!
Sep 1, 2001

nielsm posted:

Isn't the conclusion just the obvious, either you use fork() for multiprocessing, or you use pthreads, but never both.
Yes, that's the obvious conclusion except for the case of fork+exec if you have to run an external program from one of the threads. It's not that hard to do and boiler plate code has been posted a bunch of times throughout this discussion. Still, some folks think we should be using posix_spawn or something else instead, which is valid opinion.

pseudorandom name posted:

And your libraries better tell you whether or not they're multithreaded and the new versions better not suddenly become threaded.
So unless the library is a thread library, it shouldn't ever call pthread_create(3) or clone(2) behind my back. Any API call that does need to prominently state in its documentation that, that's the behavior. Ideally is should also be obvious by the function name alone that it's likely to spawn a thread.

You just don't, do that.

ExcessBLarg!
Sep 1, 2001

Jabor posted:

In sane languages, libraries are capable of using threads completely safely, as an implementation detail that users of the library don't actually have to worry about.
Yes, languages that have green threads, GILs, hide fork, and/or don't otherwise support signal handling or place limitations on signal delivery. Conversely, thread use by libraries in higher level languages may not always be safe either, even if there's a general assumption of safety by programmers.

Problems that come with threading and signals, like genuine concurrency and reentrancy, are systems problems and not an artifact of the language alone. C, which has very little of a runtime doesn't mask these at all and so "foists" the problems on the programmer. Managed languages tend to hide these to the benefit of the programmer, but which otherwise may have consequence in being able to write low level systems code.

ExcessBLarg! fucked around with this message at 18:25 on Feb 9, 2015

Adbot
ADBOT LOVES YOU

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Python exposes fork, heavily uses it (multiprocessing), also exposes threads, and can use threads behind your back, and also exposes libraries incompatible with fork (ctypes).

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply