LWN: Comments on "De Icaza: Callbacks as our Generations' Go To Statement" https://lwn.net/Articles/563613/ This is a special feed containing comments posted to the individual LWN article titled "De Icaza: Callbacks as our Generations' Go To Statement". en-us Tue, 30 Sep 2025 09:43:53 +0000 Tue, 30 Sep 2025 09:43:53 +0000 https://www.rssboard.org/rss-specification lwn@lwn.net De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564696/ https://lwn.net/Articles/564696/ smurf <div class="FormattedComment"> It would break semantics. select() returning doesn't mean "you can read or write". It means "reading or writing will not block" (the idea being that block devices and regular files don't, which is stupid but cannot be changed, among other reasons because it conflicts with the idea that you will never get a short read or write from these devices and files).<br> <p> Anyway, writing to a read-only file certainly will not block. It will instantly return an error.<br> </div> Sat, 24 Aug 2013 07:35:04 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564620/ https://lwn.net/Articles/564620/ etienne <div class="FormattedComment"> <font class="QuotedText">&gt; different select() behavior on block files</font><br> <p> Long time I did not try, but it would still be nice is select() did not return "writeable" for a file open read-only, "readable" for a write-only file, "writeable" when quota exceeded or filesystem full, and "readable" when the file position is at the end of the file and no other process has increased the size of that file...<br> </div> Fri, 23 Aug 2013 14:41:56 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564564/ https://lwn.net/Articles/564564/ smurf <div class="FormattedComment"> Yes it is standard behavior, yes every other Unix out there behaves in the same way, no you cannot have different select() behavior on block files without changing kernel semantics in an incompatible way, <br> </div> Fri, 23 Aug 2013 12:39:21 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564547/ https://lwn.net/Articles/564547/ simlo <div class="FormattedComment"> You are right: I checked the kernel code and found that the fops for ext3 at least doesn't have a poll method set. Then select returns immediately if the read bit is set.<br> <p> This really should be stated in the select() man page. I can't find anything else in the man pages either.<br> <p> Is this a standeard behaviour? How does other Unices behave? Is this something which could be fixed in Linux without breaking a lot of programs? For network filesystems the behaviour ought to be like for sockets, such a stalling network filesystem can't make your program stall.<br> <p> Fortunately for use, we only use file sockets in our test setup. In the production code all file access goes through a TCP socket to another process. A stalling filesystem can therefore not block our time critical code.<br> </div> Fri, 23 Aug 2013 08:34:03 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564535/ https://lwn.net/Articles/564535/ pbonzini <div class="FormattedComment"> sigjmp() is simply setjmp(). :)<br> <p> sigaltstack() is used with the coroutine's stack as the argument. Then a kill() or pthread_kill() is used to trick the kernel into performing the work of makecontext(). Once you do that, you can setjmp()+longjmp() back into the creator coroutine, and from that point all transfers of control are done simply with setjmp()+longjmp(). I think this originates in the GNU Pth library.<br> <p> You can find code in QEMU's coroutine-* source files. It includes makecontext/swapcontext, sigaltstack, win32 fibers, and a debugging version that uses threads. Note that the thread version has different signal behavior if a coroutine is used to "jump" from a thread to another, which is why I called it only good for debugging. With the thread version, the coroutine will keep the sigmask of the thread that created it. For all other versions, the sigmask is that of the thread that runs the coroutine.<br> </div> Fri, 23 Aug 2013 05:29:24 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564515/ https://lwn.net/Articles/564515/ nybble41 <div class="FormattedComment"> <font class="QuotedText">&gt; What is sigjmp by the way()?</font><br> <p> I don't think there is a sigjmp(). sigsetjmp() and siglongjmp() are POSIX functions which work like setjmp() and longjmp(), except that they save and restore the signal masks along with the rest of the environment.<br> <p> <font class="QuotedText">&gt; I know of sigaltstack() ... I cannot immediately see how it will help with coroutines</font><br> <p> I believe the idea is to give the signal handler an independent stack so that the two coroutines don't interfere with each other. Otherwise they would overwrite each other's stack space. You can't use longjmp() or siglongjmp() to return to a context which is deeper in the stack. Under more normal circumstances, that could only mean one which has already returned; here, in the absence of sigaltstack(), it would mean the signal hander. Using separate stacks avoids that problem, allowing you to safely switch back and forth.<br> </div> Fri, 23 Aug 2013 01:34:40 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564484/ https://lwn.net/Articles/564484/ chrisV <div class="FormattedComment"> Do you have an implementation you can point to?<br> <p> What is sigjmp by the way()? (I know of sigaltstack(): it is in POSIX though not in C, although I cannot immediately see how it will help with coroutines. sigjmp() I have never heard of.)<br> </div> Thu, 22 Aug 2013 20:14:06 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564483/ https://lwn.net/Articles/564483/ pbonzini <div class="FormattedComment"> I wrote that: sigaltstack() + kill() can be a replacement for makecontext(), and sigjmp() + longjmp() can be a replacement for swapcontext().<br> <p> However, it's not as easy as makecontext() + swapcontext().<br> </div> Thu, 22 Aug 2013 20:03:11 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564478/ https://lwn.net/Articles/564478/ chrisV <div class="FormattedComment"> I think your problem is that you have completely missed the point. The poster said those functions for implementing coroutines are available in C. They are not; nor are they now available in POSIX. So if you cannot "write a sane program with just POSIX in your environment anyway" what do you use to implement coroutines?<br> <p> </div> Thu, 22 Aug 2013 19:36:44 +0000 Callbacks are not that bad https://lwn.net/Articles/564465/ https://lwn.net/Articles/564465/ Cyberax <div class="FormattedComment"> Well, I worked with a complicated and large (about 3M lines) telecom app back in 2002 (I think) that was completely coroutine-based. It worked quite well.<br> <p> As for stacks, if we assume that we have a server with a coroutine-for-connection model then 8k connections is already a load big enough that it makes 64Mb of overhead insignificant. <br> <p> Segmented stacks would actually help a lot and reconciling them with makecontext() shouldn't be that complicated.<br> </div> Thu, 22 Aug 2013 18:29:57 +0000 Callbacks are not that bad https://lwn.net/Articles/564455/ https://lwn.net/Articles/564455/ wahern <div class="FormattedComment"> I mean, I never said it was complicated, and by "ugly and problematic" I was referring to issues with POSIX threads and similar issues where switching stacks can cause problems.<br> <p> Also, setcontext is not all that lightweight. It has to query the signal mask, and it has to save all the registers, including floating point registers. Actual POSIX threads are so highly optimized these days that the context switching costs between a ucontext_t thread and a real POSIX thread are about the same. So if all you're doing with makecontext, etc is rolling a threading implementation, you're not actually buying much. Just classic premature optimization.<br> <p> It may make sense if you're using ucontexts as classic coroutines to invert consumer/producer patterns, but C doesn't have closures or multiple return values, so that becomes very tedious. At the end of the day state machines using computed gotos can be simply easier to work with and much more straight-forward. (Yes, you can also use tricks with the switch statement, but straight-up computed gotos--without using the indexing trick GCC recommends to speed up linking--is so much more convenient and pleasant.)<br> <p> <p> <p> </div> Thu, 22 Aug 2013 18:21:37 +0000 Callbacks are not that bad https://lwn.net/Articles/564449/ https://lwn.net/Articles/564449/ wahern <div class="FormattedComment"> I never said it was complicated. I said it doesn't play well with POSIX threading in some environments. This used to be the case on Linux with the old LinuxThreads implementation, for example. And I believe it's still the case on NetBSD. So, you can't use them, _and_ POSIX threads, _and_ be portable.<br> <p> Also, unless your stacks are small it's a waste of memory. In Lua a coroutine is 100 bytes, and I can use as many of them as I want to simplify an interface. In C, your stack needs to be largish--e.g. 8K or more--depending on what libraries you use and what assumptions they make about stack size. On Linux PATH_MAX is 4K, and lots of software uses PATH_MAX to size automatic char arrays.<br> <p> Say I have 8K stacks at 8K each, that's 64MB of mostly wasted space. Also, in the future Linux may move to segmented stacks. Segmented stacks may not play nice with makecontext interfaces.<br> <p> Yes, we've all played around with makecontext and friends. It's an interesting interface. But it's a hack, pure and simple, and not something you should be building any largish project around unless you don't care about hitting a brick wall down the road.<br> <p> <p> </div> Thu, 22 Aug 2013 18:07:47 +0000 Sounds like boost::async https://lwn.net/Articles/564430/ https://lwn.net/Articles/564430/ tvld <div class="FormattedComment"> <font class="QuotedText">&gt; The idea received very favorable feedback at the committee meeting I was at.</font><br> <p> That was definitely _not_ my impression at the ISO C++ meetings I attended. What I observed was most people not commenting, some liked it, and some disliked it.<br> <p> While await (i.e., "resumable" functions) makes concurrency _look_ less complex, it's still concurrent execution even if it may look like a sequential program.<br> <p> If you look at the proposal closely, there are several open issues or unanswered questions (e.g., which properties do the execution agents have precisely? how much of a light-weight thread are they?). Second, there's no detailed discussion of why this should come in exactly this form, including having to annotate functions; there are high-level remarks about C# etc. having it, and that some of the design's properties are necessary because of certain unnamed implementation concerns, but there's no discussion at all about the implementation trade-offs.<br> <p> I'm mentioning the implementation aspect because besides making concurrency look less scary, this is clearly driven by performance concerns: There can be blocking which they want to avoid (thus, add concurrency), yet they don't want to pay the price of full OS threads (e.g., ordinary stacks, thread-local storage). Thus, await gives you lighter-weight execution agents (again, they don't specify the details, but that's how I understood the answers of the proposal's authors).<br> <p> So, overall I think it's necessary to think about to which extent standardized light-weight execution agents would be sufficient. (Note that there might be implemented similar to green threads, but unlike traditional green threads or M:N threading those execution agents don't have to pretend that the green thread is a true OS thread, so they have to do significantly less). If they are sufficient, then one probably doesn't need to burden programmers with littering their code with function annotations and await keywords, nor require them to specify all the points where cooperative scheduling can take place.<br> </div> Thu, 22 Aug 2013 16:36:37 +0000 Callbacks are not that bad https://lwn.net/Articles/564370/ https://lwn.net/Articles/564370/ Cyberax <div class="FormattedComment"> Juggling stacks in C/C++ is not that complicated. You do need platform-specific functions to do it (fibers on Windows, makecontext on Linux, etc) but once you do it then you immediately get stackfull coroutines.<br> </div> Thu, 22 Aug 2013 13:41:01 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564339/ https://lwn.net/Articles/564339/ vasvir <div class="FormattedComment"> You point very valid problems.<br> <p> For the button reclick I would say you are 100% right. You can't have the event listener in another thread entirely. So it has to run in the gui_thread but it can spawn threads from there. Now since it is running in the gui_thread you can disable the button before you spawn the thread or leave it alone be if you want multiple actions running the same time.<br> <p> I agree with the rest. Having the toolkit single threaded - event based as it is and pass messages/events from the threads is the essence of the proposal. And yes of course it is difficult to communicate back staff to the waiting threads. This is probably why it hasn't been done yet.<br> </div> Thu, 22 Aug 2013 09:56:43 +0000 Callbacks are not that bad https://lwn.net/Articles/564320/ https://lwn.net/Articles/564320/ wahern <div class="FormattedComment"> I don't understand why people are touting futures at all. Futures are just a synchronization mechanism. Futures are much too low-level.<br> <p> The answer to the problem is coroutines, which allows one to flip the producer/consumer relationship between two blocks of code, and to do so in both directions. Coroutines allow you to replace a callback with a return value, while still allowing both blocks of code to push parameters using a function invocation and retrieve results with a return value, which is the most natural form.<br> <p> In languages like Lua where coroutines are implemented as separate virtual stacks, allowing yielding across intermediate function invocations, coroutines can be used to hack together a kind of cooperative threading. And so when people hear coroutines they immediately jump to the idea of threading. But that entirely misses the fundamental benefit of coroutines, which is the ability to invert consumer/producer in an ad hoc manner at the language level, without resorting to message passing.<br> <p> Coroutines are the final answer, and it's why my favorite language is Lua. Not only does it have flawless coroutine support, it doesn't use any tricks with the C stack, which otherwise can cause headaches when writing libraries or integrating into large applications, especially with POSIX threads.<br> <p> There's no easy answer for C or C++ code. Juggling C stacks is ugly and problematic. The simplest and most straight-forward solution in C is to use GCC's computed gotos, which makes it easy to implement generators. It's _extremely_ useful, and that's why it was one of the earliest extensions. I used computed gotos all over the place in my non-blocking libraries, because I despise callbacks. Not just to restart an I/O operation, but to implement streaming-type behavior for routines which transform data in smallish chunks.<br> <p> </div> Thu, 22 Aug 2013 06:26:43 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564301/ https://lwn.net/Articles/564301/ smurf <div class="FormattedComment"> <font class="QuotedText">&gt; Those are not in the C standard.</font><br> <p> So are a whole lot of other useful functions. You're not going to be able to write a sane program with just POSIX in your environment anyway.<br> <p> So what's your problem?<br> </div> Wed, 21 Aug 2013 23:13:12 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564291/ https://lwn.net/Articles/564291/ chrisV <div class="FormattedComment"> <font class="QuotedText">&gt; You can do it relatively easily in C with makecontext() + swapcontext()</font><br> <p> Those are not in the C standard.<br> <p> They are not even in the POSIX standard anymore. They were removed in POSIX.1-2008.<br> <p> Which takes you back to setjmp/longjmp.<br> </div> Wed, 21 Aug 2013 21:15:48 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564282/ https://lwn.net/Articles/564282/ magnus <div class="FormattedComment"> How do you handle if the button is clicked a second time while the "// processing" is going on? <br> <p> Also the GUI could change state because of other callbacks being called during the processing, so maybe the window has already been closed when menu-&gt;disable is called, or it doesn't make sense to disable it any more because the conditions have changed. You get lots of possible cases to consider. <br> <p> You also haven't covered that for a more complex case you might want to read out state from the GUI, contents of text boxes and such. Do you need to make a roundtrip to the GUI thread to send a request and get a response back for each such thing? What could happen if you're holding a lock while you're making such a roundtrip?<br> <p> The point I'm trying to make is that if you view the GUI as a finite state machine, making all callbacks asynchronous greatly increases the number of states visible from the outside that it can be in... So you want the "state switching" logic (disabling/enabling widgets etc) to be in the GUI thread so it all happens "at once". <br> </div> Wed, 21 Aug 2013 19:16:52 +0000 i.e. coroutines https://lwn.net/Articles/564213/ https://lwn.net/Articles/564213/ pbonzini <div class="FormattedComment"> Reinvented continuation-passing style, actually.<br> </div> Wed, 21 Aug 2013 14:09:22 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564209/ https://lwn.net/Articles/564209/ pbonzini <div class="FormattedComment"> You can do it relatively easily in C with makecontext() + swapcontext(), more precisely. sigaltstack() + kill() can be a replacement for makecontext(), and sigjmp() + longjmp() can be a replacement for swapcontext().<br> <p> QEMU does exactly this to implement coroutines.<br> </div> Wed, 21 Aug 2013 14:07:28 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564185/ https://lwn.net/Articles/564185/ alankila <div class="FormattedComment"> The general problem here is that thr.join() is not generally permissible. You aren't allowed to wait for results of another thread in the first thread, which is usually dedicated for UI event processing. You can only join if you know it has quit already, because then you know that the join() will return without a delay.<br> <p> I've had to solve these kind of problems and I typically startup a thread pool with number of threads equal to CPU cores of system, and then start pushing work items into them. If multiple work items are dependent on each other before a further work item can be scheduled, then the work items have a counter which decrements by 1 every time the item is done and when that counter reaches 0, then another work item is pushed into the thread queue. There's also typically a way to schedule work items to be run in the UI event loop, so the work can continue in context of that thread later on.<br> <p> The problem here is that it's all kinda confusing-looking. Hence the motivation for something like async/await. It does look pretty nifty but I haven't really studied it in detail so far.<br> </div> Wed, 21 Aug 2013 11:13:09 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564182/ https://lwn.net/Articles/564182/ vasvir Here is simplified pseudocode. All disclaimers you have ever heard apply: <pre> main program: ... button-&gt;registerEventHandler(event_type, handler, boolean on_new_thread); ... The handler: if handler(...) // if (on_new_thread then runs on separate thread) { // handler doesn't know if is on gui_thread or not. We don't care // processing... // now it's time to update the GUI. // Oups. Normally we can't do that or we should be very careful // but now we are on our idealized world so let's go and do it. menu-&gt;disable(some args); } // Now on Menu widget. We have to check if we are on the gui thread or not Menu::disable(args) { if (!isGUIThread()) { // special magic - We have to reschedule the operation on the GUI Thread postEvent(GUIOperationEvent, this /*(menu)*/, Operation.Disable, args); // the post event will force the menu-&gt;disable to be handled from the GUI thread return; } // normal GUI code. We are on the gui thread. ...implementation... } </pre> This is a naive implementation. The problems are: <ul> <li>It uses the event subsystem for message passing and for rescheduling tasks on the GUI thread. I don't know if this is a good idea or a specialized message queue should be used for this. On the other hand the event queue is global and it is there on every toolkit :-).</li> <li>disable() doesn't return anything to the issuing thread so our world is ideal. If disable() needs to return something it has to do it via a channel or a future or something complicated to the waiting worker thread. This should collapse to a normal call in the case of on_new_thread == false. </li> </ul> <p> The major problem with this approach is that you need to have two ways to call the same methods with the same arguments for all GUI operations that are not thread safe. This needs some instrumentation. I don't know if it is possible to create a generic mechanism and not having to synchronize between sync and async implementation. Maybe with template wizardry you can do it. <p> On the bright size the client code can call GUI operations from any thread (or from the gui thread) and wait them to finish without complicated logic or plumbing and that's the gain. Wed, 21 Aug 2013 10:19:25 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564172/ https://lwn.net/Articles/564172/ magnus <blockquote> I don't understand why you think that. Looks doable to me. I think I am semi convinced by the design. Of course it is completely possible that we are talking about different things... </blockquote> It's doable all right, question is how much you gain from just blindly moving all callback processing into threads. I still think you need to distinguish explicitly between "instant" callback processing and long-running activity and build the kind of application-specific "plumbing" you're talking about between the two. <p> If you move all callback processing to a single separate thread, you haven't actually solved anything wrt blocking. If that thread blocks then the GUI will become unresponsive. It's unresponsive in a slightly nicer way than in the single-threaded blocking case since the toolkit's internal event handling is running so you can still click on buttons etc but nothing intelligent happens when you do. So for blocking operations you'll need to launch additional helper threads just as you could have done in the single-threaded case. <p> The alternative is to use multiple threads that listen to different sets of events but then you will probably run into complicated races and dependency problems when they start touching the same widgets. This could possibly be useful at a one thread per window level but below that is probably not very useful. Wed, 21 Aug 2013 05:55:05 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564143/ https://lwn.net/Articles/564143/ simlo <div class="FormattedComment"> From this comment as well as the main article the main problem of callbacks seems to be error handling using exceptions.<br> <p> An error is an event. I.e. in the event based, callback driven programming exceptions have to handled in specific callbacks. Say for instance a connect to a TCP port fails with "connection refused." If connect() is blocking throw an exception. But with non-blocking connect() you will get the result of the connect() operation later maybe in the same callback handling a successfull connect(). So you are forced have to have error handling right there and decide what to do. You can't wrap the whole long sequence into one big try catch and handle it all in one big error handler.<br> <p> To me it sounds like event-callback driven coding actually forces the coder to handle all failures intelligently. Maybe a showMessage("Connection failed: &lt;reason&gt;") or simply try the connect() again, or whatever is a proper failure mode.<br> <p> This only strengthens by faith in single threaded, event-callback driven programs not using exceptions. And yes, as mentioned in comments above proper GUI toolkits also supports that, so it is not only for server-programming. <br> At me this works very well for embedded programs written in C++. I compare with Java with a lot of threads. The C++ programs are much more stable and have far fewer flaws with error handling in for instance handling of TCP connections.<br> </div> Tue, 20 Aug 2013 22:19:40 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564145/ https://lwn.net/Articles/564145/ andresfreund <div class="FormattedComment"> Only in the sense that select() et al. will always return plain fd's for normal files as ready for read/write. Independent of the fact that read()/write() will block while waiting for disk io.<br> </div> Tue, 20 Aug 2013 22:16:04 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564140/ https://lwn.net/Articles/564140/ simlo <div class="FormattedComment"> I use the same code for TCP sockets and file descriptors for non-blocking read/write using select(). It works the same.<br> </div> Tue, 20 Aug 2013 21:52:03 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564116/ https://lwn.net/Articles/564116/ vasvir Actually I read (in FF mode) the PhD of the Elmar Ludwig (one of the links I posted). I don't know about BeOS so I can't comment. I tried also to read the exene paper but it was over my head. <p> It looks what we are discussing here is what he (Ludwig) is proposing. One global queue in order to keep the toolkit event based single threaded and some channels/futures so the worker threads can take input (wait) from the GUI. <p> <em> So whatever method you use, you have some parts of the application UI logic that should be synchronous to the GUI (GUI is blocked and code must be non-blocking) and some that are asynchronous (GUI is not blocked and code may block). Neither lightweight threads or using event queues for everything will solve that problem by itself... </em> <p> I don't understand why you think that. Looks doable to me. I think I am semi convinced by the design. Of course it is completely possible that we are talking about different things... Tue, 20 Aug 2013 21:47:04 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564121/ https://lwn.net/Articles/564121/ smurf <div class="FormattedComment"> open() is also used for character devices. Or FIFOs. Or (Unix-domain) sockets.<br> <p> Not all flags make sense on all file types. Or devices, for that matter. So what?<br> </div> Tue, 20 Aug 2013 20:37:19 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564103/ https://lwn.net/Articles/564103/ magnus <blockquote> I would extending the queue idea by saying that all callbacks/slots from GUI should run in different threads like you are saying. All GUI updates operations should go through the global queue. </blockquote> Hmm I did some more thinking on this. :) <p> While you don't want processing unrelated to the GUI to block the GUI thread, at the same time you DO want the GUI to be blocked while you modify the UI state because that simplifies the processing and avoids a lot of races. The toolkit can guarantee for example if you close a window inside a callback that you can not get more events to that window that were enqueued between the callback was called and the delete call. <p> So whatever method you use, you have some parts of the application UI logic that should be synchronous to the GUI (GUI is blocked and code must be non-blocking) and some that are asynchronous (GUI is not blocked and code may block). Neither lightweight threads or using event queues for everything will solve that problem by itself... Tue, 20 Aug 2013 19:26:54 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564041/ https://lwn.net/Articles/564041/ etienne <div class="FormattedComment"> <font class="QuotedText">&gt; So why does the O_NONBLOCK flag exist at all?</font><br> <p> Because a regular file is already mapped in memory, a read/write operation can only delay by a page fault and that is not considered blocking - any "jump" assembly instruction can produce a page fault...<br> The problem is that treating a page fault from an NFS/FUSE file may be long.<br> <p> On the more general subject, I wonder if this whole need for new keyword / languages is not due to a bad multi-thread design, due to the "big loop" of window 3.1, due to the inefficient fork() of windows, due to the lack of "overcommited" memory and copy-on-write... but I may be wrong.<br> </div> Tue, 20 Aug 2013 15:28:45 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564038/ https://lwn.net/Articles/564038/ HelloWorld <div class="FormattedComment"> So why does the O_NONBLOCK flag exist at all? It is, after all, a flag originally intended for use with open(2), which is primarily used for opening regular files. <br> </div> Tue, 20 Aug 2013 15:00:38 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564010/ https://lwn.net/Articles/564010/ sorpigal <cite>With a global queue a thread can block waiting from GUI thread input but The GUI thread never blocks - is always running The toolkit remains single - threaded effectively avoiding all the locking problems described at https://weblogs.java.net/blog/kgh/archive/2004/10/multithreaded_t.html</cite> <p>Isn't this essentially how BeOS has always worked? </p> Tue, 20 Aug 2013 12:22:04 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564004/ https://lwn.net/Articles/564004/ smurf <div class="FormattedComment"> No. Regular files (and block devices) do not work that way.<br> </div> Tue, 20 Aug 2013 08:59:00 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564003/ https://lwn.net/Articles/564003/ HelloWorld <div class="FormattedComment"> <font class="QuotedText">&gt; Yeah, right. You're invited to test that idea on any NFS- or SMB-stored file. :-/</font><br> Doesn't it work to make the descriptor non-blocking, i. e. fcntl(fd, F_SETFL, O_NONBLOCK)?<br> </div> Tue, 20 Aug 2013 08:08:32 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/564000/ https://lwn.net/Articles/564000/ smurf <div class="FormattedComment"> Actually, the kernel does have async IO.<br> <p> However, you get completion via a signal, which you have to poll() on with signalfd (and then lookup the context and callback for whatever you intended to do with the data), which is significantly more work than to delegate the whole rigmarole to a thread in the first place.<br> <p> Worse, most libraries don't allow you to feed data in piecemeal, so AIO won't help anyway.<br> </div> Tue, 20 Aug 2013 06:28:16 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/563999/ https://lwn.net/Articles/563999/ magnus <div class="FormattedComment"> Yes, these issues would need to be fixed in Unix to make cooperative scheduling work flawlessly. Which is never going to happen of course. So we will need to paper it over using helper threads and other means. <br> <p> So I agree with your bottom line, I'm just saying that it would be neat if cooperative scheduling in user space could be made to work. <br> <p> </div> Tue, 20 Aug 2013 05:15:58 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/563998/ https://lwn.net/Articles/563998/ Trelane <div class="FormattedComment"> perhaps I'm completely misunderstanding, but this sounds like Android'sTask stuff.<br> </div> Tue, 20 Aug 2013 01:52:47 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/563997/ https://lwn.net/Articles/563997/ foom <div class="FormattedComment"> select/poll actually don't work at all on plain files. Unfortunately, the API design is that when a fd doesn't support poll, that is indicated by claiming that it's ready for POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM.<br> <p> epoll has a different API, and actually returns a failure if the fd doesn't support polling.<br> <p> It's not clear which one is actually better. They both have their pitfalls.<br> <p> </div> Tue, 20 Aug 2013 01:34:04 +0000 De Icaza: Callbacks as our Generations' Go To Statement https://lwn.net/Articles/563991/ https://lwn.net/Articles/563991/ smurf <div class="FormattedComment"> The problem with "blocking" is that it's ill-defined. Unix semantics, for instance, states that if select/poll returns, then a non-blocking read() on the file descriptor in question will, well, not block. I.e., retutn "immediately".<br> <p> Yeah, right. You're invited to test that idea on any NFS- or SMB-stored file. :-/<br> <p> The bottom line is: Most of the time, a cooperatively-scheduled event loop is perfectly fine. But there are applications which definitely won't work without OS threads.<br> </div> Mon, 19 Aug 2013 22:53:08 +0000