abstract class Crystal::EventLoop::Polling

Overview

Polling EventLoop.

This is the abstract interface that implements Crystal::EventLoop for polling based UNIX targets, such as epoll (linux), kqueue (bsd), or poll (posix) syscalls. This class only implements the generic parts for the external world to interact with the loop. A specific implementation is required to handle the actual syscalls. See Crystal::Epoll::EventLoop and Crystal::Kqueue::EventLoop.

The event loop registers the fd into the kernel data structures when an IO operation would block, then keeps it there until the fd is closed.

NOTE the fds must have O_NONBLOCK set.

It is possible to have multiple event loop instances, but an fd can only be in one instance at a time. When trying to block from another loop, the fd will be removed from its associated loop and added to the current one (this is automatic). Trying to move a fd to another loop with pending waiters is unsupported and will raise an exception. See PollDescriptor#remove.

A timed event such as sleep or select timeout follows the following logic:

  1. create an Event (actually reuses it, see FiberChannel);
  2. register the event in @timers;
  3. supend the current fiber.

The timer will eventually trigger and resume the fiber. When an IO operation on fd would block, the loop follows the following logic:

  1. register the fd (once);
  2. create an Event;
  3. suspend the current fiber;

When the IO operation is ready, the fiber will eventually be resumed (one fiber at a time). If it's an IO operation, the operation is tried again which may block again, until the operation succeeds or an error occured (e.g. closed, broken pipe).

If the IO operation has a timeout, the event is also registered into @timers before suspending the fiber, then after resume it will raise IO::TimeoutError if the event timed out, and continue otherwise.

Direct Known Subclasses

Defined in:

crystal/event_loop/polling.cr:2
crystal/event_loop/polling.cr:58

Instance Method Summary

Instance methods inherited from class Crystal::EventLoop

create_resume_event(fiber : Fiber) : Event create_resume_event, create_timeout_event(fiber : Fiber) : Event create_timeout_event, interrupt : Nil interrupt, run(blocking : Bool) : Bool run

Constructor methods inherited from class Crystal::EventLoop

create : self create, current : self current

Class methods inherited from class Crystal::EventLoop

backend_class backend_class, current? : self | Nil current?, remove(file_descriptor : Crystal::System::FileDescriptor) : Nil
remove(socket : ::Socket) : Nil
remove

Instance methods inherited from module Crystal::EventLoop::Socket

accept(socket : ::Socket) : ::Socket::Handle | Nil accept, close(socket : ::Socket) : Nil close, connect(socket : ::Socket, address : ::Socket::Addrinfo | ::Socket::Address, timeout : Time::Span | Nil) : IO::Error | Nil connect, read(socket : ::Socket, slice : Bytes) : Int32 read, receive_from(socket : ::Socket, slice : Bytes) : Tuple(Int32, ::Socket::Address) receive_from, send_to(socket : ::Socket, slice : Bytes, address : ::Socket::Address) : Int32 send_to, write(socket : ::Socket, slice : Bytes) : Int32 write

Instance methods inherited from module Crystal::EventLoop::FileDescriptor

close(file_descriptor : Crystal::System::FileDescriptor) : Nil close, read(file_descriptor : Crystal::System::FileDescriptor, slice : Bytes) : Int32 read, write(file_descriptor : Crystal::System::FileDescriptor, slice : Bytes) : Int32 write

Instance methods inherited from class Reference

==(other : self)
==(other : JSON::Any)
==(other : YAML::Any)
==(other)
==
, dup dup, hash(hasher) hash, initialize initialize, inspect(io : IO) : Nil inspect, object_id : UInt64 object_id, pretty_print(pp) : Nil pretty_print, same?(other : Reference) : Bool
same?(other : Nil)
same?
, to_s(io : IO) : Nil to_s

Constructor methods inherited from class Reference

new new, unsafe_construct(address : Pointer, *args, **opts) : self unsafe_construct

Class methods inherited from class Reference

pre_initialize(address : Pointer) pre_initialize

Instance methods inherited from class Object

! : Bool !, !=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other)
===
, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash
hash
, in?(collection : Object) : Bool
in?(*values : Object) : Bool
in?
, inspect(io : IO) : Nil
inspect : String
inspect
, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil!
not_nil!
, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String
to_json
, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil
to_pretty_json
, to_s(io : IO) : Nil
to_s : String
to_s
, to_yaml(io : IO) : Nil
to_yaml : String
to_yaml
, try(&) try, unsafe_as(type : T.class) forall T unsafe_as

Class methods inherited from class Object

from_json(string_or_io, root : String)
from_json(string_or_io)
from_json
, from_yaml(string_or_io : String | IO) from_yaml

Macros inherited from class Object

