# Event loop

> Mediated Wiki article. Canonical URL: https://mediated.wiki/source/Event_loop
> Markdown URL: https://mediated.wiki/source/Event_loop.md
> Source: https://en.wikipedia.org/wiki/Event_loop
> Source revision: 1356752396
> License: Creative Commons Attribution-ShareAlike 4.0 International (https://creativecommons.org/licenses/by-sa/4.0/)

Software loop that processes events

In [software](/source/Software), an **event loop** is an [algorithm](/source/Algorithm) that continually dispatches [control flow](/source/Control_flow) for [events](/source/Event_(computing)). The loop requests the next event from an event provider (which generally [blocks](/source/Blocking_(computing)) the loop until an event occurs), and when an event is received, invokes its associated [event handler](/source/Event_handler). When the event loop is the central event dispatcher of a [program](/source/Computer_program), as it often is, it is called the **main loop** or **main event loop**.

In modern environments such as web browsers and server runtimes, the event loop is a fundamental mechanism that enables asynchronous execution by continuously monitoring and dispatching events or messages from a queue when the main program thread is idle. In JavaScript, the event loop allows non-blocking handling of tasks such as user interactions, timers, and I/O operations despite the language being single-threaded.[1]

The same algorithm can be used to process inbound [messages](/source/Message_(computing)), a superset of events. In this context, the algorithm is called a **message loop**, **message dispatcher**, or **message pump**. A common use for a message loop is [message passing](/source/Message_passing) [inter-process communication](/source/Inter-process_communication) where the [message queue](/source/Message_queue) is maintained outside of the program (such as by the [operating system](/source/Operating_system)).

Typically, a program that operates in a [graphical user interface](/source/Graphical_user_interface) (GUI) environment uses an event loop, and due to the predominance of GUI environments, most modern applications have a main event loop.

In the following pseudocode, get_next_message() is a placeholder for a function that is typically provided by the operating system that blocks until a message is available. Thus, the loop only repeats when there is a message to process.

**loop**
    message := get_next_message()
    process_message(message)
**while** message != quit

## Alternatives

Many programs include an event loop in the high-level design; a main event loop, but there are alternative designs.

A program can exit as soon as it completes the actions that it's designed to do without external (i.e. [user](/source/Computer_user)) interaction. Often, such a program has optional behavior that is set up before the program starts such as via the [command-line interface](/source/Command-line_interface) (CLI) or [environment variables](/source/Environment_variable). [Utility software](/source/Utility_software) is often of this nature.

Even if a program provides for user interaction, it might not use an event loop. A program that provides an internal CLI does include a [command processor](/source/Command_processor) that is similar to an event loop in that it dispatches to command handlers based on user input.

## Examples

### HTML/JavaScript

A web page and its JavaScript typically run in a single-[threaded](/source/Thread_(computing)) [web browser](/source/Web_browser) process. The browser process deals with [messages](/source/Message_(computer_science)) from a [queue](/source/Queue_(abstract_data_type)) one at a time. A JavaScript [function](/source/Subroutine) or another browser event might be associated with a given message. When the browser process has finished with a message, it proceeds to the next message in the queue.

In JavaScript environments, the event loop works with separate queues — including a task queue and a microtask queue — to manage asynchronous operations such as timers, promise callbacks, and DOM events. When the call stack is empty, the event loop selects the next task from these queues to execute.[2]

### Windows applications

In [Windows](/source/Windows), a process that interacts with the user must accept and react to incoming messages, which is almost inevitably done by a [message loop](/source/Message_loop_in_Microsoft_Windows) in that process. In Windows, a message is equated to an event created and imposed upon the operating system. An event can be user interaction, network traffic, system processing, timer activity, inter-process communication, among others. For non-interactive, I/O only events, Windows has [I/O completion ports](/source/Input%2Foutput_completion_port). I/O completion port loops run separately from the Message loop, and do not interact with the Message loop out of the box.

The heart of most [Win32](/source/Win32) [applications](/source/Application_software) is the [WinMain()](https://msdn.microsoft.com/en-us/library/ms633559.aspx) function, which calls [GetMessage()](https://msdn.microsoft.com/en-us/library/ms644936.aspx) in a loop. GetMessage() blocks until a message (event), is received (with function [PeekMessage()](https://msdn.microsoft.com/en-us/library/ms644943.aspx) as a non-blocking alternative). After some optional processing, it will call [DispatchMessage()](https://msdn.microsoft.com/en-us/library/ms644934.aspx), which dispatches the message to the relevant handler, also known as [WindowProc](/source/WindowProc). Normally, messages that have no special [WindowProc()](https://msdn.microsoft.com/en-us/library/ms633573.aspx) are dispatched to [DefWindowProc](/source/WindowProc#Default_processing), the default one. DispatchMessage() calls the WindowProc of the [HWND](/source/Handle_(computing)) [handle](/source/Smart_pointer) of the message (registered with the [RegisterClass()](https://msdn.microsoft.com/en-us/library/ms633586.aspx) function).

More recent versions of Windows guarantee that messages will be delivered to an application's message loop in the order that they were perceived by the system and its peripherals. This guarantee is essential when considering the design consequences of [multithreaded](/source/Thread_(computing)) applications. However, some messages have different rules, such as messages that are always received last, or messages with a different documented priority.[3]

### Xlib event loop

[X](/source/X_Window_System) applications using [Xlib](/source/Xlib) directly are built around the XNextEvent family of functions; XNextEvent blocks until an event appears on the event queue, whereupon the application processes it appropriately. The Xlib event loop only handles window system events; applications that need to be able to wait on other files and devices could construct their own event loop from primitives such as ConnectionNumber, but in practice tend to use [multithreading](/source/Thread_(computing)).

Very few programs use Xlib directly. In the more common case, GUI toolkits based on Xlib usually support adding events. For example, toolkits based on [Xt Intrinsics](/source/X_Toolkit_Intrinsics) have XtAppAddInput() and XtAppAddTimeout().

It is not safe to call Xlib functions from a signal handler, because the X application may have been interrupted in an arbitrary state, e.g. within XNextEvent. See [\[1\]](http://www.ist.co.uk/motif/books/vol6A/ch-26.fm.html) for a solution for X11R5, X11R6 and Xt.

### GLib event loop

The [GLib](/source/GLib) event loop was originally created for use in [GTK](/source/GTK) but is now used in non-GUI applications as well, such as [D-Bus](/source/D-Bus). The resource polled is the collection of [file descriptors](/source/File_descriptor) the application is interested in; the polling block will be interrupted if a [signal](/source/Signal_(IPC)) arrives or a [timeout](/source/Timeout_(computing)) expires (e.g. if the application has specified a timeout or idle task). While GLib has built-in support for file descriptor and child termination events, it is possible to add an event source for any event that can be handled in a prepare-check-dispatch model.[\[2\]](http://developer.gnome.org/glib/2.30/glib-The-Main-Event-Loop.html#mainloop-states)

Application libraries that are built on the GLib event loop include [GStreamer](/source/GStreamer) and the [asynchronous I/O](/source/Asynchronous_I%2FO) methods of [GnomeVFS](/source/GnomeVFS), but [GTK](/source/GTK) remains the most visible client library. Events from the [windowing system](/source/Windowing_system) (in [X](/source/X_Window_System), read off the X [socket](/source/Unix_domain_socket)) are translated by [GDK](/source/GDK) into GTK events and emitted as GLib signals on the application's widget objects.

### macOS Core Foundation run loops

Exactly one CFRunLoop is allowed per thread, and arbitrarily many sources and observers can be attached. Sources then communicate with observers through the run loop, with it organising queueing and dispatch of messages.

The CFRunLoop is abstracted in [Cocoa](/source/Cocoa_(API)) as an NSRunLoop, which allows any message (equivalent to a function call in non-[reflective](/source/Reflective_programming) runtimes) to be queued for dispatch to any object.

### File-based

In [Unix](/source/Unix), the [everything is a file](/source/Everything_is_a_file) paradigm leads to a file-based event loop. Reading from and writing to files, inter-process communication, network communication, and device control are all achieved using file I/O, with the target identified by a [file descriptor](/source/File_descriptor). The [select](/source/Select_(Unix)) and [poll](/source/Poll_(Unix)) system calls allow a set of file descriptors to be monitored for a change of state, e.g. when data becomes available to be read.

For example, consider a program that reads from a continuously updated file and displays its contents in the [X Window System](/source/X_Window_System), which communicates with clients over a socket (either [Unix domain](/source/Unix_domain_socket) or [Berkeley](/source/Berkeley_sockets)):

def main():
    file_fd = open("logfile.log")
    x_fd = open_display()
    construct_interface()
    while True:
        rlist, _, _ = select.select([file_fd, x_fd], [], []):
        if file_fd in rlist:
            data = file_fd.read()
            append_to_display(data)
            send_repaint_message()
        if x_fd in rlist:
            process_x_messages()

### Signal-based

In Unix, a [signal](/source/Signal_(IPC)) is an asynchronous event that is handled by a [signal handler](/source/Signal_(IPC)#Handling_signals) which runs while the rest of the task is suspended. If a signal is received and handled while the task is blocking in select(), select will return early with [EINTR](/source/Errno.h); if a signal is received while the task is [CPU bound](/source/CPU_bound), the task will be suspended between instructions until the signal handler returns.

A way to handle a signal is for signal handlers to set a global flag and have the event loop check for the flag immediately before and after the select() call; if it is set, handle the signal in the same manner as with events on file descriptors. Unfortunately, this gives rise to a [race condition](/source/Race_condition): if a signal arrives immediately between checking the flag and calling select(), it will not be handled until select() returns for some other reason (for example, being interrupted by a frustrated user).

The solution arrived at by [POSIX](/source/POSIX) is the pselect() call, which is similar to select() but takes an additional sigmask parameter, which describes a *signal mask*. This allows an application to mask signals in the main task, then remove the mask for the duration of the select() call such that signal handlers are only called while the application is [I/O bound](/source/I%2FO_bound). However, implementations of pselect() have not always been reliable; versions of Linux prior to 2.6.16 do not have a pselect() system call,[4] forcing [glibc](/source/Glibc) to emulate it via a method prone to the very same race condition pselect() is intended to avoid.

An alternative, more portable solution, is to convert asynchronous events to file-based events using the *self-pipe trick*,[5] where "a signal handler writes a byte to a pipe whose other end is monitored by select() in the main program".[6] In [Linux kernel](/source/Linux_kernel) version 2.6.22, a new system call signalfd() was added, which allows receiving signals via a special file descriptor.

### JavaScript and Asynchronous Execution

In environments such as web browsers and Node.js, the event loop is central to asynchronous program behavior. JavaScript runs on a single thread for execution, but host environments provide APIs for non-blocking operations, such as timers, network requests, and user events. Completed asynchronous operations are placed in queues, and the event loop repeatedly checks whether the call stack is empty to schedule queued callbacks. This enables JavaScript applications to remain responsive while handling multiple asynchronous tasks. [7]

## See also

- [Asynchronous I/O](/source/Asynchronous_I%2FO)

- [Event-driven programming](/source/Event-driven_programming)

- [Game loop](/source/Game_loop)

- [Inter-process communication](/source/Inter-process_communication)

- [Message passing](/source/Message_passing)

## References

1. **[^](#cite_ref-1)** ["JavaScript execution model - JavaScript | MDN"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model). *MDN Web Docs*. 2025-11-07. Retrieved 2026-01-03.

1. **[^](#cite_ref-2)** ["JavaScript execution model - JavaScript | MDN"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model). *MDN Web Docs*. 2025-11-07. Retrieved 2026-01-03.

1. **[^](#cite_ref-3)** [GetMessage() function](https://msdn.microsoft.com/en-us/library/ms644936.aspx) with message priority list.

1. **[^](#cite_ref-4)** ["Linux_2_6_16 - Linux Kernel Newbies"](https://kernelnewbies.org/Linux_2_6_16). *kernelnewbies.org*. Retrieved 2021-03-03.

1. **[^](#cite_ref-5)** D. J. Bernstein. ["The self-pipe trick"](http://cr.yp.to/docs/selfpipe.html).

1. **[^](#cite_ref-6)** BUGS, [pselect(2)](https://man7.org/linux/man-pages/man2/pselect.2.html): synchronous I/O multiplexing – [Linux](/source/Linux) Programmer's [Manual](/source/Man_page) – System Calls

1. **[^](#cite_ref-7)** ["JavaScript execution model - JavaScript | MDN"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model). *MDN Web Docs*. 2025-11-07. Retrieved 2026-01-03.

## External links

- [Meandering Through the Maze of MFC Message and Command Routing](http://www.microsoft.com/msj/0795/dilascia/dilascia.aspx)

- [Using Messages and Message Queues (MSDN)](https://msdn.microsoft.com/en-us/library/ms644928.aspx)

- [Using Window Procedures (MSDN)](https://msdn.microsoft.com/en-us/library/ms633570.aspx)

- [WindowProc (MSDN)](https://msdn.microsoft.com/en-us/library/ms633573.aspx)

---
Adapted from the Wikipedia article [Event loop](https://en.wikipedia.org/wiki/Event_loop) by Wikipedia contributors ([contributor history](https://en.wikipedia.org/wiki/Event_loop?action=history)). Available under [Creative Commons Attribution-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-sa/4.0/). Changes may have been made.
