Skip to content

Instantly share code, notes, and snippets.

@kassane
Created April 6, 2019 14:26
Show Gist options
  • Star 32 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save kassane/f2330ef44b070f4a5fa9d59c770f68e9 to your computer and use it in GitHub Desktop.
Save kassane/f2330ef44b070f4a5fa9d59c770f68e9 to your computer and use it in GitHub Desktop.
Explain Event Loop

Event Loop

In computer science, the event loop, message dispatcher, message loop, message pump, or run loop is a programming construct that waits for and dispatches events or messages in a program.

It works by making a request to some internal or external "event provider" (that generally blocks the request until an event has arrived), and then it calls the relevant event handler ("dispatches the event").

The event-loop may be used in conjunction with a reactor, if the event provider follows the file interface, which can be selected or 'polled' (the Unix system call, not actual polling).

The event loop almost always operates asynchronously with the message originator.

libevent

A software library that provides asynchronous event notification.

The libevent API provides a mechanism to execute a callback function when a specific event occurs on a file descriptor or after a timeout has been reached. libevent also supports callbacks triggered by signals and regular timeouts.

Programs using libevent:

  • Chromium – Google's open-source web browser (uses Libevent on Mac and Linux)
  • Memcached – a high-performance, distributed memory object caching system
  • Transmission – a fast, easy, and free BitTorrent client
  • NTP – the network time protocol that makes your clock right (uses Libevent in SNTP)
  • tmux – A clean, modern, BSD-licensed terminal multiplexer, similar to GNU screen
  • Tor – an anonymous Internet communication system.
  • libevhtp – A fast and flexible replacement for libevent's httpd API
  • Prosody – A Jabber/XMPP server written in Lua
  • PgBouncer – Lightweight connection pooler for PostgreSQL
  • redsocks – a simple transparent TCP -> Socks5/HTTPS proxy daemon.
  • Vomit – Voice Over Misconfigured Internet Telephones
  • Crawl – A Small and Efficient HTTP Crawler
  • Libio – an input/output abstraction library
  • Honeyd – a virtual honeynet daemon – can be used to fight Internet worms.
  • Fragroute – an IDS testing tool
  • Nylon – nested proxy server
  • Disconcert – a Distributed Computing Framework for Loosely-Coupled Workstations.
  • Trickle – a lightweight userspace bandwidth shaper.
  • watchcatd –software watchdog designed to take actions not as drastic as the usual solutions, which reset the machine.
  • ScanSSH – a fast SSH server and open proxy scanner.
  • Nttlscan – a network topology scanner for Honeyd.
  • NetChat – a combination of netcat and ppp's chat.
  • Io – a small programming language; uses libevent for network communication.
  • Systrace – a system call sandbox.
  • SpyBye – detect malware on web pages.
  • GreenSQL – an SQL database firewall.
  • dnsscan – a fast scanner for identifying open recursive dns resolvers
  • Kargo Event – a PHP extension for libevent.
  • Scytale – a database encryption tool.

http://libevent.org

libev

A full-featured and high-performance event loop that is loosely modelled after libevent, but without its limitations and bugs.

It supports eight event types:

  • I/O
  • real time timers
  • wall clock timers
  • signals
  • child status changes
  • idle
  • check
  • prepare handlers

It uses a priority queue to manage timers and uses arrays as fundamental data structure. It has no artificial limitations on the number of watchers waiting for the same event. It offers an emulation layer for libevent and optionally the same DNS, HTTP and buffer management (by reusing the corresponding libevent code through its emulation layer).

It is used in:

facebook/hhvm#2047

// a single header file is required
#include <ev.h>

#include <stdio.h> // for puts

// every watcher type has its own typedef'd struct
// with the name ev_TYPE
ev_io stdin_watcher;
ev_timer timeout_watcher;

// all watcher callbacks have a similar signature
// this callback is called when data is readable on stdin
static void
stdin_cb (EV_P_ ev_io *w, int revents)
{
  puts ("stdin ready");
  // for one-shot events, one must manually stop the watcher
  // with its corresponding stop function.
  ev_io_stop (EV_A_ w);

  // this causes all nested ev_run's to stop iterating
  ev_break (EV_A_ EVBREAK_ALL);
}

// another callback, this time for a time-out
static void
timeout_cb (EV_P_ ev_timer *w, int revents)
{
  puts ("timeout");
  // this causes the innermost ev_run to stop iterating
  ev_break (EV_A_ EVBREAK_ONE);
}

int
main (void)
{
  // use the default event loop unless you have special needs
  struct ev_loop *loop = EV_DEFAULT;

  // initialise an io watcher, then start it
  // this one will watch for stdin to become readable
  ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ 0, EV_READ);
  ev_io_start (loop, &stdin_watcher);

  // initialise a timer watcher, then start it
  // simple non-repeating 5.5 second timeout
  ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.);
  ev_timer_start (loop, &timeout_watcher);

  // now wait for events to arrive
  ev_run (loop, 0);

  // break was called, so exit
  return 0;
}

libuv

A multi-platform support library with a focus on asynchronous I/O.