class_getter(*names, &block) class_getter, class_getter!(*names) class_getter!, class_getter?(*names, &block) class_getter?, class_property(*names, &block) class_property, class_property!(*names) class_property!, class_property?(*names, &block) class_property?, class_setter(*names) class_setter, def_clone def_clone, def_equals(*fields) def_equals, def_equals_and_hash(*fields) def_equals_and_hash, def_hash(*fields) def_hash, delegate(*methods, to object) delegate, forward_missing_to(delegate) forward_missing_to, getter(*names, &block) getter, getter!(*names) getter!, getter?(*names, &block) getter?, property(*names, &block) property, property!(*names) property!, property?(*names, &block) property?, setter(*names) setter

Instance Method Detail

def accept(socket : ::Socket) : ::Socket::Handle | Nil #
Description copied from module Crystal::EventLoop::Socket

Accepts an incoming TCP connection on the socket.

Blocks the current fiber if no connection is waiting, continuing when one becomes available. Otherwise returns immediately.

Returns a handle to the socket for the new connection.


[View source]
def after_fork : Nil #

no parallelism issues, but let's clean-up anyway


[View source]
def after_fork_before_exec : Nil #

reset the mutexes since another thread may have acquired the lock of one event loop, which would prevent closing file descriptors for example.


[View source]
def close(file_descriptor : System::FileDescriptor) : Nil #
Description copied from module Crystal::EventLoop::FileDescriptor

Closes the file descriptor resource.


[View source]
def close(socket : ::Socket) : Nil #
Description copied from module Crystal::EventLoop::Socket

Closes the socket.


[View source]
def connect(socket : ::Socket, address : ::Socket::Addrinfo | ::Socket::Address, timeout : Time::Span | Nil) : IO::Error | Nil #
Description copied from module Crystal::EventLoop::Socket

Opens a connection on socket to the target address.

Blocks the current fiber and continues when the connection is established.

Returns IO::Error in case of an error. The caller is responsible for raising it as an exception if necessary.


[View source]
def create_resume_event(fiber : Fiber) : FiberEvent #
Description copied from class Crystal::EventLoop

Create a new resume event for a fiber.


[View source]
def create_timeout_event(fiber : Fiber) : FiberEvent #
Description copied from class Crystal::EventLoop

Creates a timeout_event.


[View source]
def read(file_descriptor : System::FileDescriptor, slice : Bytes) : Int32 #
Description copied from module Crystal::EventLoop::FileDescriptor

Reads at least one byte from the file descriptor into slice.

Blocks the current fiber if no data is available for reading, continuing when available. Otherwise returns immediately.

Returns the number of bytes read (up to slice.size). Returns 0 when EOF is reached.


[View source]
def read(socket : ::Socket, slice : Bytes) : Int32 #
Description copied from module Crystal::EventLoop::Socket

Reads at least one byte from the socket into slice.

Blocks the current fiber if no data is available for reading, continuing when available. Otherwise returns immediately.

Returns the number of bytes read (up to slice.size). Returns 0 when the socket is closed and no data available.

Use #receive_from for capturing the source address of a message.


[View source]
def receive_from(socket : ::Socket, slice : Bytes) : Tuple(Int32, ::Socket::Address) #
Description copied from module Crystal::EventLoop::Socket

Receives at least one byte from the socket into slice, capturing the source address.

Blocks the current fiber if no data is available for reading, continuing when available. Otherwise returns immediately.

Returns a tuple containing the number of bytes received (up to slice.size) and the source address.


[View source]
def run(blocking : Bool) : Bool #

NOTE thread unsafe


[View source]
def send_to(socket : ::Socket, slice : Bytes, address : ::Socket::Address) : Int32 #
Description copied from module Crystal::EventLoop::Socket

Sends at least one byte from slice to the socket with a target address address.

Blocks the current fiber if the socket is not ready for writing, continuing when ready. Otherwise returns immediately.

Returns the number of bytes sent (up to slice.size).


[View source]
def write(file_descriptor : System::FileDescriptor, slice : Bytes) : Int32 #
Description copied from module Crystal::EventLoop::FileDescriptor

Writes at least one byte from slice to the file descriptor.

Blocks the current fiber if the file descriptor isn't ready for writing, continuing when ready. Otherwise returns immediately.

Returns the number of bytes written (up to slice.size).


[View source]
def write(socket : ::Socket, slice : Bytes) : Int32 #
Description copied from module Crystal::EventLoop::Socket

Writes at least one byte from slice to the socket.

Blocks the current fiber if the socket is not ready for writing, continuing when ready. Otherwise returns immediately.

Returns the number of bytes written (up to slice.size).

Use #send_to for sending a message to a specific target address.


[View source]