-Pierre > On Dec 17, 2015, at 1:35 PM, Pierre Habouzit <pie...@habouzit.net> wrote: > >> On Dec 17, 2015, at 12:40 PM, Tony Parker via swift-corelibs-dev >> <swift-corelibs-dev@swift.org> wrote: >> >> Hi Dzianis, >> >>> On Dec 17, 2015, at 12:36 PM, Dzianis Fedarenka via swift-corelibs-dev >>> <swift-corelibs-dev@swift.org> wrote: >>> >>>>> On Dec 10, 2015, at 12:42 AM, Joakim Hassila via swift-corelibs-dev >>>>> <swift-corelibs-dev at swift.org> wrote: >>>>> >>>>> Hi, >>>>> >>>>>> On 8 dec. 2015, at 16:56, Pierre Habouzit <pierre at habouzit.net> >>>>>> wrote: >>>>>> >>>>>> FWIW, this is my personal, let’s call it enlightened, opinion, based on >>>>>> my knowledge of dispatch and my past extensive system programming >>>>>> experience with Linux before I joined Apple. >>>>>> >>>>>> I think that long term, the best way to maintain a Linux libdispatch >>>>>> port is to go away from the libkqueue that tries to emulate kqueue >>>>>> fully, where dispatch only needs a small subset of the surface of >>>>>> kqueue. Given how source.c is written today, this is not a very small >>>>>> undertaking, but eventually dispatch source map to >>>>>> epoll_ctl(EPOLLONESHOT) very very well. >>>>> >>>>> That makes sense, could simplify the implementation (and keep thing >>>>> cleaner). Then the follow up question is of course how to split/manage >>>>> source.c (as Daniel pointed out there is the merging issue). >>>> we can decide when/if someone tries to tackle it. I humbly recognize that >>>> I have no great idea of how to do so. >>> >>> I have some experience in event multiplexing programming for linux. So it >>> looks like interesting project for me. There is some conceptual questions >>> which I think should be discussed: >>> >>> 1) Obviously, kqueue and epoll have a little different semantics. For >>> example: in linux timers, signals and socket can be presented as file >>> descriptor and processed uniformly. Is there any chance that community will >>> agree to develop separate API for linux? >> >> For what it’s worth, we went ahead and based CFRunLoop.c on Linux on top of >> epoll: >> >> https://github.com/apple/swift-corelibs-foundation/blob/master/CoreFoundation/RunLoop.subproj/CFRunLoop.c >> >> https://github.com/apple/swift-corelibs-foundation/commit/d594de1bdd7f10a558e30b92809420303ded0a6a#diff-9739b4f43fc59b19e677f9e3f835d159 >> >> I think it makes total sense for dispatch’s SPI for CF to simply return an >> eventfd. > > it’s exactly what we want for runloop tied queues. The mach port that is used > for this on Darwin receives messages only to break out of the mach_msg() > call, but the handler of the message is a void function: > _dispatch_wakeup_runloop_thread(). > > The good news is that a mach_port is an uint32_t and eventfd would be an int, > so as far as storage is concerned, everything is fine. > > I would have the _dispatch_get_main_queue_port_4CF / > _dispatch_runloop_root_queue_get_port_4CF return an eventfd, and adapt the > code that disposes of it. This is a IMO straightforward patch that should be > written e.g. that way: > > #if HAVE_MACH > // current OS X Code > #elif HAVE_EVENTFD > // linux port > #else > #error should not happen > #endif > > And also have: > > DISPATCH_COCOA_COMPAT be set to one on linux (until it is, you don’t get the > main queue and runloop tied queues). > > > The one murky thing is that someone has to *consume* what’s in that eventfd, > today, it’s implicit with mach because MiG will call dispatch’s > _dispatch_wakeup_runloop_thread() for it (corresponding to the > wakeup_runloop_thread routine in protocol.defs), but for linux, it’s probably > best if CF knows that it’s an eventfd and it has to eventfd_read() from it to > consume the event before it’s calling > _dispatch_runloop_root_queue_perform_4CF(). The alternative is for > _dispatch_runloop_root_queue_perform_4CF() to do that read in a non blocking > way, but for the cases when several things have been queued on the runloop > queue and have been coalesced in a single eventfd delivery, it’s a bit dumb > to pay a syscall per dequeue. > > On Mach the coalescing happens because the port has a queue width of 1 and > incoming messages are dropped when the port is full.
Actually alternatively this could be done (no error handling for clarity, but it should have some!): static bool _dispatch_runloop_queue_drain_one(dispatch_queue_t dq) { if (!dq->dq_items_tail) { #ifdef __linux__ eventfd_read((int)dq->do_ctxt, &(eventfd_t)0); if (!dq->dq_items_tail) { return false; } #else return false; #endif } ... } IOW: consume the eventfd when we think the queue is empty, and check again it really is, that way you even have the eventfd break you out of the epoll while the queue is full which is probably nice (even if CF is supposed to already track this anyway, but I don’t know CFRunloop well so Tony should tell which alternative is better between my former mail or that one). -Pierre _______________________________________________ swift-corelibs-dev mailing list swift-corelibs-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-corelibs-dev