It was primarily developed for use by Node.js, but it's also used by Mozilla's Rust language, Luvit, Julia, pyuv, and others.

Features:

  • Full-featured event loop backed by epoll, kqueue, IOCP, event ports.
  • Asynchronous TCP and UDP sockets
  • Asynchronous DNS resolution
  • Asynchronous file and file system operations
  • File system events
  • ANSI escape code controlled TTY
  • IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
  • Child processes
  • Thread pool
  • Signal handling
  • High resolution clock
  • Threading and synchronization primitives

libuv (https://github.com/joyent/libuv) is a lightweight library which allows asynchronous IO across OpenBSD, Linux, Darwin, Windows etc by utilizing the fastest implementation on each system (epoll, kqueue, IOCP, event ports). These specialized IO polling methods are much faster on their respective platforms than just using select() like the RTS currently does.

Additionally, it also provides cross platform threads, mutex, condition vars, terminal input/output and term settings w/ cross platform ANSI escape code handling, thread pools, cross platform HRC's etc. It's currently significantly faster than libevent and slightly faster than libev. Because it's maintained and utilized heavily by Node.js it's in extremely active and maintained development.

facebook/hhvm#2047

http://nikhilm.github.io/uvbook/

GLib Event Loop

The GLib event loop manages all the sources of an event available for GLib. These events can come from different kinds of sources like file descriptors (plain file descriptors, sockets, or pipes), time-outs, or any kind of source that can be added.

Example:

#include <glib.h>
gboolean timeout_callback(gpointer data)
{
    static int i = 0;

    i++;
    g_print("timeout_callback called %d times\n", i);
    if (10 == i)
    {
        g_main_loop_quit( (GMainLoop*)data );
        return FALSE;
    }

    return TRUE;
}

int main()
{
    GMainLoop *loop;

    loop = g_main_loop_new ( NULL , FALSE );

    // add source to default context
    g_timeout_add (100 , timeout_callback , loop);
    g_main_loop_run (loop);
    g_main_loop_unref(loop);

    return 0;
}

http://devlib.symbian.slions.net/s3/GUID-7FD05006-09C1-4EF4-A2EB-AD98C2FA8866.html

https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html

Qt Event Loop

Boost.Asio

Boost.Asio is a cross-platform C++ library for network and low-level I/O programming that provides developers with a consistent asynchronous model using a modern C++ approach.

http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio.html

http://www.slideshare.net/lukejfluo/phase1-45781850

libev vs libevent

As for design philosophy, libev was created to improve on some of the architectural decisions in libevent, for example, global variable usage made it hard to use libevent safely in multithreaded environments, watcher structures are big because they combine I/O, time and signal handlers in one, the extra components such as the http and dns servers suffered from bad implementation quality and resultant security issues, and timers were inexact and didn't cope well with time jumps.

Libev tried to improve each of these, by not using global variables but using a loop context for all functions, by using small watchers for each event type (an I/O watcher uses 56 bytes on x86_64 compared to 136 for libevent), allowing extra event types such as timers based on wallclock vs. monotonic time, inter-thread interruptions, prepare and check watchers to embed other event loops or to be embedded and so on.

The extra component problem is "solved" by not having them at all, so libev can be small and efficient, but you also need to look elsewhere for an http library, because libev simply doesn't have one (for example, there is a very related library called libeio that does asynchronous I/O, which can be used independently or together with libev, so you can mix and match).

So in short, libev tries to do one thing only (POSIX event library), and this in the most efficient way possible. Libevent tries to give you the full solution (event lib, non-blocking I/O library, http server, DNS client).

Or, even shorter, libev tries to follow the UNIX toolbox philosophy of doing one thing only, as good as possible.

http://stackoverflow.com/questions/9433864/whats-the-difference-between-libev-and-libevent/13999821

libuv vs Boost.Asio

                         libuv          Boost
Event Loop:              yes            Asio
Thread Pool:             yes            Asio + Threads
Threading:
  Threads:               yes            Threads
  Synchronization:       yes            Threads
File System Operations:
  Synchronous:           yes            FileSystem
  Asynchronous:          yes            Asio + Filesystem
Timers:                  yes            Asio
Scatter/Gather I/O:      no             Asio
Networking:
  ICMP:                  no             Asio
  DNS Resolution:        async-only     Asio
  SSL:                   no             Asio
  TCP:                   async-only     Asio
  UDP:                   async-only     Asio
Signal:
  Handling:              yes            Asio
  Sending:               yes            no
IPC:
  UNIX Domain Sockets:   yes            Asio
  Windows Named Pipe:    yes            Asio
Process Management:
  Detaching:             yes            Process
  I/O Pipe:              yes            Process
  Spawning:              yes            Process
System Queries:
  CPU:                   yes            no
  Network Interface:     yes            no
Serial Ports:            no             yes
TTY:                     yes            no
Shared Library Loading:  yes            Extension

More details: http://stackoverflow.com/questions/11423426/how-does-libuv-compare-to-boost-asio/13220533

Reference

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment